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 fprintf(output, "Compiled Expression : %d elements\n",
1684 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1687 #ifdef XP_DEBUG_OBJ_USAGE
1690 * XPath object usage related debugging variables.
1692 static int xmlXPathDebugObjCounterUndefined = 0;
1693 static int xmlXPathDebugObjCounterNodeset = 0;
1694 static int xmlXPathDebugObjCounterBool = 0;
1695 static int xmlXPathDebugObjCounterNumber = 0;
1696 static int xmlXPathDebugObjCounterString = 0;
1697 static int xmlXPathDebugObjCounterPoint = 0;
1698 static int xmlXPathDebugObjCounterRange = 0;
1699 static int xmlXPathDebugObjCounterLocset = 0;
1700 static int xmlXPathDebugObjCounterUsers = 0;
1701 static int xmlXPathDebugObjCounterXSLTTree = 0;
1702 static int xmlXPathDebugObjCounterAll = 0;
1704 static int xmlXPathDebugObjTotalUndefined = 0;
1705 static int xmlXPathDebugObjTotalNodeset = 0;
1706 static int xmlXPathDebugObjTotalBool = 0;
1707 static int xmlXPathDebugObjTotalNumber = 0;
1708 static int xmlXPathDebugObjTotalString = 0;
1709 static int xmlXPathDebugObjTotalPoint = 0;
1710 static int xmlXPathDebugObjTotalRange = 0;
1711 static int xmlXPathDebugObjTotalLocset = 0;
1712 static int xmlXPathDebugObjTotalUsers = 0;
1713 static int xmlXPathDebugObjTotalXSLTTree = 0;
1714 static int xmlXPathDebugObjTotalAll = 0;
1716 static int xmlXPathDebugObjMaxUndefined = 0;
1717 static int xmlXPathDebugObjMaxNodeset = 0;
1718 static int xmlXPathDebugObjMaxBool = 0;
1719 static int xmlXPathDebugObjMaxNumber = 0;
1720 static int xmlXPathDebugObjMaxString = 0;
1721 static int xmlXPathDebugObjMaxPoint = 0;
1722 static int xmlXPathDebugObjMaxRange = 0;
1723 static int xmlXPathDebugObjMaxLocset = 0;
1724 static int xmlXPathDebugObjMaxUsers = 0;
1725 static int xmlXPathDebugObjMaxXSLTTree = 0;
1726 static int xmlXPathDebugObjMaxAll = 0;
1728 /* REVISIT TODO: Make this static when committing */
1730 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1733 if (ctxt->cache != NULL) {
1734 xmlXPathContextCachePtr cache =
1735 (xmlXPathContextCachePtr) ctxt->cache;
1737 cache->dbgCachedAll = 0;
1738 cache->dbgCachedNodeset = 0;
1739 cache->dbgCachedString = 0;
1740 cache->dbgCachedBool = 0;
1741 cache->dbgCachedNumber = 0;
1742 cache->dbgCachedPoint = 0;
1743 cache->dbgCachedRange = 0;
1744 cache->dbgCachedLocset = 0;
1745 cache->dbgCachedUsers = 0;
1746 cache->dbgCachedXSLTTree = 0;
1747 cache->dbgCachedUndefined = 0;
1749 cache->dbgReusedAll = 0;
1750 cache->dbgReusedNodeset = 0;
1751 cache->dbgReusedString = 0;
1752 cache->dbgReusedBool = 0;
1753 cache->dbgReusedNumber = 0;
1754 cache->dbgReusedPoint = 0;
1755 cache->dbgReusedRange = 0;
1756 cache->dbgReusedLocset = 0;
1757 cache->dbgReusedUsers = 0;
1758 cache->dbgReusedXSLTTree = 0;
1759 cache->dbgReusedUndefined = 0;
1763 xmlXPathDebugObjCounterUndefined = 0;
1764 xmlXPathDebugObjCounterNodeset = 0;
1765 xmlXPathDebugObjCounterBool = 0;
1766 xmlXPathDebugObjCounterNumber = 0;
1767 xmlXPathDebugObjCounterString = 0;
1768 xmlXPathDebugObjCounterPoint = 0;
1769 xmlXPathDebugObjCounterRange = 0;
1770 xmlXPathDebugObjCounterLocset = 0;
1771 xmlXPathDebugObjCounterUsers = 0;
1772 xmlXPathDebugObjCounterXSLTTree = 0;
1773 xmlXPathDebugObjCounterAll = 0;
1775 xmlXPathDebugObjTotalUndefined = 0;
1776 xmlXPathDebugObjTotalNodeset = 0;
1777 xmlXPathDebugObjTotalBool = 0;
1778 xmlXPathDebugObjTotalNumber = 0;
1779 xmlXPathDebugObjTotalString = 0;
1780 xmlXPathDebugObjTotalPoint = 0;
1781 xmlXPathDebugObjTotalRange = 0;
1782 xmlXPathDebugObjTotalLocset = 0;
1783 xmlXPathDebugObjTotalUsers = 0;
1784 xmlXPathDebugObjTotalXSLTTree = 0;
1785 xmlXPathDebugObjTotalAll = 0;
1787 xmlXPathDebugObjMaxUndefined = 0;
1788 xmlXPathDebugObjMaxNodeset = 0;
1789 xmlXPathDebugObjMaxBool = 0;
1790 xmlXPathDebugObjMaxNumber = 0;
1791 xmlXPathDebugObjMaxString = 0;
1792 xmlXPathDebugObjMaxPoint = 0;
1793 xmlXPathDebugObjMaxRange = 0;
1794 xmlXPathDebugObjMaxLocset = 0;
1795 xmlXPathDebugObjMaxUsers = 0;
1796 xmlXPathDebugObjMaxXSLTTree = 0;
1797 xmlXPathDebugObjMaxAll = 0;
1802 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1803 xmlXPathObjectType objType)
1808 if (ctxt->cache != NULL) {
1809 xmlXPathContextCachePtr cache =
1810 (xmlXPathContextCachePtr) ctxt->cache;
1814 cache->dbgReusedAll++;
1816 case XPATH_UNDEFINED:
1817 cache->dbgReusedUndefined++;
1820 cache->dbgReusedNodeset++;
1823 cache->dbgReusedBool++;
1826 cache->dbgReusedNumber++;
1829 cache->dbgReusedString++;
1832 cache->dbgReusedPoint++;
1835 cache->dbgReusedRange++;
1837 case XPATH_LOCATIONSET:
1838 cache->dbgReusedLocset++;
1841 cache->dbgReusedUsers++;
1843 case XPATH_XSLT_TREE:
1844 cache->dbgReusedXSLTTree++;
1853 case XPATH_UNDEFINED:
1855 xmlXPathDebugObjTotalUndefined++;
1856 xmlXPathDebugObjCounterUndefined++;
1857 if (xmlXPathDebugObjCounterUndefined >
1858 xmlXPathDebugObjMaxUndefined)
1859 xmlXPathDebugObjMaxUndefined =
1860 xmlXPathDebugObjCounterUndefined;
1864 xmlXPathDebugObjTotalNodeset++;
1865 xmlXPathDebugObjCounterNodeset++;
1866 if (xmlXPathDebugObjCounterNodeset >
1867 xmlXPathDebugObjMaxNodeset)
1868 xmlXPathDebugObjMaxNodeset =
1869 xmlXPathDebugObjCounterNodeset;
1873 xmlXPathDebugObjTotalBool++;
1874 xmlXPathDebugObjCounterBool++;
1875 if (xmlXPathDebugObjCounterBool >
1876 xmlXPathDebugObjMaxBool)
1877 xmlXPathDebugObjMaxBool =
1878 xmlXPathDebugObjCounterBool;
1882 xmlXPathDebugObjTotalNumber++;
1883 xmlXPathDebugObjCounterNumber++;
1884 if (xmlXPathDebugObjCounterNumber >
1885 xmlXPathDebugObjMaxNumber)
1886 xmlXPathDebugObjMaxNumber =
1887 xmlXPathDebugObjCounterNumber;
1891 xmlXPathDebugObjTotalString++;
1892 xmlXPathDebugObjCounterString++;
1893 if (xmlXPathDebugObjCounterString >
1894 xmlXPathDebugObjMaxString)
1895 xmlXPathDebugObjMaxString =
1896 xmlXPathDebugObjCounterString;
1900 xmlXPathDebugObjTotalPoint++;
1901 xmlXPathDebugObjCounterPoint++;
1902 if (xmlXPathDebugObjCounterPoint >
1903 xmlXPathDebugObjMaxPoint)
1904 xmlXPathDebugObjMaxPoint =
1905 xmlXPathDebugObjCounterPoint;
1909 xmlXPathDebugObjTotalRange++;
1910 xmlXPathDebugObjCounterRange++;
1911 if (xmlXPathDebugObjCounterRange >
1912 xmlXPathDebugObjMaxRange)
1913 xmlXPathDebugObjMaxRange =
1914 xmlXPathDebugObjCounterRange;
1916 case XPATH_LOCATIONSET:
1918 xmlXPathDebugObjTotalLocset++;
1919 xmlXPathDebugObjCounterLocset++;
1920 if (xmlXPathDebugObjCounterLocset >
1921 xmlXPathDebugObjMaxLocset)
1922 xmlXPathDebugObjMaxLocset =
1923 xmlXPathDebugObjCounterLocset;
1927 xmlXPathDebugObjTotalUsers++;
1928 xmlXPathDebugObjCounterUsers++;
1929 if (xmlXPathDebugObjCounterUsers >
1930 xmlXPathDebugObjMaxUsers)
1931 xmlXPathDebugObjMaxUsers =
1932 xmlXPathDebugObjCounterUsers;
1934 case XPATH_XSLT_TREE:
1936 xmlXPathDebugObjTotalXSLTTree++;
1937 xmlXPathDebugObjCounterXSLTTree++;
1938 if (xmlXPathDebugObjCounterXSLTTree >
1939 xmlXPathDebugObjMaxXSLTTree)
1940 xmlXPathDebugObjMaxXSLTTree =
1941 xmlXPathDebugObjCounterXSLTTree;
1947 xmlXPathDebugObjTotalAll++;
1948 xmlXPathDebugObjCounterAll++;
1949 if (xmlXPathDebugObjCounterAll >
1950 xmlXPathDebugObjMaxAll)
1951 xmlXPathDebugObjMaxAll =
1952 xmlXPathDebugObjCounterAll;
1956 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1957 xmlXPathObjectType objType)
1962 if (ctxt->cache != NULL) {
1963 xmlXPathContextCachePtr cache =
1964 (xmlXPathContextCachePtr) ctxt->cache;
1968 cache->dbgCachedAll++;
1970 case XPATH_UNDEFINED:
1971 cache->dbgCachedUndefined++;
1974 cache->dbgCachedNodeset++;
1977 cache->dbgCachedBool++;
1980 cache->dbgCachedNumber++;
1983 cache->dbgCachedString++;
1986 cache->dbgCachedPoint++;
1989 cache->dbgCachedRange++;
1991 case XPATH_LOCATIONSET:
1992 cache->dbgCachedLocset++;
1995 cache->dbgCachedUsers++;
1997 case XPATH_XSLT_TREE:
1998 cache->dbgCachedXSLTTree++;
2007 case XPATH_UNDEFINED:
2008 xmlXPathDebugObjCounterUndefined--;
2011 xmlXPathDebugObjCounterNodeset--;
2014 xmlXPathDebugObjCounterBool--;
2017 xmlXPathDebugObjCounterNumber--;
2020 xmlXPathDebugObjCounterString--;
2023 xmlXPathDebugObjCounterPoint--;
2026 xmlXPathDebugObjCounterRange--;
2028 case XPATH_LOCATIONSET:
2029 xmlXPathDebugObjCounterLocset--;
2032 xmlXPathDebugObjCounterUsers--;
2034 case XPATH_XSLT_TREE:
2035 xmlXPathDebugObjCounterXSLTTree--;
2040 xmlXPathDebugObjCounterAll--;
2043 /* REVISIT TODO: Make this static when committing */
2045 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2047 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2048 reqXSLTTree, reqUndefined;
2049 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2050 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2051 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2052 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2053 int leftObjs = xmlXPathDebugObjCounterAll;
2055 reqAll = xmlXPathDebugObjTotalAll;
2056 reqNodeset = xmlXPathDebugObjTotalNodeset;
2057 reqString = xmlXPathDebugObjTotalString;
2058 reqBool = xmlXPathDebugObjTotalBool;
2059 reqNumber = xmlXPathDebugObjTotalNumber;
2060 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2061 reqUndefined = xmlXPathDebugObjTotalUndefined;
2063 printf("# XPath object usage:\n");
2066 if (ctxt->cache != NULL) {
2067 xmlXPathContextCachePtr cache =
2068 (xmlXPathContextCachePtr) ctxt->cache;
2070 reAll = cache->dbgReusedAll;
2072 reNodeset = cache->dbgReusedNodeset;
2073 reqNodeset += reNodeset;
2074 reString = cache->dbgReusedString;
2075 reqString += reString;
2076 reBool = cache->dbgReusedBool;
2078 reNumber = cache->dbgReusedNumber;
2079 reqNumber += reNumber;
2080 reXSLTTree = cache->dbgReusedXSLTTree;
2081 reqXSLTTree += reXSLTTree;
2082 reUndefined = cache->dbgReusedUndefined;
2083 reqUndefined += reUndefined;
2085 caAll = cache->dbgCachedAll;
2086 caBool = cache->dbgCachedBool;
2087 caNodeset = cache->dbgCachedNodeset;
2088 caString = cache->dbgCachedString;
2089 caNumber = cache->dbgCachedNumber;
2090 caXSLTTree = cache->dbgCachedXSLTTree;
2091 caUndefined = cache->dbgCachedUndefined;
2093 if (cache->nodesetObjs)
2094 leftObjs -= cache->nodesetObjs->number;
2095 if (cache->stringObjs)
2096 leftObjs -= cache->stringObjs->number;
2097 if (cache->booleanObjs)
2098 leftObjs -= cache->booleanObjs->number;
2099 if (cache->numberObjs)
2100 leftObjs -= cache->numberObjs->number;
2101 if (cache->miscObjs)
2102 leftObjs -= cache->miscObjs->number;
2107 printf("# total : %d\n", reqAll);
2108 printf("# left : %d\n", leftObjs);
2109 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2110 printf("# reused : %d\n", reAll);
2111 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2113 printf("# node-sets\n");
2114 printf("# total : %d\n", reqNodeset);
2115 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2116 printf("# reused : %d\n", reNodeset);
2117 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2119 printf("# strings\n");
2120 printf("# total : %d\n", reqString);
2121 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2122 printf("# reused : %d\n", reString);
2123 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2125 printf("# booleans\n");
2126 printf("# total : %d\n", reqBool);
2127 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2128 printf("# reused : %d\n", reBool);
2129 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2131 printf("# numbers\n");
2132 printf("# total : %d\n", reqNumber);
2133 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2134 printf("# reused : %d\n", reNumber);
2135 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2137 printf("# XSLT result tree fragments\n");
2138 printf("# total : %d\n", reqXSLTTree);
2139 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2140 printf("# reused : %d\n", reXSLTTree);
2141 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2143 printf("# undefined\n");
2144 printf("# total : %d\n", reqUndefined);
2145 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2146 printf("# reused : %d\n", reUndefined);
2147 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2151 #endif /* XP_DEBUG_OBJ_USAGE */
2153 #endif /* LIBXML_DEBUG_ENABLED */
2155 /************************************************************************
2157 * XPath object caching *
2159 ************************************************************************/
2164 * Create a new object cache
2166 * Returns the xmlXPathCache just allocated.
2168 static xmlXPathContextCachePtr
2169 xmlXPathNewCache(void)
2171 xmlXPathContextCachePtr ret;
2173 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2175 xmlXPathErrMemory(NULL, "creating object cache\n");
2178 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2179 ret->maxNodeset = 100;
2180 ret->maxString = 100;
2181 ret->maxBoolean = 100;
2182 ret->maxNumber = 100;
2188 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2191 xmlXPathObjectPtr obj;
2196 for (i = 0; i < list->number; i++) {
2197 obj = list->items[i];
2199 * Note that it is already assured that we don't need to
2200 * look out for namespace nodes in the node-set.
2202 if (obj->nodesetval != NULL) {
2203 if (obj->nodesetval->nodeTab != NULL)
2204 xmlFree(obj->nodesetval->nodeTab);
2205 xmlFree(obj->nodesetval);
2208 #ifdef XP_DEBUG_OBJ_USAGE
2209 xmlXPathDebugObjCounterAll--;
2212 xmlPointerListFree(list);
2216 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2220 if (cache->nodesetObjs)
2221 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2222 if (cache->stringObjs)
2223 xmlXPathCacheFreeObjectList(cache->stringObjs);
2224 if (cache->booleanObjs)
2225 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2226 if (cache->numberObjs)
2227 xmlXPathCacheFreeObjectList(cache->numberObjs);
2228 if (cache->miscObjs)
2229 xmlXPathCacheFreeObjectList(cache->miscObjs);
2234 * xmlXPathContextSetCache:
2236 * @ctxt: the XPath context
2237 * @active: enables/disables (creates/frees) the cache
2238 * @value: a value with semantics dependant on @options
2239 * @options: options (currently only the value 0 is used)
2241 * Creates/frees an object cache on the XPath context.
2242 * If activates XPath objects (xmlXPathObject) will be cached internally
2245 * 0: This will set the XPath object caching:
2247 * This will set the maximum number of XPath objects
2248 * to be cached per slot
2249 * There are 5 slots for: node-set, string, number, boolean, and
2250 * misc objects. Use <0 for the default number (100).
2251 * Other values for @options have currently no effect.
2253 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2256 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2264 xmlXPathContextCachePtr cache;
2266 if (ctxt->cache == NULL) {
2267 ctxt->cache = xmlXPathNewCache();
2268 if (ctxt->cache == NULL)
2271 cache = (xmlXPathContextCachePtr) ctxt->cache;
2275 cache->maxNodeset = value;
2276 cache->maxString = value;
2277 cache->maxNumber = value;
2278 cache->maxBoolean = value;
2279 cache->maxMisc = value;
2281 } else if (ctxt->cache != NULL) {
2282 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2289 * xmlXPathCacheWrapNodeSet:
2290 * @ctxt: the XPath context
2291 * @val: the NodePtr value
2293 * This is the cached version of xmlXPathWrapNodeSet().
2294 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2296 * Returns the created or reused object.
2298 static xmlXPathObjectPtr
2299 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2301 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2302 xmlXPathContextCachePtr cache =
2303 (xmlXPathContextCachePtr) ctxt->cache;
2305 if ((cache->miscObjs != NULL) &&
2306 (cache->miscObjs->number != 0))
2308 xmlXPathObjectPtr ret;
2310 ret = (xmlXPathObjectPtr)
2311 cache->miscObjs->items[--cache->miscObjs->number];
2312 ret->type = XPATH_NODESET;
2313 ret->nodesetval = val;
2314 #ifdef XP_DEBUG_OBJ_USAGE
2315 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2321 return(xmlXPathWrapNodeSet(val));
2326 * xmlXPathCacheWrapString:
2327 * @ctxt: the XPath context
2328 * @val: the xmlChar * value
2330 * This is the cached version of xmlXPathWrapString().
2331 * Wraps the @val string into an XPath object.
2333 * Returns the created or reused object.
2335 static xmlXPathObjectPtr
2336 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2338 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2339 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2341 if ((cache->stringObjs != NULL) &&
2342 (cache->stringObjs->number != 0))
2345 xmlXPathObjectPtr ret;
2347 ret = (xmlXPathObjectPtr)
2348 cache->stringObjs->items[--cache->stringObjs->number];
2349 ret->type = XPATH_STRING;
2350 ret->stringval = val;
2351 #ifdef XP_DEBUG_OBJ_USAGE
2352 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2355 } else if ((cache->miscObjs != NULL) &&
2356 (cache->miscObjs->number != 0))
2358 xmlXPathObjectPtr ret;
2360 * Fallback to misc-cache.
2362 ret = (xmlXPathObjectPtr)
2363 cache->miscObjs->items[--cache->miscObjs->number];
2365 ret->type = XPATH_STRING;
2366 ret->stringval = val;
2367 #ifdef XP_DEBUG_OBJ_USAGE
2368 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2373 return(xmlXPathWrapString(val));
2377 * xmlXPathCacheNewNodeSet:
2378 * @ctxt: the XPath context
2379 * @val: the NodePtr value
2381 * This is the cached version of xmlXPathNewNodeSet().
2382 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2383 * it with the single Node @val
2385 * Returns the created or reused object.
2387 static xmlXPathObjectPtr
2388 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2390 if ((ctxt != NULL) && (ctxt->cache)) {
2391 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2393 if ((cache->nodesetObjs != NULL) &&
2394 (cache->nodesetObjs->number != 0))
2396 xmlXPathObjectPtr ret;
2398 * Use the nodset-cache.
2400 ret = (xmlXPathObjectPtr)
2401 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2402 ret->type = XPATH_NODESET;
2405 if ((ret->nodesetval->nodeMax == 0) ||
2406 (val->type == XML_NAMESPACE_DECL))
2408 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2410 ret->nodesetval->nodeTab[0] = val;
2411 ret->nodesetval->nodeNr = 1;
2414 #ifdef XP_DEBUG_OBJ_USAGE
2415 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2418 } else if ((cache->miscObjs != NULL) &&
2419 (cache->miscObjs->number != 0))
2421 xmlXPathObjectPtr ret;
2423 * Fallback to misc-cache.
2426 ret = (xmlXPathObjectPtr)
2427 cache->miscObjs->items[--cache->miscObjs->number];
2429 ret->type = XPATH_NODESET;
2431 ret->nodesetval = xmlXPathNodeSetCreate(val);
2432 if (ret->nodesetval == NULL) {
2433 ctxt->lastError.domain = XML_FROM_XPATH;
2434 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2437 #ifdef XP_DEBUG_OBJ_USAGE
2438 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2443 return(xmlXPathNewNodeSet(val));
2447 * xmlXPathCacheNewCString:
2448 * @ctxt: the XPath context
2449 * @val: the char * value
2451 * This is the cached version of xmlXPathNewCString().
2452 * Acquire an xmlXPathObjectPtr of type string and of value @val
2454 * Returns the created or reused object.
2456 static xmlXPathObjectPtr
2457 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2459 if ((ctxt != NULL) && (ctxt->cache)) {
2460 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2462 if ((cache->stringObjs != NULL) &&
2463 (cache->stringObjs->number != 0))
2465 xmlXPathObjectPtr ret;
2467 ret = (xmlXPathObjectPtr)
2468 cache->stringObjs->items[--cache->stringObjs->number];
2470 ret->type = XPATH_STRING;
2471 ret->stringval = xmlStrdup(BAD_CAST val);
2472 #ifdef XP_DEBUG_OBJ_USAGE
2473 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2476 } else if ((cache->miscObjs != NULL) &&
2477 (cache->miscObjs->number != 0))
2479 xmlXPathObjectPtr ret;
2481 ret = (xmlXPathObjectPtr)
2482 cache->miscObjs->items[--cache->miscObjs->number];
2484 ret->type = XPATH_STRING;
2485 ret->stringval = xmlStrdup(BAD_CAST val);
2486 #ifdef XP_DEBUG_OBJ_USAGE
2487 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2492 return(xmlXPathNewCString(val));
2496 * xmlXPathCacheNewString:
2497 * @ctxt: the XPath context
2498 * @val: the xmlChar * value
2500 * This is the cached version of xmlXPathNewString().
2501 * Acquire an xmlXPathObjectPtr of type string and of value @val
2503 * Returns the created or reused object.
2505 static xmlXPathObjectPtr
2506 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2508 if ((ctxt != NULL) && (ctxt->cache)) {
2509 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2511 if ((cache->stringObjs != NULL) &&
2512 (cache->stringObjs->number != 0))
2514 xmlXPathObjectPtr ret;
2516 ret = (xmlXPathObjectPtr)
2517 cache->stringObjs->items[--cache->stringObjs->number];
2518 ret->type = XPATH_STRING;
2520 ret->stringval = xmlStrdup(val);
2522 ret->stringval = xmlStrdup((const xmlChar *)"");
2523 #ifdef XP_DEBUG_OBJ_USAGE
2524 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2527 } else if ((cache->miscObjs != NULL) &&
2528 (cache->miscObjs->number != 0))
2530 xmlXPathObjectPtr ret;
2532 ret = (xmlXPathObjectPtr)
2533 cache->miscObjs->items[--cache->miscObjs->number];
2535 ret->type = XPATH_STRING;
2537 ret->stringval = xmlStrdup(val);
2539 ret->stringval = xmlStrdup((const xmlChar *)"");
2540 #ifdef XP_DEBUG_OBJ_USAGE
2541 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2546 return(xmlXPathNewString(val));
2550 * xmlXPathCacheNewBoolean:
2551 * @ctxt: the XPath context
2552 * @val: the boolean value
2554 * This is the cached version of xmlXPathNewBoolean().
2555 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2557 * Returns the created or reused object.
2559 static xmlXPathObjectPtr
2560 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2562 if ((ctxt != NULL) && (ctxt->cache)) {
2563 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2565 if ((cache->booleanObjs != NULL) &&
2566 (cache->booleanObjs->number != 0))
2568 xmlXPathObjectPtr ret;
2570 ret = (xmlXPathObjectPtr)
2571 cache->booleanObjs->items[--cache->booleanObjs->number];
2572 ret->type = XPATH_BOOLEAN;
2573 ret->boolval = (val != 0);
2574 #ifdef XP_DEBUG_OBJ_USAGE
2575 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2578 } else if ((cache->miscObjs != NULL) &&
2579 (cache->miscObjs->number != 0))
2581 xmlXPathObjectPtr ret;
2583 ret = (xmlXPathObjectPtr)
2584 cache->miscObjs->items[--cache->miscObjs->number];
2586 ret->type = XPATH_BOOLEAN;
2587 ret->boolval = (val != 0);
2588 #ifdef XP_DEBUG_OBJ_USAGE
2589 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2594 return(xmlXPathNewBoolean(val));
2598 * xmlXPathCacheNewFloat:
2599 * @ctxt: the XPath context
2600 * @val: the double value
2602 * This is the cached version of xmlXPathNewFloat().
2603 * Acquires an xmlXPathObjectPtr of type double and of value @val
2605 * Returns the created or reused object.
2607 static xmlXPathObjectPtr
2608 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2610 if ((ctxt != NULL) && (ctxt->cache)) {
2611 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2613 if ((cache->numberObjs != NULL) &&
2614 (cache->numberObjs->number != 0))
2616 xmlXPathObjectPtr ret;
2618 ret = (xmlXPathObjectPtr)
2619 cache->numberObjs->items[--cache->numberObjs->number];
2620 ret->type = XPATH_NUMBER;
2621 ret->floatval = val;
2622 #ifdef XP_DEBUG_OBJ_USAGE
2623 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2626 } else if ((cache->miscObjs != NULL) &&
2627 (cache->miscObjs->number != 0))
2629 xmlXPathObjectPtr ret;
2631 ret = (xmlXPathObjectPtr)
2632 cache->miscObjs->items[--cache->miscObjs->number];
2634 ret->type = XPATH_NUMBER;
2635 ret->floatval = val;
2636 #ifdef XP_DEBUG_OBJ_USAGE
2637 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2642 return(xmlXPathNewFloat(val));
2646 * xmlXPathCacheConvertString:
2647 * @ctxt: the XPath context
2648 * @val: an XPath object
2650 * This is the cached version of xmlXPathConvertString().
2651 * Converts an existing object to its string() equivalent
2653 * Returns a created or reused object, the old one is freed (cached)
2654 * (or the operation is done directly on @val)
2657 static xmlXPathObjectPtr
2658 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2659 xmlChar *res = NULL;
2662 return(xmlXPathCacheNewCString(ctxt, ""));
2664 switch (val->type) {
2665 case XPATH_UNDEFINED:
2667 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2671 case XPATH_XSLT_TREE:
2672 res = xmlXPathCastNodeSetToString(val->nodesetval);
2677 res = xmlXPathCastBooleanToString(val->boolval);
2680 res = xmlXPathCastNumberToString(val->floatval);
2685 case XPATH_LOCATIONSET:
2689 xmlXPathReleaseObject(ctxt, val);
2691 return(xmlXPathCacheNewCString(ctxt, ""));
2692 return(xmlXPathCacheWrapString(ctxt, res));
2696 * xmlXPathCacheObjectCopy:
2697 * @ctxt: the XPath context
2698 * @val: the original object
2700 * This is the cached version of xmlXPathObjectCopy().
2701 * Acquire a copy of a given object
2703 * Returns a created or reused created object.
2705 static xmlXPathObjectPtr
2706 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2711 if (XP_HAS_CACHE(ctxt)) {
2712 switch (val->type) {
2714 return(xmlXPathCacheWrapNodeSet(ctxt,
2715 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2717 return(xmlXPathCacheNewString(ctxt, val->stringval));
2719 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2721 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2726 return(xmlXPathObjectCopy(val));
2730 * xmlXPathCacheConvertBoolean:
2731 * @ctxt: the XPath context
2732 * @val: an XPath object
2734 * This is the cached version of xmlXPathConvertBoolean().
2735 * Converts an existing object to its boolean() equivalent
2737 * Returns a created or reused object, the old one is freed (or the operation
2738 * is done directly on @val)
2740 static xmlXPathObjectPtr
2741 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2742 xmlXPathObjectPtr ret;
2745 return(xmlXPathCacheNewBoolean(ctxt, 0));
2746 if (val->type == XPATH_BOOLEAN)
2748 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2749 xmlXPathReleaseObject(ctxt, val);
2754 * xmlXPathCacheConvertNumber:
2755 * @ctxt: the XPath context
2756 * @val: an XPath object
2758 * This is the cached version of xmlXPathConvertNumber().
2759 * Converts an existing object to its number() equivalent
2761 * Returns a created or reused object, the old one is freed (or the operation
2762 * is done directly on @val)
2764 static xmlXPathObjectPtr
2765 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2766 xmlXPathObjectPtr ret;
2769 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2770 if (val->type == XPATH_NUMBER)
2772 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2773 xmlXPathReleaseObject(ctxt, val);
2777 /************************************************************************
2779 * Parser stacks related functions and macros *
2781 ************************************************************************/
2785 * @ctxt: an XPath parser context
2787 * Set the callee evaluation frame
2789 * Returns the previous frame value to be restored once done
2792 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2797 ret = ctxt->valueFrame;
2798 ctxt->valueFrame = ctxt->valueNr;
2804 * @ctxt: an XPath parser context
2805 * @frame: the previous frame value
2807 * Remove the callee evaluation frame
2810 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2813 if (ctxt->valueNr < ctxt->valueFrame) {
2814 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2816 ctxt->valueFrame = frame;
2821 * @ctxt: an XPath evaluation context
2823 * Pops the top XPath object from the value stack
2825 * Returns the XPath object just removed
2828 valuePop(xmlXPathParserContextPtr ctxt)
2830 xmlXPathObjectPtr ret;
2832 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2835 if (ctxt->valueNr <= ctxt->valueFrame) {
2836 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2841 if (ctxt->valueNr > 0)
2842 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2845 ret = ctxt->valueTab[ctxt->valueNr];
2846 ctxt->valueTab[ctxt->valueNr] = NULL;
2851 * @ctxt: an XPath evaluation context
2852 * @value: the XPath object
2854 * Pushes a new XPath object on top of the value stack
2856 * returns the number of items on the value stack
2859 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2861 if ((ctxt == NULL) || (value == NULL)) return(-1);
2862 if (ctxt->valueNr >= ctxt->valueMax) {
2863 xmlXPathObjectPtr *tmp;
2865 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2866 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2867 ctxt->error = XPATH_MEMORY_ERROR;
2870 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2871 2 * ctxt->valueMax *
2872 sizeof(ctxt->valueTab[0]));
2874 xmlXPathErrMemory(NULL, "pushing value\n");
2875 ctxt->error = XPATH_MEMORY_ERROR;
2878 ctxt->valueMax *= 2;
2879 ctxt->valueTab = tmp;
2881 ctxt->valueTab[ctxt->valueNr] = value;
2882 ctxt->value = value;
2883 return (ctxt->valueNr++);
2887 * xmlXPathPopBoolean:
2888 * @ctxt: an XPath parser context
2890 * Pops a boolean from the stack, handling conversion if needed.
2891 * Check error with #xmlXPathCheckError.
2893 * Returns the boolean
2896 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2897 xmlXPathObjectPtr obj;
2900 obj = valuePop(ctxt);
2902 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2905 if (obj->type != XPATH_BOOLEAN)
2906 ret = xmlXPathCastToBoolean(obj);
2909 xmlXPathReleaseObject(ctxt->context, obj);
2914 * xmlXPathPopNumber:
2915 * @ctxt: an XPath parser context
2917 * Pops a number from the stack, handling conversion if needed.
2918 * Check error with #xmlXPathCheckError.
2920 * Returns the number
2923 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2924 xmlXPathObjectPtr obj;
2927 obj = valuePop(ctxt);
2929 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2932 if (obj->type != XPATH_NUMBER)
2933 ret = xmlXPathCastToNumber(obj);
2935 ret = obj->floatval;
2936 xmlXPathReleaseObject(ctxt->context, obj);
2941 * xmlXPathPopString:
2942 * @ctxt: an XPath parser context
2944 * Pops a string from the stack, handling conversion if needed.
2945 * Check error with #xmlXPathCheckError.
2947 * Returns the string
2950 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2951 xmlXPathObjectPtr obj;
2954 obj = valuePop(ctxt);
2956 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2959 ret = xmlXPathCastToString(obj); /* this does required strdup */
2960 /* TODO: needs refactoring somewhere else */
2961 if (obj->stringval == ret)
2962 obj->stringval = NULL;
2963 xmlXPathReleaseObject(ctxt->context, obj);
2968 * xmlXPathPopNodeSet:
2969 * @ctxt: an XPath parser context
2971 * Pops a node-set from the stack, handling conversion if needed.
2972 * Check error with #xmlXPathCheckError.
2974 * Returns the node-set
2977 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2978 xmlXPathObjectPtr obj;
2981 if (ctxt == NULL) return(NULL);
2982 if (ctxt->value == NULL) {
2983 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2986 if (!xmlXPathStackIsNodeSet(ctxt)) {
2987 xmlXPathSetTypeError(ctxt);
2990 obj = valuePop(ctxt);
2991 ret = obj->nodesetval;
2993 /* to fix memory leak of not clearing obj->user */
2994 if (obj->boolval && obj->user != NULL)
2995 xmlFreeNodeList((xmlNodePtr) obj->user);
2997 obj->nodesetval = NULL;
2998 xmlXPathReleaseObject(ctxt->context, obj);
3003 * xmlXPathPopExternal:
3004 * @ctxt: an XPath parser context
3006 * Pops an external object from the stack, handling conversion if needed.
3007 * Check error with #xmlXPathCheckError.
3009 * Returns the object
3012 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3013 xmlXPathObjectPtr obj;
3016 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3017 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3020 if (ctxt->value->type != XPATH_USERS) {
3021 xmlXPathSetTypeError(ctxt);
3024 obj = valuePop(ctxt);
3027 xmlXPathReleaseObject(ctxt->context, obj);
3032 * Macros for accessing the content. Those should be used only by the parser,
3035 * Dirty macros, i.e. one need to make assumption on the context to use them
3037 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3038 * CUR returns the current xmlChar value, i.e. a 8 bit value
3039 * in ISO-Latin or UTF-8.
3040 * This should be used internally by the parser
3041 * only to compare to ASCII values otherwise it would break when
3042 * running with UTF-8 encoding.
3043 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3044 * to compare on ASCII based substring.
3045 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3046 * strings within the parser.
3047 * CURRENT Returns the current char value, with the full decoding of
3048 * UTF-8 if we are using this mode. It returns an int.
3049 * NEXT Skip to the next character, this does the proper decoding
3050 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3051 * It returns the pointer to the current xmlChar.
3054 #define CUR (*ctxt->cur)
3055 #define SKIP(val) ctxt->cur += (val)
3056 #define NXT(val) ctxt->cur[(val)]
3057 #define CUR_PTR ctxt->cur
3058 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3060 #define COPY_BUF(l,b,i,v) \
3061 if (l == 1) b[i++] = (xmlChar) v; \
3062 else i += xmlCopyChar(l,&b[i],v)
3064 #define NEXTL(l) ctxt->cur += l
3066 #define SKIP_BLANKS \
3067 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3069 #define CURRENT (*ctxt->cur)
3070 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3077 #define DBL_EPSILON 1E-9
3080 #define UPPER_DOUBLE 1E9
3081 #define LOWER_DOUBLE 1E-5
3082 #define LOWER_DOUBLE_EXP 5
3084 #define INTEGER_DIGITS DBL_DIG
3085 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3086 #define EXPONENT_DIGITS (3 + 2)
3089 * xmlXPathFormatNumber:
3090 * @number: number to format
3091 * @buffer: output buffer
3092 * @buffersize: size of output buffer
3094 * Convert the number into a string representation.
3097 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3099 switch (xmlXPathIsInf(number)) {
3101 if (buffersize > (int)sizeof("Infinity"))
3102 snprintf(buffer, buffersize, "Infinity");
3105 if (buffersize > (int)sizeof("-Infinity"))
3106 snprintf(buffer, buffersize, "-Infinity");
3109 if (xmlXPathIsNaN(number)) {
3110 if (buffersize > (int)sizeof("NaN"))
3111 snprintf(buffer, buffersize, "NaN");
3112 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3113 snprintf(buffer, buffersize, "0");
3114 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3115 (number == (int) number)) {
3118 int value = (int) number;
3124 snprintf(work, 29, "%d", value);
3126 while ((*cur) && (ptr - buffer < buffersize)) {
3130 if (ptr - buffer < buffersize) {
3132 } else if (buffersize > 0) {
3138 For the dimension of work,
3139 DBL_DIG is number of significant digits
3140 EXPONENT is only needed for "scientific notation"
3141 3 is sign, decimal point, and terminating zero
3142 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3143 Note that this dimension is slightly (a few characters)
3144 larger than actually necessary.
3146 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3147 int integer_place, fraction_place;
3149 char *after_fraction;
3150 double absolute_value;
3153 absolute_value = fabs(number);
3156 * First choose format - scientific or regular floating point.
3157 * In either case, result is in work, and after_fraction points
3158 * just past the fractional part.
3160 if ( ((absolute_value > UPPER_DOUBLE) ||
3161 (absolute_value < LOWER_DOUBLE)) &&
3162 (absolute_value != 0.0) ) {
3163 /* Use scientific notation */
3164 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3165 fraction_place = DBL_DIG - 1;
3166 size = snprintf(work, sizeof(work),"%*.*e",
3167 integer_place, fraction_place, number);
3168 while ((size > 0) && (work[size] != 'e')) size--;
3172 /* Use regular notation */
3173 if (absolute_value > 0.0) {
3174 integer_place = (int)log10(absolute_value);
3175 if (integer_place > 0)
3176 fraction_place = DBL_DIG - integer_place - 1;
3178 fraction_place = DBL_DIG - integer_place;
3182 size = snprintf(work, sizeof(work), "%0.*f",
3183 fraction_place, number);
3186 /* Remove leading spaces sometimes inserted by snprintf */
3187 while (work[0] == ' ') {
3188 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3192 /* Remove fractional trailing zeroes */
3193 after_fraction = work + size;
3194 ptr = after_fraction;
3195 while (*(--ptr) == '0')
3199 while ((*ptr++ = *after_fraction++) != 0);
3201 /* Finally copy result back to caller */
3202 size = strlen(work) + 1;
3203 if (size > buffersize) {
3204 work[buffersize - 1] = 0;
3207 memmove(buffer, work, size);
3214 /************************************************************************
3216 * Routines to handle NodeSets *
3218 ************************************************************************/
3221 * xmlXPathOrderDocElems:
3222 * @doc: an input document
3224 * Call this routine to speed up XPath computation on static documents.
3225 * This stamps all the element nodes with the document order
3226 * Like for line information, the order is kept in the element->content
3227 * field, the value stored is actually - the node number (starting at -1)
3228 * to be able to differentiate from line numbers.
3230 * Returns the number of elements found in the document or -1 in case
3234 xmlXPathOrderDocElems(xmlDocPtr doc) {
3240 cur = doc->children;
3241 while (cur != NULL) {
3242 if (cur->type == XML_ELEMENT_NODE) {
3243 cur->content = (void *) (-(++count));
3244 if (cur->children != NULL) {
3245 cur = cur->children;
3249 if (cur->next != NULL) {
3257 if (cur == (xmlNodePtr) doc) {
3261 if (cur->next != NULL) {
3265 } while (cur != NULL);
3272 * @node1: the first node
3273 * @node2: the second node
3275 * Compare two nodes w.r.t document order
3277 * Returns -2 in case of error 1 if first point < second point, 0 if
3278 * it's the same node, -1 otherwise
3281 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3283 int attr1 = 0, attr2 = 0;
3284 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3285 xmlNodePtr cur, root;
3287 if ((node1 == NULL) || (node2 == NULL))
3290 * a couple of optimizations which will avoid computations in most cases
3292 if (node1 == node2) /* trivial case */
3294 if (node1->type == XML_ATTRIBUTE_NODE) {
3297 node1 = node1->parent;
3299 if (node2->type == XML_ATTRIBUTE_NODE) {
3302 node2 = node2->parent;
3304 if (node1 == node2) {
3305 if (attr1 == attr2) {
3306 /* not required, but we keep attributes in order */
3308 cur = attrNode2->prev;
3309 while (cur != NULL) {
3310 if (cur == attrNode1)
3322 if ((node1->type == XML_NAMESPACE_DECL) ||
3323 (node2->type == XML_NAMESPACE_DECL))
3325 if (node1 == node2->prev)
3327 if (node1 == node2->next)
3331 * Speedup using document order if availble.
3333 if ((node1->type == XML_ELEMENT_NODE) &&
3334 (node2->type == XML_ELEMENT_NODE) &&
3335 (0 > (long) node1->content) &&
3336 (0 > (long) node2->content) &&
3337 (node1->doc == node2->doc)) {
3340 l1 = -((long) node1->content);
3341 l2 = -((long) node2->content);
3349 * compute depth to root
3351 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3352 if (cur->parent == node1)
3357 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3358 if (cur->parent == node2)
3363 * Distinct document (or distinct entities :-( ) case.
3369 * get the nearest common ancestor.
3371 while (depth1 > depth2) {
3373 node1 = node1->parent;
3375 while (depth2 > depth1) {
3377 node2 = node2->parent;
3379 while (node1->parent != node2->parent) {
3380 node1 = node1->parent;
3381 node2 = node2->parent;
3382 /* should not happen but just in case ... */
3383 if ((node1 == NULL) || (node2 == NULL))
3389 if (node1 == node2->prev)
3391 if (node1 == node2->next)
3394 * Speedup using document order if availble.
3396 if ((node1->type == XML_ELEMENT_NODE) &&
3397 (node2->type == XML_ELEMENT_NODE) &&
3398 (0 > (long) node1->content) &&
3399 (0 > (long) node2->content) &&
3400 (node1->doc == node2->doc)) {
3403 l1 = -((long) node1->content);
3404 l2 = -((long) node2->content);
3411 for (cur = node1->next;cur != NULL;cur = cur->next)
3414 return(-1); /* assume there is no sibling list corruption */
3418 * xmlXPathNodeSetSort:
3419 * @set: the node set
3421 * Sort the node set in document order
3424 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3425 #ifndef WITH_TIM_SORT
3426 int i, j, incr, len;
3433 #ifndef WITH_TIM_SORT
3435 * Use the old Shell's sort implementation to sort the node-set
3436 * Timsort ought to be quite faster
3439 for (incr = len / 2; incr > 0; incr /= 2) {
3440 for (i = incr; i < len; i++) {
3443 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3444 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3445 set->nodeTab[j + incr]) == -1)
3447 if (xmlXPathCmpNodes(set->nodeTab[j],
3448 set->nodeTab[j + incr]) == -1)
3451 tmp = set->nodeTab[j];
3452 set->nodeTab[j] = set->nodeTab[j + incr];
3453 set->nodeTab[j + incr] = tmp;
3460 #else /* WITH_TIM_SORT */
3461 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3462 #endif /* WITH_TIM_SORT */
3465 #define XML_NODESET_DEFAULT 10
3467 * xmlXPathNodeSetDupNs:
3468 * @node: the parent node of the namespace XPath node
3469 * @ns: the libxml namespace declaration node.
3471 * Namespace node in libxml don't match the XPath semantic. In a node set
3472 * the namespace nodes are duplicated and the next pointer is set to the
3473 * parent node in the XPath semantic.
3475 * Returns the newly created object.
3478 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3481 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3483 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3484 return((xmlNodePtr) ns);
3487 * Allocate a new Namespace and fill the fields.
3489 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3491 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3494 memset(cur, 0, sizeof(xmlNs));
3495 cur->type = XML_NAMESPACE_DECL;
3496 if (ns->href != NULL)
3497 cur->href = xmlStrdup(ns->href);
3498 if (ns->prefix != NULL)
3499 cur->prefix = xmlStrdup(ns->prefix);
3500 cur->next = (xmlNsPtr) node;
3501 return((xmlNodePtr) cur);
3505 * xmlXPathNodeSetFreeNs:
3506 * @ns: the XPath namespace node found in a nodeset.
3508 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3509 * the namespace nodes are duplicated and the next pointer is set to the
3510 * parent node in the XPath semantic. Check if such a node needs to be freed
3513 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3514 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3517 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3518 if (ns->href != NULL)
3519 xmlFree((xmlChar *)ns->href);
3520 if (ns->prefix != NULL)
3521 xmlFree((xmlChar *)ns->prefix);
3527 * xmlXPathNodeSetCreate:
3528 * @val: an initial xmlNodePtr, or NULL
3530 * Create a new xmlNodeSetPtr of type double and of value @val
3532 * Returns the newly created object.
3535 xmlXPathNodeSetCreate(xmlNodePtr val) {
3538 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3540 xmlXPathErrMemory(NULL, "creating nodeset\n");
3543 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3545 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3546 sizeof(xmlNodePtr));
3547 if (ret->nodeTab == NULL) {
3548 xmlXPathErrMemory(NULL, "creating nodeset\n");
3552 memset(ret->nodeTab, 0 ,
3553 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3554 ret->nodeMax = XML_NODESET_DEFAULT;
3555 if (val->type == XML_NAMESPACE_DECL) {
3556 xmlNsPtr ns = (xmlNsPtr) val;
3558 ret->nodeTab[ret->nodeNr++] =
3559 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3561 ret->nodeTab[ret->nodeNr++] = val;
3567 * xmlXPathNodeSetCreateSize:
3568 * @size: the initial size of the set
3570 * Create a new xmlNodeSetPtr of type double and of value @val
3572 * Returns the newly created object.
3574 static xmlNodeSetPtr
3575 xmlXPathNodeSetCreateSize(int size) {
3578 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3580 xmlXPathErrMemory(NULL, "creating nodeset\n");
3583 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3584 if (size < XML_NODESET_DEFAULT)
3585 size = XML_NODESET_DEFAULT;
3586 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3587 if (ret->nodeTab == NULL) {
3588 xmlXPathErrMemory(NULL, "creating nodeset\n");
3592 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3593 ret->nodeMax = size;
3598 * xmlXPathNodeSetContains:
3599 * @cur: the node-set
3602 * checks whether @cur contains @val
3604 * Returns true (1) if @cur contains @val, false (0) otherwise
3607 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3610 if ((cur == NULL) || (val == NULL)) return(0);
3611 if (val->type == XML_NAMESPACE_DECL) {
3612 for (i = 0; i < cur->nodeNr; i++) {
3613 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3616 ns1 = (xmlNsPtr) val;
3617 ns2 = (xmlNsPtr) cur->nodeTab[i];
3620 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3621 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3626 for (i = 0; i < cur->nodeNr; i++) {
3627 if (cur->nodeTab[i] == val)
3635 * xmlXPathNodeSetAddNs:
3636 * @cur: the initial node set
3637 * @node: the hosting node
3638 * @ns: a the namespace node
3640 * add a new namespace node to an existing NodeSet
3642 * Returns 0 in case of success and -1 in case of error
3645 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3649 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3650 (ns->type != XML_NAMESPACE_DECL) ||
3651 (node->type != XML_ELEMENT_NODE))
3654 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3656 * prevent duplicates
3658 for (i = 0;i < cur->nodeNr;i++) {
3659 if ((cur->nodeTab[i] != NULL) &&
3660 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3661 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3662 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3667 * grow the nodeTab if needed
3669 if (cur->nodeMax == 0) {
3670 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3671 sizeof(xmlNodePtr));
3672 if (cur->nodeTab == NULL) {
3673 xmlXPathErrMemory(NULL, "growing nodeset\n");
3676 memset(cur->nodeTab, 0 ,
3677 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3678 cur->nodeMax = XML_NODESET_DEFAULT;
3679 } else if (cur->nodeNr == cur->nodeMax) {
3682 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3683 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3686 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3687 sizeof(xmlNodePtr));
3689 xmlXPathErrMemory(NULL, "growing nodeset\n");
3693 cur->nodeTab = temp;
3695 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3700 * xmlXPathNodeSetAdd:
3701 * @cur: the initial node set
3702 * @val: a new xmlNodePtr
3704 * add a new xmlNodePtr to an existing NodeSet
3706 * Returns 0 in case of success, and -1 in case of error
3709 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3712 if ((cur == NULL) || (val == NULL)) return(-1);
3714 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3716 * prevent duplicates
3718 for (i = 0;i < cur->nodeNr;i++)
3719 if (cur->nodeTab[i] == val) return(0);
3722 * grow the nodeTab if needed
3724 if (cur->nodeMax == 0) {
3725 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3726 sizeof(xmlNodePtr));
3727 if (cur->nodeTab == NULL) {
3728 xmlXPathErrMemory(NULL, "growing nodeset\n");
3731 memset(cur->nodeTab, 0 ,
3732 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3733 cur->nodeMax = XML_NODESET_DEFAULT;
3734 } else if (cur->nodeNr == cur->nodeMax) {
3737 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3738 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3741 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3742 sizeof(xmlNodePtr));
3744 xmlXPathErrMemory(NULL, "growing nodeset\n");
3748 cur->nodeTab = temp;
3750 if (val->type == XML_NAMESPACE_DECL) {
3751 xmlNsPtr ns = (xmlNsPtr) val;
3753 cur->nodeTab[cur->nodeNr++] =
3754 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3756 cur->nodeTab[cur->nodeNr++] = val;
3761 * xmlXPathNodeSetAddUnique:
3762 * @cur: the initial node set
3763 * @val: a new xmlNodePtr
3765 * add a new xmlNodePtr to an existing NodeSet, optimized version
3766 * when we are sure the node is not already in the set.
3768 * Returns 0 in case of success and -1 in case of failure
3771 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3772 if ((cur == NULL) || (val == NULL)) return(-1);
3774 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3776 * grow the nodeTab if needed
3778 if (cur->nodeMax == 0) {
3779 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3780 sizeof(xmlNodePtr));
3781 if (cur->nodeTab == NULL) {
3782 xmlXPathErrMemory(NULL, "growing nodeset\n");
3785 memset(cur->nodeTab, 0 ,
3786 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3787 cur->nodeMax = XML_NODESET_DEFAULT;
3788 } else if (cur->nodeNr == cur->nodeMax) {
3791 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3792 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3795 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3796 sizeof(xmlNodePtr));
3798 xmlXPathErrMemory(NULL, "growing nodeset\n");
3801 cur->nodeTab = temp;
3804 if (val->type == XML_NAMESPACE_DECL) {
3805 xmlNsPtr ns = (xmlNsPtr) val;
3807 cur->nodeTab[cur->nodeNr++] =
3808 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3810 cur->nodeTab[cur->nodeNr++] = val;
3815 * xmlXPathNodeSetMerge:
3816 * @val1: the first NodeSet or NULL
3817 * @val2: the second NodeSet
3819 * Merges two nodesets, all nodes from @val2 are added to @val1
3820 * if @val1 is NULL, a new set is created and copied from @val2
3822 * Returns @val1 once extended or NULL in case of error.
3825 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3826 int i, j, initNr, skip;
3829 if (val2 == NULL) return(val1);
3831 val1 = xmlXPathNodeSetCreate(NULL);
3836 * TODO: The optimization won't work in every case, since
3837 * those nasty namespace nodes need to be added with
3838 * xmlXPathNodeSetDupNs() to the set; thus a pure
3839 * memcpy is not possible.
3840 * If there was a flag on the nodesetval, indicating that
3841 * some temporary nodes are in, that would be helpfull.
3844 * Optimization: Create an equally sized node-set
3845 * and memcpy the content.
3847 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3850 if (val2->nodeNr != 0) {
3851 if (val2->nodeNr == 1)
3852 *(val1->nodeTab) = *(val2->nodeTab);
3854 memcpy(val1->nodeTab, val2->nodeTab,
3855 val2->nodeNr * sizeof(xmlNodePtr));
3857 val1->nodeNr = val2->nodeNr;
3863 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3864 initNr = val1->nodeNr;
3866 for (i = 0;i < val2->nodeNr;i++) {
3867 n2 = val2->nodeTab[i];
3869 * check against duplicates
3872 for (j = 0; j < initNr; j++) {
3873 n1 = val1->nodeTab[j];
3877 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3878 (n2->type == XML_NAMESPACE_DECL)) {
3879 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3880 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3881 ((xmlNsPtr) n2)->prefix)))
3892 * grow the nodeTab if needed
3894 if (val1->nodeMax == 0) {
3895 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3896 sizeof(xmlNodePtr));
3897 if (val1->nodeTab == NULL) {
3898 xmlXPathErrMemory(NULL, "merging nodeset\n");
3901 memset(val1->nodeTab, 0 ,
3902 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3903 val1->nodeMax = XML_NODESET_DEFAULT;
3904 } else if (val1->nodeNr == val1->nodeMax) {
3907 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3908 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3911 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3912 sizeof(xmlNodePtr));
3914 xmlXPathErrMemory(NULL, "merging nodeset\n");
3917 val1->nodeTab = temp;
3920 if (n2->type == XML_NAMESPACE_DECL) {
3921 xmlNsPtr ns = (xmlNsPtr) n2;
3923 val1->nodeTab[val1->nodeNr++] =
3924 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3926 val1->nodeTab[val1->nodeNr++] = n2;
3934 * xmlXPathNodeSetMergeAndClear:
3935 * @set1: the first NodeSet or NULL
3936 * @set2: the second NodeSet
3937 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3939 * Merges two nodesets, all nodes from @set2 are added to @set1
3940 * if @set1 is NULL, a new set is created and copied from @set2.
3941 * Checks for duplicate nodes. Clears set2.
3943 * Returns @set1 once extended or NULL in case of error.
3945 static xmlNodeSetPtr
3946 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3949 if ((set1 == NULL) && (hasNullEntries == 0)) {
3951 * Note that doing a memcpy of the list, namespace nodes are
3952 * just assigned to set1, since set2 is cleared anyway.
3954 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3957 if (set2->nodeNr != 0) {
3958 memcpy(set1->nodeTab, set2->nodeTab,
3959 set2->nodeNr * sizeof(xmlNodePtr));
3960 set1->nodeNr = set2->nodeNr;
3963 int i, j, initNbSet1;
3967 set1 = xmlXPathNodeSetCreate(NULL);
3971 initNbSet1 = set1->nodeNr;
3972 for (i = 0;i < set2->nodeNr;i++) {
3973 n2 = set2->nodeTab[i];
3975 * Skip NULLed entries.
3982 for (j = 0; j < initNbSet1; j++) {
3983 n1 = set1->nodeTab[j];
3986 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3987 (n2->type == XML_NAMESPACE_DECL))
3989 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3990 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3991 ((xmlNsPtr) n2)->prefix)))
3994 * Free the namespace node.
3996 set2->nodeTab[i] = NULL;
3997 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4003 * grow the nodeTab if needed
4005 if (set1->nodeMax == 0) {
4006 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4007 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4008 if (set1->nodeTab == NULL) {
4009 xmlXPathErrMemory(NULL, "merging nodeset\n");
4012 memset(set1->nodeTab, 0,
4013 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4014 set1->nodeMax = XML_NODESET_DEFAULT;
4015 } else if (set1->nodeNr >= set1->nodeMax) {
4018 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4019 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4022 temp = (xmlNodePtr *) xmlRealloc(
4023 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4025 xmlXPathErrMemory(NULL, "merging nodeset\n");
4028 set1->nodeTab = temp;
4031 set1->nodeTab[set1->nodeNr++] = n2;
4041 * xmlXPathNodeSetMergeAndClearNoDupls:
4042 * @set1: the first NodeSet or NULL
4043 * @set2: the second NodeSet
4044 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4046 * Merges two nodesets, all nodes from @set2 are added to @set1
4047 * if @set1 is NULL, a new set is created and copied from @set2.
4048 * Doesn't chack for duplicate nodes. Clears set2.
4050 * Returns @set1 once extended or NULL in case of error.
4052 static xmlNodeSetPtr
4053 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4058 if ((set1 == NULL) && (hasNullEntries == 0)) {
4060 * Note that doing a memcpy of the list, namespace nodes are
4061 * just assigned to set1, since set2 is cleared anyway.
4063 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4066 if (set2->nodeNr != 0) {
4067 memcpy(set1->nodeTab, set2->nodeTab,
4068 set2->nodeNr * sizeof(xmlNodePtr));
4069 set1->nodeNr = set2->nodeNr;
4076 set1 = xmlXPathNodeSetCreate(NULL);
4080 for (i = 0;i < set2->nodeNr;i++) {
4081 n2 = set2->nodeTab[i];
4083 * Skip NULLed entries.
4087 if (set1->nodeMax == 0) {
4088 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4089 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4090 if (set1->nodeTab == NULL) {
4091 xmlXPathErrMemory(NULL, "merging nodeset\n");
4094 memset(set1->nodeTab, 0,
4095 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4096 set1->nodeMax = XML_NODESET_DEFAULT;
4097 } else if (set1->nodeNr >= set1->nodeMax) {
4100 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4101 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4104 temp = (xmlNodePtr *) xmlRealloc(
4105 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4107 xmlXPathErrMemory(NULL, "merging nodeset\n");
4110 set1->nodeTab = temp;
4113 set1->nodeTab[set1->nodeNr++] = n2;
4121 * xmlXPathNodeSetDel:
4122 * @cur: the initial node set
4123 * @val: an xmlNodePtr
4125 * Removes an xmlNodePtr from an existing NodeSet
4128 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4131 if (cur == NULL) return;
4132 if (val == NULL) return;
4135 * find node in nodeTab
4137 for (i = 0;i < cur->nodeNr;i++)
4138 if (cur->nodeTab[i] == val) break;
4140 if (i >= cur->nodeNr) { /* not found */
4142 xmlGenericError(xmlGenericErrorContext,
4143 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4148 if ((cur->nodeTab[i] != NULL) &&
4149 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4150 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4152 for (;i < cur->nodeNr;i++)
4153 cur->nodeTab[i] = cur->nodeTab[i + 1];
4154 cur->nodeTab[cur->nodeNr] = NULL;
4158 * xmlXPathNodeSetRemove:
4159 * @cur: the initial node set
4160 * @val: the index to remove
4162 * Removes an entry from an existing NodeSet list.
4165 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4166 if (cur == NULL) return;
4167 if (val >= cur->nodeNr) return;
4168 if ((cur->nodeTab[val] != NULL) &&
4169 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4170 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4172 for (;val < cur->nodeNr;val++)
4173 cur->nodeTab[val] = cur->nodeTab[val + 1];
4174 cur->nodeTab[cur->nodeNr] = NULL;
4178 * xmlXPathFreeNodeSet:
4179 * @obj: the xmlNodeSetPtr to free
4181 * Free the NodeSet compound (not the actual nodes !).
4184 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4185 if (obj == NULL) return;
4186 if (obj->nodeTab != NULL) {
4189 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4190 for (i = 0;i < obj->nodeNr;i++)
4191 if ((obj->nodeTab[i] != NULL) &&
4192 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4193 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4194 xmlFree(obj->nodeTab);
4200 * xmlXPathNodeSetClearFromPos:
4201 * @set: the node set to be cleared
4202 * @pos: the start position to clear from
4204 * Clears the list from temporary XPath objects (e.g. namespace nodes
4205 * are feed) starting with the entry at @pos, but does *not* free the list
4206 * itself. Sets the length of the list to @pos.
4209 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4211 if ((set == NULL) || (pos >= set->nodeNr))
4213 else if ((hasNsNodes)) {
4217 for (i = pos; i < set->nodeNr; i++) {
4218 node = set->nodeTab[i];
4219 if ((node != NULL) &&
4220 (node->type == XML_NAMESPACE_DECL))
4221 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4228 * xmlXPathNodeSetClear:
4229 * @set: the node set to clear
4231 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4232 * are feed), but does *not* free the list itself. Sets the length of the
4236 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4238 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4242 * xmlXPathNodeSetKeepLast:
4243 * @set: the node set to be cleared
4245 * Move the last node to the first position and clear temporary XPath objects
4246 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4250 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4255 if ((set == NULL) || (set->nodeNr <= 1))
4257 for (i = 0; i < set->nodeNr - 1; i++) {
4258 node = set->nodeTab[i];
4259 if ((node != NULL) &&
4260 (node->type == XML_NAMESPACE_DECL))
4261 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4263 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4268 * xmlXPathFreeValueTree:
4269 * @obj: the xmlNodeSetPtr to free
4271 * Free the NodeSet compound and the actual tree, this is different
4272 * from xmlXPathFreeNodeSet()
4275 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4278 if (obj == NULL) return;
4280 if (obj->nodeTab != NULL) {
4281 for (i = 0;i < obj->nodeNr;i++) {
4282 if (obj->nodeTab[i] != NULL) {
4283 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4284 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4286 xmlFreeNodeList(obj->nodeTab[i]);
4290 xmlFree(obj->nodeTab);
4295 #if defined(DEBUG) || defined(DEBUG_STEP)
4297 * xmlGenericErrorContextNodeSet:
4298 * @output: a FILE * for the output
4299 * @obj: the xmlNodeSetPtr to display
4301 * Quick display of a NodeSet
4304 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4307 if (output == NULL) output = xmlGenericErrorContext;
4309 fprintf(output, "NodeSet == NULL !\n");
4312 if (obj->nodeNr == 0) {
4313 fprintf(output, "NodeSet is empty\n");
4316 if (obj->nodeTab == NULL) {
4317 fprintf(output, " nodeTab == NULL !\n");
4320 for (i = 0; i < obj->nodeNr; i++) {
4321 if (obj->nodeTab[i] == NULL) {
4322 fprintf(output, " NULL !\n");
4325 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4326 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4327 fprintf(output, " /");
4328 else if (obj->nodeTab[i]->name == NULL)
4329 fprintf(output, " noname!");
4330 else fprintf(output, " %s", obj->nodeTab[i]->name);
4332 fprintf(output, "\n");
4337 * xmlXPathNewNodeSet:
4338 * @val: the NodePtr value
4340 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4341 * it with the single Node @val
4343 * Returns the newly created object.
4346 xmlXPathNewNodeSet(xmlNodePtr val) {
4347 xmlXPathObjectPtr ret;
4349 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4351 xmlXPathErrMemory(NULL, "creating nodeset\n");
4354 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4355 ret->type = XPATH_NODESET;
4357 ret->nodesetval = xmlXPathNodeSetCreate(val);
4358 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4359 #ifdef XP_DEBUG_OBJ_USAGE
4360 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4366 * xmlXPathNewValueTree:
4367 * @val: the NodePtr value
4369 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4370 * it with the tree root @val
4372 * Returns the newly created object.
4375 xmlXPathNewValueTree(xmlNodePtr val) {
4376 xmlXPathObjectPtr ret;
4378 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4380 xmlXPathErrMemory(NULL, "creating result value tree\n");
4383 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4384 ret->type = XPATH_XSLT_TREE;
4386 ret->user = (void *) val;
4387 ret->nodesetval = xmlXPathNodeSetCreate(val);
4388 #ifdef XP_DEBUG_OBJ_USAGE
4389 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4395 * xmlXPathNewNodeSetList:
4396 * @val: an existing NodeSet
4398 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4399 * it with the Nodeset @val
4401 * Returns the newly created object.
4404 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4406 xmlXPathObjectPtr ret;
4411 else if (val->nodeTab == NULL)
4412 ret = xmlXPathNewNodeSet(NULL);
4414 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4416 for (i = 1; i < val->nodeNr; ++i) {
4417 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4427 * xmlXPathWrapNodeSet:
4428 * @val: the NodePtr value
4430 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4432 * Returns the newly created object.
4435 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4436 xmlXPathObjectPtr ret;
4438 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4440 xmlXPathErrMemory(NULL, "creating node set object\n");
4443 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4444 ret->type = XPATH_NODESET;
4445 ret->nodesetval = val;
4446 #ifdef XP_DEBUG_OBJ_USAGE
4447 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4453 * xmlXPathFreeNodeSetList:
4454 * @obj: an existing NodeSetList object
4456 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4457 * the list contrary to xmlXPathFreeObject().
4460 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4461 if (obj == NULL) return;
4462 #ifdef XP_DEBUG_OBJ_USAGE
4463 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4469 * xmlXPathDifference:
4470 * @nodes1: a node-set
4471 * @nodes2: a node-set
4473 * Implements the EXSLT - Sets difference() function:
4474 * node-set set:difference (node-set, node-set)
4476 * Returns the difference between the two node sets, or nodes1 if
4480 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4485 if (xmlXPathNodeSetIsEmpty(nodes2))
4488 ret = xmlXPathNodeSetCreate(NULL);
4489 if (xmlXPathNodeSetIsEmpty(nodes1))
4492 l1 = xmlXPathNodeSetGetLength(nodes1);
4494 for (i = 0; i < l1; i++) {
4495 cur = xmlXPathNodeSetItem(nodes1, i);
4496 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4497 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4505 * xmlXPathIntersection:
4506 * @nodes1: a node-set
4507 * @nodes2: a node-set
4509 * Implements the EXSLT - Sets intersection() function:
4510 * node-set set:intersection (node-set, node-set)
4512 * Returns a node set comprising the nodes that are within both the
4513 * node sets passed as arguments
4516 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4517 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4523 if (xmlXPathNodeSetIsEmpty(nodes1))
4525 if (xmlXPathNodeSetIsEmpty(nodes2))
4528 l1 = xmlXPathNodeSetGetLength(nodes1);
4530 for (i = 0; i < l1; i++) {
4531 cur = xmlXPathNodeSetItem(nodes1, i);
4532 if (xmlXPathNodeSetContains(nodes2, cur)) {
4533 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4541 * xmlXPathDistinctSorted:
4542 * @nodes: a node-set, sorted by document order
4544 * Implements the EXSLT - Sets distinct() function:
4545 * node-set set:distinct (node-set)
4547 * Returns a subset of the nodes contained in @nodes, or @nodes if
4551 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4553 xmlHashTablePtr hash;
4558 if (xmlXPathNodeSetIsEmpty(nodes))
4561 ret = xmlXPathNodeSetCreate(NULL);
4564 l = xmlXPathNodeSetGetLength(nodes);
4565 hash = xmlHashCreate (l);
4566 for (i = 0; i < l; i++) {
4567 cur = xmlXPathNodeSetItem(nodes, i);
4568 strval = xmlXPathCastNodeToString(cur);
4569 if (xmlHashLookup(hash, strval) == NULL) {
4570 xmlHashAddEntry(hash, strval, strval);
4571 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4577 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4583 * @nodes: a node-set
4585 * Implements the EXSLT - Sets distinct() function:
4586 * node-set set:distinct (node-set)
4587 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4588 * is called with the sorted node-set
4590 * Returns a subset of the nodes contained in @nodes, or @nodes if
4594 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4595 if (xmlXPathNodeSetIsEmpty(nodes))
4598 xmlXPathNodeSetSort(nodes);
4599 return(xmlXPathDistinctSorted(nodes));
4603 * xmlXPathHasSameNodes:
4604 * @nodes1: a node-set
4605 * @nodes2: a node-set
4607 * Implements the EXSLT - Sets has-same-nodes function:
4608 * boolean set:has-same-node(node-set, node-set)
4610 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4614 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4618 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4619 xmlXPathNodeSetIsEmpty(nodes2))
4622 l = xmlXPathNodeSetGetLength(nodes1);
4623 for (i = 0; i < l; i++) {
4624 cur = xmlXPathNodeSetItem(nodes1, i);
4625 if (xmlXPathNodeSetContains(nodes2, cur))
4632 * xmlXPathNodeLeadingSorted:
4633 * @nodes: a node-set, sorted by document order
4636 * Implements the EXSLT - Sets leading() function:
4637 * node-set set:leading (node-set, node-set)
4639 * Returns the nodes in @nodes that precede @node in document order,
4640 * @nodes if @node is NULL or an empty node-set if @nodes
4641 * doesn't contain @node
4644 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4652 ret = xmlXPathNodeSetCreate(NULL);
4655 if (xmlXPathNodeSetIsEmpty(nodes) ||
4656 (!xmlXPathNodeSetContains(nodes, node)))
4659 l = xmlXPathNodeSetGetLength(nodes);
4660 for (i = 0; i < l; i++) {
4661 cur = xmlXPathNodeSetItem(nodes, i);
4664 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4671 * xmlXPathNodeLeading:
4672 * @nodes: a node-set
4675 * Implements the EXSLT - Sets leading() function:
4676 * node-set set:leading (node-set, node-set)
4677 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4680 * Returns the nodes in @nodes that precede @node in document order,
4681 * @nodes if @node is NULL or an empty node-set if @nodes
4682 * doesn't contain @node
4685 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4686 xmlXPathNodeSetSort(nodes);
4687 return(xmlXPathNodeLeadingSorted(nodes, node));
4691 * xmlXPathLeadingSorted:
4692 * @nodes1: a node-set, sorted by document order
4693 * @nodes2: a node-set, sorted by document order
4695 * Implements the EXSLT - Sets leading() function:
4696 * node-set set:leading (node-set, node-set)
4698 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4699 * in document order, @nodes1 if @nodes2 is NULL or empty or
4700 * an empty node-set if @nodes1 doesn't contain @nodes2
4703 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4704 if (xmlXPathNodeSetIsEmpty(nodes2))
4706 return(xmlXPathNodeLeadingSorted(nodes1,
4707 xmlXPathNodeSetItem(nodes2, 1)));
4712 * @nodes1: a node-set
4713 * @nodes2: a node-set
4715 * Implements the EXSLT - Sets leading() function:
4716 * node-set set:leading (node-set, node-set)
4717 * @nodes1 and @nodes2 are sorted by document order, then
4718 * #exslSetsLeadingSorted is called.
4720 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4721 * in document order, @nodes1 if @nodes2 is NULL or empty or
4722 * an empty node-set if @nodes1 doesn't contain @nodes2
4725 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4726 if (xmlXPathNodeSetIsEmpty(nodes2))
4728 if (xmlXPathNodeSetIsEmpty(nodes1))
4729 return(xmlXPathNodeSetCreate(NULL));
4730 xmlXPathNodeSetSort(nodes1);
4731 xmlXPathNodeSetSort(nodes2);
4732 return(xmlXPathNodeLeadingSorted(nodes1,
4733 xmlXPathNodeSetItem(nodes2, 1)));
4737 * xmlXPathNodeTrailingSorted:
4738 * @nodes: a node-set, sorted by document order
4741 * Implements the EXSLT - Sets trailing() function:
4742 * node-set set:trailing (node-set, node-set)
4744 * Returns the nodes in @nodes that follow @node in document order,
4745 * @nodes if @node is NULL or an empty node-set if @nodes
4746 * doesn't contain @node
4749 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4757 ret = xmlXPathNodeSetCreate(NULL);
4760 if (xmlXPathNodeSetIsEmpty(nodes) ||
4761 (!xmlXPathNodeSetContains(nodes, node)))
4764 l = xmlXPathNodeSetGetLength(nodes);
4765 for (i = l - 1; i >= 0; i--) {
4766 cur = xmlXPathNodeSetItem(nodes, i);
4769 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4772 xmlXPathNodeSetSort(ret); /* bug 413451 */
4777 * xmlXPathNodeTrailing:
4778 * @nodes: a node-set
4781 * Implements the EXSLT - Sets trailing() function:
4782 * node-set set:trailing (node-set, node-set)
4783 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4786 * Returns the nodes in @nodes that follow @node in document order,
4787 * @nodes if @node is NULL or an empty node-set if @nodes
4788 * doesn't contain @node
4791 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4792 xmlXPathNodeSetSort(nodes);
4793 return(xmlXPathNodeTrailingSorted(nodes, node));
4797 * xmlXPathTrailingSorted:
4798 * @nodes1: a node-set, sorted by document order
4799 * @nodes2: a node-set, sorted by document order
4801 * Implements the EXSLT - Sets trailing() function:
4802 * node-set set:trailing (node-set, node-set)
4804 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4805 * in document order, @nodes1 if @nodes2 is NULL or empty or
4806 * an empty node-set if @nodes1 doesn't contain @nodes2
4809 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4810 if (xmlXPathNodeSetIsEmpty(nodes2))
4812 return(xmlXPathNodeTrailingSorted(nodes1,
4813 xmlXPathNodeSetItem(nodes2, 0)));
4818 * @nodes1: a node-set
4819 * @nodes2: a node-set
4821 * Implements the EXSLT - Sets trailing() function:
4822 * node-set set:trailing (node-set, node-set)
4823 * @nodes1 and @nodes2 are sorted by document order, then
4824 * #xmlXPathTrailingSorted is called.
4826 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4827 * in document order, @nodes1 if @nodes2 is NULL or empty or
4828 * an empty node-set if @nodes1 doesn't contain @nodes2
4831 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4832 if (xmlXPathNodeSetIsEmpty(nodes2))
4834 if (xmlXPathNodeSetIsEmpty(nodes1))
4835 return(xmlXPathNodeSetCreate(NULL));
4836 xmlXPathNodeSetSort(nodes1);
4837 xmlXPathNodeSetSort(nodes2);
4838 return(xmlXPathNodeTrailingSorted(nodes1,
4839 xmlXPathNodeSetItem(nodes2, 0)));
4842 /************************************************************************
4844 * Routines to handle extra functions *
4846 ************************************************************************/
4849 * xmlXPathRegisterFunc:
4850 * @ctxt: the XPath context
4851 * @name: the function name
4852 * @f: the function implementation or NULL
4854 * Register a new function. If @f is NULL it unregisters the function
4856 * Returns 0 in case of success, -1 in case of error
4859 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4860 xmlXPathFunction f) {
4861 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4865 * xmlXPathRegisterFuncNS:
4866 * @ctxt: the XPath context
4867 * @name: the function name
4868 * @ns_uri: the function namespace URI
4869 * @f: the function implementation or NULL
4871 * Register a new function. If @f is NULL it unregisters the function
4873 * Returns 0 in case of success, -1 in case of error
4876 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4877 const xmlChar *ns_uri, xmlXPathFunction f) {
4883 if (ctxt->funcHash == NULL)
4884 ctxt->funcHash = xmlHashCreate(0);
4885 if (ctxt->funcHash == NULL)
4888 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4889 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4893 * xmlXPathRegisterFuncLookup:
4894 * @ctxt: the XPath context
4895 * @f: the lookup function
4896 * @funcCtxt: the lookup data
4898 * Registers an external mechanism to do function lookup.
4901 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4902 xmlXPathFuncLookupFunc f,
4906 ctxt->funcLookupFunc = f;
4907 ctxt->funcLookupData = funcCtxt;
4911 * xmlXPathFunctionLookup:
4912 * @ctxt: the XPath context
4913 * @name: the function name
4915 * Search in the Function array of the context for the given
4918 * Returns the xmlXPathFunction or NULL if not found
4921 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4925 if (ctxt->funcLookupFunc != NULL) {
4926 xmlXPathFunction ret;
4927 xmlXPathFuncLookupFunc f;
4929 f = ctxt->funcLookupFunc;
4930 ret = f(ctxt->funcLookupData, name, NULL);
4934 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4938 * xmlXPathFunctionLookupNS:
4939 * @ctxt: the XPath context
4940 * @name: the function name
4941 * @ns_uri: the function namespace URI
4943 * Search in the Function array of the context for the given
4946 * Returns the xmlXPathFunction or NULL if not found
4949 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4950 const xmlChar *ns_uri) {
4951 xmlXPathFunction ret;
4958 if (ctxt->funcLookupFunc != NULL) {
4959 xmlXPathFuncLookupFunc f;
4961 f = ctxt->funcLookupFunc;
4962 ret = f(ctxt->funcLookupData, name, ns_uri);
4967 if (ctxt->funcHash == NULL)
4970 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4975 * xmlXPathRegisteredFuncsCleanup:
4976 * @ctxt: the XPath context
4978 * Cleanup the XPath context data associated to registered functions
4981 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4985 xmlHashFree(ctxt->funcHash, NULL);
4986 ctxt->funcHash = NULL;
4989 /************************************************************************
4991 * Routines to handle Variables *
4993 ************************************************************************/
4996 * xmlXPathRegisterVariable:
4997 * @ctxt: the XPath context
4998 * @name: the variable name
4999 * @value: the variable value or NULL
5001 * Register a new variable value. If @value is NULL it unregisters
5004 * Returns 0 in case of success, -1 in case of error
5007 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5008 xmlXPathObjectPtr value) {
5009 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5013 * xmlXPathRegisterVariableNS:
5014 * @ctxt: the XPath context
5015 * @name: the variable name
5016 * @ns_uri: the variable namespace URI
5017 * @value: the variable value or NULL
5019 * Register a new variable value. If @value is NULL it unregisters
5022 * Returns 0 in case of success, -1 in case of error
5025 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5026 const xmlChar *ns_uri,
5027 xmlXPathObjectPtr value) {
5033 if (ctxt->varHash == NULL)
5034 ctxt->varHash = xmlHashCreate(0);
5035 if (ctxt->varHash == NULL)
5038 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5039 (xmlHashDeallocator)xmlXPathFreeObject));
5040 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5042 (xmlHashDeallocator)xmlXPathFreeObject));
5046 * xmlXPathRegisterVariableLookup:
5047 * @ctxt: the XPath context
5048 * @f: the lookup function
5049 * @data: the lookup data
5051 * register an external mechanism to do variable lookup
5054 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5055 xmlXPathVariableLookupFunc f, void *data) {
5058 ctxt->varLookupFunc = f;
5059 ctxt->varLookupData = data;
5063 * xmlXPathVariableLookup:
5064 * @ctxt: the XPath context
5065 * @name: the variable name
5067 * Search in the Variable array of the context for the given
5070 * Returns a copy of the value or NULL if not found
5073 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5077 if (ctxt->varLookupFunc != NULL) {
5078 xmlXPathObjectPtr ret;
5080 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5081 (ctxt->varLookupData, name, NULL);
5084 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5088 * xmlXPathVariableLookupNS:
5089 * @ctxt: the XPath context
5090 * @name: the variable name
5091 * @ns_uri: the variable namespace URI
5093 * Search in the Variable array of the context for the given
5096 * Returns the a copy of the value or NULL if not found
5099 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5100 const xmlChar *ns_uri) {
5104 if (ctxt->varLookupFunc != NULL) {
5105 xmlXPathObjectPtr ret;
5107 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5108 (ctxt->varLookupData, name, ns_uri);
5109 if (ret != NULL) return(ret);
5112 if (ctxt->varHash == NULL)
5117 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5118 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5122 * xmlXPathRegisteredVariablesCleanup:
5123 * @ctxt: the XPath context
5125 * Cleanup the XPath context data associated to registered variables
5128 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5132 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5133 ctxt->varHash = NULL;
5137 * xmlXPathRegisterNs:
5138 * @ctxt: the XPath context
5139 * @prefix: the namespace prefix cannot be NULL or empty string
5140 * @ns_uri: the namespace name
5142 * Register a new namespace. If @ns_uri is NULL it unregisters
5145 * Returns 0 in case of success, -1 in case of error
5148 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5149 const xmlChar *ns_uri) {
5157 if (ctxt->nsHash == NULL)
5158 ctxt->nsHash = xmlHashCreate(10);
5159 if (ctxt->nsHash == NULL)
5162 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5163 (xmlHashDeallocator)xmlFree));
5164 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5165 (xmlHashDeallocator)xmlFree));
5170 * @ctxt: the XPath context
5171 * @prefix: the namespace prefix value
5173 * Search in the namespace declaration array of the context for the given
5174 * namespace name associated to the given prefix
5176 * Returns the value or NULL if not found
5179 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5185 #ifdef XML_XML_NAMESPACE
5186 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5187 return(XML_XML_NAMESPACE);
5190 if (ctxt->namespaces != NULL) {
5193 for (i = 0;i < ctxt->nsNr;i++) {
5194 if ((ctxt->namespaces[i] != NULL) &&
5195 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5196 return(ctxt->namespaces[i]->href);
5200 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5204 * xmlXPathRegisteredNsCleanup:
5205 * @ctxt: the XPath context
5207 * Cleanup the XPath context data associated to registered variables
5210 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5214 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5215 ctxt->nsHash = NULL;
5218 /************************************************************************
5220 * Routines to handle Values *
5222 ************************************************************************/
5224 /* Allocations are terrible, one needs to optimize all this !!! */
5228 * @val: the double value
5230 * Create a new xmlXPathObjectPtr of type double and of value @val
5232 * Returns the newly created object.
5235 xmlXPathNewFloat(double val) {
5236 xmlXPathObjectPtr ret;
5238 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5240 xmlXPathErrMemory(NULL, "creating float object\n");
5243 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5244 ret->type = XPATH_NUMBER;
5245 ret->floatval = val;
5246 #ifdef XP_DEBUG_OBJ_USAGE
5247 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5253 * xmlXPathNewBoolean:
5254 * @val: the boolean value
5256 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5258 * Returns the newly created object.
5261 xmlXPathNewBoolean(int val) {
5262 xmlXPathObjectPtr ret;
5264 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5266 xmlXPathErrMemory(NULL, "creating boolean object\n");
5269 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5270 ret->type = XPATH_BOOLEAN;
5271 ret->boolval = (val != 0);
5272 #ifdef XP_DEBUG_OBJ_USAGE
5273 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5279 * xmlXPathNewString:
5280 * @val: the xmlChar * value
5282 * Create a new xmlXPathObjectPtr of type string and of value @val
5284 * Returns the newly created object.
5287 xmlXPathNewString(const xmlChar *val) {
5288 xmlXPathObjectPtr ret;
5290 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5292 xmlXPathErrMemory(NULL, "creating string object\n");
5295 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5296 ret->type = XPATH_STRING;
5298 ret->stringval = xmlStrdup(val);
5300 ret->stringval = xmlStrdup((const xmlChar *)"");
5301 #ifdef XP_DEBUG_OBJ_USAGE
5302 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5308 * xmlXPathWrapString:
5309 * @val: the xmlChar * value
5311 * Wraps the @val string into an XPath object.
5313 * Returns the newly created object.
5316 xmlXPathWrapString (xmlChar *val) {
5317 xmlXPathObjectPtr ret;
5319 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5321 xmlXPathErrMemory(NULL, "creating string object\n");
5324 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5325 ret->type = XPATH_STRING;
5326 ret->stringval = val;
5327 #ifdef XP_DEBUG_OBJ_USAGE
5328 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5334 * xmlXPathNewCString:
5335 * @val: the char * value
5337 * Create a new xmlXPathObjectPtr of type string and of value @val
5339 * Returns the newly created object.
5342 xmlXPathNewCString(const char *val) {
5343 xmlXPathObjectPtr ret;
5345 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5347 xmlXPathErrMemory(NULL, "creating string object\n");
5350 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5351 ret->type = XPATH_STRING;
5352 ret->stringval = xmlStrdup(BAD_CAST val);
5353 #ifdef XP_DEBUG_OBJ_USAGE
5354 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5360 * xmlXPathWrapCString:
5361 * @val: the char * value
5363 * Wraps a string into an XPath object.
5365 * Returns the newly created object.
5368 xmlXPathWrapCString (char * val) {
5369 return(xmlXPathWrapString((xmlChar *)(val)));
5373 * xmlXPathWrapExternal:
5374 * @val: the user data
5376 * Wraps the @val data into an XPath object.
5378 * Returns the newly created object.
5381 xmlXPathWrapExternal (void *val) {
5382 xmlXPathObjectPtr ret;
5384 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5386 xmlXPathErrMemory(NULL, "creating user object\n");
5389 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5390 ret->type = XPATH_USERS;
5392 #ifdef XP_DEBUG_OBJ_USAGE
5393 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5399 * xmlXPathObjectCopy:
5400 * @val: the original object
5402 * allocate a new copy of a given object
5404 * Returns the newly created object.
5407 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5408 xmlXPathObjectPtr ret;
5413 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5415 xmlXPathErrMemory(NULL, "copying object\n");
5418 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5419 #ifdef XP_DEBUG_OBJ_USAGE
5420 xmlXPathDebugObjUsageRequested(NULL, val->type);
5422 switch (val->type) {
5429 ret->stringval = xmlStrdup(val->stringval);
5431 case XPATH_XSLT_TREE:
5434 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5435 this previous handling is no longer correct, and can cause some serious
5436 problems (ref. bug 145547)
5438 if ((val->nodesetval != NULL) &&
5439 (val->nodesetval->nodeTab != NULL)) {
5440 xmlNodePtr cur, tmp;
5444 top = xmlNewDoc(NULL);
5445 top->name = (char *)
5446 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5450 cur = val->nodesetval->nodeTab[0]->children;
5451 while (cur != NULL) {
5452 tmp = xmlDocCopyNode(cur, top, 1);
5453 xmlAddChild((xmlNodePtr) top, tmp);
5458 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5460 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5461 /* Deallocate the copied tree value */
5465 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5466 /* Do not deallocate the copied tree value */
5469 case XPATH_LOCATIONSET:
5470 #ifdef LIBXML_XPTR_ENABLED
5472 xmlLocationSetPtr loc = val->user;
5473 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5478 ret->user = val->user;
5480 case XPATH_UNDEFINED:
5481 xmlGenericError(xmlGenericErrorContext,
5482 "xmlXPathObjectCopy: unsupported type %d\n",
5490 * xmlXPathFreeObject:
5491 * @obj: the object to free
5493 * Free up an xmlXPathObjectPtr object.
5496 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5497 if (obj == NULL) return;
5498 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5501 if (obj->user != NULL) {
5502 xmlXPathFreeNodeSet(obj->nodesetval);
5503 xmlFreeNodeList((xmlNodePtr) obj->user);
5506 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5507 if (obj->nodesetval != NULL)
5508 xmlXPathFreeValueTree(obj->nodesetval);
5510 if (obj->nodesetval != NULL)
5511 xmlXPathFreeNodeSet(obj->nodesetval);
5513 #ifdef LIBXML_XPTR_ENABLED
5514 } else if (obj->type == XPATH_LOCATIONSET) {
5515 if (obj->user != NULL)
5516 xmlXPtrFreeLocationSet(obj->user);
5518 } else if (obj->type == XPATH_STRING) {
5519 if (obj->stringval != NULL)
5520 xmlFree(obj->stringval);
5522 #ifdef XP_DEBUG_OBJ_USAGE
5523 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5529 * xmlXPathReleaseObject:
5530 * @obj: the xmlXPathObjectPtr to free or to cache
5532 * Depending on the state of the cache this frees the given
5533 * XPath object or stores it in the cache.
5536 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5538 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5539 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5540 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5542 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5546 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5547 xmlXPathFreeObject(obj);
5549 xmlXPathContextCachePtr cache =
5550 (xmlXPathContextCachePtr) ctxt->cache;
5552 switch (obj->type) {
5554 case XPATH_XSLT_TREE:
5555 if (obj->nodesetval != NULL) {
5558 * It looks like the @boolval is used for
5559 * evaluation if this an XSLT Result Tree Fragment.
5560 * TODO: Check if this assumption is correct.
5562 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5563 xmlXPathFreeValueTree(obj->nodesetval);
5564 obj->nodesetval = NULL;
5565 } else if ((obj->nodesetval->nodeMax <= 40) &&
5566 (XP_CACHE_WANTS(cache->nodesetObjs,
5567 cache->maxNodeset)))
5569 XP_CACHE_ADD(cache->nodesetObjs, obj);
5572 xmlXPathFreeNodeSet(obj->nodesetval);
5573 obj->nodesetval = NULL;
5578 if (obj->stringval != NULL)
5579 xmlFree(obj->stringval);
5581 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5582 XP_CACHE_ADD(cache->stringObjs, obj);
5587 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5588 XP_CACHE_ADD(cache->booleanObjs, obj);
5593 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5594 XP_CACHE_ADD(cache->numberObjs, obj);
5598 #ifdef LIBXML_XPTR_ENABLED
5599 case XPATH_LOCATIONSET:
5600 if (obj->user != NULL) {
5601 xmlXPtrFreeLocationSet(obj->user);
5610 * Fallback to adding to the misc-objects slot.
5612 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5613 XP_CACHE_ADD(cache->miscObjs, obj);
5619 #ifdef XP_DEBUG_OBJ_USAGE
5620 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5623 if (obj->nodesetval != NULL) {
5624 xmlNodeSetPtr tmpset = obj->nodesetval;
5627 * TODO: Due to those nasty ns-nodes, we need to traverse
5628 * the list and free the ns-nodes.
5629 * URGENT TODO: Check if it's actually slowing things down.
5630 * Maybe we shouldn't try to preserve the list.
5632 if (tmpset->nodeNr > 1) {
5636 for (i = 0; i < tmpset->nodeNr; i++) {
5637 node = tmpset->nodeTab[i];
5638 if ((node != NULL) &&
5639 (node->type == XML_NAMESPACE_DECL))
5641 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5644 } else if (tmpset->nodeNr == 1) {
5645 if ((tmpset->nodeTab[0] != NULL) &&
5646 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5647 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5650 memset(obj, 0, sizeof(xmlXPathObject));
5651 obj->nodesetval = tmpset;
5653 memset(obj, 0, sizeof(xmlXPathObject));
5659 * Cache is full; free the object.
5661 if (obj->nodesetval != NULL)
5662 xmlXPathFreeNodeSet(obj->nodesetval);
5663 #ifdef XP_DEBUG_OBJ_USAGE
5664 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5672 /************************************************************************
5674 * Type Casting Routines *
5676 ************************************************************************/
5679 * xmlXPathCastBooleanToString:
5682 * Converts a boolean to its string value.
5684 * Returns a newly allocated string.
5687 xmlXPathCastBooleanToString (int val) {
5690 ret = xmlStrdup((const xmlChar *) "true");
5692 ret = xmlStrdup((const xmlChar *) "false");
5697 * xmlXPathCastNumberToString:
5700 * Converts a number to its string value.
5702 * Returns a newly allocated string.
5705 xmlXPathCastNumberToString (double val) {
5707 switch (xmlXPathIsInf(val)) {
5709 ret = xmlStrdup((const xmlChar *) "Infinity");
5712 ret = xmlStrdup((const xmlChar *) "-Infinity");
5715 if (xmlXPathIsNaN(val)) {
5716 ret = xmlStrdup((const xmlChar *) "NaN");
5717 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5718 ret = xmlStrdup((const xmlChar *) "0");
5720 /* could be improved */
5722 xmlXPathFormatNumber(val, buf, 99);
5724 ret = xmlStrdup((const xmlChar *) buf);
5731 * xmlXPathCastNodeToString:
5734 * Converts a node to its string value.
5736 * Returns a newly allocated string.
5739 xmlXPathCastNodeToString (xmlNodePtr node) {
5741 if ((ret = xmlNodeGetContent(node)) == NULL)
5742 ret = xmlStrdup((const xmlChar *) "");
5747 * xmlXPathCastNodeSetToString:
5750 * Converts a node-set to its string value.
5752 * Returns a newly allocated string.
5755 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5756 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5757 return(xmlStrdup((const xmlChar *) ""));
5760 xmlXPathNodeSetSort(ns);
5761 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5765 * xmlXPathCastToString:
5766 * @val: an XPath object
5768 * Converts an existing object to its string() equivalent
5770 * Returns the allocated string value of the object, NULL in case of error.
5771 * It's up to the caller to free the string memory with xmlFree().
5774 xmlXPathCastToString(xmlXPathObjectPtr val) {
5775 xmlChar *ret = NULL;
5778 return(xmlStrdup((const xmlChar *) ""));
5779 switch (val->type) {
5780 case XPATH_UNDEFINED:
5782 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5784 ret = xmlStrdup((const xmlChar *) "");
5787 case XPATH_XSLT_TREE:
5788 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5791 return(xmlStrdup(val->stringval));
5793 ret = xmlXPathCastBooleanToString(val->boolval);
5795 case XPATH_NUMBER: {
5796 ret = xmlXPathCastNumberToString(val->floatval);
5802 case XPATH_LOCATIONSET:
5804 ret = xmlStrdup((const xmlChar *) "");
5811 * xmlXPathConvertString:
5812 * @val: an XPath object
5814 * Converts an existing object to its string() equivalent
5816 * Returns the new object, the old one is freed (or the operation
5817 * is done directly on @val)
5820 xmlXPathConvertString(xmlXPathObjectPtr val) {
5821 xmlChar *res = NULL;
5824 return(xmlXPathNewCString(""));
5826 switch (val->type) {
5827 case XPATH_UNDEFINED:
5829 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5833 case XPATH_XSLT_TREE:
5834 res = xmlXPathCastNodeSetToString(val->nodesetval);
5839 res = xmlXPathCastBooleanToString(val->boolval);
5842 res = xmlXPathCastNumberToString(val->floatval);
5847 case XPATH_LOCATIONSET:
5851 xmlXPathFreeObject(val);
5853 return(xmlXPathNewCString(""));
5854 return(xmlXPathWrapString(res));
5858 * xmlXPathCastBooleanToNumber:
5861 * Converts a boolean to its number value
5863 * Returns the number value
5866 xmlXPathCastBooleanToNumber(int val) {
5873 * xmlXPathCastStringToNumber:
5876 * Converts a string to its number value
5878 * Returns the number value
5881 xmlXPathCastStringToNumber(const xmlChar * val) {
5882 return(xmlXPathStringEvalNumber(val));
5886 * xmlXPathCastNodeToNumber:
5889 * Converts a node to its number value
5891 * Returns the number value
5894 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5899 return(xmlXPathNAN);
5900 strval = xmlXPathCastNodeToString(node);
5902 return(xmlXPathNAN);
5903 ret = xmlXPathCastStringToNumber(strval);
5910 * xmlXPathCastNodeSetToNumber:
5913 * Converts a node-set to its number value
5915 * Returns the number value
5918 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5923 return(xmlXPathNAN);
5924 str = xmlXPathCastNodeSetToString(ns);
5925 ret = xmlXPathCastStringToNumber(str);
5931 * xmlXPathCastToNumber:
5932 * @val: an XPath object
5934 * Converts an XPath object to its number value
5936 * Returns the number value
5939 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5943 return(xmlXPathNAN);
5944 switch (val->type) {
5945 case XPATH_UNDEFINED:
5947 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5952 case XPATH_XSLT_TREE:
5953 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5956 ret = xmlXPathCastStringToNumber(val->stringval);
5959 ret = val->floatval;
5962 ret = xmlXPathCastBooleanToNumber(val->boolval);
5967 case XPATH_LOCATIONSET:
5976 * xmlXPathConvertNumber:
5977 * @val: an XPath object
5979 * Converts an existing object to its number() equivalent
5981 * Returns the new object, the old one is freed (or the operation
5982 * is done directly on @val)
5985 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5986 xmlXPathObjectPtr ret;
5989 return(xmlXPathNewFloat(0.0));
5990 if (val->type == XPATH_NUMBER)
5992 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5993 xmlXPathFreeObject(val);
5998 * xmlXPathCastNumberToBoolean:
6001 * Converts a number to its boolean value
6003 * Returns the boolean value
6006 xmlXPathCastNumberToBoolean (double val) {
6007 if (xmlXPathIsNaN(val) || (val == 0.0))
6013 * xmlXPathCastStringToBoolean:
6016 * Converts a string to its boolean value
6018 * Returns the boolean value
6021 xmlXPathCastStringToBoolean (const xmlChar *val) {
6022 if ((val == NULL) || (xmlStrlen(val) == 0))
6028 * xmlXPathCastNodeSetToBoolean:
6031 * Converts a node-set to its boolean value
6033 * Returns the boolean value
6036 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6037 if ((ns == NULL) || (ns->nodeNr == 0))
6043 * xmlXPathCastToBoolean:
6044 * @val: an XPath object
6046 * Converts an XPath object to its boolean value
6048 * Returns the boolean value
6051 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6056 switch (val->type) {
6057 case XPATH_UNDEFINED:
6059 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6064 case XPATH_XSLT_TREE:
6065 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6068 ret = xmlXPathCastStringToBoolean(val->stringval);
6071 ret = xmlXPathCastNumberToBoolean(val->floatval);
6079 case XPATH_LOCATIONSET:
6089 * xmlXPathConvertBoolean:
6090 * @val: an XPath object
6092 * Converts an existing object to its boolean() equivalent
6094 * Returns the new object, the old one is freed (or the operation
6095 * is done directly on @val)
6098 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6099 xmlXPathObjectPtr ret;
6102 return(xmlXPathNewBoolean(0));
6103 if (val->type == XPATH_BOOLEAN)
6105 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6106 xmlXPathFreeObject(val);
6110 /************************************************************************
6112 * Routines to handle XPath contexts *
6114 ************************************************************************/
6117 * xmlXPathNewContext:
6118 * @doc: the XML document
6120 * Create a new xmlXPathContext
6122 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6125 xmlXPathNewContext(xmlDocPtr doc) {
6126 xmlXPathContextPtr ret;
6128 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6130 xmlXPathErrMemory(NULL, "creating context\n");
6133 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6137 ret->varHash = NULL;
6143 ret->funcHash = xmlHashCreate(0);
6152 ret->contextSize = -1;
6153 ret->proximityPosition = -1;
6155 #ifdef XP_DEFAULT_CACHE_ON
6156 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6157 xmlXPathFreeContext(ret);
6162 xmlXPathRegisterAllFunctions(ret);
6168 * xmlXPathFreeContext:
6169 * @ctxt: the context to free
6171 * Free up an xmlXPathContext
6174 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6175 if (ctxt == NULL) return;
6177 if (ctxt->cache != NULL)
6178 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6179 xmlXPathRegisteredNsCleanup(ctxt);
6180 xmlXPathRegisteredFuncsCleanup(ctxt);
6181 xmlXPathRegisteredVariablesCleanup(ctxt);
6182 xmlResetError(&ctxt->lastError);
6186 /************************************************************************
6188 * Routines to handle XPath parser contexts *
6190 ************************************************************************/
6192 #define CHECK_CTXT(ctxt) \
6193 if (ctxt == NULL) { \
6194 __xmlRaiseError(NULL, NULL, NULL, \
6195 NULL, NULL, XML_FROM_XPATH, \
6196 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6197 __FILE__, __LINE__, \
6198 NULL, NULL, NULL, 0, 0, \
6199 "NULL context pointer\n"); \
6203 #define CHECK_CTXT_NEG(ctxt) \
6204 if (ctxt == NULL) { \
6205 __xmlRaiseError(NULL, NULL, NULL, \
6206 NULL, NULL, XML_FROM_XPATH, \
6207 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6208 __FILE__, __LINE__, \
6209 NULL, NULL, NULL, 0, 0, \
6210 "NULL context pointer\n"); \
6215 #define CHECK_CONTEXT(ctxt) \
6216 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6217 (ctxt->doc->children == NULL)) { \
6218 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6224 * xmlXPathNewParserContext:
6225 * @str: the XPath expression
6226 * @ctxt: the XPath context
6228 * Create a new xmlXPathParserContext
6230 * Returns the xmlXPathParserContext just allocated.
6232 xmlXPathParserContextPtr
6233 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6234 xmlXPathParserContextPtr ret;
6236 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6238 xmlXPathErrMemory(ctxt, "creating parser context\n");
6241 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6242 ret->cur = ret->base = str;
6243 ret->context = ctxt;
6245 ret->comp = xmlXPathNewCompExpr();
6246 if (ret->comp == NULL) {
6247 xmlFree(ret->valueTab);
6251 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6252 ret->comp->dict = ctxt->dict;
6253 xmlDictReference(ret->comp->dict);
6260 * xmlXPathCompParserContext:
6261 * @comp: the XPath compiled expression
6262 * @ctxt: the XPath context
6264 * Create a new xmlXPathParserContext when processing a compiled expression
6266 * Returns the xmlXPathParserContext just allocated.
6268 static xmlXPathParserContextPtr
6269 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6270 xmlXPathParserContextPtr ret;
6272 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6274 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6277 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6279 /* Allocate the value stack */
6280 ret->valueTab = (xmlXPathObjectPtr *)
6281 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6282 if (ret->valueTab == NULL) {
6284 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6290 ret->valueFrame = 0;
6292 ret->context = ctxt;
6299 * xmlXPathFreeParserContext:
6300 * @ctxt: the context to free
6302 * Free up an xmlXPathParserContext
6305 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6308 if (ctxt->valueTab != NULL) {
6309 for (i = 0; i < ctxt->valueNr; i++) {
6311 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6313 xmlXPathFreeObject(ctxt->valueTab[i]);
6315 xmlFree(ctxt->valueTab);
6317 if (ctxt->comp != NULL) {
6318 #ifdef XPATH_STREAMING
6319 if (ctxt->comp->stream != NULL) {
6320 xmlFreePatternList(ctxt->comp->stream);
6321 ctxt->comp->stream = NULL;
6324 xmlXPathFreeCompExpr(ctxt->comp);
6329 /************************************************************************
6331 * The implicit core function library *
6333 ************************************************************************/
6336 * xmlXPathNodeValHash:
6337 * @node: a node pointer
6339 * Function computing the beginning of the string value of the node,
6340 * used to speed up comparisons
6342 * Returns an int usable as a hash
6345 xmlXPathNodeValHash(xmlNodePtr node) {
6347 const xmlChar * string = NULL;
6348 xmlNodePtr tmp = NULL;
6349 unsigned int ret = 0;
6354 if (node->type == XML_DOCUMENT_NODE) {
6355 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6357 node = node->children;
6365 switch (node->type) {
6366 case XML_COMMENT_NODE:
6368 case XML_CDATA_SECTION_NODE:
6370 string = node->content;
6375 return(((unsigned int) string[0]) +
6376 (((unsigned int) string[1]) << 8));
6377 case XML_NAMESPACE_DECL:
6378 string = ((xmlNsPtr)node)->href;
6383 return(((unsigned int) string[0]) +
6384 (((unsigned int) string[1]) << 8));
6385 case XML_ATTRIBUTE_NODE:
6386 tmp = ((xmlAttrPtr) node)->children;
6388 case XML_ELEMENT_NODE:
6389 tmp = node->children;
6394 while (tmp != NULL) {
6395 switch (tmp->type) {
6396 case XML_COMMENT_NODE:
6398 case XML_CDATA_SECTION_NODE:
6400 string = tmp->content;
6402 case XML_NAMESPACE_DECL:
6403 string = ((xmlNsPtr)tmp)->href;
6408 if ((string != NULL) && (string[0] != 0)) {
6410 return(ret + (((unsigned int) string[0]) << 8));
6412 if (string[1] == 0) {
6414 ret = (unsigned int) string[0];
6416 return(((unsigned int) string[0]) +
6417 (((unsigned int) string[1]) << 8));
6423 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6424 if (tmp->children->type != XML_ENTITY_DECL) {
6425 tmp = tmp->children;
6432 if (tmp->next != NULL) {
6445 if (tmp->next != NULL) {
6449 } while (tmp != NULL);
6455 * xmlXPathStringHash:
6458 * Function computing the beginning of the string value of the node,
6459 * used to speed up comparisons
6461 * Returns an int usable as a hash
6464 xmlXPathStringHash(const xmlChar * string) {
6466 return((unsigned int) 0);
6469 return(((unsigned int) string[0]) +
6470 (((unsigned int) string[1]) << 8));
6474 * xmlXPathCompareNodeSetFloat:
6475 * @ctxt: the XPath Parser context
6476 * @inf: less than (1) or greater than (0)
6477 * @strict: is the comparison strict
6478 * @arg: the node set
6481 * Implement the compare operation between a nodeset and a number
6482 * @ns < @val (1, 1, ...
6483 * @ns <= @val (1, 0, ...
6484 * @ns > @val (0, 1, ...
6485 * @ns >= @val (0, 0, ...
6487 * If one object to be compared is a node-set and the other is a number,
6488 * then the comparison will be true if and only if there is a node in the
6489 * node-set such that the result of performing the comparison on the number
6490 * to be compared and on the result of converting the string-value of that
6491 * node to a number using the number function is true.
6493 * Returns 0 or 1 depending on the results of the test.
6496 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6497 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6502 if ((f == NULL) || (arg == NULL) ||
6503 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6504 xmlXPathReleaseObject(ctxt->context, arg);
6505 xmlXPathReleaseObject(ctxt->context, f);
6508 ns = arg->nodesetval;
6510 for (i = 0;i < ns->nodeNr;i++) {
6511 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6514 xmlXPathCacheNewString(ctxt->context, str2));
6516 xmlXPathNumberFunction(ctxt, 1);
6517 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6518 ret = xmlXPathCompareValues(ctxt, inf, strict);
6524 xmlXPathReleaseObject(ctxt->context, arg);
6525 xmlXPathReleaseObject(ctxt->context, f);
6530 * xmlXPathCompareNodeSetString:
6531 * @ctxt: the XPath Parser context
6532 * @inf: less than (1) or greater than (0)
6533 * @strict: is the comparison strict
6534 * @arg: the node set
6537 * Implement the compare operation between a nodeset and a string
6538 * @ns < @val (1, 1, ...
6539 * @ns <= @val (1, 0, ...
6540 * @ns > @val (0, 1, ...
6541 * @ns >= @val (0, 0, ...
6543 * If one object to be compared is a node-set and the other is a string,
6544 * then the comparison will be true if and only if there is a node in
6545 * the node-set such that the result of performing the comparison on the
6546 * string-value of the node and the other string is true.
6548 * Returns 0 or 1 depending on the results of the test.
6551 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6552 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6557 if ((s == NULL) || (arg == NULL) ||
6558 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6559 xmlXPathReleaseObject(ctxt->context, arg);
6560 xmlXPathReleaseObject(ctxt->context, s);
6563 ns = arg->nodesetval;
6565 for (i = 0;i < ns->nodeNr;i++) {
6566 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6569 xmlXPathCacheNewString(ctxt->context, str2));
6571 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6572 ret = xmlXPathCompareValues(ctxt, inf, strict);
6578 xmlXPathReleaseObject(ctxt->context, arg);
6579 xmlXPathReleaseObject(ctxt->context, s);
6584 * xmlXPathCompareNodeSets:
6585 * @inf: less than (1) or greater than (0)
6586 * @strict: is the comparison strict
6587 * @arg1: the first node set object
6588 * @arg2: the second node set object
6590 * Implement the compare operation on nodesets:
6592 * If both objects to be compared are node-sets, then the comparison
6593 * will be true if and only if there is a node in the first node-set
6594 * and a node in the second node-set such that the result of performing
6595 * the comparison on the string-values of the two nodes is true.
6597 * When neither object to be compared is a node-set and the operator
6598 * is <=, <, >= or >, then the objects are compared by converting both
6599 * objects to numbers and comparing the numbers according to IEEE 754.
6601 * The number function converts its argument to a number as follows:
6602 * - a string that consists of optional whitespace followed by an
6603 * optional minus sign followed by a Number followed by whitespace
6604 * is converted to the IEEE 754 number that is nearest (according
6605 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6606 * represented by the string; any other string is converted to NaN
6608 * Conclusion all nodes need to be converted first to their string value
6609 * and then the comparison must be done when possible
6612 xmlXPathCompareNodeSets(int inf, int strict,
6613 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6621 if ((arg1 == NULL) ||
6622 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6623 xmlXPathFreeObject(arg2);
6626 if ((arg2 == NULL) ||
6627 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6628 xmlXPathFreeObject(arg1);
6629 xmlXPathFreeObject(arg2);
6633 ns1 = arg1->nodesetval;
6634 ns2 = arg2->nodesetval;
6636 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6637 xmlXPathFreeObject(arg1);
6638 xmlXPathFreeObject(arg2);
6641 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6642 xmlXPathFreeObject(arg1);
6643 xmlXPathFreeObject(arg2);
6647 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6648 if (values2 == NULL) {
6649 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6650 xmlXPathFreeObject(arg1);
6651 xmlXPathFreeObject(arg2);
6654 for (i = 0;i < ns1->nodeNr;i++) {
6655 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6656 if (xmlXPathIsNaN(val1))
6658 for (j = 0;j < ns2->nodeNr;j++) {
6660 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6662 if (xmlXPathIsNaN(values2[j]))
6665 ret = (val1 < values2[j]);
6666 else if (inf && !strict)
6667 ret = (val1 <= values2[j]);
6668 else if (!inf && strict)
6669 ret = (val1 > values2[j]);
6670 else if (!inf && !strict)
6671 ret = (val1 >= values2[j]);
6680 xmlXPathFreeObject(arg1);
6681 xmlXPathFreeObject(arg2);
6686 * xmlXPathCompareNodeSetValue:
6687 * @ctxt: the XPath Parser context
6688 * @inf: less than (1) or greater than (0)
6689 * @strict: is the comparison strict
6690 * @arg: the node set
6693 * Implement the compare operation between a nodeset and a value
6694 * @ns < @val (1, 1, ...
6695 * @ns <= @val (1, 0, ...
6696 * @ns > @val (0, 1, ...
6697 * @ns >= @val (0, 0, ...
6699 * If one object to be compared is a node-set and the other is a boolean,
6700 * then the comparison will be true if and only if the result of performing
6701 * the comparison on the boolean and on the result of converting
6702 * the node-set to a boolean using the boolean function is true.
6704 * Returns 0 or 1 depending on the results of the test.
6707 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6708 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6709 if ((val == NULL) || (arg == NULL) ||
6710 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6715 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6717 case XPATH_XSLT_TREE:
6718 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6720 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6722 valuePush(ctxt, arg);
6723 xmlXPathBooleanFunction(ctxt, 1);
6724 valuePush(ctxt, val);
6725 return(xmlXPathCompareValues(ctxt, inf, strict));
6727 xmlGenericError(xmlGenericErrorContext,
6728 "xmlXPathCompareNodeSetValue: Can't compare node set "
6729 "and object of type %d\n",
6731 xmlXPathReleaseObject(ctxt->context, arg);
6732 xmlXPathReleaseObject(ctxt->context, val);
6733 XP_ERROR0(XPATH_INVALID_TYPE);
6739 * xmlXPathEqualNodeSetString:
6740 * @arg: the nodeset object argument
6741 * @str: the string to compare to.
6742 * @neq: flag to show whether for '=' (0) or '!=' (1)
6744 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6745 * If one object to be compared is a node-set and the other is a string,
6746 * then the comparison will be true if and only if there is a node in
6747 * the node-set such that the result of performing the comparison on the
6748 * string-value of the node and the other string is true.
6750 * Returns 0 or 1 depending on the results of the test.
6753 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6760 if ((str == NULL) || (arg == NULL) ||
6761 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6763 ns = arg->nodesetval;
6765 * A NULL nodeset compared with a string is always false
6766 * (since there is no node equal, and no node not equal)
6768 if ((ns == NULL) || (ns->nodeNr <= 0) )
6770 hash = xmlXPathStringHash(str);
6771 for (i = 0; i < ns->nodeNr; i++) {
6772 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6773 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6774 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6779 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6797 * xmlXPathEqualNodeSetFloat:
6798 * @arg: the nodeset object argument
6799 * @f: the float to compare to
6800 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6802 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6803 * If one object to be compared is a node-set and the other is a number,
6804 * then the comparison will be true if and only if there is a node in
6805 * the node-set such that the result of performing the comparison on the
6806 * number to be compared and on the result of converting the string-value
6807 * of that node to a number using the number function is true.
6809 * Returns 0 or 1 depending on the results of the test.
6812 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6813 xmlXPathObjectPtr arg, double f, int neq) {
6817 xmlXPathObjectPtr val;
6820 if ((arg == NULL) ||
6821 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6824 ns = arg->nodesetval;
6826 for (i=0;i<ns->nodeNr;i++) {
6827 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6829 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6831 xmlXPathNumberFunction(ctxt, 1);
6832 val = valuePop(ctxt);
6834 xmlXPathReleaseObject(ctxt->context, val);
6835 if (!xmlXPathIsNaN(v)) {
6836 if ((!neq) && (v==f)) {
6839 } else if ((neq) && (v!=f)) {
6843 } else { /* NaN is unequal to any value */
6856 * xmlXPathEqualNodeSets:
6857 * @arg1: first nodeset object argument
6858 * @arg2: second nodeset object argument
6859 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6861 * Implement the equal / not equal operation on XPath nodesets:
6862 * @arg1 == @arg2 or @arg1 != @arg2
6863 * If both objects to be compared are node-sets, then the comparison
6864 * will be true if and only if there is a node in the first node-set and
6865 * a node in the second node-set such that the result of performing the
6866 * comparison on the string-values of the two nodes is true.
6868 * (needless to say, this is a costly operation)
6870 * Returns 0 or 1 depending on the results of the test.
6873 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6875 unsigned int *hashs1;
6876 unsigned int *hashs2;
6883 if ((arg1 == NULL) ||
6884 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6886 if ((arg2 == NULL) ||
6887 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6890 ns1 = arg1->nodesetval;
6891 ns2 = arg2->nodesetval;
6893 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6895 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6899 * for equal, check if there is a node pertaining to both sets
6902 for (i = 0;i < ns1->nodeNr;i++)
6903 for (j = 0;j < ns2->nodeNr;j++)
6904 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6907 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6908 if (values1 == NULL) {
6909 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6912 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6913 if (hashs1 == NULL) {
6914 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6918 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6919 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6920 if (values2 == NULL) {
6921 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6926 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6927 if (hashs2 == NULL) {
6928 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6934 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6935 for (i = 0;i < ns1->nodeNr;i++) {
6936 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6937 for (j = 0;j < ns2->nodeNr;j++) {
6939 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6940 if (hashs1[i] != hashs2[j]) {
6947 if (values1[i] == NULL)
6948 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6949 if (values2[j] == NULL)
6950 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6951 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6959 for (i = 0;i < ns1->nodeNr;i++)
6960 if (values1[i] != NULL)
6961 xmlFree(values1[i]);
6962 for (j = 0;j < ns2->nodeNr;j++)
6963 if (values2[j] != NULL)
6964 xmlFree(values2[j]);
6973 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6974 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6977 *At this point we are assured neither arg1 nor arg2
6978 *is a nodeset, so we can just pick the appropriate routine.
6980 switch (arg1->type) {
6981 case XPATH_UNDEFINED:
6983 xmlGenericError(xmlGenericErrorContext,
6984 "Equal: undefined\n");
6988 switch (arg2->type) {
6989 case XPATH_UNDEFINED:
6991 xmlGenericError(xmlGenericErrorContext,
6992 "Equal: undefined\n");
6997 xmlGenericError(xmlGenericErrorContext,
6998 "Equal: %d boolean %d \n",
6999 arg1->boolval, arg2->boolval);
7001 ret = (arg1->boolval == arg2->boolval);
7004 ret = (arg1->boolval ==
7005 xmlXPathCastNumberToBoolean(arg2->floatval));
7008 if ((arg2->stringval == NULL) ||
7009 (arg2->stringval[0] == 0)) ret = 0;
7012 ret = (arg1->boolval == ret);
7017 case XPATH_LOCATIONSET:
7021 case XPATH_XSLT_TREE:
7026 switch (arg2->type) {
7027 case XPATH_UNDEFINED:
7029 xmlGenericError(xmlGenericErrorContext,
7030 "Equal: undefined\n");
7034 ret = (arg2->boolval==
7035 xmlXPathCastNumberToBoolean(arg1->floatval));
7038 valuePush(ctxt, arg2);
7039 xmlXPathNumberFunction(ctxt, 1);
7040 arg2 = valuePop(ctxt);
7041 /* no break on purpose */
7043 /* Hand check NaN and Infinity equalities */
7044 if (xmlXPathIsNaN(arg1->floatval) ||
7045 xmlXPathIsNaN(arg2->floatval)) {
7047 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7048 if (xmlXPathIsInf(arg2->floatval) == 1)
7052 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7053 if (xmlXPathIsInf(arg2->floatval) == -1)
7057 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7058 if (xmlXPathIsInf(arg1->floatval) == 1)
7062 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7063 if (xmlXPathIsInf(arg1->floatval) == -1)
7068 ret = (arg1->floatval == arg2->floatval);
7074 case XPATH_LOCATIONSET:
7078 case XPATH_XSLT_TREE:
7083 switch (arg2->type) {
7084 case XPATH_UNDEFINED:
7086 xmlGenericError(xmlGenericErrorContext,
7087 "Equal: undefined\n");
7091 if ((arg1->stringval == NULL) ||
7092 (arg1->stringval[0] == 0)) ret = 0;
7095 ret = (arg2->boolval == ret);
7098 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7101 valuePush(ctxt, arg1);
7102 xmlXPathNumberFunction(ctxt, 1);
7103 arg1 = valuePop(ctxt);
7104 /* Hand check NaN and Infinity equalities */
7105 if (xmlXPathIsNaN(arg1->floatval) ||
7106 xmlXPathIsNaN(arg2->floatval)) {
7108 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7109 if (xmlXPathIsInf(arg2->floatval) == 1)
7113 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7114 if (xmlXPathIsInf(arg2->floatval) == -1)
7118 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7119 if (xmlXPathIsInf(arg1->floatval) == 1)
7123 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7124 if (xmlXPathIsInf(arg1->floatval) == -1)
7129 ret = (arg1->floatval == arg2->floatval);
7135 case XPATH_LOCATIONSET:
7139 case XPATH_XSLT_TREE:
7146 case XPATH_LOCATIONSET:
7150 case XPATH_XSLT_TREE:
7153 xmlXPathReleaseObject(ctxt->context, arg1);
7154 xmlXPathReleaseObject(ctxt->context, arg2);
7159 * xmlXPathEqualValues:
7160 * @ctxt: the XPath Parser context
7162 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7164 * Returns 0 or 1 depending on the results of the test.
7167 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7168 xmlXPathObjectPtr arg1, arg2, argtmp;
7171 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7172 arg2 = valuePop(ctxt);
7173 arg1 = valuePop(ctxt);
7174 if ((arg1 == NULL) || (arg2 == NULL)) {
7176 xmlXPathReleaseObject(ctxt->context, arg1);
7178 xmlXPathReleaseObject(ctxt->context, arg2);
7179 XP_ERROR0(XPATH_INVALID_OPERAND);
7184 xmlGenericError(xmlGenericErrorContext,
7185 "Equal: by pointer\n");
7187 xmlXPathFreeObject(arg1);
7192 *If either argument is a nodeset, it's a 'special case'
7194 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7195 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7197 *Hack it to assure arg1 is the nodeset
7199 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7204 switch (arg2->type) {
7205 case XPATH_UNDEFINED:
7207 xmlGenericError(xmlGenericErrorContext,
7208 "Equal: undefined\n");
7212 case XPATH_XSLT_TREE:
7213 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7216 if ((arg1->nodesetval == NULL) ||
7217 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7220 ret = (ret == arg2->boolval);
7223 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7226 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7231 case XPATH_LOCATIONSET:
7235 xmlXPathReleaseObject(ctxt->context, arg1);
7236 xmlXPathReleaseObject(ctxt->context, arg2);
7240 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7244 * xmlXPathNotEqualValues:
7245 * @ctxt: the XPath Parser context
7247 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7249 * Returns 0 or 1 depending on the results of the test.
7252 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7253 xmlXPathObjectPtr arg1, arg2, argtmp;
7256 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7257 arg2 = valuePop(ctxt);
7258 arg1 = valuePop(ctxt);
7259 if ((arg1 == NULL) || (arg2 == NULL)) {
7261 xmlXPathReleaseObject(ctxt->context, arg1);
7263 xmlXPathReleaseObject(ctxt->context, arg2);
7264 XP_ERROR0(XPATH_INVALID_OPERAND);
7269 xmlGenericError(xmlGenericErrorContext,
7270 "NotEqual: by pointer\n");
7272 xmlXPathReleaseObject(ctxt->context, arg1);
7277 *If either argument is a nodeset, it's a 'special case'
7279 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7280 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7282 *Hack it to assure arg1 is the nodeset
7284 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7289 switch (arg2->type) {
7290 case XPATH_UNDEFINED:
7292 xmlGenericError(xmlGenericErrorContext,
7293 "NotEqual: undefined\n");
7297 case XPATH_XSLT_TREE:
7298 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7301 if ((arg1->nodesetval == NULL) ||
7302 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7305 ret = (ret != arg2->boolval);
7308 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7311 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7316 case XPATH_LOCATIONSET:
7320 xmlXPathReleaseObject(ctxt->context, arg1);
7321 xmlXPathReleaseObject(ctxt->context, arg2);
7325 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7329 * xmlXPathCompareValues:
7330 * @ctxt: the XPath Parser context
7331 * @inf: less than (1) or greater than (0)
7332 * @strict: is the comparison strict
7334 * Implement the compare operation on XPath objects:
7335 * @arg1 < @arg2 (1, 1, ...
7336 * @arg1 <= @arg2 (1, 0, ...
7337 * @arg1 > @arg2 (0, 1, ...
7338 * @arg1 >= @arg2 (0, 0, ...
7340 * When neither object to be compared is a node-set and the operator is
7341 * <=, <, >=, >, then the objects are compared by converted both objects
7342 * to numbers and comparing the numbers according to IEEE 754. The <
7343 * comparison will be true if and only if the first number is less than the
7344 * second number. The <= comparison will be true if and only if the first
7345 * number is less than or equal to the second number. The > comparison
7346 * will be true if and only if the first number is greater than the second
7347 * number. The >= comparison will be true if and only if the first number
7348 * is greater than or equal to the second number.
7350 * Returns 1 if the comparison succeeded, 0 if it failed
7353 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7354 int ret = 0, arg1i = 0, arg2i = 0;
7355 xmlXPathObjectPtr arg1, arg2;
7357 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7358 arg2 = valuePop(ctxt);
7359 arg1 = valuePop(ctxt);
7360 if ((arg1 == NULL) || (arg2 == NULL)) {
7362 xmlXPathReleaseObject(ctxt->context, arg1);
7364 xmlXPathReleaseObject(ctxt->context, arg2);
7365 XP_ERROR0(XPATH_INVALID_OPERAND);
7368 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7369 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7371 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7372 * are not freed from within this routine; they will be freed from the
7373 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7375 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7376 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7377 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7379 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7380 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7383 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7390 if (arg1->type != XPATH_NUMBER) {
7391 valuePush(ctxt, arg1);
7392 xmlXPathNumberFunction(ctxt, 1);
7393 arg1 = valuePop(ctxt);
7395 if (arg1->type != XPATH_NUMBER) {
7396 xmlXPathFreeObject(arg1);
7397 xmlXPathFreeObject(arg2);
7398 XP_ERROR0(XPATH_INVALID_OPERAND);
7400 if (arg2->type != XPATH_NUMBER) {
7401 valuePush(ctxt, arg2);
7402 xmlXPathNumberFunction(ctxt, 1);
7403 arg2 = valuePop(ctxt);
7405 if (arg2->type != XPATH_NUMBER) {
7406 xmlXPathReleaseObject(ctxt->context, arg1);
7407 xmlXPathReleaseObject(ctxt->context, arg2);
7408 XP_ERROR0(XPATH_INVALID_OPERAND);
7411 * Add tests for infinity and nan
7412 * => feedback on 3.4 for Inf and NaN
7414 /* Hand check NaN and Infinity comparisons */
7415 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7418 arg1i=xmlXPathIsInf(arg1->floatval);
7419 arg2i=xmlXPathIsInf(arg2->floatval);
7420 if (inf && strict) {
7421 if ((arg1i == -1 && arg2i != -1) ||
7422 (arg2i == 1 && arg1i != 1)) {
7424 } else if (arg1i == 0 && arg2i == 0) {
7425 ret = (arg1->floatval < arg2->floatval);
7430 else if (inf && !strict) {
7431 if (arg1i == -1 || arg2i == 1) {
7433 } else if (arg1i == 0 && arg2i == 0) {
7434 ret = (arg1->floatval <= arg2->floatval);
7439 else if (!inf && strict) {
7440 if ((arg1i == 1 && arg2i != 1) ||
7441 (arg2i == -1 && arg1i != -1)) {
7443 } else if (arg1i == 0 && arg2i == 0) {
7444 ret = (arg1->floatval > arg2->floatval);
7449 else if (!inf && !strict) {
7450 if (arg1i == 1 || arg2i == -1) {
7452 } else if (arg1i == 0 && arg2i == 0) {
7453 ret = (arg1->floatval >= arg2->floatval);
7459 xmlXPathReleaseObject(ctxt->context, arg1);
7460 xmlXPathReleaseObject(ctxt->context, arg2);
7465 * xmlXPathValueFlipSign:
7466 * @ctxt: the XPath Parser context
7468 * Implement the unary - operation on an XPath object
7469 * The numeric operators convert their operands to numbers as if
7470 * by calling the number function.
7473 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7474 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7476 CHECK_TYPE(XPATH_NUMBER);
7477 if (xmlXPathIsNaN(ctxt->value->floatval))
7478 ctxt->value->floatval=xmlXPathNAN;
7479 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7480 ctxt->value->floatval=xmlXPathNINF;
7481 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7482 ctxt->value->floatval=xmlXPathPINF;
7483 else if (ctxt->value->floatval == 0) {
7484 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7485 ctxt->value->floatval = xmlXPathNZERO;
7487 ctxt->value->floatval = 0;
7490 ctxt->value->floatval = - ctxt->value->floatval;
7494 * xmlXPathAddValues:
7495 * @ctxt: the XPath Parser context
7497 * Implement the add operation on XPath objects:
7498 * The numeric operators convert their operands to numbers as if
7499 * by calling the number function.
7502 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7503 xmlXPathObjectPtr arg;
7506 arg = valuePop(ctxt);
7508 XP_ERROR(XPATH_INVALID_OPERAND);
7509 val = xmlXPathCastToNumber(arg);
7510 xmlXPathReleaseObject(ctxt->context, arg);
7512 CHECK_TYPE(XPATH_NUMBER);
7513 ctxt->value->floatval += val;
7517 * xmlXPathSubValues:
7518 * @ctxt: the XPath Parser context
7520 * Implement the subtraction operation on XPath objects:
7521 * The numeric operators convert their operands to numbers as if
7522 * by calling the number function.
7525 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7526 xmlXPathObjectPtr arg;
7529 arg = valuePop(ctxt);
7531 XP_ERROR(XPATH_INVALID_OPERAND);
7532 val = xmlXPathCastToNumber(arg);
7533 xmlXPathReleaseObject(ctxt->context, arg);
7535 CHECK_TYPE(XPATH_NUMBER);
7536 ctxt->value->floatval -= val;
7540 * xmlXPathMultValues:
7541 * @ctxt: the XPath Parser context
7543 * Implement the multiply operation on XPath objects:
7544 * The numeric operators convert their operands to numbers as if
7545 * by calling the number function.
7548 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7549 xmlXPathObjectPtr arg;
7552 arg = valuePop(ctxt);
7554 XP_ERROR(XPATH_INVALID_OPERAND);
7555 val = xmlXPathCastToNumber(arg);
7556 xmlXPathReleaseObject(ctxt->context, arg);
7558 CHECK_TYPE(XPATH_NUMBER);
7559 ctxt->value->floatval *= val;
7563 * xmlXPathDivValues:
7564 * @ctxt: the XPath Parser context
7566 * Implement the div operation on XPath objects @arg1 / @arg2:
7567 * The numeric operators convert their operands to numbers as if
7568 * by calling the number function.
7571 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7572 xmlXPathObjectPtr arg;
7575 arg = valuePop(ctxt);
7577 XP_ERROR(XPATH_INVALID_OPERAND);
7578 val = xmlXPathCastToNumber(arg);
7579 xmlXPathReleaseObject(ctxt->context, arg);
7581 CHECK_TYPE(XPATH_NUMBER);
7582 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7583 ctxt->value->floatval = xmlXPathNAN;
7584 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7585 if (ctxt->value->floatval == 0)
7586 ctxt->value->floatval = xmlXPathNAN;
7587 else if (ctxt->value->floatval > 0)
7588 ctxt->value->floatval = xmlXPathNINF;
7589 else if (ctxt->value->floatval < 0)
7590 ctxt->value->floatval = xmlXPathPINF;
7592 else if (val == 0) {
7593 if (ctxt->value->floatval == 0)
7594 ctxt->value->floatval = xmlXPathNAN;
7595 else if (ctxt->value->floatval > 0)
7596 ctxt->value->floatval = xmlXPathPINF;
7597 else if (ctxt->value->floatval < 0)
7598 ctxt->value->floatval = xmlXPathNINF;
7600 ctxt->value->floatval /= val;
7604 * xmlXPathModValues:
7605 * @ctxt: the XPath Parser context
7607 * Implement the mod operation on XPath objects: @arg1 / @arg2
7608 * The numeric operators convert their operands to numbers as if
7609 * by calling the number function.
7612 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7613 xmlXPathObjectPtr arg;
7616 arg = valuePop(ctxt);
7618 XP_ERROR(XPATH_INVALID_OPERAND);
7619 arg2 = xmlXPathCastToNumber(arg);
7620 xmlXPathReleaseObject(ctxt->context, arg);
7622 CHECK_TYPE(XPATH_NUMBER);
7623 arg1 = ctxt->value->floatval;
7625 ctxt->value->floatval = xmlXPathNAN;
7627 ctxt->value->floatval = fmod(arg1, arg2);
7631 /************************************************************************
7633 * The traversal functions *
7635 ************************************************************************/
7638 * A traversal function enumerates nodes along an axis.
7639 * Initially it must be called with NULL, and it indicates
7640 * termination on the axis by returning NULL.
7642 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7643 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7646 * xmlXPathTraversalFunctionExt:
7647 * A traversal function enumerates nodes along an axis.
7648 * Initially it must be called with NULL, and it indicates
7649 * termination on the axis by returning NULL.
7650 * The context node of the traversal is specified via @contextNode.
7652 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7653 (xmlNodePtr cur, xmlNodePtr contextNode);
7656 * xmlXPathNodeSetMergeFunction:
7657 * Used for merging node sets in xmlXPathCollectAndTest().
7659 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7660 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7665 * @ctxt: the XPath Parser context
7666 * @cur: the current node in the traversal
7668 * Traversal function for the "self" direction
7669 * The self axis contains just the context node itself
7671 * Returns the next element following that axis
7674 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7675 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7677 return(ctxt->context->node);
7682 * xmlXPathNextChild:
7683 * @ctxt: the XPath Parser context
7684 * @cur: the current node in the traversal
7686 * Traversal function for the "child" direction
7687 * The child axis contains the children of the context node in document order.
7689 * Returns the next element following that axis
7692 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7693 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7695 if (ctxt->context->node == NULL) return(NULL);
7696 switch (ctxt->context->node->type) {
7697 case XML_ELEMENT_NODE:
7699 case XML_CDATA_SECTION_NODE:
7700 case XML_ENTITY_REF_NODE:
7701 case XML_ENTITY_NODE:
7703 case XML_COMMENT_NODE:
7704 case XML_NOTATION_NODE:
7706 return(ctxt->context->node->children);
7707 case XML_DOCUMENT_NODE:
7708 case XML_DOCUMENT_TYPE_NODE:
7709 case XML_DOCUMENT_FRAG_NODE:
7710 case XML_HTML_DOCUMENT_NODE:
7711 #ifdef LIBXML_DOCB_ENABLED
7712 case XML_DOCB_DOCUMENT_NODE:
7714 return(((xmlDocPtr) ctxt->context->node)->children);
7715 case XML_ELEMENT_DECL:
7716 case XML_ATTRIBUTE_DECL:
7717 case XML_ENTITY_DECL:
7718 case XML_ATTRIBUTE_NODE:
7719 case XML_NAMESPACE_DECL:
7720 case XML_XINCLUDE_START:
7721 case XML_XINCLUDE_END:
7726 if ((cur->type == XML_DOCUMENT_NODE) ||
7727 (cur->type == XML_HTML_DOCUMENT_NODE))
7733 * xmlXPathNextChildElement:
7734 * @ctxt: the XPath Parser context
7735 * @cur: the current node in the traversal
7737 * Traversal function for the "child" direction and nodes of type element.
7738 * The child axis contains the children of the context node in document order.
7740 * Returns the next element following that axis
7743 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7744 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7746 cur = ctxt->context->node;
7747 if (cur == NULL) return(NULL);
7749 * Get the first element child.
7751 switch (cur->type) {
7752 case XML_ELEMENT_NODE:
7753 case XML_DOCUMENT_FRAG_NODE:
7754 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7755 case XML_ENTITY_NODE:
7756 cur = cur->children;
7758 if (cur->type == XML_ELEMENT_NODE)
7762 } while ((cur != NULL) &&
7763 (cur->type != XML_ELEMENT_NODE));
7767 case XML_DOCUMENT_NODE:
7768 case XML_HTML_DOCUMENT_NODE:
7769 #ifdef LIBXML_DOCB_ENABLED
7770 case XML_DOCB_DOCUMENT_NODE:
7772 return(xmlDocGetRootElement((xmlDocPtr) cur));
7779 * Get the next sibling element node.
7781 switch (cur->type) {
7782 case XML_ELEMENT_NODE:
7784 case XML_ENTITY_REF_NODE:
7785 case XML_ENTITY_NODE:
7786 case XML_CDATA_SECTION_NODE:
7788 case XML_COMMENT_NODE:
7789 case XML_XINCLUDE_END:
7791 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7795 if (cur->next != NULL) {
7796 if (cur->next->type == XML_ELEMENT_NODE)
7801 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7809 * xmlXPathNextDescendantOrSelfElemParent:
7810 * @ctxt: the XPath Parser context
7811 * @cur: the current node in the traversal
7813 * Traversal function for the "descendant-or-self" axis.
7814 * Additionally it returns only nodes which can be parents of
7818 * Returns the next element following that axis
7821 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7822 xmlNodePtr contextNode)
7825 if (contextNode == NULL)
7827 switch (contextNode->type) {
7828 case XML_ELEMENT_NODE:
7829 case XML_XINCLUDE_START:
7830 case XML_DOCUMENT_FRAG_NODE:
7831 case XML_DOCUMENT_NODE:
7832 #ifdef LIBXML_DOCB_ENABLED
7833 case XML_DOCB_DOCUMENT_NODE:
7835 case XML_HTML_DOCUMENT_NODE:
7836 return(contextNode);
7842 xmlNodePtr start = cur;
7844 while (cur != NULL) {
7845 switch (cur->type) {
7846 case XML_ELEMENT_NODE:
7847 /* TODO: OK to have XInclude here? */
7848 case XML_XINCLUDE_START:
7849 case XML_DOCUMENT_FRAG_NODE:
7852 if (cur->children != NULL) {
7853 cur = cur->children;
7857 /* Not sure if we need those here. */
7858 case XML_DOCUMENT_NODE:
7859 #ifdef LIBXML_DOCB_ENABLED
7860 case XML_DOCB_DOCUMENT_NODE:
7862 case XML_HTML_DOCUMENT_NODE:
7865 return(xmlDocGetRootElement((xmlDocPtr) cur));
7871 if ((cur == NULL) || (cur == contextNode))
7873 if (cur->next != NULL) {
7886 * xmlXPathNextDescendant:
7887 * @ctxt: the XPath Parser context
7888 * @cur: the current node in the traversal
7890 * Traversal function for the "descendant" direction
7891 * the descendant axis contains the descendants of the context node in document
7892 * order; a descendant is a child or a child of a child and so on.
7894 * Returns the next element following that axis
7897 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7898 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7900 if (ctxt->context->node == NULL)
7902 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7903 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7906 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7907 return(ctxt->context->doc->children);
7908 return(ctxt->context->node->children);
7911 if (cur->type == XML_NAMESPACE_DECL)
7913 if (cur->children != NULL) {
7915 * Do not descend on entities declarations
7917 if (cur->children->type != XML_ENTITY_DECL) {
7918 cur = cur->children;
7922 if (cur->type != XML_DTD_NODE)
7927 if (cur == ctxt->context->node) return(NULL);
7929 while (cur->next != NULL) {
7931 if ((cur->type != XML_ENTITY_DECL) &&
7932 (cur->type != XML_DTD_NODE))
7938 if (cur == NULL) break;
7939 if (cur == ctxt->context->node) return(NULL);
7940 if (cur->next != NULL) {
7944 } while (cur != NULL);
7949 * xmlXPathNextDescendantOrSelf:
7950 * @ctxt: the XPath Parser context
7951 * @cur: the current node in the traversal
7953 * Traversal function for the "descendant-or-self" direction
7954 * the descendant-or-self axis contains the context node and the descendants
7955 * of the context node in document order; thus the context node is the first
7956 * node on the axis, and the first child of the context node is the second node
7959 * Returns the next element following that axis
7962 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7963 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7965 return(ctxt->context->node);
7967 if (ctxt->context->node == NULL)
7969 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7970 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7973 return(xmlXPathNextDescendant(ctxt, cur));
7977 * xmlXPathNextParent:
7978 * @ctxt: the XPath Parser context
7979 * @cur: the current node in the traversal
7981 * Traversal function for the "parent" direction
7982 * The parent axis contains the parent of the context node, if there is one.
7984 * Returns the next element following that axis
7987 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7988 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7990 * the parent of an attribute or namespace node is the element
7991 * to which the attribute or namespace node is attached
7992 * Namespace handling !!!
7995 if (ctxt->context->node == NULL) return(NULL);
7996 switch (ctxt->context->node->type) {
7997 case XML_ELEMENT_NODE:
7999 case XML_CDATA_SECTION_NODE:
8000 case XML_ENTITY_REF_NODE:
8001 case XML_ENTITY_NODE:
8003 case XML_COMMENT_NODE:
8004 case XML_NOTATION_NODE:
8006 case XML_ELEMENT_DECL:
8007 case XML_ATTRIBUTE_DECL:
8008 case XML_XINCLUDE_START:
8009 case XML_XINCLUDE_END:
8010 case XML_ENTITY_DECL:
8011 if (ctxt->context->node->parent == NULL)
8012 return((xmlNodePtr) ctxt->context->doc);
8013 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8014 ((ctxt->context->node->parent->name[0] == ' ') ||
8015 (xmlStrEqual(ctxt->context->node->parent->name,
8016 BAD_CAST "fake node libxslt"))))
8018 return(ctxt->context->node->parent);
8019 case XML_ATTRIBUTE_NODE: {
8020 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8022 return(att->parent);
8024 case XML_DOCUMENT_NODE:
8025 case XML_DOCUMENT_TYPE_NODE:
8026 case XML_DOCUMENT_FRAG_NODE:
8027 case XML_HTML_DOCUMENT_NODE:
8028 #ifdef LIBXML_DOCB_ENABLED
8029 case XML_DOCB_DOCUMENT_NODE:
8032 case XML_NAMESPACE_DECL: {
8033 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8035 if ((ns->next != NULL) &&
8036 (ns->next->type != XML_NAMESPACE_DECL))
8037 return((xmlNodePtr) ns->next);
8046 * xmlXPathNextAncestor:
8047 * @ctxt: the XPath Parser context
8048 * @cur: the current node in the traversal
8050 * Traversal function for the "ancestor" direction
8051 * the ancestor axis contains the ancestors of the context node; the ancestors
8052 * of the context node consist of the parent of context node and the parent's
8053 * parent and so on; the nodes are ordered in reverse document order; thus the
8054 * parent is the first node on the axis, and the parent's parent is the second
8057 * Returns the next element following that axis
8060 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8061 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8063 * the parent of an attribute or namespace node is the element
8064 * to which the attribute or namespace node is attached
8068 if (ctxt->context->node == NULL) return(NULL);
8069 switch (ctxt->context->node->type) {
8070 case XML_ELEMENT_NODE:
8072 case XML_CDATA_SECTION_NODE:
8073 case XML_ENTITY_REF_NODE:
8074 case XML_ENTITY_NODE:
8076 case XML_COMMENT_NODE:
8078 case XML_ELEMENT_DECL:
8079 case XML_ATTRIBUTE_DECL:
8080 case XML_ENTITY_DECL:
8081 case XML_NOTATION_NODE:
8082 case XML_XINCLUDE_START:
8083 case XML_XINCLUDE_END:
8084 if (ctxt->context->node->parent == NULL)
8085 return((xmlNodePtr) ctxt->context->doc);
8086 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8087 ((ctxt->context->node->parent->name[0] == ' ') ||
8088 (xmlStrEqual(ctxt->context->node->parent->name,
8089 BAD_CAST "fake node libxslt"))))
8091 return(ctxt->context->node->parent);
8092 case XML_ATTRIBUTE_NODE: {
8093 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8095 return(tmp->parent);
8097 case XML_DOCUMENT_NODE:
8098 case XML_DOCUMENT_TYPE_NODE:
8099 case XML_DOCUMENT_FRAG_NODE:
8100 case XML_HTML_DOCUMENT_NODE:
8101 #ifdef LIBXML_DOCB_ENABLED
8102 case XML_DOCB_DOCUMENT_NODE:
8105 case XML_NAMESPACE_DECL: {
8106 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8108 if ((ns->next != NULL) &&
8109 (ns->next->type != XML_NAMESPACE_DECL))
8110 return((xmlNodePtr) ns->next);
8111 /* Bad, how did that namespace end up here ? */
8117 if (cur == ctxt->context->doc->children)
8118 return((xmlNodePtr) ctxt->context->doc);
8119 if (cur == (xmlNodePtr) ctxt->context->doc)
8121 switch (cur->type) {
8122 case XML_ELEMENT_NODE:
8124 case XML_CDATA_SECTION_NODE:
8125 case XML_ENTITY_REF_NODE:
8126 case XML_ENTITY_NODE:
8128 case XML_COMMENT_NODE:
8129 case XML_NOTATION_NODE:
8131 case XML_ELEMENT_DECL:
8132 case XML_ATTRIBUTE_DECL:
8133 case XML_ENTITY_DECL:
8134 case XML_XINCLUDE_START:
8135 case XML_XINCLUDE_END:
8136 if (cur->parent == NULL)
8138 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8139 ((cur->parent->name[0] == ' ') ||
8140 (xmlStrEqual(cur->parent->name,
8141 BAD_CAST "fake node libxslt"))))
8143 return(cur->parent);
8144 case XML_ATTRIBUTE_NODE: {
8145 xmlAttrPtr att = (xmlAttrPtr) cur;
8147 return(att->parent);
8149 case XML_NAMESPACE_DECL: {
8150 xmlNsPtr ns = (xmlNsPtr) cur;
8152 if ((ns->next != NULL) &&
8153 (ns->next->type != XML_NAMESPACE_DECL))
8154 return((xmlNodePtr) ns->next);
8155 /* Bad, how did that namespace end up here ? */
8158 case XML_DOCUMENT_NODE:
8159 case XML_DOCUMENT_TYPE_NODE:
8160 case XML_DOCUMENT_FRAG_NODE:
8161 case XML_HTML_DOCUMENT_NODE:
8162 #ifdef LIBXML_DOCB_ENABLED
8163 case XML_DOCB_DOCUMENT_NODE:
8171 * xmlXPathNextAncestorOrSelf:
8172 * @ctxt: the XPath Parser context
8173 * @cur: the current node in the traversal
8175 * Traversal function for the "ancestor-or-self" direction
8176 * he ancestor-or-self axis contains the context node and ancestors of
8177 * the context node in reverse document order; thus the context node is
8178 * the first node on the axis, and the context node's parent the second;
8179 * parent here is defined the same as with the parent axis.
8181 * Returns the next element following that axis
8184 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8185 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8187 return(ctxt->context->node);
8188 return(xmlXPathNextAncestor(ctxt, cur));
8192 * xmlXPathNextFollowingSibling:
8193 * @ctxt: the XPath Parser context
8194 * @cur: the current node in the traversal
8196 * Traversal function for the "following-sibling" direction
8197 * The following-sibling axis contains the following siblings of the context
8198 * node in document order.
8200 * Returns the next element following that axis
8203 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8204 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8205 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8206 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8208 if (cur == (xmlNodePtr) ctxt->context->doc)
8211 return(ctxt->context->node->next);
8216 * xmlXPathNextPrecedingSibling:
8217 * @ctxt: the XPath Parser context
8218 * @cur: the current node in the traversal
8220 * Traversal function for the "preceding-sibling" direction
8221 * The preceding-sibling axis contains the preceding siblings of the context
8222 * node in reverse document order; the first preceding sibling is first on the
8223 * axis; the sibling preceding that node is the second on the axis and so on.
8225 * Returns the next element following that axis
8228 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8229 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8230 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8231 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8233 if (cur == (xmlNodePtr) ctxt->context->doc)
8236 return(ctxt->context->node->prev);
8237 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8240 return(ctxt->context->node->prev);
8246 * xmlXPathNextFollowing:
8247 * @ctxt: the XPath Parser context
8248 * @cur: the current node in the traversal
8250 * Traversal function for the "following" direction
8251 * The following axis contains all nodes in the same document as the context
8252 * node that are after the context node in document order, excluding any
8253 * descendants and excluding attribute nodes and namespace nodes; the nodes
8254 * are ordered in document order
8256 * Returns the next element following that axis
8259 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8260 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8261 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8262 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8263 return(cur->children);
8266 cur = ctxt->context->node;
8267 if (cur->type == XML_ATTRIBUTE_NODE) {
8269 } else if (cur->type == XML_NAMESPACE_DECL) {
8270 xmlNsPtr ns = (xmlNsPtr) cur;
8272 if ((ns->next == NULL) ||
8273 (ns->next->type == XML_NAMESPACE_DECL))
8275 cur = (xmlNodePtr) ns->next;
8278 if (cur == NULL) return(NULL) ; /* ERROR */
8279 if (cur->next != NULL) return(cur->next) ;
8282 if (cur == NULL) break;
8283 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8284 if (cur->next != NULL) return(cur->next);
8285 } while (cur != NULL);
8290 * xmlXPathIsAncestor:
8291 * @ancestor: the ancestor node
8292 * @node: the current node
8294 * Check that @ancestor is a @node's ancestor
8296 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8299 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8300 if ((ancestor == NULL) || (node == NULL)) return(0);
8301 if (node->type == XML_NAMESPACE_DECL)
8303 if (ancestor->type == XML_NAMESPACE_DECL)
8305 /* nodes need to be in the same document */
8306 if (ancestor->doc != node->doc) return(0);
8307 /* avoid searching if ancestor or node is the root node */
8308 if (ancestor == (xmlNodePtr) node->doc) return(1);
8309 if (node == (xmlNodePtr) ancestor->doc) return(0);
8310 while (node->parent != NULL) {
8311 if (node->parent == ancestor)
8313 node = node->parent;
8319 * xmlXPathNextPreceding:
8320 * @ctxt: the XPath Parser context
8321 * @cur: the current node in the traversal
8323 * Traversal function for the "preceding" direction
8324 * the preceding axis contains all nodes in the same document as the context
8325 * node that are before the context node in document order, excluding any
8326 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8327 * ordered in reverse document order
8329 * Returns the next element following that axis
8332 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8334 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8336 cur = ctxt->context->node;
8337 if (cur->type == XML_ATTRIBUTE_NODE) {
8339 } else if (cur->type == XML_NAMESPACE_DECL) {
8340 xmlNsPtr ns = (xmlNsPtr) cur;
8342 if ((ns->next == NULL) ||
8343 (ns->next->type == XML_NAMESPACE_DECL))
8345 cur = (xmlNodePtr) ns->next;
8348 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8350 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8353 if (cur->prev != NULL) {
8354 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8361 if (cur == ctxt->context->doc->children)
8363 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8368 * xmlXPathNextPrecedingInternal:
8369 * @ctxt: the XPath Parser context
8370 * @cur: the current node in the traversal
8372 * Traversal function for the "preceding" direction
8373 * the preceding axis contains all nodes in the same document as the context
8374 * node that are before the context node in document order, excluding any
8375 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8376 * ordered in reverse document order
8377 * This is a faster implementation but internal only since it requires a
8378 * state kept in the parser context: ctxt->ancestor.
8380 * Returns the next element following that axis
8383 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8386 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8388 cur = ctxt->context->node;
8391 if (cur->type == XML_ATTRIBUTE_NODE) {
8393 } else if (cur->type == XML_NAMESPACE_DECL) {
8394 xmlNsPtr ns = (xmlNsPtr) cur;
8396 if ((ns->next == NULL) ||
8397 (ns->next->type == XML_NAMESPACE_DECL))
8399 cur = (xmlNodePtr) ns->next;
8401 ctxt->ancestor = cur->parent;
8403 if (cur->type == XML_NAMESPACE_DECL)
8405 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8407 while (cur->prev == NULL) {
8411 if (cur == ctxt->context->doc->children)
8413 if (cur != ctxt->ancestor)
8415 ctxt->ancestor = cur->parent;
8418 while (cur->last != NULL)
8424 * xmlXPathNextNamespace:
8425 * @ctxt: the XPath Parser context
8426 * @cur: the current attribute in the traversal
8428 * Traversal function for the "namespace" direction
8429 * the namespace axis contains the namespace nodes of the context node;
8430 * the order of nodes on this axis is implementation-defined; the axis will
8431 * be empty unless the context node is an element
8433 * We keep the XML namespace node at the end of the list.
8435 * Returns the next element following that axis
8438 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8439 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8440 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8442 if (ctxt->context->tmpNsList != NULL)
8443 xmlFree(ctxt->context->tmpNsList);
8444 ctxt->context->tmpNsList =
8445 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8446 ctxt->context->tmpNsNr = 0;
8447 if (ctxt->context->tmpNsList != NULL) {
8448 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8449 ctxt->context->tmpNsNr++;
8452 return((xmlNodePtr) xmlXPathXMLNamespace);
8454 if (ctxt->context->tmpNsNr > 0) {
8455 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8457 if (ctxt->context->tmpNsList != NULL)
8458 xmlFree(ctxt->context->tmpNsList);
8459 ctxt->context->tmpNsList = NULL;
8465 * xmlXPathNextAttribute:
8466 * @ctxt: the XPath Parser context
8467 * @cur: the current attribute in the traversal
8469 * Traversal function for the "attribute" direction
8470 * TODO: support DTD inherited default attributes
8472 * Returns the next element following that axis
8475 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8476 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8477 if (ctxt->context->node == NULL)
8479 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8482 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8484 return((xmlNodePtr)ctxt->context->node->properties);
8486 return((xmlNodePtr)cur->next);
8489 /************************************************************************
8491 * NodeTest Functions *
8493 ************************************************************************/
8495 #define IS_FUNCTION 200
8498 /************************************************************************
8500 * Implicit tree core function library *
8502 ************************************************************************/
8506 * @ctxt: the XPath Parser context
8508 * Initialize the context to the root of the document
8511 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8512 if ((ctxt == NULL) || (ctxt->context == NULL))
8514 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8515 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8516 ctxt->context->node));
8519 /************************************************************************
8521 * The explicit core function library *
8522 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8524 ************************************************************************/
8528 * xmlXPathLastFunction:
8529 * @ctxt: the XPath Parser context
8530 * @nargs: the number of arguments
8532 * Implement the last() XPath function
8534 * The last function returns the number of nodes in the context node list.
8537 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8539 if (ctxt->context->contextSize >= 0) {
8541 xmlXPathCacheNewFloat(ctxt->context,
8542 (double) ctxt->context->contextSize));
8544 xmlGenericError(xmlGenericErrorContext,
8545 "last() : %d\n", ctxt->context->contextSize);
8548 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8553 * xmlXPathPositionFunction:
8554 * @ctxt: the XPath Parser context
8555 * @nargs: the number of arguments
8557 * Implement the position() XPath function
8559 * The position function returns the position of the context node in the
8560 * context node list. The first position is 1, and so the last position
8561 * will be equal to last().
8564 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8566 if (ctxt->context->proximityPosition >= 0) {
8568 xmlXPathCacheNewFloat(ctxt->context,
8569 (double) ctxt->context->proximityPosition));
8571 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8572 ctxt->context->proximityPosition);
8575 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8580 * xmlXPathCountFunction:
8581 * @ctxt: the XPath Parser context
8582 * @nargs: the number of arguments
8584 * Implement the count() XPath function
8585 * number count(node-set)
8588 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8589 xmlXPathObjectPtr cur;
8592 if ((ctxt->value == NULL) ||
8593 ((ctxt->value->type != XPATH_NODESET) &&
8594 (ctxt->value->type != XPATH_XSLT_TREE)))
8595 XP_ERROR(XPATH_INVALID_TYPE);
8596 cur = valuePop(ctxt);
8598 if ((cur == NULL) || (cur->nodesetval == NULL))
8599 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8600 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8601 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8602 (double) cur->nodesetval->nodeNr));
8604 if ((cur->nodesetval->nodeNr != 1) ||
8605 (cur->nodesetval->nodeTab == NULL)) {
8606 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8611 tmp = cur->nodesetval->nodeTab[0];
8612 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8613 tmp = tmp->children;
8614 while (tmp != NULL) {
8619 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8622 xmlXPathReleaseObject(ctxt->context, cur);
8626 * xmlXPathGetElementsByIds:
8627 * @doc: the document
8628 * @ids: a whitespace separated list of IDs
8630 * Selects elements by their unique ID.
8632 * Returns a node-set of selected elements.
8634 static xmlNodeSetPtr
8635 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8637 const xmlChar *cur = ids;
8640 xmlNodePtr elem = NULL;
8642 if (ids == NULL) return(NULL);
8644 ret = xmlXPathNodeSetCreate(NULL);
8648 while (IS_BLANK_CH(*cur)) cur++;
8650 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8653 ID = xmlStrndup(ids, cur - ids);
8656 * We used to check the fact that the value passed
8657 * was an NCName, but this generated much troubles for
8658 * me and Aleksey Sanin, people blatantly violated that
8659 * constaint, like Visa3D spec.
8660 * if (xmlValidateNCName(ID, 1) == 0)
8662 attr = xmlGetID(doc, ID);
8664 if (attr->type == XML_ATTRIBUTE_NODE)
8665 elem = attr->parent;
8666 else if (attr->type == XML_ELEMENT_NODE)
8667 elem = (xmlNodePtr) attr;
8671 xmlXPathNodeSetAdd(ret, elem);
8676 while (IS_BLANK_CH(*cur)) cur++;
8683 * xmlXPathIdFunction:
8684 * @ctxt: the XPath Parser context
8685 * @nargs: the number of arguments
8687 * Implement the id() XPath function
8688 * node-set id(object)
8689 * The id function selects elements by their unique ID
8690 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8691 * then the result is the union of the result of applying id to the
8692 * string value of each of the nodes in the argument node-set. When the
8693 * argument to id is of any other type, the argument is converted to a
8694 * string as if by a call to the string function; the string is split
8695 * into a whitespace-separated list of tokens (whitespace is any sequence
8696 * of characters matching the production S); the result is a node-set
8697 * containing the elements in the same document as the context node that
8698 * have a unique ID equal to any of the tokens in the list.
8701 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8704 xmlXPathObjectPtr obj;
8707 obj = valuePop(ctxt);
8708 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8709 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8713 ret = xmlXPathNodeSetCreate(NULL);
8715 * FIXME -- in an out-of-memory condition this will behave badly.
8716 * The solution is not clear -- we already popped an item from
8717 * ctxt, so the object is in a corrupt state.
8720 if (obj->nodesetval != NULL) {
8721 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8723 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8724 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8725 ret = xmlXPathNodeSetMerge(ret, ns);
8726 xmlXPathFreeNodeSet(ns);
8731 xmlXPathReleaseObject(ctxt->context, obj);
8732 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8735 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8736 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8737 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8738 xmlXPathReleaseObject(ctxt->context, obj);
8743 * xmlXPathLocalNameFunction:
8744 * @ctxt: the XPath Parser context
8745 * @nargs: the number of arguments
8747 * Implement the local-name() XPath function
8748 * string local-name(node-set?)
8749 * The local-name function returns a string containing the local part
8750 * of the name of the node in the argument node-set that is first in
8751 * document order. If the node-set is empty or the first node has no
8752 * name, an empty string is returned. If the argument is omitted it
8753 * defaults to the context node.
8756 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8757 xmlXPathObjectPtr cur;
8759 if (ctxt == NULL) return;
8762 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8763 ctxt->context->node));
8768 if ((ctxt->value == NULL) ||
8769 ((ctxt->value->type != XPATH_NODESET) &&
8770 (ctxt->value->type != XPATH_XSLT_TREE)))
8771 XP_ERROR(XPATH_INVALID_TYPE);
8772 cur = valuePop(ctxt);
8774 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8775 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8777 int i = 0; /* Should be first in document order !!!!! */
8778 switch (cur->nodesetval->nodeTab[i]->type) {
8779 case XML_ELEMENT_NODE:
8780 case XML_ATTRIBUTE_NODE:
8782 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8783 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8786 xmlXPathCacheNewString(ctxt->context,
8787 cur->nodesetval->nodeTab[i]->name));
8789 case XML_NAMESPACE_DECL:
8790 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8791 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8794 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8797 xmlXPathReleaseObject(ctxt->context, cur);
8801 * xmlXPathNamespaceURIFunction:
8802 * @ctxt: the XPath Parser context
8803 * @nargs: the number of arguments
8805 * Implement the namespace-uri() XPath function
8806 * string namespace-uri(node-set?)
8807 * The namespace-uri function returns a string containing the
8808 * namespace URI of the expanded name of the node in the argument
8809 * node-set that is first in document order. If the node-set is empty,
8810 * the first node has no name, or the expanded name has no namespace
8811 * URI, an empty string is returned. If the argument is omitted it
8812 * defaults to the context node.
8815 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8816 xmlXPathObjectPtr cur;
8818 if (ctxt == NULL) return;
8821 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8822 ctxt->context->node));
8826 if ((ctxt->value == NULL) ||
8827 ((ctxt->value->type != XPATH_NODESET) &&
8828 (ctxt->value->type != XPATH_XSLT_TREE)))
8829 XP_ERROR(XPATH_INVALID_TYPE);
8830 cur = valuePop(ctxt);
8832 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8833 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8835 int i = 0; /* Should be first in document order !!!!! */
8836 switch (cur->nodesetval->nodeTab[i]->type) {
8837 case XML_ELEMENT_NODE:
8838 case XML_ATTRIBUTE_NODE:
8839 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8840 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8842 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8843 cur->nodesetval->nodeTab[i]->ns->href));
8846 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8849 xmlXPathReleaseObject(ctxt->context, cur);
8853 * xmlXPathNameFunction:
8854 * @ctxt: the XPath Parser context
8855 * @nargs: the number of arguments
8857 * Implement the name() XPath function
8858 * string name(node-set?)
8859 * The name function returns a string containing a QName representing
8860 * the name of the node in the argument node-set that is first in document
8861 * order. The QName must represent the name with respect to the namespace
8862 * declarations in effect on the node whose name is being represented.
8863 * Typically, this will be the form in which the name occurred in the XML
8864 * source. This need not be the case if there are namespace declarations
8865 * in effect on the node that associate multiple prefixes with the same
8866 * namespace. However, an implementation may include information about
8867 * the original prefix in its representation of nodes; in this case, an
8868 * implementation can ensure that the returned string is always the same
8869 * as the QName used in the XML source. If the argument it omitted it
8870 * defaults to the context node.
8871 * Libxml keep the original prefix so the "real qualified name" used is
8875 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8877 xmlXPathObjectPtr cur;
8880 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8881 ctxt->context->node));
8886 if ((ctxt->value == NULL) ||
8887 ((ctxt->value->type != XPATH_NODESET) &&
8888 (ctxt->value->type != XPATH_XSLT_TREE)))
8889 XP_ERROR(XPATH_INVALID_TYPE);
8890 cur = valuePop(ctxt);
8892 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8893 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8895 int i = 0; /* Should be first in document order !!!!! */
8897 switch (cur->nodesetval->nodeTab[i]->type) {
8898 case XML_ELEMENT_NODE:
8899 case XML_ATTRIBUTE_NODE:
8900 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8902 xmlXPathCacheNewCString(ctxt->context, ""));
8903 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8904 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8906 xmlXPathCacheNewString(ctxt->context,
8907 cur->nodesetval->nodeTab[i]->name));
8911 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8912 cur->nodesetval->nodeTab[i]->ns->prefix,
8914 if (fullname == cur->nodesetval->nodeTab[i]->name)
8915 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8916 if (fullname == NULL) {
8917 XP_ERROR(XPATH_MEMORY_ERROR);
8919 valuePush(ctxt, xmlXPathCacheWrapString(
8920 ctxt->context, fullname));
8924 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8925 cur->nodesetval->nodeTab[i]));
8926 xmlXPathLocalNameFunction(ctxt, 1);
8929 xmlXPathReleaseObject(ctxt->context, cur);
8934 * xmlXPathStringFunction:
8935 * @ctxt: the XPath Parser context
8936 * @nargs: the number of arguments
8938 * Implement the string() XPath function
8939 * string string(object?)
8940 * The string function converts an object to a string as follows:
8941 * - A node-set is converted to a string by returning the value of
8942 * the node in the node-set that is first in document order.
8943 * If the node-set is empty, an empty string is returned.
8944 * - A number is converted to a string as follows
8945 * + NaN is converted to the string NaN
8946 * + positive zero is converted to the string 0
8947 * + negative zero is converted to the string 0
8948 * + positive infinity is converted to the string Infinity
8949 * + negative infinity is converted to the string -Infinity
8950 * + if the number is an integer, the number is represented in
8951 * decimal form as a Number with no decimal point and no leading
8952 * zeros, preceded by a minus sign (-) if the number is negative
8953 * + otherwise, the number is represented in decimal form as a
8954 * Number including a decimal point with at least one digit
8955 * before the decimal point and at least one digit after the
8956 * decimal point, preceded by a minus sign (-) if the number
8957 * is negative; there must be no leading zeros before the decimal
8958 * point apart possibly from the one required digit immediately
8959 * before the decimal point; beyond the one required digit
8960 * after the decimal point there must be as many, but only as
8961 * many, more digits as are needed to uniquely distinguish the
8962 * number from all other IEEE 754 numeric values.
8963 * - The boolean false value is converted to the string false.
8964 * The boolean true value is converted to the string true.
8966 * If the argument is omitted, it defaults to a node-set with the
8967 * context node as its only member.
8970 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8971 xmlXPathObjectPtr cur;
8973 if (ctxt == NULL) return;
8976 xmlXPathCacheWrapString(ctxt->context,
8977 xmlXPathCastNodeToString(ctxt->context->node)));
8982 cur = valuePop(ctxt);
8983 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8984 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8988 * xmlXPathStringLengthFunction:
8989 * @ctxt: the XPath Parser context
8990 * @nargs: the number of arguments
8992 * Implement the string-length() XPath function
8993 * number string-length(string?)
8994 * The string-length returns the number of characters in the string
8995 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8996 * the context node converted to a string, in other words the value
8997 * of the context node.
9000 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9001 xmlXPathObjectPtr cur;
9004 if ((ctxt == NULL) || (ctxt->context == NULL))
9006 if (ctxt->context->node == NULL) {
9007 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9011 content = xmlXPathCastNodeToString(ctxt->context->node);
9012 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9013 xmlUTF8Strlen(content)));
9020 CHECK_TYPE(XPATH_STRING);
9021 cur = valuePop(ctxt);
9022 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9023 xmlUTF8Strlen(cur->stringval)));
9024 xmlXPathReleaseObject(ctxt->context, cur);
9028 * xmlXPathConcatFunction:
9029 * @ctxt: the XPath Parser context
9030 * @nargs: the number of arguments
9032 * Implement the concat() XPath function
9033 * string concat(string, string, string*)
9034 * The concat function returns the concatenation of its arguments.
9037 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038 xmlXPathObjectPtr cur, newobj;
9041 if (ctxt == NULL) return;
9047 cur = valuePop(ctxt);
9048 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9049 xmlXPathReleaseObject(ctxt->context, cur);
9056 newobj = valuePop(ctxt);
9057 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9058 xmlXPathReleaseObject(ctxt->context, newobj);
9059 xmlXPathReleaseObject(ctxt->context, cur);
9060 XP_ERROR(XPATH_INVALID_TYPE);
9062 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9063 newobj->stringval = cur->stringval;
9064 cur->stringval = tmp;
9065 xmlXPathReleaseObject(ctxt->context, newobj);
9068 valuePush(ctxt, cur);
9072 * xmlXPathContainsFunction:
9073 * @ctxt: the XPath Parser context
9074 * @nargs: the number of arguments
9076 * Implement the contains() XPath function
9077 * boolean contains(string, string)
9078 * The contains function returns true if the first argument string
9079 * contains the second argument string, and otherwise returns false.
9082 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9083 xmlXPathObjectPtr hay, needle;
9087 CHECK_TYPE(XPATH_STRING);
9088 needle = valuePop(ctxt);
9090 hay = valuePop(ctxt);
9092 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9093 xmlXPathReleaseObject(ctxt->context, hay);
9094 xmlXPathReleaseObject(ctxt->context, needle);
9095 XP_ERROR(XPATH_INVALID_TYPE);
9097 if (xmlStrstr(hay->stringval, needle->stringval))
9098 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9100 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9101 xmlXPathReleaseObject(ctxt->context, hay);
9102 xmlXPathReleaseObject(ctxt->context, needle);
9106 * xmlXPathStartsWithFunction:
9107 * @ctxt: the XPath Parser context
9108 * @nargs: the number of arguments
9110 * Implement the starts-with() XPath function
9111 * boolean starts-with(string, string)
9112 * The starts-with function returns true if the first argument string
9113 * starts with the second argument string, and otherwise returns false.
9116 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9117 xmlXPathObjectPtr hay, needle;
9122 CHECK_TYPE(XPATH_STRING);
9123 needle = valuePop(ctxt);
9125 hay = valuePop(ctxt);
9127 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9128 xmlXPathReleaseObject(ctxt->context, hay);
9129 xmlXPathReleaseObject(ctxt->context, needle);
9130 XP_ERROR(XPATH_INVALID_TYPE);
9132 n = xmlStrlen(needle->stringval);
9133 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9134 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9136 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9137 xmlXPathReleaseObject(ctxt->context, hay);
9138 xmlXPathReleaseObject(ctxt->context, needle);
9142 * xmlXPathSubstringFunction:
9143 * @ctxt: the XPath Parser context
9144 * @nargs: the number of arguments
9146 * Implement the substring() XPath function
9147 * string substring(string, number, number?)
9148 * The substring function returns the substring of the first argument
9149 * starting at the position specified in the second argument with
9150 * length specified in the third argument. For example,
9151 * substring("12345",2,3) returns "234". If the third argument is not
9152 * specified, it returns the substring starting at the position specified
9153 * in the second argument and continuing to the end of the string. For
9154 * example, substring("12345",2) returns "2345". More precisely, each
9155 * character in the string (see [3.6 Strings]) is considered to have a
9156 * numeric position: the position of the first character is 1, the position
9157 * of the second character is 2 and so on. The returned substring contains
9158 * those characters for which the position of the character is greater than
9159 * or equal to the second argument and, if the third argument is specified,
9160 * less than the sum of the second and third arguments; the comparisons
9161 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9162 * - substring("12345", 1.5, 2.6) returns "234"
9163 * - substring("12345", 0, 3) returns "12"
9164 * - substring("12345", 0 div 0, 3) returns ""
9165 * - substring("12345", 1, 0 div 0) returns ""
9166 * - substring("12345", -42, 1 div 0) returns "12345"
9167 * - substring("12345", -1 div 0, 1 div 0) returns ""
9170 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9171 xmlXPathObjectPtr str, start, len;
9183 * take care of possible last (position) argument
9187 CHECK_TYPE(XPATH_NUMBER);
9188 len = valuePop(ctxt);
9190 xmlXPathReleaseObject(ctxt->context, len);
9194 CHECK_TYPE(XPATH_NUMBER);
9195 start = valuePop(ctxt);
9196 in = start->floatval;
9197 xmlXPathReleaseObject(ctxt->context, start);
9199 CHECK_TYPE(XPATH_STRING);
9200 str = valuePop(ctxt);
9201 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9204 * If last pos not present, calculate last position
9212 /* Need to check for the special cases where either
9213 * the index is NaN, the length is NaN, or both
9214 * arguments are infinity (relying on Inf + -Inf = NaN)
9216 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9218 * To meet the requirements of the spec, the arguments
9219 * must be converted to integer format before
9220 * initial index calculations are done
9222 * First we go to integer form, rounding up
9223 * and checking for special cases
9226 if (((double)i)+0.5 <= in) i++;
9228 if (xmlXPathIsInf(le) == 1) {
9233 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9237 if (((double)l)+0.5 <= le) l++;
9240 /* Now we normalize inidices */
9248 /* number of chars to copy */
9251 ret = xmlUTF8Strsub(str->stringval, i, l);
9257 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9259 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9262 xmlXPathReleaseObject(ctxt->context, str);
9266 * xmlXPathSubstringBeforeFunction:
9267 * @ctxt: the XPath Parser context
9268 * @nargs: the number of arguments
9270 * Implement the substring-before() XPath function
9271 * string substring-before(string, string)
9272 * The substring-before function returns the substring of the first
9273 * argument string that precedes the first occurrence of the second
9274 * argument string in the first argument string, or the empty string
9275 * if the first argument string does not contain the second argument
9276 * string. For example, substring-before("1999/04/01","/") returns 1999.
9279 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9280 xmlXPathObjectPtr str;
9281 xmlXPathObjectPtr find;
9283 const xmlChar *point;
9288 find = valuePop(ctxt);
9290 str = valuePop(ctxt);
9292 target = xmlBufCreate();
9294 point = xmlStrstr(str->stringval, find->stringval);
9296 offset = (int)(point - str->stringval);
9297 xmlBufAdd(target, str->stringval, offset);
9299 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9300 xmlBufContent(target)));
9303 xmlXPathReleaseObject(ctxt->context, str);
9304 xmlXPathReleaseObject(ctxt->context, find);
9308 * xmlXPathSubstringAfterFunction:
9309 * @ctxt: the XPath Parser context
9310 * @nargs: the number of arguments
9312 * Implement the substring-after() XPath function
9313 * string substring-after(string, string)
9314 * The substring-after function returns the substring of the first
9315 * argument string that follows the first occurrence of the second
9316 * argument string in the first argument string, or the empty stringi
9317 * if the first argument string does not contain the second argument
9318 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9319 * and substring-after("1999/04/01","19") returns 99/04/01.
9322 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9323 xmlXPathObjectPtr str;
9324 xmlXPathObjectPtr find;
9326 const xmlChar *point;
9331 find = valuePop(ctxt);
9333 str = valuePop(ctxt);
9335 target = xmlBufCreate();
9337 point = xmlStrstr(str->stringval, find->stringval);
9339 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9340 xmlBufAdd(target, &str->stringval[offset],
9341 xmlStrlen(str->stringval) - offset);
9343 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9344 xmlBufContent(target)));
9347 xmlXPathReleaseObject(ctxt->context, str);
9348 xmlXPathReleaseObject(ctxt->context, find);
9352 * xmlXPathNormalizeFunction:
9353 * @ctxt: the XPath Parser context
9354 * @nargs: the number of arguments
9356 * Implement the normalize-space() XPath function
9357 * string normalize-space(string?)
9358 * The normalize-space function returns the argument string with white
9359 * space normalized by stripping leading and trailing whitespace
9360 * and replacing sequences of whitespace characters by a single
9361 * space. Whitespace characters are the same allowed by the S production
9362 * in XML. If the argument is omitted, it defaults to the context
9363 * node converted to a string, in other words the value of the context node.
9366 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9367 xmlXPathObjectPtr obj = NULL;
9368 xmlChar *source = NULL;
9372 if (ctxt == NULL) return;
9374 /* Use current context node */
9376 xmlXPathCacheWrapString(ctxt->context,
9377 xmlXPathCastNodeToString(ctxt->context->node)));
9383 CHECK_TYPE(XPATH_STRING);
9384 obj = valuePop(ctxt);
9385 source = obj->stringval;
9387 target = xmlBufCreate();
9388 if (target && source) {
9390 /* Skip leading whitespaces */
9391 while (IS_BLANK_CH(*source))
9394 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9397 if (IS_BLANK_CH(*source)) {
9401 xmlBufAdd(target, &blank, 1);
9404 xmlBufAdd(target, source, 1);
9408 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9409 xmlBufContent(target)));
9412 xmlXPathReleaseObject(ctxt->context, obj);
9416 * xmlXPathTranslateFunction:
9417 * @ctxt: the XPath Parser context
9418 * @nargs: the number of arguments
9420 * Implement the translate() XPath function
9421 * string translate(string, string, string)
9422 * The translate function returns the first argument string with
9423 * occurrences of characters in the second argument string replaced
9424 * by the character at the corresponding position in the third argument
9425 * string. For example, translate("bar","abc","ABC") returns the string
9426 * BAr. If there is a character in the second argument string with no
9427 * character at a corresponding position in the third argument string
9428 * (because the second argument string is longer than the third argument
9429 * string), then occurrences of that character in the first argument
9430 * string are removed. For example, translate("--aaa--","abc-","ABC")
9431 * returns "AAA". If a character occurs more than once in second
9432 * argument string, then the first occurrence determines the replacement
9433 * character. If the third argument string is longer than the second
9434 * argument string, then excess characters are ignored.
9437 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9438 xmlXPathObjectPtr str;
9439 xmlXPathObjectPtr from;
9440 xmlXPathObjectPtr to;
9444 const xmlChar *point;
9450 to = valuePop(ctxt);
9452 from = valuePop(ctxt);
9454 str = valuePop(ctxt);
9456 target = xmlBufCreate();
9458 max = xmlUTF8Strlen(to->stringval);
9459 for (cptr = str->stringval; (ch=*cptr); ) {
9460 offset = xmlUTF8Strloc(from->stringval, cptr);
9463 point = xmlUTF8Strpos(to->stringval, offset);
9465 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9468 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9470 /* Step to next character in input */
9473 /* if not simple ascii, verify proper format */
9474 if ( (ch & 0xc0) != 0xc0 ) {
9475 xmlGenericError(xmlGenericErrorContext,
9476 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9477 /* not asserting an XPath error is probably better */
9480 /* then skip over remaining bytes for this char */
9481 while ( (ch <<= 1) & 0x80 )
9482 if ( (*cptr++ & 0xc0) != 0x80 ) {
9483 xmlGenericError(xmlGenericErrorContext,
9484 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9485 /* not asserting an XPath error is probably better */
9488 if (ch & 0x80) /* must have had error encountered */
9493 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9494 xmlBufContent(target)));
9496 xmlXPathReleaseObject(ctxt->context, str);
9497 xmlXPathReleaseObject(ctxt->context, from);
9498 xmlXPathReleaseObject(ctxt->context, to);
9502 * xmlXPathBooleanFunction:
9503 * @ctxt: the XPath Parser context
9504 * @nargs: the number of arguments
9506 * Implement the boolean() XPath function
9507 * boolean boolean(object)
9508 * The boolean function converts its argument to a boolean as follows:
9509 * - a number is true if and only if it is neither positive or
9510 * negative zero nor NaN
9511 * - a node-set is true if and only if it is non-empty
9512 * - a string is true if and only if its length is non-zero
9515 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9516 xmlXPathObjectPtr cur;
9519 cur = valuePop(ctxt);
9520 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9521 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9522 valuePush(ctxt, cur);
9526 * xmlXPathNotFunction:
9527 * @ctxt: the XPath Parser context
9528 * @nargs: the number of arguments
9530 * Implement the not() XPath function
9531 * boolean not(boolean)
9532 * The not function returns true if its argument is false,
9533 * and false otherwise.
9536 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9539 CHECK_TYPE(XPATH_BOOLEAN);
9540 ctxt->value->boolval = ! ctxt->value->boolval;
9544 * xmlXPathTrueFunction:
9545 * @ctxt: the XPath Parser context
9546 * @nargs: the number of arguments
9548 * Implement the true() XPath function
9552 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9554 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9558 * xmlXPathFalseFunction:
9559 * @ctxt: the XPath Parser context
9560 * @nargs: the number of arguments
9562 * Implement the false() XPath function
9566 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9568 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9572 * xmlXPathLangFunction:
9573 * @ctxt: the XPath Parser context
9574 * @nargs: the number of arguments
9576 * Implement the lang() XPath function
9577 * boolean lang(string)
9578 * The lang function returns true or false depending on whether the
9579 * language of the context node as specified by xml:lang attributes
9580 * is the same as or is a sublanguage of the language specified by
9581 * the argument string. The language of the context node is determined
9582 * by the value of the xml:lang attribute on the context node, or, if
9583 * the context node has no xml:lang attribute, by the value of the
9584 * xml:lang attribute on the nearest ancestor of the context node that
9585 * has an xml:lang attribute. If there is no such attribute, then lang
9586 * returns false. If there is such an attribute, then lang returns
9587 * true if the attribute value is equal to the argument ignoring case,
9588 * or if there is some suffix starting with - such that the attribute
9589 * value is equal to the argument ignoring that suffix of the attribute
9590 * value and ignoring case.
9593 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9594 xmlXPathObjectPtr val = NULL;
9595 const xmlChar *theLang = NULL;
9596 const xmlChar *lang;
9602 CHECK_TYPE(XPATH_STRING);
9603 val = valuePop(ctxt);
9604 lang = val->stringval;
9605 theLang = xmlNodeGetLang(ctxt->context->node);
9606 if ((theLang != NULL) && (lang != NULL)) {
9607 for (i = 0;lang[i] != 0;i++)
9608 if (toupper(lang[i]) != toupper(theLang[i]))
9610 if ((theLang[i] == 0) || (theLang[i] == '-'))
9614 if (theLang != NULL)
9615 xmlFree((void *)theLang);
9617 xmlXPathReleaseObject(ctxt->context, val);
9618 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9622 * xmlXPathNumberFunction:
9623 * @ctxt: the XPath Parser context
9624 * @nargs: the number of arguments
9626 * Implement the number() XPath function
9627 * number number(object?)
9630 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9631 xmlXPathObjectPtr cur;
9634 if (ctxt == NULL) return;
9636 if (ctxt->context->node == NULL) {
9637 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9639 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9641 res = xmlXPathStringEvalNumber(content);
9642 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9649 cur = valuePop(ctxt);
9650 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9654 * xmlXPathSumFunction:
9655 * @ctxt: the XPath Parser context
9656 * @nargs: the number of arguments
9658 * Implement the sum() XPath function
9659 * number sum(node-set)
9660 * The sum function returns the sum of the values of the nodes in
9661 * the argument node-set.
9664 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9665 xmlXPathObjectPtr cur;
9670 if ((ctxt->value == NULL) ||
9671 ((ctxt->value->type != XPATH_NODESET) &&
9672 (ctxt->value->type != XPATH_XSLT_TREE)))
9673 XP_ERROR(XPATH_INVALID_TYPE);
9674 cur = valuePop(ctxt);
9676 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9677 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9678 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9681 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9682 xmlXPathReleaseObject(ctxt->context, cur);
9686 * xmlXPathFloorFunction:
9687 * @ctxt: the XPath Parser context
9688 * @nargs: the number of arguments
9690 * Implement the floor() XPath function
9691 * number floor(number)
9692 * The floor function returns the largest (closest to positive infinity)
9693 * number that is not greater than the argument and that is an integer.
9696 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9699 CHECK_TYPE(XPATH_NUMBER);
9701 ctxt->value->floatval = floor(ctxt->value->floatval);
9705 * xmlXPathCeilingFunction:
9706 * @ctxt: the XPath Parser context
9707 * @nargs: the number of arguments
9709 * Implement the ceiling() XPath function
9710 * number ceiling(number)
9711 * The ceiling function returns the smallest (closest to negative infinity)
9712 * number that is not less than the argument and that is an integer.
9715 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9718 CHECK_TYPE(XPATH_NUMBER);
9720 ctxt->value->floatval = ceil(ctxt->value->floatval);
9724 * xmlXPathRoundFunction:
9725 * @ctxt: the XPath Parser context
9726 * @nargs: the number of arguments
9728 * Implement the round() XPath function
9729 * number round(number)
9730 * The round function returns the number that is closest to the
9731 * argument and that is an integer. If there are two such numbers,
9732 * then the one that is closest to positive infinity is returned.
9735 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9740 CHECK_TYPE(XPATH_NUMBER);
9742 f = ctxt->value->floatval;
9744 /* Test for zero to keep negative zero unchanged. */
9745 if ((xmlXPathIsNaN(f)) || (f == 0.0))
9748 if ((f >= -0.5) && (f < 0.0)) {
9749 /* Negative zero. */
9750 ctxt->value->floatval = xmlXPathNZERO;
9753 double rounded = floor(f);
9754 if (f - rounded >= 0.5)
9756 ctxt->value->floatval = rounded;
9760 /************************************************************************
9764 ************************************************************************/
9767 * a few forward declarations since we use a recursive call based
9770 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9771 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9772 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9773 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9774 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9778 * xmlXPathCurrentChar:
9779 * @ctxt: the XPath parser context
9780 * @cur: pointer to the beginning of the char
9781 * @len: pointer to the length of the char read
9783 * The current char value, if using UTF-8 this may actually span multiple
9784 * bytes in the input buffer.
9786 * Returns the current char value and its length
9790 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9800 * We are supposed to handle UTF8, check it's valid
9801 * From rfc2044: encoding of the Unicode values on UTF-8:
9803 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9804 * 0000 0000-0000 007F 0xxxxxxx
9805 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9806 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9808 * Check for the 0x110000 limit too
9812 if ((cur[1] & 0xc0) != 0x80)
9813 goto encoding_error;
9814 if ((c & 0xe0) == 0xe0) {
9816 if ((cur[2] & 0xc0) != 0x80)
9817 goto encoding_error;
9818 if ((c & 0xf0) == 0xf0) {
9819 if (((c & 0xf8) != 0xf0) ||
9820 ((cur[3] & 0xc0) != 0x80))
9821 goto encoding_error;
9824 val = (cur[0] & 0x7) << 18;
9825 val |= (cur[1] & 0x3f) << 12;
9826 val |= (cur[2] & 0x3f) << 6;
9827 val |= cur[3] & 0x3f;
9831 val = (cur[0] & 0xf) << 12;
9832 val |= (cur[1] & 0x3f) << 6;
9833 val |= cur[2] & 0x3f;
9838 val = (cur[0] & 0x1f) << 6;
9839 val |= cur[1] & 0x3f;
9841 if (!IS_CHAR(val)) {
9842 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9852 * If we detect an UTF8 error that probably means that the
9853 * input encoding didn't get properly advertised in the
9854 * declaration header. Report the error and switch the encoding
9855 * to ISO-Latin-1 (if you don't like this policy, just declare the
9859 XP_ERROR0(XPATH_ENCODING_ERROR);
9863 * xmlXPathParseNCName:
9864 * @ctxt: the XPath Parser context
9866 * parse an XML namespace non qualified name.
9868 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9870 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9871 * CombiningChar | Extender
9873 * Returns the namespace name or NULL
9877 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9882 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9884 * Accelerator for simple ASCII names
9887 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9888 ((*in >= 0x41) && (*in <= 0x5A)) ||
9891 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9892 ((*in >= 0x41) && (*in <= 0x5A)) ||
9893 ((*in >= 0x30) && (*in <= 0x39)) ||
9894 (*in == '_') || (*in == '.') ||
9897 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9898 (*in == '[') || (*in == ']') || (*in == ':') ||
9899 (*in == '@') || (*in == '*')) {
9900 count = in - ctxt->cur;
9903 ret = xmlStrndup(ctxt->cur, count);
9908 return(xmlXPathParseNameComplex(ctxt, 0));
9913 * xmlXPathParseQName:
9914 * @ctxt: the XPath Parser context
9915 * @prefix: a xmlChar **
9917 * parse an XML qualified name
9919 * [NS 5] QName ::= (Prefix ':')? LocalPart
9921 * [NS 6] Prefix ::= NCName
9923 * [NS 7] LocalPart ::= NCName
9925 * Returns the function returns the local part, and prefix is updated
9926 * to get the Prefix if any.
9930 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9931 xmlChar *ret = NULL;
9934 ret = xmlXPathParseNCName(ctxt);
9935 if (ret && CUR == ':') {
9938 ret = xmlXPathParseNCName(ctxt);
9944 * xmlXPathParseName:
9945 * @ctxt: the XPath Parser context
9949 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9950 * CombiningChar | Extender
9952 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9954 * Returns the namespace name or NULL
9958 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9963 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9965 * Accelerator for simple ASCII names
9968 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9969 ((*in >= 0x41) && (*in <= 0x5A)) ||
9970 (*in == '_') || (*in == ':')) {
9972 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9973 ((*in >= 0x41) && (*in <= 0x5A)) ||
9974 ((*in >= 0x30) && (*in <= 0x39)) ||
9975 (*in == '_') || (*in == '-') ||
9976 (*in == ':') || (*in == '.'))
9978 if ((*in > 0) && (*in < 0x80)) {
9979 count = in - ctxt->cur;
9980 if (count > XML_MAX_NAME_LENGTH) {
9982 XP_ERRORNULL(XPATH_EXPR_ERROR);
9984 ret = xmlStrndup(ctxt->cur, count);
9989 return(xmlXPathParseNameComplex(ctxt, 1));
9993 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9994 xmlChar buf[XML_MAX_NAMELEN + 5];
9999 * Handler for more complex cases
10002 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10003 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10004 (c == '*') || /* accelerators */
10005 (!IS_LETTER(c) && (c != '_') &&
10006 ((!qualified) || (c != ':')))) {
10010 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10011 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10012 (c == '.') || (c == '-') ||
10013 (c == '_') || ((qualified) && (c == ':')) ||
10014 (IS_COMBINING(c)) ||
10015 (IS_EXTENDER(c)))) {
10016 COPY_BUF(l,buf,len,c);
10019 if (len >= XML_MAX_NAMELEN) {
10021 * Okay someone managed to make a huge name, so he's ready to pay
10022 * for the processing speed.
10027 if (len > XML_MAX_NAME_LENGTH) {
10028 XP_ERRORNULL(XPATH_EXPR_ERROR);
10030 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10031 if (buffer == NULL) {
10032 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10034 memcpy(buffer, buf, len);
10035 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10036 (c == '.') || (c == '-') ||
10037 (c == '_') || ((qualified) && (c == ':')) ||
10038 (IS_COMBINING(c)) ||
10039 (IS_EXTENDER(c))) {
10040 if (len + 10 > max) {
10041 if (max > XML_MAX_NAME_LENGTH) {
10042 XP_ERRORNULL(XPATH_EXPR_ERROR);
10045 buffer = (xmlChar *) xmlRealloc(buffer,
10046 max * sizeof(xmlChar));
10047 if (buffer == NULL) {
10048 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10051 COPY_BUF(l,buffer,len,c);
10061 return(xmlStrndup(buf, len));
10064 #define MAX_FRAC 20
10067 * xmlXPathStringEvalNumber:
10068 * @str: A string to scan
10070 * [30a] Float ::= Number ('e' Digits?)?
10072 * [30] Number ::= Digits ('.' Digits?)?
10074 * [31] Digits ::= [0-9]+
10076 * Compile a Number in the string
10077 * In complement of the Number expression, this function also handles
10078 * negative values : '-' Number.
10080 * Returns the double value.
10083 xmlXPathStringEvalNumber(const xmlChar *str) {
10084 const xmlChar *cur = str;
10089 int is_exponent_negative = 0;
10091 unsigned long tmp = 0;
10094 if (cur == NULL) return(0);
10095 while (IS_BLANK_CH(*cur)) cur++;
10096 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10097 return(xmlXPathNAN);
10106 * tmp/temp is a workaround against a gcc compiler bug
10107 * http://veillard.com/gcc.bug
10110 while ((*cur >= '0') && (*cur <= '9')) {
10112 tmp = (*cur - '0');
10115 temp = (double) tmp;
10120 while ((*cur >= '0') && (*cur <= '9')) {
10121 ret = ret * 10 + (*cur - '0');
10128 int v, frac = 0, max;
10129 double fraction = 0;
10132 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10133 return(xmlXPathNAN);
10135 while (*cur == '0') {
10139 max = frac + MAX_FRAC;
10140 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10142 fraction = fraction * 10 + v;
10146 fraction /= pow(10.0, frac);
10147 ret = ret + fraction;
10148 while ((*cur >= '0') && (*cur <= '9'))
10151 if ((*cur == 'e') || (*cur == 'E')) {
10154 is_exponent_negative = 1;
10156 } else if (*cur == '+') {
10159 while ((*cur >= '0') && (*cur <= '9')) {
10160 if (exponent < 1000000)
10161 exponent = exponent * 10 + (*cur - '0');
10165 while (IS_BLANK_CH(*cur)) cur++;
10166 if (*cur != 0) return(xmlXPathNAN);
10167 if (isneg) ret = -ret;
10168 if (is_exponent_negative) exponent = -exponent;
10169 ret *= pow(10.0, (double)exponent);
10174 * xmlXPathCompNumber:
10175 * @ctxt: the XPath Parser context
10177 * [30] Number ::= Digits ('.' Digits?)?
10179 * [31] Digits ::= [0-9]+
10181 * Compile a Number, then push it on the stack
10185 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10190 int is_exponent_negative = 0;
10192 unsigned long tmp = 0;
10197 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10198 XP_ERROR(XPATH_NUMBER_ERROR);
10202 * tmp/temp is a workaround against a gcc compiler bug
10203 * http://veillard.com/gcc.bug
10206 while ((CUR >= '0') && (CUR <= '9')) {
10211 temp = (double) tmp;
10216 while ((CUR >= '0') && (CUR <= '9')) {
10217 ret = ret * 10 + (CUR - '0');
10223 int v, frac = 0, max;
10224 double fraction = 0;
10227 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10228 XP_ERROR(XPATH_NUMBER_ERROR);
10230 while (CUR == '0') {
10234 max = frac + MAX_FRAC;
10235 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10237 fraction = fraction * 10 + v;
10241 fraction /= pow(10.0, frac);
10242 ret = ret + fraction;
10243 while ((CUR >= '0') && (CUR <= '9'))
10246 if ((CUR == 'e') || (CUR == 'E')) {
10249 is_exponent_negative = 1;
10251 } else if (CUR == '+') {
10254 while ((CUR >= '0') && (CUR <= '9')) {
10255 if (exponent < 1000000)
10256 exponent = exponent * 10 + (CUR - '0');
10259 if (is_exponent_negative)
10260 exponent = -exponent;
10261 ret *= pow(10.0, (double) exponent);
10263 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10264 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10268 * xmlXPathParseLiteral:
10269 * @ctxt: the XPath Parser context
10273 * [29] Literal ::= '"' [^"]* '"'
10276 * Returns the value found or NULL in case of error
10279 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10281 xmlChar *ret = NULL;
10286 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10288 if (!IS_CHAR_CH(CUR)) {
10289 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10291 ret = xmlStrndup(q, CUR_PTR - q);
10294 } else if (CUR == '\'') {
10297 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10299 if (!IS_CHAR_CH(CUR)) {
10300 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10302 ret = xmlStrndup(q, CUR_PTR - q);
10306 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10312 * xmlXPathCompLiteral:
10313 * @ctxt: the XPath Parser context
10315 * Parse a Literal and push it on the stack.
10317 * [29] Literal ::= '"' [^"]* '"'
10320 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10323 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10325 xmlChar *ret = NULL;
10330 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10332 if (!IS_CHAR_CH(CUR)) {
10333 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10335 ret = xmlStrndup(q, CUR_PTR - q);
10338 } else if (CUR == '\'') {
10341 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10343 if (!IS_CHAR_CH(CUR)) {
10344 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10346 ret = xmlStrndup(q, CUR_PTR - q);
10350 XP_ERROR(XPATH_START_LITERAL_ERROR);
10352 if (ret == NULL) return;
10353 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10354 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10359 * xmlXPathCompVariableReference:
10360 * @ctxt: the XPath Parser context
10362 * Parse a VariableReference, evaluate it and push it on the stack.
10364 * The variable bindings consist of a mapping from variable names
10365 * to variable values. The value of a variable is an object, which can be
10366 * of any of the types that are possible for the value of an expression,
10367 * and may also be of additional types not specified here.
10369 * Early evaluation is possible since:
10370 * The variable bindings [...] used to evaluate a subexpression are
10371 * always the same as those used to evaluate the containing expression.
10373 * [36] VariableReference ::= '$' QName
10376 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10382 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10385 name = xmlXPathParseQName(ctxt, &prefix);
10386 if (name == NULL) {
10388 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10390 ctxt->comp->last = -1;
10391 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10394 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10395 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10400 * xmlXPathIsNodeType:
10401 * @name: a name string
10403 * Is the name given a NodeType one.
10405 * [38] NodeType ::= 'comment'
10407 * | 'processing-instruction'
10410 * Returns 1 if true 0 otherwise
10413 xmlXPathIsNodeType(const xmlChar *name) {
10417 if (xmlStrEqual(name, BAD_CAST "node"))
10419 if (xmlStrEqual(name, BAD_CAST "text"))
10421 if (xmlStrEqual(name, BAD_CAST "comment"))
10423 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10429 * xmlXPathCompFunctionCall:
10430 * @ctxt: the XPath Parser context
10432 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10433 * [17] Argument ::= Expr
10435 * Compile a function call, the evaluation of all arguments are
10436 * pushed on the stack
10439 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10445 name = xmlXPathParseQName(ctxt, &prefix);
10446 if (name == NULL) {
10448 XP_ERROR(XPATH_EXPR_ERROR);
10452 if (prefix == NULL)
10453 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10456 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10463 XP_ERROR(XPATH_EXPR_ERROR);
10469 * Optimization for count(): we don't need the node-set to be sorted.
10471 if ((prefix == NULL) && (name[0] == 'c') &&
10472 xmlStrEqual(name, BAD_CAST "count"))
10476 ctxt->comp->last = -1;
10479 int op1 = ctxt->comp->last;
10480 ctxt->comp->last = -1;
10481 xmlXPathCompileExpr(ctxt, sort);
10482 if (ctxt->error != XPATH_EXPRESSION_OK) {
10487 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10489 if (CUR == ')') break;
10493 XP_ERROR(XPATH_EXPR_ERROR);
10499 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10506 * xmlXPathCompPrimaryExpr:
10507 * @ctxt: the XPath Parser context
10509 * [15] PrimaryExpr ::= VariableReference
10515 * Compile a primary expression.
10518 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10520 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10521 else if (CUR == '(') {
10524 xmlXPathCompileExpr(ctxt, 1);
10527 XP_ERROR(XPATH_EXPR_ERROR);
10531 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10532 xmlXPathCompNumber(ctxt);
10533 } else if ((CUR == '\'') || (CUR == '"')) {
10534 xmlXPathCompLiteral(ctxt);
10536 xmlXPathCompFunctionCall(ctxt);
10542 * xmlXPathCompFilterExpr:
10543 * @ctxt: the XPath Parser context
10545 * [20] FilterExpr ::= PrimaryExpr
10546 * | FilterExpr Predicate
10548 * Compile a filter expression.
10549 * Square brackets are used to filter expressions in the same way that
10550 * they are used in location paths. It is an error if the expression to
10551 * be filtered does not evaluate to a node-set. The context node list
10552 * used for evaluating the expression in square brackets is the node-set
10553 * to be filtered listed in document order.
10557 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10558 xmlXPathCompPrimaryExpr(ctxt);
10562 while (CUR == '[') {
10563 xmlXPathCompPredicate(ctxt, 1);
10571 * xmlXPathScanName:
10572 * @ctxt: the XPath Parser context
10574 * Trickery: parse an XML name but without consuming the input flow
10575 * Needed to avoid insanity in the parser state.
10577 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10578 * CombiningChar | Extender
10580 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10582 * [6] Names ::= Name (S Name)*
10584 * Returns the Name parsed or NULL
10588 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10591 const xmlChar *cur;
10597 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10598 (!IS_LETTER(c) && (c != '_') &&
10603 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10604 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10605 (c == '.') || (c == '-') ||
10606 (c == '_') || (c == ':') ||
10607 (IS_COMBINING(c)) ||
10608 (IS_EXTENDER(c)))) {
10613 ret = xmlStrndup(cur, ctxt->cur - cur);
10619 * xmlXPathCompPathExpr:
10620 * @ctxt: the XPath Parser context
10622 * [19] PathExpr ::= LocationPath
10624 * | FilterExpr '/' RelativeLocationPath
10625 * | FilterExpr '//' RelativeLocationPath
10627 * Compile a path expression.
10628 * The / operator and // operators combine an arbitrary expression
10629 * and a relative location path. It is an error if the expression
10630 * does not evaluate to a node-set.
10631 * The / operator does composition in the same way as when / is
10632 * used in a location path. As in location paths, // is short for
10633 * /descendant-or-self::node()/.
10637 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10638 int lc = 1; /* Should we branch to LocationPath ? */
10639 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10642 if ((CUR == '$') || (CUR == '(') ||
10643 (IS_ASCII_DIGIT(CUR)) ||
10644 (CUR == '\'') || (CUR == '"') ||
10645 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10647 } else if (CUR == '*') {
10648 /* relative or absolute location path */
10650 } else if (CUR == '/') {
10651 /* relative or absolute location path */
10653 } else if (CUR == '@') {
10654 /* relative abbreviated attribute location path */
10656 } else if (CUR == '.') {
10657 /* relative abbreviated attribute location path */
10661 * Problem is finding if we have a name here whether it's:
10663 * - a function call in which case it's followed by '('
10664 * - an axis in which case it's followed by ':'
10666 * We do an a priori analysis here rather than having to
10667 * maintain parsed token content through the recursive function
10668 * calls. This looks uglier but makes the code easier to
10669 * read/write/debug.
10672 name = xmlXPathScanName(ctxt);
10673 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10675 xmlGenericError(xmlGenericErrorContext,
10676 "PathExpr: Axis\n");
10680 } else if (name != NULL) {
10681 int len =xmlStrlen(name);
10684 while (NXT(len) != 0) {
10685 if (NXT(len) == '/') {
10688 xmlGenericError(xmlGenericErrorContext,
10689 "PathExpr: AbbrRelLocation\n");
10693 } else if (IS_BLANK_CH(NXT(len))) {
10694 /* ignore blanks */
10696 } else if (NXT(len) == ':') {
10698 xmlGenericError(xmlGenericErrorContext,
10699 "PathExpr: AbbrRelLocation\n");
10703 } else if ((NXT(len) == '(')) {
10704 /* Node Type or Function */
10705 if (xmlXPathIsNodeType(name)) {
10707 xmlGenericError(xmlGenericErrorContext,
10708 "PathExpr: Type search\n");
10711 #ifdef LIBXML_XPTR_ENABLED
10712 } else if (ctxt->xptr &&
10713 xmlStrEqual(name, BAD_CAST "range-to")) {
10718 xmlGenericError(xmlGenericErrorContext,
10719 "PathExpr: function call\n");
10724 } else if ((NXT(len) == '[')) {
10727 xmlGenericError(xmlGenericErrorContext,
10728 "PathExpr: AbbrRelLocation\n");
10732 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10733 (NXT(len) == '=')) {
10742 if (NXT(len) == 0) {
10744 xmlGenericError(xmlGenericErrorContext,
10745 "PathExpr: AbbrRelLocation\n");
10752 /* make sure all cases are covered explicitly */
10753 XP_ERROR(XPATH_EXPR_ERROR);
10759 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10761 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10763 xmlXPathCompLocationPath(ctxt);
10765 xmlXPathCompFilterExpr(ctxt);
10767 if ((CUR == '/') && (NXT(1) == '/')) {
10771 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10772 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10773 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10775 xmlXPathCompRelativeLocationPath(ctxt);
10776 } else if (CUR == '/') {
10777 xmlXPathCompRelativeLocationPath(ctxt);
10784 * xmlXPathCompUnionExpr:
10785 * @ctxt: the XPath Parser context
10787 * [18] UnionExpr ::= PathExpr
10788 * | UnionExpr '|' PathExpr
10790 * Compile an union expression.
10794 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10795 xmlXPathCompPathExpr(ctxt);
10798 while (CUR == '|') {
10799 int op1 = ctxt->comp->last;
10800 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10804 xmlXPathCompPathExpr(ctxt);
10806 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10813 * xmlXPathCompUnaryExpr:
10814 * @ctxt: the XPath Parser context
10816 * [27] UnaryExpr ::= UnionExpr
10819 * Compile an unary expression.
10823 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10828 while (CUR == '-') {
10835 xmlXPathCompUnionExpr(ctxt);
10839 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10841 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10846 * xmlXPathCompMultiplicativeExpr:
10847 * @ctxt: the XPath Parser context
10849 * [26] MultiplicativeExpr ::= UnaryExpr
10850 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10851 * | MultiplicativeExpr 'div' UnaryExpr
10852 * | MultiplicativeExpr 'mod' UnaryExpr
10853 * [34] MultiplyOperator ::= '*'
10855 * Compile an Additive expression.
10859 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10860 xmlXPathCompUnaryExpr(ctxt);
10863 while ((CUR == '*') ||
10864 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10865 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10867 int op1 = ctxt->comp->last;
10872 } else if (CUR == 'd') {
10875 } else if (CUR == 'm') {
10880 xmlXPathCompUnaryExpr(ctxt);
10882 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10888 * xmlXPathCompAdditiveExpr:
10889 * @ctxt: the XPath Parser context
10891 * [25] AdditiveExpr ::= MultiplicativeExpr
10892 * | AdditiveExpr '+' MultiplicativeExpr
10893 * | AdditiveExpr '-' MultiplicativeExpr
10895 * Compile an Additive expression.
10899 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10901 xmlXPathCompMultiplicativeExpr(ctxt);
10904 while ((CUR == '+') || (CUR == '-')) {
10906 int op1 = ctxt->comp->last;
10908 if (CUR == '+') plus = 1;
10912 xmlXPathCompMultiplicativeExpr(ctxt);
10914 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10920 * xmlXPathCompRelationalExpr:
10921 * @ctxt: the XPath Parser context
10923 * [24] RelationalExpr ::= AdditiveExpr
10924 * | RelationalExpr '<' AdditiveExpr
10925 * | RelationalExpr '>' AdditiveExpr
10926 * | RelationalExpr '<=' AdditiveExpr
10927 * | RelationalExpr '>=' AdditiveExpr
10929 * A <= B > C is allowed ? Answer from James, yes with
10930 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10931 * which is basically what got implemented.
10933 * Compile a Relational expression, then push the result
10938 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10939 xmlXPathCompAdditiveExpr(ctxt);
10942 while ((CUR == '<') ||
10944 ((CUR == '<') && (NXT(1) == '=')) ||
10945 ((CUR == '>') && (NXT(1) == '='))) {
10947 int op1 = ctxt->comp->last;
10949 if (CUR == '<') inf = 1;
10951 if (NXT(1) == '=') strict = 0;
10956 xmlXPathCompAdditiveExpr(ctxt);
10958 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10964 * xmlXPathCompEqualityExpr:
10965 * @ctxt: the XPath Parser context
10967 * [23] EqualityExpr ::= RelationalExpr
10968 * | EqualityExpr '=' RelationalExpr
10969 * | EqualityExpr '!=' RelationalExpr
10971 * A != B != C is allowed ? Answer from James, yes with
10972 * (RelationalExpr = RelationalExpr) = RelationalExpr
10973 * (RelationalExpr != RelationalExpr) != RelationalExpr
10974 * which is basically what got implemented.
10976 * Compile an Equality expression.
10980 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10981 xmlXPathCompRelationalExpr(ctxt);
10984 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10986 int op1 = ctxt->comp->last;
10988 if (CUR == '=') eq = 1;
10993 xmlXPathCompRelationalExpr(ctxt);
10995 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
11001 * xmlXPathCompAndExpr:
11002 * @ctxt: the XPath Parser context
11004 * [22] AndExpr ::= EqualityExpr
11005 * | AndExpr 'and' EqualityExpr
11007 * Compile an AND expression.
11011 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11012 xmlXPathCompEqualityExpr(ctxt);
11015 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11016 int op1 = ctxt->comp->last;
11019 xmlXPathCompEqualityExpr(ctxt);
11021 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11027 * xmlXPathCompileExpr:
11028 * @ctxt: the XPath Parser context
11030 * [14] Expr ::= OrExpr
11031 * [21] OrExpr ::= AndExpr
11032 * | OrExpr 'or' AndExpr
11034 * Parse and compile an expression
11037 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11038 xmlXPathCompAndExpr(ctxt);
11041 while ((CUR == 'o') && (NXT(1) == 'r')) {
11042 int op1 = ctxt->comp->last;
11045 xmlXPathCompAndExpr(ctxt);
11047 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11050 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11051 /* more ops could be optimized too */
11053 * This is the main place to eliminate sorting for
11054 * operations which don't require a sorted node-set.
11057 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11062 * xmlXPathCompPredicate:
11063 * @ctxt: the XPath Parser context
11064 * @filter: act as a filter
11066 * [8] Predicate ::= '[' PredicateExpr ']'
11067 * [9] PredicateExpr ::= Expr
11069 * Compile a predicate expression
11072 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11073 int op1 = ctxt->comp->last;
11077 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11082 ctxt->comp->last = -1;
11084 * This call to xmlXPathCompileExpr() will deactivate sorting
11085 * of the predicate result.
11086 * TODO: Sorting is still activated for filters, since I'm not
11087 * sure if needed. Normally sorting should not be needed, since
11088 * a filter can only diminish the number of items in a sequence,
11089 * but won't change its order; so if the initial sequence is sorted,
11090 * subsequent sorting is not needed.
11093 xmlXPathCompileExpr(ctxt, 0);
11095 xmlXPathCompileExpr(ctxt, 1);
11099 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11103 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11105 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11112 * xmlXPathCompNodeTest:
11113 * @ctxt: the XPath Parser context
11114 * @test: pointer to a xmlXPathTestVal
11115 * @type: pointer to a xmlXPathTypeVal
11116 * @prefix: placeholder for a possible name prefix
11118 * [7] NodeTest ::= NameTest
11119 * | NodeType '(' ')'
11120 * | 'processing-instruction' '(' Literal ')'
11122 * [37] NameTest ::= '*'
11125 * [38] NodeType ::= 'comment'
11127 * | 'processing-instruction'
11130 * Returns the name found and updates @test, @type and @prefix appropriately
11133 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11134 xmlXPathTypeVal *type, const xmlChar **prefix,
11138 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11142 *type = (xmlXPathTypeVal) 0;
11143 *test = (xmlXPathTestVal) 0;
11147 if ((name == NULL) && (CUR == '*')) {
11152 *test = NODE_TEST_ALL;
11157 name = xmlXPathParseNCName(ctxt);
11158 if (name == NULL) {
11159 XP_ERRORNULL(XPATH_EXPR_ERROR);
11162 blanks = IS_BLANK_CH(CUR);
11167 * NodeType or PI search
11169 if (xmlStrEqual(name, BAD_CAST "comment"))
11170 *type = NODE_TYPE_COMMENT;
11171 else if (xmlStrEqual(name, BAD_CAST "node"))
11172 *type = NODE_TYPE_NODE;
11173 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11174 *type = NODE_TYPE_PI;
11175 else if (xmlStrEqual(name, BAD_CAST "text"))
11176 *type = NODE_TYPE_TEXT;
11180 XP_ERRORNULL(XPATH_EXPR_ERROR);
11183 *test = NODE_TEST_TYPE;
11186 if (*type == NODE_TYPE_PI) {
11188 * Specific case: search a PI by name.
11194 name = xmlXPathParseLiteral(ctxt);
11196 *test = NODE_TEST_PI;
11203 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11208 *test = NODE_TEST_NAME;
11209 if ((!blanks) && (CUR == ':')) {
11213 * Since currently the parser context don't have a
11214 * namespace list associated:
11215 * The namespace name for this prefix can be computed
11216 * only at evaluation time. The compilation is done
11217 * outside of any context.
11220 *prefix = xmlXPathNsLookup(ctxt->context, name);
11223 if (*prefix == NULL) {
11224 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11235 *test = NODE_TEST_ALL;
11239 name = xmlXPathParseNCName(ctxt);
11240 if (name == NULL) {
11241 XP_ERRORNULL(XPATH_EXPR_ERROR);
11248 * xmlXPathIsAxisName:
11249 * @name: a preparsed name token
11251 * [6] AxisName ::= 'ancestor'
11252 * | 'ancestor-or-self'
11256 * | 'descendant-or-self'
11258 * | 'following-sibling'
11262 * | 'preceding-sibling'
11265 * Returns the axis or 0
11267 static xmlXPathAxisVal
11268 xmlXPathIsAxisName(const xmlChar *name) {
11269 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11272 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11273 ret = AXIS_ANCESTOR;
11274 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11275 ret = AXIS_ANCESTOR_OR_SELF;
11276 if (xmlStrEqual(name, BAD_CAST "attribute"))
11277 ret = AXIS_ATTRIBUTE;
11280 if (xmlStrEqual(name, BAD_CAST "child"))
11284 if (xmlStrEqual(name, BAD_CAST "descendant"))
11285 ret = AXIS_DESCENDANT;
11286 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11287 ret = AXIS_DESCENDANT_OR_SELF;
11290 if (xmlStrEqual(name, BAD_CAST "following"))
11291 ret = AXIS_FOLLOWING;
11292 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11293 ret = AXIS_FOLLOWING_SIBLING;
11296 if (xmlStrEqual(name, BAD_CAST "namespace"))
11297 ret = AXIS_NAMESPACE;
11300 if (xmlStrEqual(name, BAD_CAST "parent"))
11302 if (xmlStrEqual(name, BAD_CAST "preceding"))
11303 ret = AXIS_PRECEDING;
11304 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11305 ret = AXIS_PRECEDING_SIBLING;
11308 if (xmlStrEqual(name, BAD_CAST "self"))
11316 * xmlXPathCompStep:
11317 * @ctxt: the XPath Parser context
11319 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11320 * | AbbreviatedStep
11322 * [12] AbbreviatedStep ::= '.' | '..'
11324 * [5] AxisSpecifier ::= AxisName '::'
11325 * | AbbreviatedAxisSpecifier
11327 * [13] AbbreviatedAxisSpecifier ::= '@'?
11329 * Modified for XPtr range support as:
11331 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11332 * | AbbreviatedStep
11333 * | 'range-to' '(' Expr ')' Predicate*
11335 * Compile one step in a Location Path
11336 * A location step of . is short for self::node(). This is
11337 * particularly useful in conjunction with //. For example, the
11338 * location path .//para is short for
11339 * self::node()/descendant-or-self::node()/child::para
11340 * and so will select all para descendant elements of the context
11342 * Similarly, a location step of .. is short for parent::node().
11343 * For example, ../title is short for parent::node()/child::title
11344 * and so will select the title children of the parent of the context
11348 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11349 #ifdef LIBXML_XPTR_ENABLED
11355 if ((CUR == '.') && (NXT(1) == '.')) {
11358 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11359 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11360 } else if (CUR == '.') {
11364 xmlChar *name = NULL;
11365 const xmlChar *prefix = NULL;
11366 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11367 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11368 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11372 * The modification needed for XPointer change to the production
11374 #ifdef LIBXML_XPTR_ENABLED
11376 name = xmlXPathParseNCName(ctxt);
11377 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11378 op2 = ctxt->comp->last;
11382 XP_ERROR(XPATH_EXPR_ERROR);
11387 xmlXPathCompileExpr(ctxt, 1);
11388 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11393 XP_ERROR(XPATH_EXPR_ERROR);
11397 goto eval_predicates;
11405 name = xmlXPathParseNCName(ctxt);
11406 if (name != NULL) {
11407 axis = xmlXPathIsAxisName(name);
11410 if ((CUR == ':') && (NXT(1) == ':')) {
11415 /* an element name can conflict with an axis one :-\ */
11421 } else if (CUR == '@') {
11423 axis = AXIS_ATTRIBUTE;
11429 if (ctxt->error != XPATH_EXPRESSION_OK) {
11434 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11438 if ((prefix != NULL) && (ctxt->context != NULL) &&
11439 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11440 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11441 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11445 xmlGenericError(xmlGenericErrorContext,
11446 "Basis : computing new set\n");
11450 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11451 if (ctxt->value == NULL)
11452 xmlGenericError(xmlGenericErrorContext, "no value\n");
11453 else if (ctxt->value->nodesetval == NULL)
11454 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11456 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11459 #ifdef LIBXML_XPTR_ENABLED
11462 op1 = ctxt->comp->last;
11463 ctxt->comp->last = -1;
11466 while (CUR == '[') {
11467 xmlXPathCompPredicate(ctxt, 0);
11470 #ifdef LIBXML_XPTR_ENABLED
11472 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11475 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11476 test, type, (void *)prefix, (void *)name);
11480 xmlGenericError(xmlGenericErrorContext, "Step : ");
11481 if (ctxt->value == NULL)
11482 xmlGenericError(xmlGenericErrorContext, "no value\n");
11483 else if (ctxt->value->nodesetval == NULL)
11484 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11486 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11487 ctxt->value->nodesetval);
11492 * xmlXPathCompRelativeLocationPath:
11493 * @ctxt: the XPath Parser context
11495 * [3] RelativeLocationPath ::= Step
11496 * | RelativeLocationPath '/' Step
11497 * | AbbreviatedRelativeLocationPath
11498 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11500 * Compile a relative location path.
11503 xmlXPathCompRelativeLocationPath
11504 (xmlXPathParserContextPtr ctxt) {
11506 if ((CUR == '/') && (NXT(1) == '/')) {
11509 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11510 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11511 } else if (CUR == '/') {
11515 xmlXPathCompStep(ctxt);
11518 while (CUR == '/') {
11519 if ((CUR == '/') && (NXT(1) == '/')) {
11522 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11523 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11524 xmlXPathCompStep(ctxt);
11525 } else if (CUR == '/') {
11528 xmlXPathCompStep(ctxt);
11535 * xmlXPathCompLocationPath:
11536 * @ctxt: the XPath Parser context
11538 * [1] LocationPath ::= RelativeLocationPath
11539 * | AbsoluteLocationPath
11540 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11541 * | AbbreviatedAbsoluteLocationPath
11542 * [10] AbbreviatedAbsoluteLocationPath ::=
11543 * '//' RelativeLocationPath
11545 * Compile a location path
11547 * // is short for /descendant-or-self::node()/. For example,
11548 * //para is short for /descendant-or-self::node()/child::para and
11549 * so will select any para element in the document (even a para element
11550 * that is a document element will be selected by //para since the
11551 * document element node is a child of the root node); div//para is
11552 * short for div/descendant-or-self::node()/child::para and so will
11553 * select all para descendants of div children.
11556 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11559 xmlXPathCompRelativeLocationPath(ctxt);
11561 while (CUR == '/') {
11562 if ((CUR == '/') && (NXT(1) == '/')) {
11565 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11566 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11567 xmlXPathCompRelativeLocationPath(ctxt);
11568 } else if (CUR == '/') {
11572 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11573 (CUR == '@') || (CUR == '*')))
11574 xmlXPathCompRelativeLocationPath(ctxt);
11581 /************************************************************************
11583 * XPath precompiled expression evaluation *
11585 ************************************************************************/
11588 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11592 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11595 xmlGenericError(xmlGenericErrorContext, "new step : ");
11596 switch (op->value) {
11597 case AXIS_ANCESTOR:
11598 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11600 case AXIS_ANCESTOR_OR_SELF:
11601 xmlGenericError(xmlGenericErrorContext,
11602 "axis 'ancestors-or-self' ");
11604 case AXIS_ATTRIBUTE:
11605 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11608 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11610 case AXIS_DESCENDANT:
11611 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11613 case AXIS_DESCENDANT_OR_SELF:
11614 xmlGenericError(xmlGenericErrorContext,
11615 "axis 'descendant-or-self' ");
11617 case AXIS_FOLLOWING:
11618 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11620 case AXIS_FOLLOWING_SIBLING:
11621 xmlGenericError(xmlGenericErrorContext,
11622 "axis 'following-siblings' ");
11624 case AXIS_NAMESPACE:
11625 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11628 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11630 case AXIS_PRECEDING:
11631 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11633 case AXIS_PRECEDING_SIBLING:
11634 xmlGenericError(xmlGenericErrorContext,
11635 "axis 'preceding-sibling' ");
11638 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11641 xmlGenericError(xmlGenericErrorContext,
11642 " context contains %d nodes\n", nbNodes);
11643 switch (op->value2) {
11644 case NODE_TEST_NONE:
11645 xmlGenericError(xmlGenericErrorContext,
11646 " searching for none !!!\n");
11648 case NODE_TEST_TYPE:
11649 xmlGenericError(xmlGenericErrorContext,
11650 " searching for type %d\n", op->value3);
11653 xmlGenericError(xmlGenericErrorContext,
11654 " searching for PI !!!\n");
11656 case NODE_TEST_ALL:
11657 xmlGenericError(xmlGenericErrorContext,
11658 " searching for *\n");
11661 xmlGenericError(xmlGenericErrorContext,
11662 " searching for namespace %s\n",
11665 case NODE_TEST_NAME:
11666 xmlGenericError(xmlGenericErrorContext,
11667 " searching for name %s\n", op->value5);
11669 xmlGenericError(xmlGenericErrorContext,
11670 " with namespace %s\n", op->value4);
11673 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11675 #endif /* DEBUG_STEP */
11678 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11679 xmlXPathStepOpPtr op,
11684 if (op->ch1 != -1) {
11685 xmlXPathCompExprPtr comp = ctxt->comp;
11687 * Process inner predicates first.
11689 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11691 * TODO: raise an internal error.
11694 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11695 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11697 if (contextSize <= 0)
11700 if (op->ch2 != -1) {
11701 xmlXPathContextPtr xpctxt = ctxt->context;
11702 xmlNodePtr contextNode, oldContextNode;
11703 xmlDocPtr oldContextDoc;
11704 int i, res, contextPos = 0, newContextSize;
11705 xmlXPathStepOpPtr exprOp;
11706 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11708 #ifdef LIBXML_XPTR_ENABLED
11710 * URGENT TODO: Check the following:
11711 * We don't expect location sets if evaluating prediates, right?
11712 * Only filters should expect location sets, right?
11717 * "For each node in the node-set to be filtered, the
11718 * PredicateExpr is evaluated with that node as the
11719 * context node, with the number of nodes in the
11720 * node-set as the context size, and with the proximity
11721 * position of the node in the node-set with respect to
11722 * the axis as the context position;"
11723 * @oldset is the node-set" to be filtered.
11726 * "only predicates change the context position and
11727 * context size (see [2.4 Predicates])."
11729 * node-set context pos
11733 * After applying predicate [position() > 1] :
11734 * node-set context pos
11738 oldContextNode = xpctxt->node;
11739 oldContextDoc = xpctxt->doc;
11741 * Get the expression of this predicate.
11743 exprOp = &ctxt->comp->steps[op->ch2];
11744 newContextSize = 0;
11745 for (i = 0; i < set->nodeNr; i++) {
11746 if (set->nodeTab[i] == NULL)
11749 contextNode = set->nodeTab[i];
11750 xpctxt->node = contextNode;
11751 xpctxt->contextSize = contextSize;
11752 xpctxt->proximityPosition = ++contextPos;
11755 * Also set the xpath document in case things like
11756 * key() are evaluated in the predicate.
11758 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11759 (contextNode->doc != NULL))
11760 xpctxt->doc = contextNode->doc;
11762 * Evaluate the predicate expression with 1 context node
11763 * at a time; this node is packaged into a node set; this
11764 * node set is handed over to the evaluation mechanism.
11766 if (contextObj == NULL)
11767 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11769 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11770 contextNode) < 0) {
11771 ctxt->error = XPATH_MEMORY_ERROR;
11772 goto evaluation_exit;
11776 valuePush(ctxt, contextObj);
11778 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11780 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11781 xmlXPathNodeSetClear(set, hasNsNodes);
11782 newContextSize = 0;
11783 goto evaluation_exit;
11790 * Remove the entry from the initial node set.
11792 set->nodeTab[i] = NULL;
11793 if (contextNode->type == XML_NAMESPACE_DECL)
11794 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11796 if (ctxt->value == contextObj) {
11798 * Don't free the temporary XPath object holding the
11799 * context node, in order to avoid massive recreation
11800 * inside this loop.
11803 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11806 * TODO: The object was lost in the evaluation machinery.
11807 * Can this happen? Maybe in internal-error cases.
11813 if (contextObj != NULL) {
11814 if (ctxt->value == contextObj)
11816 xmlXPathReleaseObject(xpctxt, contextObj);
11819 if (exprRes != NULL)
11820 xmlXPathReleaseObject(ctxt->context, exprRes);
11822 * Reset/invalidate the context.
11824 xpctxt->node = oldContextNode;
11825 xpctxt->doc = oldContextDoc;
11826 xpctxt->contextSize = -1;
11827 xpctxt->proximityPosition = -1;
11828 return(newContextSize);
11830 return(contextSize);
11834 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11835 xmlXPathStepOpPtr op,
11842 if (op->ch1 != -1) {
11843 xmlXPathCompExprPtr comp = ctxt->comp;
11844 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11846 * TODO: raise an internal error.
11849 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11850 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11852 if (contextSize <= 0)
11856 * Check if the node set contains a sufficient number of nodes for
11857 * the requested range.
11859 if (contextSize < minPos) {
11860 xmlXPathNodeSetClear(set, hasNsNodes);
11863 if (op->ch2 == -1) {
11865 * TODO: Can this ever happen?
11867 return (contextSize);
11869 xmlDocPtr oldContextDoc;
11870 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11871 xmlXPathStepOpPtr exprOp;
11872 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11873 xmlNodePtr oldContextNode, contextNode = NULL;
11874 xmlXPathContextPtr xpctxt = ctxt->context;
11877 #ifdef LIBXML_XPTR_ENABLED
11879 * URGENT TODO: Check the following:
11880 * We don't expect location sets if evaluating prediates, right?
11881 * Only filters should expect location sets, right?
11883 #endif /* LIBXML_XPTR_ENABLED */
11886 * Save old context.
11888 oldContextNode = xpctxt->node;
11889 oldContextDoc = xpctxt->doc;
11891 * Get the expression of this predicate.
11893 exprOp = &ctxt->comp->steps[op->ch2];
11894 for (i = 0; i < set->nodeNr; i++) {
11895 xmlXPathObjectPtr tmp;
11897 if (set->nodeTab[i] == NULL)
11900 contextNode = set->nodeTab[i];
11901 xpctxt->node = contextNode;
11902 xpctxt->contextSize = contextSize;
11903 xpctxt->proximityPosition = ++contextPos;
11906 * Initialize the new set.
11907 * Also set the xpath document in case things like
11908 * key() evaluation are attempted on the predicate
11910 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11911 (contextNode->doc != NULL))
11912 xpctxt->doc = contextNode->doc;
11914 * Evaluate the predicate expression with 1 context node
11915 * at a time; this node is packaged into a node set; this
11916 * node set is handed over to the evaluation mechanism.
11918 if (contextObj == NULL)
11919 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11921 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11922 contextNode) < 0) {
11923 ctxt->error = XPATH_MEMORY_ERROR;
11924 goto evaluation_exit;
11928 frame = xmlXPathSetFrame(ctxt);
11929 valuePush(ctxt, contextObj);
11930 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11931 tmp = valuePop(ctxt);
11932 xmlXPathPopFrame(ctxt, frame);
11934 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11935 while (tmp != contextObj) {
11937 * Free up the result
11938 * then pop off contextObj, which will be freed later
11940 xmlXPathReleaseObject(xpctxt, tmp);
11941 tmp = valuePop(ctxt);
11943 goto evaluation_error;
11945 /* push the result back onto the stack */
11946 valuePush(ctxt, tmp);
11951 if (res && (pos >= minPos) && (pos <= maxPos)) {
11953 * Fits in the requested range.
11956 if (minPos == maxPos) {
11958 * Only 1 node was requested.
11960 if (contextNode->type == XML_NAMESPACE_DECL) {
11962 * As always: take care of those nasty
11965 set->nodeTab[i] = NULL;
11967 xmlXPathNodeSetClear(set, hasNsNodes);
11969 set->nodeTab[0] = contextNode;
11970 goto evaluation_exit;
11972 if (pos == maxPos) {
11976 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11977 goto evaluation_exit;
11981 * Remove the entry from the initial node set.
11983 set->nodeTab[i] = NULL;
11984 if (contextNode->type == XML_NAMESPACE_DECL)
11985 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11987 if (exprRes != NULL) {
11988 xmlXPathReleaseObject(ctxt->context, exprRes);
11991 if (ctxt->value == contextObj) {
11993 * Don't free the temporary XPath object holding the
11994 * context node, in order to avoid massive recreation
11995 * inside this loop.
11998 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
12001 * The object was lost in the evaluation machinery.
12002 * Can this happen? Maybe in case of internal-errors.
12007 goto evaluation_exit;
12010 xmlXPathNodeSetClear(set, hasNsNodes);
12011 newContextSize = 0;
12014 if (contextObj != NULL) {
12015 if (ctxt->value == contextObj)
12017 xmlXPathReleaseObject(xpctxt, contextObj);
12019 if (exprRes != NULL)
12020 xmlXPathReleaseObject(ctxt->context, exprRes);
12022 * Reset/invalidate the context.
12024 xpctxt->node = oldContextNode;
12025 xpctxt->doc = oldContextDoc;
12026 xpctxt->contextSize = -1;
12027 xpctxt->proximityPosition = -1;
12028 return(newContextSize);
12030 return(contextSize);
12034 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12035 xmlXPathStepOpPtr op,
12039 xmlXPathStepOpPtr exprOp;
12042 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12046 * If not -1, then ch1 will point to:
12047 * 1) For predicates (XPATH_OP_PREDICATE):
12048 * - an inner predicate operator
12049 * 2) For filters (XPATH_OP_FILTER):
12050 * - an inner filter operater OR
12051 * - an expression selecting the node set.
12052 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12054 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12057 if (op->ch2 != -1) {
12058 exprOp = &ctxt->comp->steps[op->ch2];
12062 if ((exprOp != NULL) &&
12063 (exprOp->op == XPATH_OP_VALUE) &&
12064 (exprOp->value4 != NULL) &&
12065 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12067 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12070 * We have a "[n]" predicate here.
12071 * TODO: Unfortunately this simplistic test here is not
12072 * able to detect a position() predicate in compound
12073 * expressions like "[@attr = 'a" and position() = 1],
12074 * and even not the usage of position() in
12075 * "[position() = 1]"; thus - obviously - a position-range,
12076 * like it "[position() < 5]", is also not detected.
12077 * Maybe we could rewrite the AST to ease the optimization.
12080 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12081 *maxPos = (int) floatval;
12082 if (floatval == (double) *maxPos)
12090 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12091 xmlXPathStepOpPtr op,
12092 xmlNodePtr * first, xmlNodePtr * last,
12096 #define XP_TEST_HIT \
12097 if (hasAxisRange != 0) { \
12098 if (++pos == maxPos) { \
12099 if (addNode(seq, cur) < 0) \
12100 ctxt->error = XPATH_MEMORY_ERROR; \
12101 goto axis_range_end; } \
12103 if (addNode(seq, cur) < 0) \
12104 ctxt->error = XPATH_MEMORY_ERROR; \
12105 if (breakOnFirstHit) goto first_hit; }
12107 #define XP_TEST_HIT_NS \
12108 if (hasAxisRange != 0) { \
12109 if (++pos == maxPos) { \
12111 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12112 ctxt->error = XPATH_MEMORY_ERROR; \
12113 goto axis_range_end; } \
12116 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12117 ctxt->error = XPATH_MEMORY_ERROR; \
12118 if (breakOnFirstHit) goto first_hit; }
12120 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12121 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12122 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12123 const xmlChar *prefix = op->value4;
12124 const xmlChar *name = op->value5;
12125 const xmlChar *URI = NULL;
12128 int nbMatches = 0, prevMatches = 0;
12130 int total = 0, hasNsNodes = 0;
12131 /* The popped object holding the context nodes */
12132 xmlXPathObjectPtr obj;
12133 /* The set of context nodes for the node tests */
12134 xmlNodeSetPtr contextSeq;
12136 xmlNodePtr contextNode;
12137 /* The final resulting node set wrt to all context nodes */
12138 xmlNodeSetPtr outSeq;
12140 * The temporary resulting node set wrt 1 context node.
12141 * Used to feed predicate evaluation.
12145 /* First predicate operator */
12146 xmlXPathStepOpPtr predOp;
12147 int maxPos; /* The requested position() (when a "[n]" predicate) */
12148 int hasPredicateRange, hasAxisRange, pos, size, newSize;
12149 int breakOnFirstHit;
12151 xmlXPathTraversalFunction next = NULL;
12152 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12153 xmlXPathNodeSetMergeFunction mergeAndClear;
12154 xmlNodePtr oldContextNode;
12155 xmlXPathContextPtr xpctxt = ctxt->context;
12158 CHECK_TYPE0(XPATH_NODESET);
12159 obj = valuePop(ctxt);
12161 * Setup namespaces.
12163 if (prefix != NULL) {
12164 URI = xmlXPathNsLookup(xpctxt, prefix);
12166 xmlXPathReleaseObject(xpctxt, obj);
12167 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12173 * MAYBE FUTURE TODO: merging optimizations:
12174 * - If the nodes to be traversed wrt to the initial nodes and
12175 * the current axis cannot overlap, then we could avoid searching
12176 * for duplicates during the merge.
12177 * But the question is how/when to evaluate if they cannot overlap.
12178 * Example: if we know that for two initial nodes, the one is
12179 * not in the ancestor-or-self axis of the other, then we could safely
12180 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12181 * the descendant-or-self axis.
12183 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12185 case AXIS_ANCESTOR:
12187 next = xmlXPathNextAncestor;
12189 case AXIS_ANCESTOR_OR_SELF:
12191 next = xmlXPathNextAncestorOrSelf;
12193 case AXIS_ATTRIBUTE:
12196 next = xmlXPathNextAttribute;
12197 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12201 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12202 (type == NODE_TYPE_NODE))
12205 * Optimization if an element node type is 'element'.
12207 next = xmlXPathNextChildElement;
12209 next = xmlXPathNextChild;
12210 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12212 case AXIS_DESCENDANT:
12214 next = xmlXPathNextDescendant;
12216 case AXIS_DESCENDANT_OR_SELF:
12218 next = xmlXPathNextDescendantOrSelf;
12220 case AXIS_FOLLOWING:
12222 next = xmlXPathNextFollowing;
12224 case AXIS_FOLLOWING_SIBLING:
12226 next = xmlXPathNextFollowingSibling;
12228 case AXIS_NAMESPACE:
12231 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12232 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12236 next = xmlXPathNextParent;
12238 case AXIS_PRECEDING:
12240 next = xmlXPathNextPrecedingInternal;
12242 case AXIS_PRECEDING_SIBLING:
12244 next = xmlXPathNextPrecedingSibling;
12249 next = xmlXPathNextSelf;
12250 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12255 xmlXPathDebugDumpStepAxis(op,
12256 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12259 if (next == NULL) {
12260 xmlXPathReleaseObject(xpctxt, obj);
12263 contextSeq = obj->nodesetval;
12264 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12265 xmlXPathReleaseObject(xpctxt, obj);
12266 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12270 * Predicate optimization ---------------------------------------------
12271 * If this step has a last predicate, which contains a position(),
12272 * then we'll optimize (although not exactly "position()", but only
12273 * the short-hand form, i.e., "[n]".
12275 * Example - expression "/foo[parent::bar][1]":
12277 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12279 * PREDICATE -- op->ch2 (predOp)
12280 * PREDICATE -- predOp->ch1 = [parent::bar]
12282 * COLLECT 'parent' 'name' 'node' bar
12284 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12289 hasPredicateRange = 0;
12291 if (op->ch2 != -1) {
12293 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12295 predOp = &ctxt->comp->steps[op->ch2];
12296 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12297 if (predOp->ch1 != -1) {
12299 * Use the next inner predicate operator.
12301 predOp = &ctxt->comp->steps[predOp->ch1];
12302 hasPredicateRange = 1;
12305 * There's no other predicate than the [n] predicate.
12312 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12314 * Axis traversal -----------------------------------------------------
12318 * - For the attribute axis, the principal node type is attribute.
12319 * - For the namespace axis, the principal node type is namespace.
12320 * - For other axes, the principal node type is element.
12322 * A node test * is true for any node of the
12323 * principal node type. For example, child::* will
12324 * select all element children of the context node
12326 oldContextNode = xpctxt->node;
12327 addNode = xmlXPathNodeSetAddUnique;
12330 contextNode = NULL;
12334 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12335 (ctxt->error == XPATH_EXPRESSION_OK)) {
12336 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12339 seq = xmlXPathNodeSetCreate(NULL);
12346 * Traverse the axis and test the nodes.
12352 cur = next(ctxt, cur);
12357 * QUESTION TODO: What does the "first" and "last" stuff do?
12359 if ((first != NULL) && (*first != NULL)) {
12362 if (((total % 256) == 0) &&
12363 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12364 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12366 (xmlXPathCmpNodes(*first, cur) >= 0))
12372 if ((last != NULL) && (*last != NULL)) {
12375 if (((total % 256) == 0) &&
12376 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12377 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12379 (xmlXPathCmpNodes(cur, *last) >= 0))
12389 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12393 case NODE_TEST_NONE:
12397 case NODE_TEST_TYPE:
12398 if (type == NODE_TYPE_NODE) {
12399 switch (cur->type) {
12400 case XML_DOCUMENT_NODE:
12401 case XML_HTML_DOCUMENT_NODE:
12402 #ifdef LIBXML_DOCB_ENABLED
12403 case XML_DOCB_DOCUMENT_NODE:
12405 case XML_ELEMENT_NODE:
12406 case XML_ATTRIBUTE_NODE:
12408 case XML_COMMENT_NODE:
12409 case XML_CDATA_SECTION_NODE:
12410 case XML_TEXT_NODE:
12413 case XML_NAMESPACE_DECL: {
12414 if (axis == AXIS_NAMESPACE) {
12425 } else if (cur->type == type) {
12426 if (cur->type == XML_NAMESPACE_DECL)
12430 } else if ((type == NODE_TYPE_TEXT) &&
12431 (cur->type == XML_CDATA_SECTION_NODE))
12437 if ((cur->type == XML_PI_NODE) &&
12438 ((name == NULL) || xmlStrEqual(name, cur->name)))
12443 case NODE_TEST_ALL:
12444 if (axis == AXIS_ATTRIBUTE) {
12445 if (cur->type == XML_ATTRIBUTE_NODE)
12447 if (prefix == NULL)
12450 } else if ((cur->ns != NULL) &&
12451 (xmlStrEqual(URI, cur->ns->href)))
12456 } else if (axis == AXIS_NAMESPACE) {
12457 if (cur->type == XML_NAMESPACE_DECL)
12462 if (cur->type == XML_ELEMENT_NODE) {
12463 if (prefix == NULL)
12467 } else if ((cur->ns != NULL) &&
12468 (xmlStrEqual(URI, cur->ns->href)))
12475 case NODE_TEST_NS:{
12479 case NODE_TEST_NAME:
12480 if (axis == AXIS_ATTRIBUTE) {
12481 if (cur->type != XML_ATTRIBUTE_NODE)
12483 } else if (axis == AXIS_NAMESPACE) {
12484 if (cur->type != XML_NAMESPACE_DECL)
12487 if (cur->type != XML_ELEMENT_NODE)
12490 switch (cur->type) {
12491 case XML_ELEMENT_NODE:
12492 if (xmlStrEqual(name, cur->name)) {
12493 if (prefix == NULL) {
12494 if (cur->ns == NULL)
12499 if ((cur->ns != NULL) &&
12500 (xmlStrEqual(URI, cur->ns->href)))
12507 case XML_ATTRIBUTE_NODE:{
12508 xmlAttrPtr attr = (xmlAttrPtr) cur;
12510 if (xmlStrEqual(name, attr->name)) {
12511 if (prefix == NULL) {
12512 if ((attr->ns == NULL) ||
12513 (attr->ns->prefix == NULL))
12518 if ((attr->ns != NULL) &&
12528 case XML_NAMESPACE_DECL:
12529 if (cur->type == XML_NAMESPACE_DECL) {
12530 xmlNsPtr ns = (xmlNsPtr) cur;
12532 if ((ns->prefix != NULL) && (name != NULL)
12533 && (xmlStrEqual(ns->prefix, name)))
12543 } /* switch(test) */
12544 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12546 goto apply_predicates;
12548 axis_range_end: /* ----------------------------------------------------- */
12550 * We have a "/foo[n]", and position() = n was reached.
12551 * Note that we can have as well "/foo/::parent::foo[1]", so
12552 * a duplicate-aware merge is still needed.
12553 * Merge with the result.
12555 if (outSeq == NULL) {
12559 outSeq = mergeAndClear(outSeq, seq, 0);
12561 * Break if only a true/false result was requested.
12567 first_hit: /* ---------------------------------------------------------- */
12569 * Break if only a true/false result was requested and
12570 * no predicates existed and a node test succeeded.
12572 if (outSeq == NULL) {
12576 outSeq = mergeAndClear(outSeq, seq, 0);
12581 nbMatches += seq->nodeNr;
12584 apply_predicates: /* --------------------------------------------------- */
12585 if (ctxt->error != XPATH_EXPRESSION_OK)
12589 * Apply predicates.
12591 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12593 * E.g. when we have a "/foo[some expression][n]".
12596 * QUESTION TODO: The old predicate evaluation took into
12597 * account location-sets.
12598 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12599 * Do we expect such a set here?
12600 * All what I learned now from the evaluation semantics
12601 * does not indicate that a location-set will be processed
12602 * here, so this looks OK.
12605 * Iterate over all predicates, starting with the outermost
12607 * TODO: Problem: we cannot execute the inner predicates first
12608 * since we cannot go back *up* the operator tree!
12610 * 1) Use of recursive functions (like is it currently done
12611 * via xmlXPathCompOpEval())
12612 * 2) Add a predicate evaluation information stack to the
12614 * 3) Change the way the operators are linked; we need a
12615 * "parent" field on xmlXPathStepOp
12617 * For the moment, I'll try to solve this with a recursive
12618 * function: xmlXPathCompOpEvalPredicate().
12620 size = seq->nodeNr;
12621 if (hasPredicateRange != 0)
12622 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12623 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12625 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12626 predOp, seq, size, hasNsNodes);
12628 if (ctxt->error != XPATH_EXPRESSION_OK) {
12633 * Add the filtered set of nodes to the result node set.
12635 if (newSize == 0) {
12637 * The predicates filtered all nodes out.
12639 xmlXPathNodeSetClear(seq, hasNsNodes);
12640 } else if (seq->nodeNr > 0) {
12642 * Add to result set.
12644 if (outSeq == NULL) {
12645 if (size != newSize) {
12647 * We need to merge and clear here, since
12648 * the sequence will contained NULLed entries.
12650 outSeq = mergeAndClear(NULL, seq, 1);
12656 outSeq = mergeAndClear(outSeq, seq,
12657 (size != newSize) ? 1: 0);
12659 * Break if only a true/false result was requested.
12664 } else if (seq->nodeNr > 0) {
12666 * Add to result set.
12668 if (outSeq == NULL) {
12672 outSeq = mergeAndClear(outSeq, seq, 0);
12678 if ((obj->boolval) && (obj->user != NULL)) {
12680 * QUESTION TODO: What does this do and why?
12681 * TODO: Do we have to do this also for the "error"
12682 * cleanup further down?
12684 ctxt->value->boolval = 1;
12685 ctxt->value->user = obj->user;
12689 xmlXPathReleaseObject(xpctxt, obj);
12692 * Ensure we return at least an emtpy set.
12694 if (outSeq == NULL) {
12695 if ((seq != NULL) && (seq->nodeNr == 0))
12698 outSeq = xmlXPathNodeSetCreate(NULL);
12699 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12701 if ((seq != NULL) && (seq != outSeq)) {
12702 xmlXPathFreeNodeSet(seq);
12705 * Hand over the result. Better to push the set also in
12708 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12710 * Reset the context node.
12712 xpctxt->node = oldContextNode;
12714 * When traversing the namespace axis in "toBool" mode, it's
12715 * possible that tmpNsList wasn't freed.
12717 if (xpctxt->tmpNsList != NULL) {
12718 xmlFree(xpctxt->tmpNsList);
12719 xpctxt->tmpNsList = NULL;
12723 xmlGenericError(xmlGenericErrorContext,
12724 "\nExamined %d nodes, found %d nodes at that step\n",
12732 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12733 xmlXPathStepOpPtr op, xmlNodePtr * first);
12736 * xmlXPathCompOpEvalFirst:
12737 * @ctxt: the XPath parser context with the compiled expression
12738 * @op: an XPath compiled operation
12739 * @first: the first elem found so far
12741 * Evaluate the Precompiled XPath operation searching only the first
12742 * element in document order
12744 * Returns the number of examined objects.
12747 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12748 xmlXPathStepOpPtr op, xmlNodePtr * first)
12750 int total = 0, cur;
12751 xmlXPathCompExprPtr comp;
12752 xmlXPathObjectPtr arg1, arg2;
12759 case XPATH_OP_UNION:
12761 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12764 if ((ctxt->value != NULL)
12765 && (ctxt->value->type == XPATH_NODESET)
12766 && (ctxt->value->nodesetval != NULL)
12767 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12769 * limit tree traversing to first node in the result
12772 * OPTIMIZE TODO: This implicitely sorts
12773 * the result, even if not needed. E.g. if the argument
12774 * of the count() function, no sorting is needed.
12775 * OPTIMIZE TODO: How do we know if the node-list wasn't
12778 if (ctxt->value->nodesetval->nodeNr > 1)
12779 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12780 *first = ctxt->value->nodesetval->nodeTab[0];
12783 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12787 arg2 = valuePop(ctxt);
12788 arg1 = valuePop(ctxt);
12789 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12790 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12791 xmlXPathReleaseObject(ctxt->context, arg1);
12792 xmlXPathReleaseObject(ctxt->context, arg2);
12793 XP_ERROR0(XPATH_INVALID_TYPE);
12796 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12798 valuePush(ctxt, arg1);
12799 xmlXPathReleaseObject(ctxt->context, arg2);
12802 xmlXPathCompSwap(op);
12803 return (total + cur);
12804 case XPATH_OP_ROOT:
12805 xmlXPathRoot(ctxt);
12807 case XPATH_OP_NODE:
12809 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12812 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12814 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12815 ctxt->context->node));
12817 case XPATH_OP_RESET:
12819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12822 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12824 ctxt->context->node = NULL;
12826 case XPATH_OP_COLLECT:{
12830 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12833 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12836 case XPATH_OP_VALUE:
12838 xmlXPathCacheObjectCopy(ctxt->context,
12839 (xmlXPathObjectPtr) op->value4));
12841 case XPATH_OP_SORT:
12844 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12847 if ((ctxt->value != NULL)
12848 && (ctxt->value->type == XPATH_NODESET)
12849 && (ctxt->value->nodesetval != NULL)
12850 && (ctxt->value->nodesetval->nodeNr > 1))
12851 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12853 #ifdef XP_OPTIMIZED_FILTER_FIRST
12854 case XPATH_OP_FILTER:
12855 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12859 return (xmlXPathCompOpEval(ctxt, op));
12864 * xmlXPathCompOpEvalLast:
12865 * @ctxt: the XPath parser context with the compiled expression
12866 * @op: an XPath compiled operation
12867 * @last: the last elem found so far
12869 * Evaluate the Precompiled XPath operation searching only the last
12870 * element in document order
12872 * Returns the number of nodes traversed
12875 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12878 int total = 0, cur;
12879 xmlXPathCompExprPtr comp;
12880 xmlXPathObjectPtr arg1, arg2;
12891 case XPATH_OP_UNION:
12892 bakd = ctxt->context->doc;
12893 bak = ctxt->context->node;
12894 pp = ctxt->context->proximityPosition;
12895 cs = ctxt->context->contextSize;
12897 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12899 if ((ctxt->value != NULL)
12900 && (ctxt->value->type == XPATH_NODESET)
12901 && (ctxt->value->nodesetval != NULL)
12902 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12904 * limit tree traversing to first node in the result
12906 if (ctxt->value->nodesetval->nodeNr > 1)
12907 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12909 ctxt->value->nodesetval->nodeTab[ctxt->value->
12910 nodesetval->nodeNr -
12913 ctxt->context->doc = bakd;
12914 ctxt->context->node = bak;
12915 ctxt->context->proximityPosition = pp;
12916 ctxt->context->contextSize = cs;
12918 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12920 if ((ctxt->value != NULL)
12921 && (ctxt->value->type == XPATH_NODESET)
12922 && (ctxt->value->nodesetval != NULL)
12923 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12926 arg2 = valuePop(ctxt);
12927 arg1 = valuePop(ctxt);
12928 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12929 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12930 xmlXPathReleaseObject(ctxt->context, arg1);
12931 xmlXPathReleaseObject(ctxt->context, arg2);
12932 XP_ERROR0(XPATH_INVALID_TYPE);
12935 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12937 valuePush(ctxt, arg1);
12938 xmlXPathReleaseObject(ctxt->context, arg2);
12941 xmlXPathCompSwap(op);
12942 return (total + cur);
12943 case XPATH_OP_ROOT:
12944 xmlXPathRoot(ctxt);
12946 case XPATH_OP_NODE:
12948 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12951 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12953 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12954 ctxt->context->node));
12956 case XPATH_OP_RESET:
12958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12961 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12963 ctxt->context->node = NULL;
12965 case XPATH_OP_COLLECT:{
12969 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12972 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12975 case XPATH_OP_VALUE:
12977 xmlXPathCacheObjectCopy(ctxt->context,
12978 (xmlXPathObjectPtr) op->value4));
12980 case XPATH_OP_SORT:
12983 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12986 if ((ctxt->value != NULL)
12987 && (ctxt->value->type == XPATH_NODESET)
12988 && (ctxt->value->nodesetval != NULL)
12989 && (ctxt->value->nodesetval->nodeNr > 1))
12990 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12993 return (xmlXPathCompOpEval(ctxt, op));
12997 #ifdef XP_OPTIMIZED_FILTER_FIRST
12999 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13000 xmlXPathStepOpPtr op, xmlNodePtr * first)
13003 xmlXPathCompExprPtr comp;
13004 xmlXPathObjectPtr res;
13005 xmlXPathObjectPtr obj;
13006 xmlNodeSetPtr oldset;
13007 xmlNodePtr oldnode;
13014 * Optimization for ()[last()] selection i.e. the last elem
13016 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13017 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13018 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13019 int f = comp->steps[op->ch2].ch1;
13022 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13023 (comp->steps[f].value5 == NULL) &&
13024 (comp->steps[f].value == 0) &&
13025 (comp->steps[f].value4 != NULL) &&
13027 (comp->steps[f].value4, BAD_CAST "last"))) {
13028 xmlNodePtr last = NULL;
13031 xmlXPathCompOpEvalLast(ctxt,
13032 &comp->steps[op->ch1],
13036 * The nodeset should be in document order,
13037 * Keep only the last value
13039 if ((ctxt->value != NULL) &&
13040 (ctxt->value->type == XPATH_NODESET) &&
13041 (ctxt->value->nodesetval != NULL) &&
13042 (ctxt->value->nodesetval->nodeTab != NULL) &&
13043 (ctxt->value->nodesetval->nodeNr > 1)) {
13044 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13045 *first = *(ctxt->value->nodesetval->nodeTab);
13052 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13056 if (ctxt->value == NULL)
13059 #ifdef LIBXML_XPTR_ENABLED
13060 oldnode = ctxt->context->node;
13062 * Hum are we filtering the result of an XPointer expression
13064 if (ctxt->value->type == XPATH_LOCATIONSET) {
13065 xmlXPathObjectPtr tmp = NULL;
13066 xmlLocationSetPtr newlocset = NULL;
13067 xmlLocationSetPtr oldlocset;
13070 * Extract the old locset, and then evaluate the result of the
13071 * expression for all the element in the locset. use it to grow
13074 CHECK_TYPE0(XPATH_LOCATIONSET);
13075 obj = valuePop(ctxt);
13076 oldlocset = obj->user;
13077 ctxt->context->node = NULL;
13079 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13080 ctxt->context->contextSize = 0;
13081 ctxt->context->proximityPosition = 0;
13083 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13084 res = valuePop(ctxt);
13086 xmlXPathReleaseObject(ctxt->context, res);
13088 valuePush(ctxt, obj);
13092 newlocset = xmlXPtrLocationSetCreate(NULL);
13094 for (i = 0; i < oldlocset->locNr; i++) {
13096 * Run the evaluation with a node list made of a
13097 * single item in the nodelocset.
13099 ctxt->context->node = oldlocset->locTab[i]->user;
13100 ctxt->context->contextSize = oldlocset->locNr;
13101 ctxt->context->proximityPosition = i + 1;
13103 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13104 ctxt->context->node);
13106 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13107 ctxt->context->node) < 0) {
13108 ctxt->error = XPATH_MEMORY_ERROR;
13111 valuePush(ctxt, tmp);
13113 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13114 if (ctxt->error != XPATH_EXPRESSION_OK) {
13115 xmlXPathFreeObject(obj);
13119 * The result of the evaluation need to be tested to
13120 * decided whether the filter succeeded or not
13122 res = valuePop(ctxt);
13123 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13124 xmlXPtrLocationSetAdd(newlocset,
13125 xmlXPathCacheObjectCopy(ctxt->context,
13126 oldlocset->locTab[i]));
13132 xmlXPathReleaseObject(ctxt->context, res);
13134 if (ctxt->value == tmp) {
13136 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13138 * REVISIT TODO: Don't create a temporary nodeset
13139 * for everly iteration.
13141 /* OLD: xmlXPathFreeObject(res); */
13144 ctxt->context->node = NULL;
13146 * Only put the first node in the result, then leave.
13148 if (newlocset->locNr > 0) {
13149 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13154 xmlXPathReleaseObject(ctxt->context, tmp);
13157 * The result is used as the new evaluation locset.
13159 xmlXPathReleaseObject(ctxt->context, obj);
13160 ctxt->context->node = NULL;
13161 ctxt->context->contextSize = -1;
13162 ctxt->context->proximityPosition = -1;
13163 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13164 ctxt->context->node = oldnode;
13167 #endif /* LIBXML_XPTR_ENABLED */
13170 * Extract the old set, and then evaluate the result of the
13171 * expression for all the element in the set. use it to grow
13174 CHECK_TYPE0(XPATH_NODESET);
13175 obj = valuePop(ctxt);
13176 oldset = obj->nodesetval;
13178 oldnode = ctxt->context->node;
13179 oldDoc = ctxt->context->doc;
13180 ctxt->context->node = NULL;
13182 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13183 ctxt->context->contextSize = 0;
13184 ctxt->context->proximityPosition = 0;
13185 /* QUESTION TODO: Why was this code commented out?
13188 xmlXPathCompOpEval(ctxt,
13189 &comp->steps[op->ch2]);
13191 res = valuePop(ctxt);
13193 xmlXPathFreeObject(res);
13195 valuePush(ctxt, obj);
13196 ctxt->context->node = oldnode;
13199 xmlNodeSetPtr newset;
13200 xmlXPathObjectPtr tmp = NULL;
13202 * Initialize the new set.
13203 * Also set the xpath document in case things like
13204 * key() evaluation are attempted on the predicate
13206 newset = xmlXPathNodeSetCreate(NULL);
13207 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13209 for (i = 0; i < oldset->nodeNr; i++) {
13211 * Run the evaluation with a node list made of
13212 * a single item in the nodeset.
13214 ctxt->context->node = oldset->nodeTab[i];
13215 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13216 (oldset->nodeTab[i]->doc != NULL))
13217 ctxt->context->doc = oldset->nodeTab[i]->doc;
13219 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13220 ctxt->context->node);
13222 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13223 ctxt->context->node) < 0) {
13224 ctxt->error = XPATH_MEMORY_ERROR;
13227 valuePush(ctxt, tmp);
13228 ctxt->context->contextSize = oldset->nodeNr;
13229 ctxt->context->proximityPosition = i + 1;
13231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13232 if (ctxt->error != XPATH_EXPRESSION_OK) {
13233 xmlXPathFreeNodeSet(newset);
13234 xmlXPathFreeObject(obj);
13238 * The result of the evaluation needs to be tested to
13239 * decide whether the filter succeeded or not
13241 res = valuePop(ctxt);
13242 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13243 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13244 ctxt->error = XPATH_MEMORY_ERROR;
13250 xmlXPathReleaseObject(ctxt->context, res);
13252 if (ctxt->value == tmp) {
13255 * Don't free the temporary nodeset
13256 * in order to avoid massive recreation inside this
13259 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13262 ctxt->context->node = NULL;
13264 * Only put the first node in the result, then leave.
13266 if (newset->nodeNr > 0) {
13267 *first = *(newset->nodeTab);
13272 xmlXPathReleaseObject(ctxt->context, tmp);
13275 * The result is used as the new evaluation set.
13277 xmlXPathReleaseObject(ctxt->context, obj);
13278 ctxt->context->node = NULL;
13279 ctxt->context->contextSize = -1;
13280 ctxt->context->proximityPosition = -1;
13281 /* may want to move this past the '}' later */
13282 ctxt->context->doc = oldDoc;
13283 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13285 ctxt->context->node = oldnode;
13288 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13291 * xmlXPathCompOpEval:
13292 * @ctxt: the XPath parser context with the compiled expression
13293 * @op: an XPath compiled operation
13295 * Evaluate the Precompiled XPath operation
13296 * Returns the number of nodes traversed
13299 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13303 xmlXPathCompExprPtr comp;
13304 xmlXPathObjectPtr arg1, arg2;
13316 bakd = ctxt->context->doc;
13317 bak = ctxt->context->node;
13318 pp = ctxt->context->proximityPosition;
13319 cs = ctxt->context->contextSize;
13320 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13322 xmlXPathBooleanFunction(ctxt, 1);
13323 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13325 arg2 = valuePop(ctxt);
13326 ctxt->context->doc = bakd;
13327 ctxt->context->node = bak;
13328 ctxt->context->proximityPosition = pp;
13329 ctxt->context->contextSize = cs;
13330 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13332 xmlXPathFreeObject(arg2);
13335 xmlXPathBooleanFunction(ctxt, 1);
13336 arg1 = valuePop(ctxt);
13337 arg1->boolval &= arg2->boolval;
13338 valuePush(ctxt, arg1);
13339 xmlXPathReleaseObject(ctxt->context, arg2);
13342 bakd = ctxt->context->doc;
13343 bak = ctxt->context->node;
13344 pp = ctxt->context->proximityPosition;
13345 cs = ctxt->context->contextSize;
13346 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13348 xmlXPathBooleanFunction(ctxt, 1);
13349 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13351 arg2 = valuePop(ctxt);
13352 ctxt->context->doc = bakd;
13353 ctxt->context->node = bak;
13354 ctxt->context->proximityPosition = pp;
13355 ctxt->context->contextSize = cs;
13356 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13358 xmlXPathFreeObject(arg2);
13361 xmlXPathBooleanFunction(ctxt, 1);
13362 arg1 = valuePop(ctxt);
13363 arg1->boolval |= arg2->boolval;
13364 valuePush(ctxt, arg1);
13365 xmlXPathReleaseObject(ctxt->context, arg2);
13367 case XPATH_OP_EQUAL:
13368 bakd = ctxt->context->doc;
13369 bak = ctxt->context->node;
13370 pp = ctxt->context->proximityPosition;
13371 cs = ctxt->context->contextSize;
13372 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13374 ctxt->context->doc = bakd;
13375 ctxt->context->node = bak;
13376 ctxt->context->proximityPosition = pp;
13377 ctxt->context->contextSize = cs;
13378 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13381 equal = xmlXPathEqualValues(ctxt);
13383 equal = xmlXPathNotEqualValues(ctxt);
13384 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13387 bakd = ctxt->context->doc;
13388 bak = ctxt->context->node;
13389 pp = ctxt->context->proximityPosition;
13390 cs = ctxt->context->contextSize;
13391 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13393 ctxt->context->doc = bakd;
13394 ctxt->context->node = bak;
13395 ctxt->context->proximityPosition = pp;
13396 ctxt->context->contextSize = cs;
13397 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13399 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13400 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13402 case XPATH_OP_PLUS:
13403 bakd = ctxt->context->doc;
13404 bak = ctxt->context->node;
13405 pp = ctxt->context->proximityPosition;
13406 cs = ctxt->context->contextSize;
13407 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13409 if (op->ch2 != -1) {
13410 ctxt->context->doc = bakd;
13411 ctxt->context->node = bak;
13412 ctxt->context->proximityPosition = pp;
13413 ctxt->context->contextSize = cs;
13414 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13417 if (op->value == 0)
13418 xmlXPathSubValues(ctxt);
13419 else if (op->value == 1)
13420 xmlXPathAddValues(ctxt);
13421 else if (op->value == 2)
13422 xmlXPathValueFlipSign(ctxt);
13423 else if (op->value == 3) {
13425 CHECK_TYPE0(XPATH_NUMBER);
13428 case XPATH_OP_MULT:
13429 bakd = ctxt->context->doc;
13430 bak = ctxt->context->node;
13431 pp = ctxt->context->proximityPosition;
13432 cs = ctxt->context->contextSize;
13433 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13435 ctxt->context->doc = bakd;
13436 ctxt->context->node = bak;
13437 ctxt->context->proximityPosition = pp;
13438 ctxt->context->contextSize = cs;
13439 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13441 if (op->value == 0)
13442 xmlXPathMultValues(ctxt);
13443 else if (op->value == 1)
13444 xmlXPathDivValues(ctxt);
13445 else if (op->value == 2)
13446 xmlXPathModValues(ctxt);
13448 case XPATH_OP_UNION:
13449 bakd = ctxt->context->doc;
13450 bak = ctxt->context->node;
13451 pp = ctxt->context->proximityPosition;
13452 cs = ctxt->context->contextSize;
13453 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13455 ctxt->context->doc = bakd;
13456 ctxt->context->node = bak;
13457 ctxt->context->proximityPosition = pp;
13458 ctxt->context->contextSize = cs;
13459 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13462 arg2 = valuePop(ctxt);
13463 arg1 = valuePop(ctxt);
13464 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13465 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13466 xmlXPathReleaseObject(ctxt->context, arg1);
13467 xmlXPathReleaseObject(ctxt->context, arg2);
13468 XP_ERROR0(XPATH_INVALID_TYPE);
13471 if ((arg1->nodesetval == NULL) ||
13472 ((arg2->nodesetval != NULL) &&
13473 (arg2->nodesetval->nodeNr != 0)))
13475 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13479 valuePush(ctxt, arg1);
13480 xmlXPathReleaseObject(ctxt->context, arg2);
13482 case XPATH_OP_ROOT:
13483 xmlXPathRoot(ctxt);
13485 case XPATH_OP_NODE:
13487 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13490 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13492 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13493 ctxt->context->node));
13495 case XPATH_OP_RESET:
13497 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13500 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13502 ctxt->context->node = NULL;
13504 case XPATH_OP_COLLECT:{
13508 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13511 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13514 case XPATH_OP_VALUE:
13516 xmlXPathCacheObjectCopy(ctxt->context,
13517 (xmlXPathObjectPtr) op->value4));
13519 case XPATH_OP_VARIABLE:{
13520 xmlXPathObjectPtr val;
13524 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13525 if (op->value5 == NULL) {
13526 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13528 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13531 valuePush(ctxt, val);
13533 const xmlChar *URI;
13535 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13537 xmlGenericError(xmlGenericErrorContext,
13538 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13539 (char *) op->value4, (char *)op->value5);
13540 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13543 val = xmlXPathVariableLookupNS(ctxt->context,
13546 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13549 valuePush(ctxt, val);
13553 case XPATH_OP_FUNCTION:{
13554 xmlXPathFunction func;
13555 const xmlChar *oldFunc, *oldFuncURI;
13559 frame = xmlXPathSetFrame(ctxt);
13560 if (op->ch1 != -1) {
13562 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13563 if (ctxt->error != XPATH_EXPRESSION_OK) {
13564 xmlXPathPopFrame(ctxt, frame);
13568 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13569 xmlGenericError(xmlGenericErrorContext,
13570 "xmlXPathCompOpEval: parameter error\n");
13571 ctxt->error = XPATH_INVALID_OPERAND;
13572 xmlXPathPopFrame(ctxt, frame);
13575 for (i = 0; i < op->value; i++) {
13576 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13577 xmlGenericError(xmlGenericErrorContext,
13578 "xmlXPathCompOpEval: parameter error\n");
13579 ctxt->error = XPATH_INVALID_OPERAND;
13580 xmlXPathPopFrame(ctxt, frame);
13584 if (op->cache != NULL)
13587 const xmlChar *URI = NULL;
13589 if (op->value5 == NULL)
13591 xmlXPathFunctionLookup(ctxt->context,
13594 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13596 xmlGenericError(xmlGenericErrorContext,
13597 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13598 (char *)op->value4, (char *)op->value5);
13599 xmlXPathPopFrame(ctxt, frame);
13600 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13603 func = xmlXPathFunctionLookupNS(ctxt->context,
13606 if (func == NULL) {
13607 xmlGenericError(xmlGenericErrorContext,
13608 "xmlXPathCompOpEval: function %s not found\n",
13609 (char *)op->value4);
13610 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13613 op->cacheURI = (void *) URI;
13615 oldFunc = ctxt->context->function;
13616 oldFuncURI = ctxt->context->functionURI;
13617 ctxt->context->function = op->value4;
13618 ctxt->context->functionURI = op->cacheURI;
13619 func(ctxt, op->value);
13620 ctxt->context->function = oldFunc;
13621 ctxt->context->functionURI = oldFuncURI;
13622 xmlXPathPopFrame(ctxt, frame);
13626 bakd = ctxt->context->doc;
13627 bak = ctxt->context->node;
13628 pp = ctxt->context->proximityPosition;
13629 cs = ctxt->context->contextSize;
13630 if (op->ch1 != -1) {
13631 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13632 ctxt->context->contextSize = cs;
13633 ctxt->context->proximityPosition = pp;
13634 ctxt->context->node = bak;
13635 ctxt->context->doc = bakd;
13638 if (op->ch2 != -1) {
13639 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13640 ctxt->context->contextSize = cs;
13641 ctxt->context->proximityPosition = pp;
13642 ctxt->context->node = bak;
13643 ctxt->context->doc = bakd;
13647 case XPATH_OP_PREDICATE:
13648 case XPATH_OP_FILTER:{
13649 xmlXPathObjectPtr res;
13650 xmlXPathObjectPtr obj, tmp;
13651 xmlNodeSetPtr newset = NULL;
13652 xmlNodeSetPtr oldset;
13653 xmlNodePtr oldnode;
13658 * Optimization for ()[1] selection i.e. the first elem
13660 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13661 #ifdef XP_OPTIMIZED_FILTER_FIRST
13663 * FILTER TODO: Can we assume that the inner processing
13664 * will result in an ordered list if we have an
13666 * What about an additional field or flag on
13667 * xmlXPathObject like @sorted ? This way we wouln'd need
13668 * to assume anything, so it would be more robust and
13669 * easier to optimize.
13671 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13672 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13674 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13676 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13677 xmlXPathObjectPtr val;
13679 val = comp->steps[op->ch2].value4;
13680 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13681 (val->floatval == 1.0)) {
13682 xmlNodePtr first = NULL;
13685 xmlXPathCompOpEvalFirst(ctxt,
13686 &comp->steps[op->ch1],
13690 * The nodeset should be in document order,
13691 * Keep only the first value
13693 if ((ctxt->value != NULL) &&
13694 (ctxt->value->type == XPATH_NODESET) &&
13695 (ctxt->value->nodesetval != NULL) &&
13696 (ctxt->value->nodesetval->nodeNr > 1))
13697 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13703 * Optimization for ()[last()] selection i.e. the last elem
13705 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13706 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13707 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13708 int f = comp->steps[op->ch2].ch1;
13711 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13712 (comp->steps[f].value5 == NULL) &&
13713 (comp->steps[f].value == 0) &&
13714 (comp->steps[f].value4 != NULL) &&
13716 (comp->steps[f].value4, BAD_CAST "last"))) {
13717 xmlNodePtr last = NULL;
13720 xmlXPathCompOpEvalLast(ctxt,
13721 &comp->steps[op->ch1],
13725 * The nodeset should be in document order,
13726 * Keep only the last value
13728 if ((ctxt->value != NULL) &&
13729 (ctxt->value->type == XPATH_NODESET) &&
13730 (ctxt->value->nodesetval != NULL) &&
13731 (ctxt->value->nodesetval->nodeTab != NULL) &&
13732 (ctxt->value->nodesetval->nodeNr > 1))
13733 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13738 * Process inner predicates first.
13739 * Example "index[parent::book][1]":
13741 * PREDICATE <-- we are here "[1]"
13742 * PREDICATE <-- process "[parent::book]" first
13744 * COLLECT 'parent' 'name' 'node' book
13746 * ELEM Object is a number : 1
13750 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13754 if (ctxt->value == NULL)
13757 oldnode = ctxt->context->node;
13759 #ifdef LIBXML_XPTR_ENABLED
13761 * Hum are we filtering the result of an XPointer expression
13763 if (ctxt->value->type == XPATH_LOCATIONSET) {
13764 xmlLocationSetPtr newlocset = NULL;
13765 xmlLocationSetPtr oldlocset;
13768 * Extract the old locset, and then evaluate the result of the
13769 * expression for all the element in the locset. use it to grow
13772 CHECK_TYPE0(XPATH_LOCATIONSET);
13773 obj = valuePop(ctxt);
13774 oldlocset = obj->user;
13775 ctxt->context->node = NULL;
13777 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13778 ctxt->context->contextSize = 0;
13779 ctxt->context->proximityPosition = 0;
13782 xmlXPathCompOpEval(ctxt,
13783 &comp->steps[op->ch2]);
13784 res = valuePop(ctxt);
13786 xmlXPathReleaseObject(ctxt->context, res);
13788 valuePush(ctxt, obj);
13792 newlocset = xmlXPtrLocationSetCreate(NULL);
13794 for (i = 0; i < oldlocset->locNr; i++) {
13796 * Run the evaluation with a node list made of a
13797 * single item in the nodelocset.
13799 ctxt->context->node = oldlocset->locTab[i]->user;
13800 ctxt->context->contextSize = oldlocset->locNr;
13801 ctxt->context->proximityPosition = i + 1;
13802 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13803 ctxt->context->node);
13804 valuePush(ctxt, tmp);
13808 xmlXPathCompOpEval(ctxt,
13809 &comp->steps[op->ch2]);
13810 if (ctxt->error != XPATH_EXPRESSION_OK) {
13811 xmlXPathFreeObject(obj);
13816 * The result of the evaluation need to be tested to
13817 * decided whether the filter succeeded or not
13819 res = valuePop(ctxt);
13820 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13821 xmlXPtrLocationSetAdd(newlocset,
13823 (oldlocset->locTab[i]));
13830 xmlXPathReleaseObject(ctxt->context, res);
13832 if (ctxt->value == tmp) {
13833 res = valuePop(ctxt);
13834 xmlXPathReleaseObject(ctxt->context, res);
13837 ctxt->context->node = NULL;
13841 * The result is used as the new evaluation locset.
13843 xmlXPathReleaseObject(ctxt->context, obj);
13844 ctxt->context->node = NULL;
13845 ctxt->context->contextSize = -1;
13846 ctxt->context->proximityPosition = -1;
13847 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13848 ctxt->context->node = oldnode;
13851 #endif /* LIBXML_XPTR_ENABLED */
13854 * Extract the old set, and then evaluate the result of the
13855 * expression for all the element in the set. use it to grow
13858 CHECK_TYPE0(XPATH_NODESET);
13859 obj = valuePop(ctxt);
13860 oldset = obj->nodesetval;
13862 oldnode = ctxt->context->node;
13863 oldDoc = ctxt->context->doc;
13864 ctxt->context->node = NULL;
13866 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13867 ctxt->context->contextSize = 0;
13868 ctxt->context->proximityPosition = 0;
13872 xmlXPathCompOpEval(ctxt,
13873 &comp->steps[op->ch2]);
13875 res = valuePop(ctxt);
13877 xmlXPathFreeObject(res);
13879 valuePush(ctxt, obj);
13880 ctxt->context->node = oldnode;
13885 * Initialize the new set.
13886 * Also set the xpath document in case things like
13887 * key() evaluation are attempted on the predicate
13889 newset = xmlXPathNodeSetCreate(NULL);
13892 * "For each node in the node-set to be filtered, the
13893 * PredicateExpr is evaluated with that node as the
13894 * context node, with the number of nodes in the
13895 * node-set as the context size, and with the proximity
13896 * position of the node in the node-set with respect to
13897 * the axis as the context position;"
13898 * @oldset is the node-set" to be filtered.
13901 * "only predicates change the context position and
13902 * context size (see [2.4 Predicates])."
13904 * node-set context pos
13908 * After applying predicate [position() > 1] :
13909 * node-set context pos
13913 * removed the first node in the node-set, then
13914 * the context position of the
13916 for (i = 0; i < oldset->nodeNr; i++) {
13918 * Run the evaluation with a node list made of
13919 * a single item in the nodeset.
13921 ctxt->context->node = oldset->nodeTab[i];
13922 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13923 (oldset->nodeTab[i]->doc != NULL))
13924 ctxt->context->doc = oldset->nodeTab[i]->doc;
13926 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13927 ctxt->context->node);
13929 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13930 ctxt->context->node) < 0) {
13931 ctxt->error = XPATH_MEMORY_ERROR;
13934 valuePush(ctxt, tmp);
13935 ctxt->context->contextSize = oldset->nodeNr;
13936 ctxt->context->proximityPosition = i + 1;
13938 * Evaluate the predicate against the context node.
13939 * Can/should we optimize position() predicates
13940 * here (e.g. "[1]")?
13944 xmlXPathCompOpEval(ctxt,
13945 &comp->steps[op->ch2]);
13946 if (ctxt->error != XPATH_EXPRESSION_OK) {
13947 xmlXPathFreeNodeSet(newset);
13948 xmlXPathFreeObject(obj);
13953 * The result of the evaluation needs to be tested to
13954 * decide whether the filter succeeded or not
13957 * OPTIMIZE TODO: Can we use
13958 * xmlXPathNodeSetAdd*Unique()* instead?
13960 res = valuePop(ctxt);
13961 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13962 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13964 ctxt->error = XPATH_MEMORY_ERROR;
13971 xmlXPathReleaseObject(ctxt->context, res);
13973 if (ctxt->value == tmp) {
13975 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13977 * Don't free the temporary nodeset
13978 * in order to avoid massive recreation inside this
13983 ctxt->context->node = NULL;
13986 xmlXPathReleaseObject(ctxt->context, tmp);
13988 * The result is used as the new evaluation set.
13990 xmlXPathReleaseObject(ctxt->context, obj);
13991 ctxt->context->node = NULL;
13992 ctxt->context->contextSize = -1;
13993 ctxt->context->proximityPosition = -1;
13994 /* may want to move this past the '}' later */
13995 ctxt->context->doc = oldDoc;
13997 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13999 ctxt->context->node = oldnode;
14002 case XPATH_OP_SORT:
14004 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14006 if ((ctxt->value != NULL) &&
14007 (ctxt->value->type == XPATH_NODESET) &&
14008 (ctxt->value->nodesetval != NULL) &&
14009 (ctxt->value->nodesetval->nodeNr > 1))
14011 xmlXPathNodeSetSort(ctxt->value->nodesetval);
14014 #ifdef LIBXML_XPTR_ENABLED
14015 case XPATH_OP_RANGETO:{
14016 xmlXPathObjectPtr range;
14017 xmlXPathObjectPtr res, obj;
14018 xmlXPathObjectPtr tmp;
14019 xmlLocationSetPtr newlocset = NULL;
14020 xmlLocationSetPtr oldlocset;
14021 xmlNodeSetPtr oldset;
14024 if (op->ch1 != -1) {
14026 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14029 if (ctxt->value == NULL) {
14030 XP_ERROR0(XPATH_INVALID_OPERAND);
14035 if (ctxt->value->type == XPATH_LOCATIONSET) {
14037 * Extract the old locset, and then evaluate the result of the
14038 * expression for all the element in the locset. use it to grow
14041 CHECK_TYPE0(XPATH_LOCATIONSET);
14042 obj = valuePop(ctxt);
14043 oldlocset = obj->user;
14045 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14046 ctxt->context->node = NULL;
14047 ctxt->context->contextSize = 0;
14048 ctxt->context->proximityPosition = 0;
14049 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14050 res = valuePop(ctxt);
14052 xmlXPathReleaseObject(ctxt->context, res);
14054 valuePush(ctxt, obj);
14058 newlocset = xmlXPtrLocationSetCreate(NULL);
14060 for (i = 0; i < oldlocset->locNr; i++) {
14062 * Run the evaluation with a node list made of a
14063 * single item in the nodelocset.
14065 ctxt->context->node = oldlocset->locTab[i]->user;
14066 ctxt->context->contextSize = oldlocset->locNr;
14067 ctxt->context->proximityPosition = i + 1;
14068 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14069 ctxt->context->node);
14070 valuePush(ctxt, tmp);
14074 xmlXPathCompOpEval(ctxt,
14075 &comp->steps[op->ch2]);
14076 if (ctxt->error != XPATH_EXPRESSION_OK) {
14077 xmlXPathFreeObject(obj);
14081 res = valuePop(ctxt);
14082 if (res->type == XPATH_LOCATIONSET) {
14083 xmlLocationSetPtr rloc =
14084 (xmlLocationSetPtr)res->user;
14085 for (j=0; j<rloc->locNr; j++) {
14086 range = xmlXPtrNewRange(
14087 oldlocset->locTab[i]->user,
14088 oldlocset->locTab[i]->index,
14089 rloc->locTab[j]->user2,
14090 rloc->locTab[j]->index2);
14091 if (range != NULL) {
14092 xmlXPtrLocationSetAdd(newlocset, range);
14096 range = xmlXPtrNewRangeNodeObject(
14097 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14098 if (range != NULL) {
14099 xmlXPtrLocationSetAdd(newlocset,range);
14107 xmlXPathReleaseObject(ctxt->context, res);
14109 if (ctxt->value == tmp) {
14110 res = valuePop(ctxt);
14111 xmlXPathReleaseObject(ctxt->context, res);
14114 ctxt->context->node = NULL;
14116 } else { /* Not a location set */
14117 CHECK_TYPE0(XPATH_NODESET);
14118 obj = valuePop(ctxt);
14119 oldset = obj->nodesetval;
14120 ctxt->context->node = NULL;
14122 newlocset = xmlXPtrLocationSetCreate(NULL);
14124 if (oldset != NULL) {
14125 for (i = 0; i < oldset->nodeNr; i++) {
14127 * Run the evaluation with a node list made of a single item
14130 ctxt->context->node = oldset->nodeTab[i];
14132 * OPTIMIZE TODO: Avoid recreation for every iteration.
14134 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14135 ctxt->context->node);
14136 valuePush(ctxt, tmp);
14140 xmlXPathCompOpEval(ctxt,
14141 &comp->steps[op->ch2]);
14142 if (ctxt->error != XPATH_EXPRESSION_OK) {
14143 xmlXPathFreeObject(obj);
14147 res = valuePop(ctxt);
14149 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14151 if (range != NULL) {
14152 xmlXPtrLocationSetAdd(newlocset, range);
14159 xmlXPathReleaseObject(ctxt->context, res);
14161 if (ctxt->value == tmp) {
14162 res = valuePop(ctxt);
14163 xmlXPathReleaseObject(ctxt->context, res);
14166 ctxt->context->node = NULL;
14172 * The result is used as the new evaluation set.
14174 xmlXPathReleaseObject(ctxt->context, obj);
14175 ctxt->context->node = NULL;
14176 ctxt->context->contextSize = -1;
14177 ctxt->context->proximityPosition = -1;
14178 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14181 #endif /* LIBXML_XPTR_ENABLED */
14183 xmlGenericError(xmlGenericErrorContext,
14184 "XPath: unknown precompiled operation %d\n", op->op);
14185 ctxt->error = XPATH_INVALID_OPERAND;
14190 * xmlXPathCompOpEvalToBoolean:
14191 * @ctxt: the XPath parser context
14193 * Evaluates if the expression evaluates to true.
14195 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14198 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14199 xmlXPathStepOpPtr op,
14202 xmlXPathObjectPtr resObj = NULL;
14205 /* comp = ctxt->comp; */
14209 case XPATH_OP_VALUE:
14210 resObj = (xmlXPathObjectPtr) op->value4;
14212 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14213 return(xmlXPathCastToBoolean(resObj));
14214 case XPATH_OP_SORT:
14216 * We don't need sorting for boolean results. Skip this one.
14218 if (op->ch1 != -1) {
14219 op = &ctxt->comp->steps[op->ch1];
14223 case XPATH_OP_COLLECT:
14227 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14228 if (ctxt->error != XPATH_EXPRESSION_OK)
14231 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14232 if (ctxt->error != XPATH_EXPRESSION_OK)
14235 resObj = valuePop(ctxt);
14236 if (resObj == NULL)
14241 * Fallback to call xmlXPathCompOpEval().
14243 xmlXPathCompOpEval(ctxt, op);
14244 if (ctxt->error != XPATH_EXPRESSION_OK)
14247 resObj = valuePop(ctxt);
14248 if (resObj == NULL)
14256 if (resObj->type == XPATH_BOOLEAN) {
14257 res = resObj->boolval;
14258 } else if (isPredicate) {
14260 * For predicates a result of type "number" is handled
14263 * "If the result is a number, the result will be converted
14264 * to true if the number is equal to the context position
14265 * and will be converted to false otherwise;"
14267 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14269 res = xmlXPathCastToBoolean(resObj);
14271 xmlXPathReleaseObject(ctxt->context, resObj);
14278 #ifdef XPATH_STREAMING
14280 * xmlXPathRunStreamEval:
14281 * @ctxt: the XPath parser context with the compiled expression
14283 * Evaluate the Precompiled Streamable XPath expression in the given context.
14286 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14287 xmlXPathObjectPtr *resultSeq, int toBool)
14289 int max_depth, min_depth;
14292 int eval_all_nodes;
14293 xmlNodePtr cur = NULL, limit = NULL;
14294 xmlStreamCtxtPtr patstream = NULL;
14298 if ((ctxt == NULL) || (comp == NULL))
14300 max_depth = xmlPatternMaxDepth(comp);
14301 if (max_depth == -1)
14303 if (max_depth == -2)
14305 min_depth = xmlPatternMinDepth(comp);
14306 if (min_depth == -1)
14308 from_root = xmlPatternFromRoot(comp);
14312 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14316 if (resultSeq == NULL)
14318 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14319 if (*resultSeq == NULL)
14324 * handle the special cases of "/" amd "." being matched
14326 if (min_depth == 0) {
14331 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14332 (xmlNodePtr) ctxt->doc);
14334 /* Select "self::node()" */
14337 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14340 if (max_depth == 0) {
14345 cur = (xmlNodePtr)ctxt->doc;
14346 } else if (ctxt->node != NULL) {
14347 switch (ctxt->node->type) {
14348 case XML_ELEMENT_NODE:
14349 case XML_DOCUMENT_NODE:
14350 case XML_DOCUMENT_FRAG_NODE:
14351 case XML_HTML_DOCUMENT_NODE:
14352 #ifdef LIBXML_DOCB_ENABLED
14353 case XML_DOCB_DOCUMENT_NODE:
14357 case XML_ATTRIBUTE_NODE:
14358 case XML_TEXT_NODE:
14359 case XML_CDATA_SECTION_NODE:
14360 case XML_ENTITY_REF_NODE:
14361 case XML_ENTITY_NODE:
14363 case XML_COMMENT_NODE:
14364 case XML_NOTATION_NODE:
14366 case XML_DOCUMENT_TYPE_NODE:
14367 case XML_ELEMENT_DECL:
14368 case XML_ATTRIBUTE_DECL:
14369 case XML_ENTITY_DECL:
14370 case XML_NAMESPACE_DECL:
14371 case XML_XINCLUDE_START:
14372 case XML_XINCLUDE_END:
14381 patstream = xmlPatternGetStreamCtxt(comp);
14382 if (patstream == NULL) {
14384 * QUESTION TODO: Is this an error?
14389 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14392 ret = xmlStreamPush(patstream, NULL, NULL);
14394 } else if (ret == 1) {
14397 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14401 goto scan_children;
14406 switch (cur->type) {
14407 case XML_ELEMENT_NODE:
14408 case XML_TEXT_NODE:
14409 case XML_CDATA_SECTION_NODE:
14410 case XML_COMMENT_NODE:
14412 if (cur->type == XML_ELEMENT_NODE) {
14413 ret = xmlStreamPush(patstream, cur->name,
14414 (cur->ns ? cur->ns->href : NULL));
14415 } else if (eval_all_nodes)
14416 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14422 } else if (ret == 1) {
14425 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14427 ctxt->lastError.domain = XML_FROM_XPATH;
14428 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14431 if ((cur->children == NULL) || (depth >= max_depth)) {
14432 ret = xmlStreamPop(patstream);
14433 while (cur->next != NULL) {
14435 if ((cur->type != XML_ENTITY_DECL) &&
14436 (cur->type != XML_DTD_NODE))
14445 if (cur->type == XML_NAMESPACE_DECL) break;
14446 if ((cur->children != NULL) && (depth < max_depth)) {
14448 * Do not descend on entities declarations
14450 if (cur->children->type != XML_ENTITY_DECL) {
14451 cur = cur->children;
14456 if (cur->type != XML_DTD_NODE)
14464 while (cur->next != NULL) {
14466 if ((cur->type != XML_ENTITY_DECL) &&
14467 (cur->type != XML_DTD_NODE))
14474 if ((cur == NULL) || (cur == limit))
14476 if (cur->type == XML_ELEMENT_NODE) {
14477 ret = xmlStreamPop(patstream);
14478 } else if ((eval_all_nodes) &&
14479 ((cur->type == XML_TEXT_NODE) ||
14480 (cur->type == XML_CDATA_SECTION_NODE) ||
14481 (cur->type == XML_COMMENT_NODE) ||
14482 (cur->type == XML_PI_NODE)))
14484 ret = xmlStreamPop(patstream);
14486 if (cur->next != NULL) {
14490 } while (cur != NULL);
14492 } while ((cur != NULL) && (depth >= 0));
14497 printf("stream eval: checked %d nodes selected %d\n",
14498 nb_nodes, retObj->nodesetval->nodeNr);
14502 xmlFreeStreamCtxt(patstream);
14507 xmlFreeStreamCtxt(patstream);
14510 #endif /* XPATH_STREAMING */
14514 * @ctxt: the XPath parser context with the compiled expression
14515 * @toBool: evaluate to a boolean result
14517 * Evaluate the Precompiled XPath expression in the given context.
14520 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14522 xmlXPathCompExprPtr comp;
14524 if ((ctxt == NULL) || (ctxt->comp == NULL))
14527 if (ctxt->valueTab == NULL) {
14528 /* Allocate the value stack */
14529 ctxt->valueTab = (xmlXPathObjectPtr *)
14530 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14531 if (ctxt->valueTab == NULL) {
14532 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14536 ctxt->valueMax = 10;
14537 ctxt->value = NULL;
14538 ctxt->valueFrame = 0;
14540 #ifdef XPATH_STREAMING
14541 if (ctxt->comp->stream) {
14546 * Evaluation to boolean result.
14548 res = xmlXPathRunStreamEval(ctxt->context,
14549 ctxt->comp->stream, NULL, 1);
14553 xmlXPathObjectPtr resObj = NULL;
14556 * Evaluation to a sequence.
14558 res = xmlXPathRunStreamEval(ctxt->context,
14559 ctxt->comp->stream, &resObj, 0);
14561 if ((res != -1) && (resObj != NULL)) {
14562 valuePush(ctxt, resObj);
14565 if (resObj != NULL)
14566 xmlXPathReleaseObject(ctxt->context, resObj);
14569 * QUESTION TODO: This falls back to normal XPath evaluation
14570 * if res == -1. Is this intended?
14575 if (comp->last < 0) {
14576 xmlGenericError(xmlGenericErrorContext,
14577 "xmlXPathRunEval: last is less than zero\n");
14581 return(xmlXPathCompOpEvalToBoolean(ctxt,
14582 &comp->steps[comp->last], 0));
14584 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14589 /************************************************************************
14591 * Public interfaces *
14593 ************************************************************************/
14596 * xmlXPathEvalPredicate:
14597 * @ctxt: the XPath context
14598 * @res: the Predicate Expression evaluation result
14600 * Evaluate a predicate result for the current node.
14601 * A PredicateExpr is evaluated by evaluating the Expr and converting
14602 * the result to a boolean. If the result is a number, the result will
14603 * be converted to true if the number is equal to the position of the
14604 * context node in the context node list (as returned by the position
14605 * function) and will be converted to false otherwise; if the result
14606 * is not a number, then the result will be converted as if by a call
14607 * to the boolean function.
14609 * Returns 1 if predicate is true, 0 otherwise
14612 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14613 if ((ctxt == NULL) || (res == NULL)) return(0);
14614 switch (res->type) {
14615 case XPATH_BOOLEAN:
14616 return(res->boolval);
14618 return(res->floatval == ctxt->proximityPosition);
14619 case XPATH_NODESET:
14620 case XPATH_XSLT_TREE:
14621 if (res->nodesetval == NULL)
14623 return(res->nodesetval->nodeNr != 0);
14625 return((res->stringval != NULL) &&
14626 (xmlStrlen(res->stringval) != 0));
14634 * xmlXPathEvaluatePredicateResult:
14635 * @ctxt: the XPath Parser context
14636 * @res: the Predicate Expression evaluation result
14638 * Evaluate a predicate result for the current node.
14639 * A PredicateExpr is evaluated by evaluating the Expr and converting
14640 * the result to a boolean. If the result is a number, the result will
14641 * be converted to true if the number is equal to the position of the
14642 * context node in the context node list (as returned by the position
14643 * function) and will be converted to false otherwise; if the result
14644 * is not a number, then the result will be converted as if by a call
14645 * to the boolean function.
14647 * Returns 1 if predicate is true, 0 otherwise
14650 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14651 xmlXPathObjectPtr res) {
14652 if ((ctxt == NULL) || (res == NULL)) return(0);
14653 switch (res->type) {
14654 case XPATH_BOOLEAN:
14655 return(res->boolval);
14657 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14658 return((res->floatval == ctxt->context->proximityPosition) &&
14659 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14661 return(res->floatval == ctxt->context->proximityPosition);
14663 case XPATH_NODESET:
14664 case XPATH_XSLT_TREE:
14665 if (res->nodesetval == NULL)
14667 return(res->nodesetval->nodeNr != 0);
14669 return((res->stringval != NULL) && (res->stringval[0] != 0));
14670 #ifdef LIBXML_XPTR_ENABLED
14671 case XPATH_LOCATIONSET:{
14672 xmlLocationSetPtr ptr = res->user;
14675 return (ptr->locNr != 0);
14684 #ifdef XPATH_STREAMING
14686 * xmlXPathTryStreamCompile:
14687 * @ctxt: an XPath context
14688 * @str: the XPath expression
14690 * Try to compile the XPath expression as a streamable subset.
14692 * Returns the compiled expression or NULL if failed to compile.
14694 static xmlXPathCompExprPtr
14695 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14697 * Optimization: use streaming patterns when the XPath expression can
14698 * be compiled to a stream lookup
14700 xmlPatternPtr stream;
14701 xmlXPathCompExprPtr comp;
14702 xmlDictPtr dict = NULL;
14703 const xmlChar **namespaces = NULL;
14707 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14708 (!xmlStrchr(str, '@'))) {
14709 const xmlChar *tmp;
14712 * We don't try to handle expressions using the verbose axis
14713 * specifiers ("::"), just the simplied form at this point.
14714 * Additionally, if there is no list of namespaces available and
14715 * there's a ":" in the expression, indicating a prefixed QName,
14716 * then we won't try to compile either. xmlPatterncompile() needs
14717 * to have a list of namespaces at compilation time in order to
14718 * compile prefixed name tests.
14720 tmp = xmlStrchr(str, ':');
14721 if ((tmp != NULL) &&
14722 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14725 if (ctxt != NULL) {
14727 if (ctxt->nsNr > 0) {
14728 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14729 if (namespaces == NULL) {
14730 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14733 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14734 ns = ctxt->namespaces[j];
14735 namespaces[i++] = ns->href;
14736 namespaces[i++] = ns->prefix;
14738 namespaces[i++] = NULL;
14739 namespaces[i] = NULL;
14743 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14745 if (namespaces != NULL) {
14746 xmlFree((xmlChar **)namespaces);
14748 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14749 comp = xmlXPathNewCompExpr();
14750 if (comp == NULL) {
14751 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14754 comp->stream = stream;
14757 xmlDictReference(comp->dict);
14760 xmlFreePattern(stream);
14764 #endif /* XPATH_STREAMING */
14767 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14770 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14771 * internal representation.
14774 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14776 (op->ch2 == -1 /* no predicate */))
14778 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14780 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14781 ((xmlXPathAxisVal) prevop->value ==
14782 AXIS_DESCENDANT_OR_SELF) &&
14783 (prevop->ch2 == -1) &&
14784 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14785 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14788 * This is a "descendant-or-self::node()" without predicates.
14789 * Try to eliminate it.
14792 switch ((xmlXPathAxisVal) op->value) {
14794 case AXIS_DESCENDANT:
14796 * Convert "descendant-or-self::node()/child::" or
14797 * "descendant-or-self::node()/descendant::" to
14800 op->ch1 = prevop->ch1;
14801 op->value = AXIS_DESCENDANT;
14804 case AXIS_DESCENDANT_OR_SELF:
14806 * Convert "descendant-or-self::node()/self::" or
14807 * "descendant-or-self::node()/descendant-or-self::" to
14808 * to "descendant-or-self::"
14810 op->ch1 = prevop->ch1;
14811 op->value = AXIS_DESCENDANT_OR_SELF;
14819 /* OP_VALUE has invalid ch1. */
14820 if (op->op == XPATH_OP_VALUE)
14825 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14827 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14831 * xmlXPathCtxtCompile:
14832 * @ctxt: an XPath context
14833 * @str: the XPath expression
14835 * Compile an XPath expression
14837 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14838 * the caller has to free the object.
14840 xmlXPathCompExprPtr
14841 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14842 xmlXPathParserContextPtr pctxt;
14843 xmlXPathCompExprPtr comp;
14845 #ifdef XPATH_STREAMING
14846 comp = xmlXPathTryStreamCompile(ctxt, str);
14853 pctxt = xmlXPathNewParserContext(str, ctxt);
14856 xmlXPathCompileExpr(pctxt, 1);
14858 if( pctxt->error != XPATH_EXPRESSION_OK )
14860 xmlXPathFreeParserContext(pctxt);
14864 if (*pctxt->cur != 0) {
14866 * aleksey: in some cases this line prints *second* error message
14867 * (see bug #78858) and probably this should be fixed.
14868 * However, we are not sure that all error messages are printed
14869 * out in other places. It's not critical so we leave it as-is for now
14871 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14874 comp = pctxt->comp;
14875 pctxt->comp = NULL;
14877 xmlXPathFreeParserContext(pctxt);
14879 if (comp != NULL) {
14880 comp->expr = xmlStrdup(str);
14881 #ifdef DEBUG_EVAL_COUNTS
14882 comp->string = xmlStrdup(str);
14885 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14886 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14894 * @str: the XPath expression
14896 * Compile an XPath expression
14898 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14899 * the caller has to free the object.
14901 xmlXPathCompExprPtr
14902 xmlXPathCompile(const xmlChar *str) {
14903 return(xmlXPathCtxtCompile(NULL, str));
14907 * xmlXPathCompiledEvalInternal:
14908 * @comp: the compiled XPath expression
14909 * @ctxt: the XPath context
14910 * @resObj: the resulting XPath object or NULL
14911 * @toBool: 1 if only a boolean result is requested
14913 * Evaluate the Precompiled XPath expression in the given context.
14914 * The caller has to free @resObj.
14916 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14917 * the caller has to free the object.
14920 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14921 xmlXPathContextPtr ctxt,
14922 xmlXPathObjectPtr *resObjPtr,
14925 xmlXPathParserContextPtr pctxt;
14926 xmlXPathObjectPtr resObj;
14927 #ifndef LIBXML_THREAD_ENABLED
14928 static int reentance = 0;
14932 CHECK_CTXT_NEG(ctxt)
14938 #ifndef LIBXML_THREAD_ENABLED
14941 xmlXPathDisableOptimizer = 1;
14944 #ifdef DEBUG_EVAL_COUNTS
14946 if ((comp->string != NULL) && (comp->nb > 100)) {
14947 fprintf(stderr, "100 x %s\n", comp->string);
14951 pctxt = xmlXPathCompParserContext(comp, ctxt);
14952 res = xmlXPathRunEval(pctxt, toBool);
14954 if (pctxt->error != XPATH_EXPRESSION_OK) {
14957 resObj = valuePop(pctxt);
14958 if (resObj == NULL) {
14960 xmlGenericError(xmlGenericErrorContext,
14961 "xmlXPathCompiledEval: No result on the stack.\n");
14962 } else if (pctxt->valueNr > 0) {
14963 xmlGenericError(xmlGenericErrorContext,
14964 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14970 *resObjPtr = resObj;
14972 xmlXPathReleaseObject(ctxt, resObj);
14974 pctxt->comp = NULL;
14975 xmlXPathFreeParserContext(pctxt);
14976 #ifndef LIBXML_THREAD_ENABLED
14984 * xmlXPathCompiledEval:
14985 * @comp: the compiled XPath expression
14986 * @ctx: the XPath context
14988 * Evaluate the Precompiled XPath expression in the given context.
14990 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14991 * the caller has to free the object.
14994 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14996 xmlXPathObjectPtr res = NULL;
14998 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
15003 * xmlXPathCompiledEvalToBoolean:
15004 * @comp: the compiled XPath expression
15005 * @ctxt: the XPath context
15007 * Applies the XPath boolean() function on the result of the given
15008 * compiled expression.
15010 * Returns 1 if the expression evaluated to true, 0 if to false and
15011 * -1 in API and internal errors.
15014 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15015 xmlXPathContextPtr ctxt)
15017 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15021 * xmlXPathEvalExpr:
15022 * @ctxt: the XPath Parser context
15024 * Parse and evaluate an XPath expression in the given context,
15025 * then push the result on the context stack
15028 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15029 #ifdef XPATH_STREAMING
15030 xmlXPathCompExprPtr comp;
15033 if (ctxt == NULL) return;
15035 #ifdef XPATH_STREAMING
15036 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15037 if (comp != NULL) {
15038 if (ctxt->comp != NULL)
15039 xmlXPathFreeCompExpr(ctxt->comp);
15044 xmlXPathCompileExpr(ctxt, 1);
15047 /* Check for trailing characters. */
15048 if (*ctxt->cur != 0)
15049 XP_ERROR(XPATH_EXPR_ERROR);
15051 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
15052 xmlXPathOptimizeExpression(ctxt->comp,
15053 &ctxt->comp->steps[ctxt->comp->last]);
15056 xmlXPathRunEval(ctxt, 0);
15061 * @str: the XPath expression
15062 * @ctx: the XPath context
15064 * Evaluate the XPath Location Path in the given context.
15066 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15067 * the caller has to free the object.
15070 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15071 xmlXPathParserContextPtr ctxt;
15072 xmlXPathObjectPtr res;
15078 ctxt = xmlXPathNewParserContext(str, ctx);
15081 xmlXPathEvalExpr(ctxt);
15083 if (ctxt->error != XPATH_EXPRESSION_OK) {
15086 res = valuePop(ctxt);
15088 xmlGenericError(xmlGenericErrorContext,
15089 "xmlXPathCompiledEval: No result on the stack.\n");
15090 } else if (ctxt->valueNr > 0) {
15091 xmlGenericError(xmlGenericErrorContext,
15092 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15097 xmlXPathFreeParserContext(ctxt);
15102 * xmlXPathSetContextNode:
15103 * @node: the node to to use as the context node
15104 * @ctx: the XPath context
15106 * Sets 'node' as the context node. The node must be in the same
15107 * document as that associated with the context.
15109 * Returns -1 in case of error or 0 if successful
15112 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15113 if ((node == NULL) || (ctx == NULL))
15116 if (node->doc == ctx->doc) {
15124 * xmlXPathNodeEval:
15125 * @node: the node to to use as the context node
15126 * @str: the XPath expression
15127 * @ctx: the XPath context
15129 * Evaluate the XPath Location Path in the given context. The node 'node'
15130 * is set as the context node. The context node is not restored.
15132 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15133 * the caller has to free the object.
15136 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15139 if (xmlXPathSetContextNode(node, ctx) < 0)
15141 return(xmlXPathEval(str, ctx));
15145 * xmlXPathEvalExpression:
15146 * @str: the XPath expression
15147 * @ctxt: the XPath context
15149 * Alias for xmlXPathEval().
15151 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15152 * the caller has to free the object.
15155 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15156 return(xmlXPathEval(str, ctxt));
15159 /************************************************************************
15161 * Extra functions not pertaining to the XPath spec *
15163 ************************************************************************/
15165 * xmlXPathEscapeUriFunction:
15166 * @ctxt: the XPath Parser context
15167 * @nargs: the number of arguments
15169 * Implement the escape-uri() XPath function
15170 * string escape-uri(string $str, bool $escape-reserved)
15172 * This function applies the URI escaping rules defined in section 2 of [RFC
15173 * 2396] to the string supplied as $uri-part, which typically represents all
15174 * or part of a URI. The effect of the function is to replace any special
15175 * character in the string by an escape sequence of the form %xx%yy...,
15176 * where xxyy... is the hexadecimal representation of the octets used to
15177 * represent the character in UTF-8.
15179 * The set of characters that are escaped depends on the setting of the
15180 * boolean argument $escape-reserved.
15182 * If $escape-reserved is true, all characters are escaped other than lower
15183 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15184 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15185 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15186 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15189 * If $escape-reserved is false, the behavior differs in that characters
15190 * referred to in [RFC 2396] as reserved characters are not escaped. These
15191 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15193 * [RFC 2396] does not define whether escaped URIs should use lower case or
15194 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15195 * compared using string comparison functions, this function must always use
15196 * the upper-case letters A-F.
15198 * Generally, $escape-reserved should be set to true when escaping a string
15199 * that is to form a single part of a URI, and to false when escaping an
15200 * entire URI or URI reference.
15202 * In the case of non-ascii characters, the string is encoded according to
15203 * utf-8 and then converted according to RFC 2396.
15206 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15207 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15208 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15209 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15213 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15214 xmlXPathObjectPtr str;
15215 int escape_reserved;
15222 escape_reserved = xmlXPathPopBoolean(ctxt);
15225 str = valuePop(ctxt);
15227 target = xmlBufCreate();
15233 for (cptr = str->stringval; *cptr; cptr++) {
15234 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15235 (*cptr >= 'a' && *cptr <= 'z') ||
15236 (*cptr >= '0' && *cptr <= '9') ||
15237 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15238 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15239 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15241 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15242 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15243 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15244 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15245 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15246 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15247 (!escape_reserved &&
15248 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15249 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15250 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15252 xmlBufAdd(target, cptr, 1);
15254 if ((*cptr >> 4) < 10)
15255 escape[1] = '0' + (*cptr >> 4);
15257 escape[1] = 'A' - 10 + (*cptr >> 4);
15258 if ((*cptr & 0xF) < 10)
15259 escape[2] = '0' + (*cptr & 0xF);
15261 escape[2] = 'A' - 10 + (*cptr & 0xF);
15263 xmlBufAdd(target, &escape[0], 3);
15267 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15268 xmlBufContent(target)));
15269 xmlBufFree(target);
15270 xmlXPathReleaseObject(ctxt->context, str);
15274 * xmlXPathRegisterAllFunctions:
15275 * @ctxt: the XPath context
15277 * Registers all default XPath functions in this context
15280 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15282 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15283 xmlXPathBooleanFunction);
15284 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15285 xmlXPathCeilingFunction);
15286 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15287 xmlXPathCountFunction);
15288 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15289 xmlXPathConcatFunction);
15290 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15291 xmlXPathContainsFunction);
15292 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15293 xmlXPathIdFunction);
15294 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15295 xmlXPathFalseFunction);
15296 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15297 xmlXPathFloorFunction);
15298 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15299 xmlXPathLastFunction);
15300 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15301 xmlXPathLangFunction);
15302 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15303 xmlXPathLocalNameFunction);
15304 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15305 xmlXPathNotFunction);
15306 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15307 xmlXPathNameFunction);
15308 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15309 xmlXPathNamespaceURIFunction);
15310 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15311 xmlXPathNormalizeFunction);
15312 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15313 xmlXPathNumberFunction);
15314 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15315 xmlXPathPositionFunction);
15316 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15317 xmlXPathRoundFunction);
15318 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15319 xmlXPathStringFunction);
15320 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15321 xmlXPathStringLengthFunction);
15322 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15323 xmlXPathStartsWithFunction);
15324 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15325 xmlXPathSubstringFunction);
15326 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15327 xmlXPathSubstringBeforeFunction);
15328 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15329 xmlXPathSubstringAfterFunction);
15330 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15331 xmlXPathSumFunction);
15332 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15333 xmlXPathTrueFunction);
15334 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15335 xmlXPathTranslateFunction);
15337 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15338 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15339 xmlXPathEscapeUriFunction);
15342 #endif /* LIBXML_XPATH_ENABLED */
15343 #define bottom_xpath
15344 #include "elfgcchack.h"