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")
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
72 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
101 #define XP_OPTIMIZED_FILTER_FIRST
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
108 /* #define XP_DEBUG_OBJ_USAGE */
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
117 #define XPATH_MAX_STEPS 1000000
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
126 #define XPATH_MAX_STACK_DEPTH 1000000
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
136 #define XPATH_MAX_NODESET_LENGTH 10000000
140 * There are a few spots where some tests are done which depend upon ascii
141 * data. These should be enhanced for full UTF8 support (see particularly
142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
147 * xmlXPathCmpNodesExt:
148 * @node1: the first node
149 * @node2: the second node
151 * Compare two nodes w.r.t document order.
152 * This one is optimized for handling of non-element nodes.
154 * Returns -2 in case of error 1 if first point < second point, 0 if
155 * it's the same node, -1 otherwise
158 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
160 int misc = 0, precedence1 = 0, precedence2 = 0;
161 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
162 xmlNodePtr cur, root;
165 if ((node1 == NULL) || (node2 == NULL))
172 * a couple of optimizations which will avoid computations in most cases
174 switch (node1->type) {
175 case XML_ELEMENT_NODE:
176 if (node2->type == XML_ELEMENT_NODE) {
177 if ((0 > (ptrdiff_t) node1->content) &&
178 (0 > (ptrdiff_t) node2->content) &&
179 (node1->doc == node2->doc))
181 l1 = -((ptrdiff_t) node1->content);
182 l2 = -((ptrdiff_t) node2->content);
188 goto turtle_comparison;
191 case XML_ATTRIBUTE_NODE:
192 precedence1 = 1; /* element is owner */
194 node1 = node1->parent;
198 case XML_CDATA_SECTION_NODE:
199 case XML_COMMENT_NODE:
203 * Find nearest element node.
205 if (node1->prev != NULL) {
208 if (node1->type == XML_ELEMENT_NODE) {
209 precedence1 = 3; /* element in prev-sibl axis */
212 if (node1->prev == NULL) {
213 precedence1 = 2; /* element is parent */
215 * URGENT TODO: Are there any cases, where the
216 * parent of such a node is not an element node?
218 node1 = node1->parent;
223 precedence1 = 2; /* element is parent */
224 node1 = node1->parent;
226 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
227 (0 <= (ptrdiff_t) node1->content)) {
229 * Fallback for whatever case.
237 case XML_NAMESPACE_DECL:
239 * TODO: why do we return 1 for namespace nodes?
245 switch (node2->type) {
246 case XML_ELEMENT_NODE:
248 case XML_ATTRIBUTE_NODE:
249 precedence2 = 1; /* element is owner */
251 node2 = node2->parent;
255 case XML_CDATA_SECTION_NODE:
256 case XML_COMMENT_NODE:
259 if (node2->prev != NULL) {
262 if (node2->type == XML_ELEMENT_NODE) {
263 precedence2 = 3; /* element in prev-sibl axis */
266 if (node2->prev == NULL) {
267 precedence2 = 2; /* element is parent */
268 node2 = node2->parent;
273 precedence2 = 2; /* element is parent */
274 node2 = node2->parent;
276 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
277 (0 <= (ptrdiff_t) node2->content))
285 case XML_NAMESPACE_DECL:
291 if (node1 == node2) {
292 if (precedence1 == precedence2) {
294 * The ugly case; but normally there aren't many
295 * adjacent non-element nodes around.
297 cur = miscNode2->prev;
298 while (cur != NULL) {
299 if (cur == miscNode1)
301 if (cur->type == XML_ELEMENT_NODE)
308 * Evaluate based on higher precedence wrt to the element.
309 * TODO: This assumes attributes are sorted before content.
310 * Is this 100% correct?
312 if (precedence1 < precedence2)
319 * Special case: One of the helper-elements is contained by the other.
322 * <node1>Text-1(precedence1 == 2)</node1>
324 * Text-6(precedence2 == 3)
327 if ((precedence2 == 3) && (precedence1 > 1)) {
335 if ((precedence1 == 3) && (precedence2 > 1)) {
346 * Speedup using document order if availble.
348 if ((node1->type == XML_ELEMENT_NODE) &&
349 (node2->type == XML_ELEMENT_NODE) &&
350 (0 > (ptrdiff_t) node1->content) &&
351 (0 > (ptrdiff_t) node2->content) &&
352 (node1->doc == node2->doc)) {
354 l1 = -((ptrdiff_t) node1->content);
355 l2 = -((ptrdiff_t) node2->content);
364 if (node1 == node2->prev)
366 if (node1 == node2->next)
369 * compute depth to root
371 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
372 if (cur->parent == node1)
377 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
378 if (cur->parent == node2)
383 * Distinct document (or distinct entities :-( ) case.
389 * get the nearest common ancestor.
391 while (depth1 > depth2) {
393 node1 = node1->parent;
395 while (depth2 > depth1) {
397 node2 = node2->parent;
399 while (node1->parent != node2->parent) {
400 node1 = node1->parent;
401 node2 = node2->parent;
402 /* should not happen but just in case ... */
403 if ((node1 == NULL) || (node2 == NULL))
409 if (node1 == node2->prev)
411 if (node1 == node2->next)
414 * Speedup using document order if availble.
416 if ((node1->type == XML_ELEMENT_NODE) &&
417 (node2->type == XML_ELEMENT_NODE) &&
418 (0 > (ptrdiff_t) node1->content) &&
419 (0 > (ptrdiff_t) node2->content) &&
420 (node1->doc == node2->doc)) {
422 l1 = -((ptrdiff_t) node1->content);
423 l2 = -((ptrdiff_t) node2->content);
430 for (cur = node1->next;cur != NULL;cur = cur->next)
433 return(-1); /* assume there is no sibling list corruption */
435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
438 * Wrapper for the Timsort argorithm from timsort.h
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
448 * Comparison function for the Timsort implementation
450 * Returns -2 in case of error -1 if first point < second point, 0 if
451 * it's the same node, +1 otherwise
454 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
456 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
458 int res = xmlXPathCmpNodesExt(x, y);
459 return res == -2 ? res : -res;
462 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
464 int res = xmlXPathCmpNodes(x, y);
465 return res == -2 ? res : -res;
468 #define SORT_CMP(x, y) (wrap_cmp(x, y))
470 #endif /* WITH_TIM_SORT */
472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
474 /************************************************************************
476 * Floating point stuff *
478 ************************************************************************/
480 #ifndef TRIO_REPLACE_STDIO
481 #define TRIO_PUBLIC static
486 * The lack of portability of this section of the libc is annoying !
488 double xmlXPathNAN = 0;
489 double xmlXPathPINF = 1;
490 double xmlXPathNINF = -1;
491 static double xmlXPathNZERO = 0; /* not exported from headers */
492 static int xmlXPathInitialized = 0;
497 * Initialize the XPath environment
501 if (xmlXPathInitialized) return;
503 xmlXPathPINF = trio_pinf();
504 xmlXPathNINF = trio_ninf();
505 xmlXPathNAN = trio_nan();
506 xmlXPathNZERO = trio_nzero();
508 xmlXPathInitialized = 1;
513 * @val: a double value
515 * Provides a portable isnan() function to detect whether a double
516 * is a NotaNumber. Based on trio code
517 * http://sourceforge.net/projects/ctrio/
519 * Returns 1 if the value is a NaN, 0 otherwise
522 xmlXPathIsNaN(double val) {
523 return(trio_isnan(val));
528 * @val: a double value
530 * Provides a portable isinf() function to detect whether a double
531 * is a +Infinite or -Infinite. Based on trio code
532 * http://sourceforge.net/projects/ctrio/
534 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
537 xmlXPathIsInf(double val) {
538 return(trio_isinf(val));
541 #endif /* SCHEMAS or XPATH */
542 #ifdef LIBXML_XPATH_ENABLED
545 * @val: a double value
547 * Provides a portable function to detect the sign of a double
548 * Modified from trio code
549 * http://sourceforge.net/projects/ctrio/
551 * Returns 1 if the value is Negative, 0 if positive
554 xmlXPathGetSign(double val) {
555 return(trio_signbit(val));
560 * TODO: when compatibility allows remove all "fake node libxslt" strings
561 * the test should just be name[0] = ' '
563 #ifdef DEBUG_XPATH_EXPRESSION
566 #define DEBUG_EVAL_COUNTS
569 static xmlNs xmlXPathXMLNamespaceStruct = {
577 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
578 #ifndef LIBXML_THREAD_ENABLED
580 * Optimizer is disabled only when threaded apps are detected while
581 * the library ain't compiled for thread safety.
583 static int xmlXPathDisableOptimizer = 0;
586 /************************************************************************
588 * Error handling routines *
590 ************************************************************************/
596 * Macro to raise an XPath error and return NULL.
598 #define XP_ERRORNULL(X) \
599 { xmlXPathErr(ctxt, X); return(NULL); }
602 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
604 static const char *xmlXPathErrorMessages[] = {
607 "Unfinished literal\n",
608 "Start of literal\n",
609 "Expected $ for variable reference\n",
610 "Undefined variable\n",
611 "Invalid predicate\n",
612 "Invalid expression\n",
613 "Missing closing curly brace\n",
614 "Unregistered function\n",
617 "Invalid number of arguments\n",
618 "Invalid context size\n",
619 "Invalid context position\n",
620 "Memory allocation error\n",
623 "Sub resource error\n",
624 "Undefined namespace prefix\n",
626 "Char out of XML range\n",
627 "Invalid or incomplete context\n",
628 "Stack usage error\n",
629 "Forbidden variable\n",
630 "?? Unknown error ??\n" /* Must be last in the list! */
632 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
633 sizeof(xmlXPathErrorMessages[0])) - 1)
636 * @ctxt: an XPath context
637 * @extra: extra informations
639 * Handle a redefinition of attribute error
642 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
648 xmlStrPrintf(buf, 200,
649 "Memory allocation failed : %s\n",
651 ctxt->lastError.message = (char *) xmlStrdup(buf);
653 ctxt->lastError.message = (char *)
654 xmlStrdup(BAD_CAST "Memory allocation failed\n");
656 ctxt->lastError.domain = XML_FROM_XPATH;
657 ctxt->lastError.code = XML_ERR_NO_MEMORY;
658 if (ctxt->error != NULL)
659 ctxt->error(ctxt->userData, &ctxt->lastError);
662 __xmlRaiseError(NULL, NULL, NULL,
663 NULL, NULL, XML_FROM_XPATH,
664 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
665 extra, NULL, NULL, 0, 0,
666 "Memory allocation failed : %s\n", extra);
668 __xmlRaiseError(NULL, NULL, NULL,
669 NULL, NULL, XML_FROM_XPATH,
670 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
671 NULL, NULL, NULL, 0, 0,
672 "Memory allocation failed\n");
677 * xmlXPathPErrMemory:
678 * @ctxt: an XPath parser context
679 * @extra: extra informations
681 * Handle a redefinition of attribute error
684 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
687 xmlXPathErrMemory(NULL, extra);
689 ctxt->error = XPATH_MEMORY_ERROR;
690 xmlXPathErrMemory(ctxt->context, extra);
696 * @ctxt: a XPath parser context
697 * @error: the error code
699 * Handle an XPath error
702 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
704 if ((error < 0) || (error > MAXERRNO))
707 __xmlRaiseError(NULL, NULL, NULL,
708 NULL, NULL, XML_FROM_XPATH,
709 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
710 XML_ERR_ERROR, NULL, 0,
711 NULL, NULL, NULL, 0, 0,
712 "%s", xmlXPathErrorMessages[error]);
716 if (ctxt->context == NULL) {
717 __xmlRaiseError(NULL, NULL, NULL,
718 NULL, NULL, XML_FROM_XPATH,
719 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
720 XML_ERR_ERROR, NULL, 0,
721 (const char *) ctxt->base, NULL, NULL,
722 ctxt->cur - ctxt->base, 0,
723 "%s", xmlXPathErrorMessages[error]);
727 /* cleanup current last error */
728 xmlResetError(&ctxt->context->lastError);
730 ctxt->context->lastError.domain = XML_FROM_XPATH;
731 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
733 ctxt->context->lastError.level = XML_ERR_ERROR;
734 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
735 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
736 ctxt->context->lastError.node = ctxt->context->debugNode;
737 if (ctxt->context->error != NULL) {
738 ctxt->context->error(ctxt->context->userData,
739 &ctxt->context->lastError);
741 __xmlRaiseError(NULL, NULL, NULL,
742 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
743 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
744 XML_ERR_ERROR, NULL, 0,
745 (const char *) ctxt->base, NULL, NULL,
746 ctxt->cur - ctxt->base, 0,
747 "%s", xmlXPathErrorMessages[error]);
754 * @ctxt: the XPath Parser context
755 * @file: the file name
756 * @line: the line number
757 * @no: the error number
759 * Formats an error message.
762 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
763 int line ATTRIBUTE_UNUSED, int no) {
764 xmlXPathErr(ctxt, no);
767 /************************************************************************
771 ************************************************************************/
776 * Pointer-list for various purposes.
778 typedef struct _xmlPointerList xmlPointerList;
779 typedef xmlPointerList *xmlPointerListPtr;
780 struct _xmlPointerList {
786 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
787 * and here, we should make the functions public.
790 xmlPointerListAddSize(xmlPointerListPtr list,
794 if (list->items == NULL) {
795 if (initialSize <= 0)
797 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
798 if (list->items == NULL) {
799 xmlXPathErrMemory(NULL,
800 "xmlPointerListCreate: allocating item\n");
804 list->size = initialSize;
805 } else if (list->size <= list->number) {
806 if (list->size > 50000000) {
807 xmlXPathErrMemory(NULL,
808 "xmlPointerListAddSize: re-allocating item\n");
812 list->items = (void **) xmlRealloc(list->items,
813 list->size * sizeof(void *));
814 if (list->items == NULL) {
815 xmlXPathErrMemory(NULL,
816 "xmlPointerListAddSize: re-allocating item\n");
821 list->items[list->number++] = item;
826 * xsltPointerListCreate:
828 * Creates an xsltPointerList structure.
830 * Returns a xsltPointerList structure or NULL in case of an error.
832 static xmlPointerListPtr
833 xmlPointerListCreate(int initialSize)
835 xmlPointerListPtr ret;
837 ret = xmlMalloc(sizeof(xmlPointerList));
839 xmlXPathErrMemory(NULL,
840 "xmlPointerListCreate: allocating item\n");
843 memset(ret, 0, sizeof(xmlPointerList));
844 if (initialSize > 0) {
845 xmlPointerListAddSize(ret, NULL, initialSize);
852 * xsltPointerListFree:
854 * Frees the xsltPointerList structure. This does not free
855 * the content of the list.
858 xmlPointerListFree(xmlPointerListPtr list)
862 if (list->items != NULL)
863 xmlFree(list->items);
867 /************************************************************************
871 ************************************************************************/
888 XPATH_OP_RESET, /* 10 */
890 XPATH_OP_VALUE, /* 12 */
895 XPATH_OP_FILTER, /* 17 */
896 XPATH_OP_SORT /* 18 */
897 #ifdef LIBXML_XPTR_ENABLED
904 AXIS_ANCESTOR_OR_SELF,
908 AXIS_DESCENDANT_OR_SELF,
910 AXIS_FOLLOWING_SIBLING,
914 AXIS_PRECEDING_SIBLING,
929 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
930 NODE_TYPE_TEXT = XML_TEXT_NODE,
931 NODE_TYPE_PI = XML_PI_NODE
934 typedef struct _xmlXPathStepOp xmlXPathStepOp;
935 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
936 struct _xmlXPathStepOp {
937 xmlXPathOp op; /* The identifier of the operation */
938 int ch1; /* First child */
939 int ch2; /* Second child */
945 xmlXPathFunction cache;
949 struct _xmlXPathCompExpr {
950 int nbStep; /* Number of steps in this expression */
951 int maxStep; /* Maximum number of steps allocated */
952 xmlXPathStepOp *steps; /* ops for computation of this expression */
953 int last; /* index of last step in expression */
954 xmlChar *expr; /* the expression being computed */
955 xmlDictPtr dict; /* the dictionary to use if any */
956 #ifdef DEBUG_EVAL_COUNTS
960 #ifdef XPATH_STREAMING
961 xmlPatternPtr stream;
965 /************************************************************************
967 * Forward declarations *
969 ************************************************************************/
971 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
973 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
975 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
976 xmlXPathStepOpPtr op, xmlNodePtr *first);
978 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
979 xmlXPathStepOpPtr op,
982 /************************************************************************
984 * Parser Type functions *
986 ************************************************************************/
989 * xmlXPathNewCompExpr:
991 * Create a new Xpath component
993 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
995 static xmlXPathCompExprPtr
996 xmlXPathNewCompExpr(void) {
997 xmlXPathCompExprPtr cur;
999 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1001 xmlXPathErrMemory(NULL, "allocating component\n");
1004 memset(cur, 0, sizeof(xmlXPathCompExpr));
1007 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1008 sizeof(xmlXPathStepOp));
1009 if (cur->steps == NULL) {
1010 xmlXPathErrMemory(NULL, "allocating steps\n");
1014 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1016 #ifdef DEBUG_EVAL_COUNTS
1023 * xmlXPathFreeCompExpr:
1024 * @comp: an XPATH comp
1026 * Free up the memory allocated by @comp
1029 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1031 xmlXPathStepOpPtr op;
1036 if (comp->dict == NULL) {
1037 for (i = 0; i < comp->nbStep; i++) {
1038 op = &comp->steps[i];
1039 if (op->value4 != NULL) {
1040 if (op->op == XPATH_OP_VALUE)
1041 xmlXPathFreeObject(op->value4);
1043 xmlFree(op->value4);
1045 if (op->value5 != NULL)
1046 xmlFree(op->value5);
1049 for (i = 0; i < comp->nbStep; i++) {
1050 op = &comp->steps[i];
1051 if (op->value4 != NULL) {
1052 if (op->op == XPATH_OP_VALUE)
1053 xmlXPathFreeObject(op->value4);
1056 xmlDictFree(comp->dict);
1058 if (comp->steps != NULL) {
1059 xmlFree(comp->steps);
1061 #ifdef DEBUG_EVAL_COUNTS
1062 if (comp->string != NULL) {
1063 xmlFree(comp->string);
1066 #ifdef XPATH_STREAMING
1067 if (comp->stream != NULL) {
1068 xmlFreePatternList(comp->stream);
1071 if (comp->expr != NULL) {
1072 xmlFree(comp->expr);
1079 * xmlXPathCompExprAdd:
1080 * @comp: the compiled expression
1081 * @ch1: first child index
1082 * @ch2: second child index
1084 * @value: the first int value
1085 * @value2: the second int value
1086 * @value3: the third int value
1087 * @value4: the first string value
1088 * @value5: the second string value
1090 * Add a step to an XPath Compiled Expression
1092 * Returns -1 in case of failure, the index otherwise
1095 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1096 xmlXPathOp op, int value,
1097 int value2, int value3, void *value4, void *value5) {
1098 if (comp->nbStep >= comp->maxStep) {
1099 xmlXPathStepOp *real;
1101 if (comp->maxStep >= XPATH_MAX_STEPS) {
1102 xmlXPathErrMemory(NULL, "adding step\n");
1106 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1107 comp->maxStep * sizeof(xmlXPathStepOp));
1110 xmlXPathErrMemory(NULL, "adding step\n");
1115 comp->last = comp->nbStep;
1116 comp->steps[comp->nbStep].ch1 = ch1;
1117 comp->steps[comp->nbStep].ch2 = ch2;
1118 comp->steps[comp->nbStep].op = op;
1119 comp->steps[comp->nbStep].value = value;
1120 comp->steps[comp->nbStep].value2 = value2;
1121 comp->steps[comp->nbStep].value3 = value3;
1122 if ((comp->dict != NULL) &&
1123 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1124 (op == XPATH_OP_COLLECT))) {
1125 if (value4 != NULL) {
1126 comp->steps[comp->nbStep].value4 = (xmlChar *)
1127 (void *)xmlDictLookup(comp->dict, value4, -1);
1130 comp->steps[comp->nbStep].value4 = NULL;
1131 if (value5 != NULL) {
1132 comp->steps[comp->nbStep].value5 = (xmlChar *)
1133 (void *)xmlDictLookup(comp->dict, value5, -1);
1136 comp->steps[comp->nbStep].value5 = NULL;
1138 comp->steps[comp->nbStep].value4 = value4;
1139 comp->steps[comp->nbStep].value5 = value5;
1141 comp->steps[comp->nbStep].cache = NULL;
1142 return(comp->nbStep++);
1147 * @comp: the compiled expression
1148 * @op: operation index
1150 * Swaps 2 operations in the compiled expression
1153 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1156 #ifndef LIBXML_THREAD_ENABLED
1158 * Since this manipulates possibly shared variables, this is
1159 * disabled if one detects that the library is used in a multithreaded
1162 if (xmlXPathDisableOptimizer)
1171 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1172 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1173 (op), (val), (val2), (val3), (val4), (val5))
1174 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1175 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1176 (op), (val), (val2), (val3), (val4), (val5))
1178 #define PUSH_LEAVE_EXPR(op, val, val2) \
1179 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1181 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1182 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1184 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1185 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1186 (val), (val2), 0 ,NULL ,NULL)
1188 /************************************************************************
1190 * XPath object cache structures *
1192 ************************************************************************/
1194 /* #define XP_DEFAULT_CACHE_ON */
1196 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1198 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1199 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1200 struct _xmlXPathContextCache {
1201 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1202 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1203 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1204 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1205 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1211 #ifdef XP_DEBUG_OBJ_USAGE
1213 int dbgCachedNodeset;
1214 int dbgCachedString;
1216 int dbgCachedNumber;
1219 int dbgCachedLocset;
1221 int dbgCachedXSLTTree;
1222 int dbgCachedUndefined;
1226 int dbgReusedNodeset;
1227 int dbgReusedString;
1229 int dbgReusedNumber;
1232 int dbgReusedLocset;
1234 int dbgReusedXSLTTree;
1235 int dbgReusedUndefined;
1240 /************************************************************************
1242 * Debugging related functions *
1244 ************************************************************************/
1247 xmlGenericError(xmlGenericErrorContext, \
1248 "Internal error at %s:%d\n", \
1249 __FILE__, __LINE__);
1251 #ifdef LIBXML_DEBUG_ENABLED
1253 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1257 for (i = 0;((i < depth) && (i < 25));i++)
1258 shift[2 * i] = shift[2 * i + 1] = ' ';
1259 shift[2 * i] = shift[2 * i + 1] = 0;
1261 fprintf(output, "%s", shift);
1262 fprintf(output, "Node is NULL !\n");
1267 if ((cur->type == XML_DOCUMENT_NODE) ||
1268 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1269 fprintf(output, "%s", shift);
1270 fprintf(output, " /\n");
1271 } else if (cur->type == XML_ATTRIBUTE_NODE)
1272 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1274 xmlDebugDumpOneNode(output, cur, depth);
1277 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1282 for (i = 0;((i < depth) && (i < 25));i++)
1283 shift[2 * i] = shift[2 * i + 1] = ' ';
1284 shift[2 * i] = shift[2 * i + 1] = 0;
1286 fprintf(output, "%s", shift);
1287 fprintf(output, "Node is NULL !\n");
1292 while (cur != NULL) {
1295 xmlDebugDumpOneNode(output, tmp, depth);
1300 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1304 for (i = 0;((i < depth) && (i < 25));i++)
1305 shift[2 * i] = shift[2 * i + 1] = ' ';
1306 shift[2 * i] = shift[2 * i + 1] = 0;
1309 fprintf(output, "%s", shift);
1310 fprintf(output, "NodeSet is NULL !\n");
1316 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1317 for (i = 0;i < cur->nodeNr;i++) {
1318 fprintf(output, "%s", shift);
1319 fprintf(output, "%d", i + 1);
1320 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1326 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1330 for (i = 0;((i < depth) && (i < 25));i++)
1331 shift[2 * i] = shift[2 * i + 1] = ' ';
1332 shift[2 * i] = shift[2 * i + 1] = 0;
1334 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1335 fprintf(output, "%s", shift);
1336 fprintf(output, "Value Tree is NULL !\n");
1341 fprintf(output, "%s", shift);
1342 fprintf(output, "%d", i + 1);
1343 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1345 #if defined(LIBXML_XPTR_ENABLED)
1347 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1351 for (i = 0;((i < depth) && (i < 25));i++)
1352 shift[2 * i] = shift[2 * i + 1] = ' ';
1353 shift[2 * i] = shift[2 * i + 1] = 0;
1356 fprintf(output, "%s", shift);
1357 fprintf(output, "LocationSet is NULL !\n");
1362 for (i = 0;i < cur->locNr;i++) {
1363 fprintf(output, "%s", shift);
1364 fprintf(output, "%d : ", i + 1);
1365 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1368 #endif /* LIBXML_XPTR_ENABLED */
1371 * xmlXPathDebugDumpObject:
1372 * @output: the FILE * to dump the output
1373 * @cur: the object to inspect
1374 * @depth: indentation level
1376 * Dump the content of the object for debugging purposes
1379 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1383 if (output == NULL) return;
1385 for (i = 0;((i < depth) && (i < 25));i++)
1386 shift[2 * i] = shift[2 * i + 1] = ' ';
1387 shift[2 * i] = shift[2 * i + 1] = 0;
1390 fprintf(output, "%s", shift);
1393 fprintf(output, "Object is empty (NULL)\n");
1397 case XPATH_UNDEFINED:
1398 fprintf(output, "Object is uninitialized\n");
1401 fprintf(output, "Object is a Node Set :\n");
1402 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1404 case XPATH_XSLT_TREE:
1405 fprintf(output, "Object is an XSLT value tree :\n");
1406 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1409 fprintf(output, "Object is a Boolean : ");
1410 if (cur->boolval) fprintf(output, "true\n");
1411 else fprintf(output, "false\n");
1414 switch (xmlXPathIsInf(cur->floatval)) {
1416 fprintf(output, "Object is a number : Infinity\n");
1419 fprintf(output, "Object is a number : -Infinity\n");
1422 if (xmlXPathIsNaN(cur->floatval)) {
1423 fprintf(output, "Object is a number : NaN\n");
1424 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1425 fprintf(output, "Object is a number : 0\n");
1427 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1432 fprintf(output, "Object is a string : ");
1433 xmlDebugDumpString(output, cur->stringval);
1434 fprintf(output, "\n");
1437 fprintf(output, "Object is a point : index %d in node", cur->index);
1438 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1439 fprintf(output, "\n");
1442 if ((cur->user2 == NULL) ||
1443 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1444 fprintf(output, "Object is a collapsed range :\n");
1445 fprintf(output, "%s", shift);
1446 if (cur->index >= 0)
1447 fprintf(output, "index %d in ", cur->index);
1448 fprintf(output, "node\n");
1449 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1452 fprintf(output, "Object is a range :\n");
1453 fprintf(output, "%s", shift);
1454 fprintf(output, "From ");
1455 if (cur->index >= 0)
1456 fprintf(output, "index %d in ", cur->index);
1457 fprintf(output, "node\n");
1458 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1460 fprintf(output, "%s", shift);
1461 fprintf(output, "To ");
1462 if (cur->index2 >= 0)
1463 fprintf(output, "index %d in ", cur->index2);
1464 fprintf(output, "node\n");
1465 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1467 fprintf(output, "\n");
1470 case XPATH_LOCATIONSET:
1471 #if defined(LIBXML_XPTR_ENABLED)
1472 fprintf(output, "Object is a Location Set:\n");
1473 xmlXPathDebugDumpLocationSet(output,
1474 (xmlLocationSetPtr) cur->user, depth);
1478 fprintf(output, "Object is user defined\n");
1484 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1485 xmlXPathStepOpPtr op, int depth) {
1489 for (i = 0;((i < depth) && (i < 25));i++)
1490 shift[2 * i] = shift[2 * i + 1] = ' ';
1491 shift[2 * i] = shift[2 * i + 1] = 0;
1493 fprintf(output, "%s", shift);
1495 fprintf(output, "Step is NULL\n");
1500 fprintf(output, "END"); break;
1502 fprintf(output, "AND"); break;
1504 fprintf(output, "OR"); break;
1505 case XPATH_OP_EQUAL:
1507 fprintf(output, "EQUAL =");
1509 fprintf(output, "EQUAL !=");
1513 fprintf(output, "CMP <");
1515 fprintf(output, "CMP >");
1517 fprintf(output, "=");
1521 fprintf(output, "PLUS -");
1522 else if (op->value == 1)
1523 fprintf(output, "PLUS +");
1524 else if (op->value == 2)
1525 fprintf(output, "PLUS unary -");
1526 else if (op->value == 3)
1527 fprintf(output, "PLUS unary - -");
1531 fprintf(output, "MULT *");
1532 else if (op->value == 1)
1533 fprintf(output, "MULT div");
1535 fprintf(output, "MULT mod");
1537 case XPATH_OP_UNION:
1538 fprintf(output, "UNION"); break;
1540 fprintf(output, "ROOT"); break;
1542 fprintf(output, "NODE"); break;
1543 case XPATH_OP_RESET:
1544 fprintf(output, "RESET"); break;
1546 fprintf(output, "SORT"); break;
1547 case XPATH_OP_COLLECT: {
1548 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1549 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1550 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1551 const xmlChar *prefix = op->value4;
1552 const xmlChar *name = op->value5;
1554 fprintf(output, "COLLECT ");
1557 fprintf(output, " 'ancestors' "); break;
1558 case AXIS_ANCESTOR_OR_SELF:
1559 fprintf(output, " 'ancestors-or-self' "); break;
1560 case AXIS_ATTRIBUTE:
1561 fprintf(output, " 'attributes' "); break;
1563 fprintf(output, " 'child' "); break;
1564 case AXIS_DESCENDANT:
1565 fprintf(output, " 'descendant' "); break;
1566 case AXIS_DESCENDANT_OR_SELF:
1567 fprintf(output, " 'descendant-or-self' "); break;
1568 case AXIS_FOLLOWING:
1569 fprintf(output, " 'following' "); break;
1570 case AXIS_FOLLOWING_SIBLING:
1571 fprintf(output, " 'following-siblings' "); break;
1572 case AXIS_NAMESPACE:
1573 fprintf(output, " 'namespace' "); break;
1575 fprintf(output, " 'parent' "); break;
1576 case AXIS_PRECEDING:
1577 fprintf(output, " 'preceding' "); break;
1578 case AXIS_PRECEDING_SIBLING:
1579 fprintf(output, " 'preceding-sibling' "); break;
1581 fprintf(output, " 'self' "); break;
1584 case NODE_TEST_NONE:
1585 fprintf(output, "'none' "); break;
1586 case NODE_TEST_TYPE:
1587 fprintf(output, "'type' "); break;
1589 fprintf(output, "'PI' "); break;
1591 fprintf(output, "'all' "); break;
1593 fprintf(output, "'namespace' "); break;
1594 case NODE_TEST_NAME:
1595 fprintf(output, "'name' "); break;
1598 case NODE_TYPE_NODE:
1599 fprintf(output, "'node' "); break;
1600 case NODE_TYPE_COMMENT:
1601 fprintf(output, "'comment' "); break;
1602 case NODE_TYPE_TEXT:
1603 fprintf(output, "'text' "); break;
1605 fprintf(output, "'PI' "); break;
1608 fprintf(output, "%s:", prefix);
1610 fprintf(output, "%s", (const char *) name);
1614 case XPATH_OP_VALUE: {
1615 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1617 fprintf(output, "ELEM ");
1618 xmlXPathDebugDumpObject(output, object, 0);
1621 case XPATH_OP_VARIABLE: {
1622 const xmlChar *prefix = op->value5;
1623 const xmlChar *name = op->value4;
1626 fprintf(output, "VARIABLE %s:%s", prefix, name);
1628 fprintf(output, "VARIABLE %s", name);
1631 case XPATH_OP_FUNCTION: {
1632 int nbargs = op->value;
1633 const xmlChar *prefix = op->value5;
1634 const xmlChar *name = op->value4;
1637 fprintf(output, "FUNCTION %s:%s(%d args)",
1638 prefix, name, nbargs);
1640 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1643 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1644 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1645 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1646 #ifdef LIBXML_XPTR_ENABLED
1647 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1650 fprintf(output, "UNKNOWN %d\n", op->op); return;
1652 fprintf(output, "\n");
1655 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1657 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1661 * xmlXPathDebugDumpCompExpr:
1662 * @output: the FILE * for the output
1663 * @comp: the precompiled XPath expression
1664 * @depth: the indentation level.
1666 * Dumps the tree of the compiled XPath expression.
1669 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1674 if ((output == NULL) || (comp == NULL)) return;
1676 for (i = 0;((i < depth) && (i < 25));i++)
1677 shift[2 * i] = shift[2 * i + 1] = ' ';
1678 shift[2 * i] = shift[2 * i + 1] = 0;
1680 fprintf(output, "%s", shift);
1682 #ifdef XPATH_STREAMING
1684 fprintf(output, "Streaming Expression\n");
1688 fprintf(output, "Compiled Expression : %d elements\n",
1691 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1695 #ifdef XP_DEBUG_OBJ_USAGE
1698 * XPath object usage related debugging variables.
1700 static int xmlXPathDebugObjCounterUndefined = 0;
1701 static int xmlXPathDebugObjCounterNodeset = 0;
1702 static int xmlXPathDebugObjCounterBool = 0;
1703 static int xmlXPathDebugObjCounterNumber = 0;
1704 static int xmlXPathDebugObjCounterString = 0;
1705 static int xmlXPathDebugObjCounterPoint = 0;
1706 static int xmlXPathDebugObjCounterRange = 0;
1707 static int xmlXPathDebugObjCounterLocset = 0;
1708 static int xmlXPathDebugObjCounterUsers = 0;
1709 static int xmlXPathDebugObjCounterXSLTTree = 0;
1710 static int xmlXPathDebugObjCounterAll = 0;
1712 static int xmlXPathDebugObjTotalUndefined = 0;
1713 static int xmlXPathDebugObjTotalNodeset = 0;
1714 static int xmlXPathDebugObjTotalBool = 0;
1715 static int xmlXPathDebugObjTotalNumber = 0;
1716 static int xmlXPathDebugObjTotalString = 0;
1717 static int xmlXPathDebugObjTotalPoint = 0;
1718 static int xmlXPathDebugObjTotalRange = 0;
1719 static int xmlXPathDebugObjTotalLocset = 0;
1720 static int xmlXPathDebugObjTotalUsers = 0;
1721 static int xmlXPathDebugObjTotalXSLTTree = 0;
1722 static int xmlXPathDebugObjTotalAll = 0;
1724 static int xmlXPathDebugObjMaxUndefined = 0;
1725 static int xmlXPathDebugObjMaxNodeset = 0;
1726 static int xmlXPathDebugObjMaxBool = 0;
1727 static int xmlXPathDebugObjMaxNumber = 0;
1728 static int xmlXPathDebugObjMaxString = 0;
1729 static int xmlXPathDebugObjMaxPoint = 0;
1730 static int xmlXPathDebugObjMaxRange = 0;
1731 static int xmlXPathDebugObjMaxLocset = 0;
1732 static int xmlXPathDebugObjMaxUsers = 0;
1733 static int xmlXPathDebugObjMaxXSLTTree = 0;
1734 static int xmlXPathDebugObjMaxAll = 0;
1736 /* REVISIT TODO: Make this static when committing */
1738 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1741 if (ctxt->cache != NULL) {
1742 xmlXPathContextCachePtr cache =
1743 (xmlXPathContextCachePtr) ctxt->cache;
1745 cache->dbgCachedAll = 0;
1746 cache->dbgCachedNodeset = 0;
1747 cache->dbgCachedString = 0;
1748 cache->dbgCachedBool = 0;
1749 cache->dbgCachedNumber = 0;
1750 cache->dbgCachedPoint = 0;
1751 cache->dbgCachedRange = 0;
1752 cache->dbgCachedLocset = 0;
1753 cache->dbgCachedUsers = 0;
1754 cache->dbgCachedXSLTTree = 0;
1755 cache->dbgCachedUndefined = 0;
1757 cache->dbgReusedAll = 0;
1758 cache->dbgReusedNodeset = 0;
1759 cache->dbgReusedString = 0;
1760 cache->dbgReusedBool = 0;
1761 cache->dbgReusedNumber = 0;
1762 cache->dbgReusedPoint = 0;
1763 cache->dbgReusedRange = 0;
1764 cache->dbgReusedLocset = 0;
1765 cache->dbgReusedUsers = 0;
1766 cache->dbgReusedXSLTTree = 0;
1767 cache->dbgReusedUndefined = 0;
1771 xmlXPathDebugObjCounterUndefined = 0;
1772 xmlXPathDebugObjCounterNodeset = 0;
1773 xmlXPathDebugObjCounterBool = 0;
1774 xmlXPathDebugObjCounterNumber = 0;
1775 xmlXPathDebugObjCounterString = 0;
1776 xmlXPathDebugObjCounterPoint = 0;
1777 xmlXPathDebugObjCounterRange = 0;
1778 xmlXPathDebugObjCounterLocset = 0;
1779 xmlXPathDebugObjCounterUsers = 0;
1780 xmlXPathDebugObjCounterXSLTTree = 0;
1781 xmlXPathDebugObjCounterAll = 0;
1783 xmlXPathDebugObjTotalUndefined = 0;
1784 xmlXPathDebugObjTotalNodeset = 0;
1785 xmlXPathDebugObjTotalBool = 0;
1786 xmlXPathDebugObjTotalNumber = 0;
1787 xmlXPathDebugObjTotalString = 0;
1788 xmlXPathDebugObjTotalPoint = 0;
1789 xmlXPathDebugObjTotalRange = 0;
1790 xmlXPathDebugObjTotalLocset = 0;
1791 xmlXPathDebugObjTotalUsers = 0;
1792 xmlXPathDebugObjTotalXSLTTree = 0;
1793 xmlXPathDebugObjTotalAll = 0;
1795 xmlXPathDebugObjMaxUndefined = 0;
1796 xmlXPathDebugObjMaxNodeset = 0;
1797 xmlXPathDebugObjMaxBool = 0;
1798 xmlXPathDebugObjMaxNumber = 0;
1799 xmlXPathDebugObjMaxString = 0;
1800 xmlXPathDebugObjMaxPoint = 0;
1801 xmlXPathDebugObjMaxRange = 0;
1802 xmlXPathDebugObjMaxLocset = 0;
1803 xmlXPathDebugObjMaxUsers = 0;
1804 xmlXPathDebugObjMaxXSLTTree = 0;
1805 xmlXPathDebugObjMaxAll = 0;
1810 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1811 xmlXPathObjectType objType)
1816 if (ctxt->cache != NULL) {
1817 xmlXPathContextCachePtr cache =
1818 (xmlXPathContextCachePtr) ctxt->cache;
1822 cache->dbgReusedAll++;
1824 case XPATH_UNDEFINED:
1825 cache->dbgReusedUndefined++;
1828 cache->dbgReusedNodeset++;
1831 cache->dbgReusedBool++;
1834 cache->dbgReusedNumber++;
1837 cache->dbgReusedString++;
1840 cache->dbgReusedPoint++;
1843 cache->dbgReusedRange++;
1845 case XPATH_LOCATIONSET:
1846 cache->dbgReusedLocset++;
1849 cache->dbgReusedUsers++;
1851 case XPATH_XSLT_TREE:
1852 cache->dbgReusedXSLTTree++;
1861 case XPATH_UNDEFINED:
1863 xmlXPathDebugObjTotalUndefined++;
1864 xmlXPathDebugObjCounterUndefined++;
1865 if (xmlXPathDebugObjCounterUndefined >
1866 xmlXPathDebugObjMaxUndefined)
1867 xmlXPathDebugObjMaxUndefined =
1868 xmlXPathDebugObjCounterUndefined;
1872 xmlXPathDebugObjTotalNodeset++;
1873 xmlXPathDebugObjCounterNodeset++;
1874 if (xmlXPathDebugObjCounterNodeset >
1875 xmlXPathDebugObjMaxNodeset)
1876 xmlXPathDebugObjMaxNodeset =
1877 xmlXPathDebugObjCounterNodeset;
1881 xmlXPathDebugObjTotalBool++;
1882 xmlXPathDebugObjCounterBool++;
1883 if (xmlXPathDebugObjCounterBool >
1884 xmlXPathDebugObjMaxBool)
1885 xmlXPathDebugObjMaxBool =
1886 xmlXPathDebugObjCounterBool;
1890 xmlXPathDebugObjTotalNumber++;
1891 xmlXPathDebugObjCounterNumber++;
1892 if (xmlXPathDebugObjCounterNumber >
1893 xmlXPathDebugObjMaxNumber)
1894 xmlXPathDebugObjMaxNumber =
1895 xmlXPathDebugObjCounterNumber;
1899 xmlXPathDebugObjTotalString++;
1900 xmlXPathDebugObjCounterString++;
1901 if (xmlXPathDebugObjCounterString >
1902 xmlXPathDebugObjMaxString)
1903 xmlXPathDebugObjMaxString =
1904 xmlXPathDebugObjCounterString;
1908 xmlXPathDebugObjTotalPoint++;
1909 xmlXPathDebugObjCounterPoint++;
1910 if (xmlXPathDebugObjCounterPoint >
1911 xmlXPathDebugObjMaxPoint)
1912 xmlXPathDebugObjMaxPoint =
1913 xmlXPathDebugObjCounterPoint;
1917 xmlXPathDebugObjTotalRange++;
1918 xmlXPathDebugObjCounterRange++;
1919 if (xmlXPathDebugObjCounterRange >
1920 xmlXPathDebugObjMaxRange)
1921 xmlXPathDebugObjMaxRange =
1922 xmlXPathDebugObjCounterRange;
1924 case XPATH_LOCATIONSET:
1926 xmlXPathDebugObjTotalLocset++;
1927 xmlXPathDebugObjCounterLocset++;
1928 if (xmlXPathDebugObjCounterLocset >
1929 xmlXPathDebugObjMaxLocset)
1930 xmlXPathDebugObjMaxLocset =
1931 xmlXPathDebugObjCounterLocset;
1935 xmlXPathDebugObjTotalUsers++;
1936 xmlXPathDebugObjCounterUsers++;
1937 if (xmlXPathDebugObjCounterUsers >
1938 xmlXPathDebugObjMaxUsers)
1939 xmlXPathDebugObjMaxUsers =
1940 xmlXPathDebugObjCounterUsers;
1942 case XPATH_XSLT_TREE:
1944 xmlXPathDebugObjTotalXSLTTree++;
1945 xmlXPathDebugObjCounterXSLTTree++;
1946 if (xmlXPathDebugObjCounterXSLTTree >
1947 xmlXPathDebugObjMaxXSLTTree)
1948 xmlXPathDebugObjMaxXSLTTree =
1949 xmlXPathDebugObjCounterXSLTTree;
1955 xmlXPathDebugObjTotalAll++;
1956 xmlXPathDebugObjCounterAll++;
1957 if (xmlXPathDebugObjCounterAll >
1958 xmlXPathDebugObjMaxAll)
1959 xmlXPathDebugObjMaxAll =
1960 xmlXPathDebugObjCounterAll;
1964 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1965 xmlXPathObjectType objType)
1970 if (ctxt->cache != NULL) {
1971 xmlXPathContextCachePtr cache =
1972 (xmlXPathContextCachePtr) ctxt->cache;
1976 cache->dbgCachedAll++;
1978 case XPATH_UNDEFINED:
1979 cache->dbgCachedUndefined++;
1982 cache->dbgCachedNodeset++;
1985 cache->dbgCachedBool++;
1988 cache->dbgCachedNumber++;
1991 cache->dbgCachedString++;
1994 cache->dbgCachedPoint++;
1997 cache->dbgCachedRange++;
1999 case XPATH_LOCATIONSET:
2000 cache->dbgCachedLocset++;
2003 cache->dbgCachedUsers++;
2005 case XPATH_XSLT_TREE:
2006 cache->dbgCachedXSLTTree++;
2015 case XPATH_UNDEFINED:
2016 xmlXPathDebugObjCounterUndefined--;
2019 xmlXPathDebugObjCounterNodeset--;
2022 xmlXPathDebugObjCounterBool--;
2025 xmlXPathDebugObjCounterNumber--;
2028 xmlXPathDebugObjCounterString--;
2031 xmlXPathDebugObjCounterPoint--;
2034 xmlXPathDebugObjCounterRange--;
2036 case XPATH_LOCATIONSET:
2037 xmlXPathDebugObjCounterLocset--;
2040 xmlXPathDebugObjCounterUsers--;
2042 case XPATH_XSLT_TREE:
2043 xmlXPathDebugObjCounterXSLTTree--;
2048 xmlXPathDebugObjCounterAll--;
2051 /* REVISIT TODO: Make this static when committing */
2053 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2055 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2056 reqXSLTTree, reqUndefined;
2057 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2058 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2059 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2060 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2061 int leftObjs = xmlXPathDebugObjCounterAll;
2063 reqAll = xmlXPathDebugObjTotalAll;
2064 reqNodeset = xmlXPathDebugObjTotalNodeset;
2065 reqString = xmlXPathDebugObjTotalString;
2066 reqBool = xmlXPathDebugObjTotalBool;
2067 reqNumber = xmlXPathDebugObjTotalNumber;
2068 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2069 reqUndefined = xmlXPathDebugObjTotalUndefined;
2071 printf("# XPath object usage:\n");
2074 if (ctxt->cache != NULL) {
2075 xmlXPathContextCachePtr cache =
2076 (xmlXPathContextCachePtr) ctxt->cache;
2078 reAll = cache->dbgReusedAll;
2080 reNodeset = cache->dbgReusedNodeset;
2081 reqNodeset += reNodeset;
2082 reString = cache->dbgReusedString;
2083 reqString += reString;
2084 reBool = cache->dbgReusedBool;
2086 reNumber = cache->dbgReusedNumber;
2087 reqNumber += reNumber;
2088 reXSLTTree = cache->dbgReusedXSLTTree;
2089 reqXSLTTree += reXSLTTree;
2090 reUndefined = cache->dbgReusedUndefined;
2091 reqUndefined += reUndefined;
2093 caAll = cache->dbgCachedAll;
2094 caBool = cache->dbgCachedBool;
2095 caNodeset = cache->dbgCachedNodeset;
2096 caString = cache->dbgCachedString;
2097 caNumber = cache->dbgCachedNumber;
2098 caXSLTTree = cache->dbgCachedXSLTTree;
2099 caUndefined = cache->dbgCachedUndefined;
2101 if (cache->nodesetObjs)
2102 leftObjs -= cache->nodesetObjs->number;
2103 if (cache->stringObjs)
2104 leftObjs -= cache->stringObjs->number;
2105 if (cache->booleanObjs)
2106 leftObjs -= cache->booleanObjs->number;
2107 if (cache->numberObjs)
2108 leftObjs -= cache->numberObjs->number;
2109 if (cache->miscObjs)
2110 leftObjs -= cache->miscObjs->number;
2115 printf("# total : %d\n", reqAll);
2116 printf("# left : %d\n", leftObjs);
2117 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2118 printf("# reused : %d\n", reAll);
2119 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2121 printf("# node-sets\n");
2122 printf("# total : %d\n", reqNodeset);
2123 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2124 printf("# reused : %d\n", reNodeset);
2125 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2127 printf("# strings\n");
2128 printf("# total : %d\n", reqString);
2129 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2130 printf("# reused : %d\n", reString);
2131 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2133 printf("# booleans\n");
2134 printf("# total : %d\n", reqBool);
2135 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2136 printf("# reused : %d\n", reBool);
2137 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2139 printf("# numbers\n");
2140 printf("# total : %d\n", reqNumber);
2141 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2142 printf("# reused : %d\n", reNumber);
2143 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2145 printf("# XSLT result tree fragments\n");
2146 printf("# total : %d\n", reqXSLTTree);
2147 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2148 printf("# reused : %d\n", reXSLTTree);
2149 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2151 printf("# undefined\n");
2152 printf("# total : %d\n", reqUndefined);
2153 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2154 printf("# reused : %d\n", reUndefined);
2155 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2159 #endif /* XP_DEBUG_OBJ_USAGE */
2161 #endif /* LIBXML_DEBUG_ENABLED */
2163 /************************************************************************
2165 * XPath object caching *
2167 ************************************************************************/
2172 * Create a new object cache
2174 * Returns the xmlXPathCache just allocated.
2176 static xmlXPathContextCachePtr
2177 xmlXPathNewCache(void)
2179 xmlXPathContextCachePtr ret;
2181 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2183 xmlXPathErrMemory(NULL, "creating object cache\n");
2186 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2187 ret->maxNodeset = 100;
2188 ret->maxString = 100;
2189 ret->maxBoolean = 100;
2190 ret->maxNumber = 100;
2196 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2199 xmlXPathObjectPtr obj;
2204 for (i = 0; i < list->number; i++) {
2205 obj = list->items[i];
2207 * Note that it is already assured that we don't need to
2208 * look out for namespace nodes in the node-set.
2210 if (obj->nodesetval != NULL) {
2211 if (obj->nodesetval->nodeTab != NULL)
2212 xmlFree(obj->nodesetval->nodeTab);
2213 xmlFree(obj->nodesetval);
2216 #ifdef XP_DEBUG_OBJ_USAGE
2217 xmlXPathDebugObjCounterAll--;
2220 xmlPointerListFree(list);
2224 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2228 if (cache->nodesetObjs)
2229 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2230 if (cache->stringObjs)
2231 xmlXPathCacheFreeObjectList(cache->stringObjs);
2232 if (cache->booleanObjs)
2233 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2234 if (cache->numberObjs)
2235 xmlXPathCacheFreeObjectList(cache->numberObjs);
2236 if (cache->miscObjs)
2237 xmlXPathCacheFreeObjectList(cache->miscObjs);
2242 * xmlXPathContextSetCache:
2244 * @ctxt: the XPath context
2245 * @active: enables/disables (creates/frees) the cache
2246 * @value: a value with semantics dependant on @options
2247 * @options: options (currently only the value 0 is used)
2249 * Creates/frees an object cache on the XPath context.
2250 * If activates XPath objects (xmlXPathObject) will be cached internally
2253 * 0: This will set the XPath object caching:
2255 * This will set the maximum number of XPath objects
2256 * to be cached per slot
2257 * There are 5 slots for: node-set, string, number, boolean, and
2258 * misc objects. Use <0 for the default number (100).
2259 * Other values for @options have currently no effect.
2261 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2264 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2272 xmlXPathContextCachePtr cache;
2274 if (ctxt->cache == NULL) {
2275 ctxt->cache = xmlXPathNewCache();
2276 if (ctxt->cache == NULL)
2279 cache = (xmlXPathContextCachePtr) ctxt->cache;
2283 cache->maxNodeset = value;
2284 cache->maxString = value;
2285 cache->maxNumber = value;
2286 cache->maxBoolean = value;
2287 cache->maxMisc = value;
2289 } else if (ctxt->cache != NULL) {
2290 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2297 * xmlXPathCacheWrapNodeSet:
2298 * @ctxt: the XPath context
2299 * @val: the NodePtr value
2301 * This is the cached version of xmlXPathWrapNodeSet().
2302 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2304 * Returns the created or reused object.
2306 static xmlXPathObjectPtr
2307 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2309 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2310 xmlXPathContextCachePtr cache =
2311 (xmlXPathContextCachePtr) ctxt->cache;
2313 if ((cache->miscObjs != NULL) &&
2314 (cache->miscObjs->number != 0))
2316 xmlXPathObjectPtr ret;
2318 ret = (xmlXPathObjectPtr)
2319 cache->miscObjs->items[--cache->miscObjs->number];
2320 ret->type = XPATH_NODESET;
2321 ret->nodesetval = val;
2322 #ifdef XP_DEBUG_OBJ_USAGE
2323 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2329 return(xmlXPathWrapNodeSet(val));
2334 * xmlXPathCacheWrapString:
2335 * @ctxt: the XPath context
2336 * @val: the xmlChar * value
2338 * This is the cached version of xmlXPathWrapString().
2339 * Wraps the @val string into an XPath object.
2341 * Returns the created or reused object.
2343 static xmlXPathObjectPtr
2344 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2346 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2347 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2349 if ((cache->stringObjs != NULL) &&
2350 (cache->stringObjs->number != 0))
2353 xmlXPathObjectPtr ret;
2355 ret = (xmlXPathObjectPtr)
2356 cache->stringObjs->items[--cache->stringObjs->number];
2357 ret->type = XPATH_STRING;
2358 ret->stringval = val;
2359 #ifdef XP_DEBUG_OBJ_USAGE
2360 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2363 } else if ((cache->miscObjs != NULL) &&
2364 (cache->miscObjs->number != 0))
2366 xmlXPathObjectPtr ret;
2368 * Fallback to misc-cache.
2370 ret = (xmlXPathObjectPtr)
2371 cache->miscObjs->items[--cache->miscObjs->number];
2373 ret->type = XPATH_STRING;
2374 ret->stringval = val;
2375 #ifdef XP_DEBUG_OBJ_USAGE
2376 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2381 return(xmlXPathWrapString(val));
2385 * xmlXPathCacheNewNodeSet:
2386 * @ctxt: the XPath context
2387 * @val: the NodePtr value
2389 * This is the cached version of xmlXPathNewNodeSet().
2390 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2391 * it with the single Node @val
2393 * Returns the created or reused object.
2395 static xmlXPathObjectPtr
2396 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2398 if ((ctxt != NULL) && (ctxt->cache)) {
2399 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2401 if ((cache->nodesetObjs != NULL) &&
2402 (cache->nodesetObjs->number != 0))
2404 xmlXPathObjectPtr ret;
2406 * Use the nodset-cache.
2408 ret = (xmlXPathObjectPtr)
2409 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2410 ret->type = XPATH_NODESET;
2413 if ((ret->nodesetval->nodeMax == 0) ||
2414 (val->type == XML_NAMESPACE_DECL))
2416 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2418 ret->nodesetval->nodeTab[0] = val;
2419 ret->nodesetval->nodeNr = 1;
2422 #ifdef XP_DEBUG_OBJ_USAGE
2423 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2426 } else if ((cache->miscObjs != NULL) &&
2427 (cache->miscObjs->number != 0))
2429 xmlXPathObjectPtr ret;
2431 * Fallback to misc-cache.
2434 ret = (xmlXPathObjectPtr)
2435 cache->miscObjs->items[--cache->miscObjs->number];
2437 ret->type = XPATH_NODESET;
2439 ret->nodesetval = xmlXPathNodeSetCreate(val);
2440 if (ret->nodesetval == NULL) {
2441 ctxt->lastError.domain = XML_FROM_XPATH;
2442 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2445 #ifdef XP_DEBUG_OBJ_USAGE
2446 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2451 return(xmlXPathNewNodeSet(val));
2455 * xmlXPathCacheNewCString:
2456 * @ctxt: the XPath context
2457 * @val: the char * value
2459 * This is the cached version of xmlXPathNewCString().
2460 * Acquire an xmlXPathObjectPtr of type string and of value @val
2462 * Returns the created or reused object.
2464 static xmlXPathObjectPtr
2465 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2467 if ((ctxt != NULL) && (ctxt->cache)) {
2468 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2470 if ((cache->stringObjs != NULL) &&
2471 (cache->stringObjs->number != 0))
2473 xmlXPathObjectPtr ret;
2475 ret = (xmlXPathObjectPtr)
2476 cache->stringObjs->items[--cache->stringObjs->number];
2478 ret->type = XPATH_STRING;
2479 ret->stringval = xmlStrdup(BAD_CAST val);
2480 #ifdef XP_DEBUG_OBJ_USAGE
2481 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2484 } else if ((cache->miscObjs != NULL) &&
2485 (cache->miscObjs->number != 0))
2487 xmlXPathObjectPtr ret;
2489 ret = (xmlXPathObjectPtr)
2490 cache->miscObjs->items[--cache->miscObjs->number];
2492 ret->type = XPATH_STRING;
2493 ret->stringval = xmlStrdup(BAD_CAST val);
2494 #ifdef XP_DEBUG_OBJ_USAGE
2495 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2500 return(xmlXPathNewCString(val));
2504 * xmlXPathCacheNewString:
2505 * @ctxt: the XPath context
2506 * @val: the xmlChar * value
2508 * This is the cached version of xmlXPathNewString().
2509 * Acquire an xmlXPathObjectPtr of type string and of value @val
2511 * Returns the created or reused object.
2513 static xmlXPathObjectPtr
2514 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2516 if ((ctxt != NULL) && (ctxt->cache)) {
2517 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2519 if ((cache->stringObjs != NULL) &&
2520 (cache->stringObjs->number != 0))
2522 xmlXPathObjectPtr ret;
2524 ret = (xmlXPathObjectPtr)
2525 cache->stringObjs->items[--cache->stringObjs->number];
2526 ret->type = XPATH_STRING;
2528 ret->stringval = xmlStrdup(val);
2530 ret->stringval = xmlStrdup((const xmlChar *)"");
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2535 } else if ((cache->miscObjs != NULL) &&
2536 (cache->miscObjs->number != 0))
2538 xmlXPathObjectPtr ret;
2540 ret = (xmlXPathObjectPtr)
2541 cache->miscObjs->items[--cache->miscObjs->number];
2543 ret->type = XPATH_STRING;
2545 ret->stringval = xmlStrdup(val);
2547 ret->stringval = xmlStrdup((const xmlChar *)"");
2548 #ifdef XP_DEBUG_OBJ_USAGE
2549 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2554 return(xmlXPathNewString(val));
2558 * xmlXPathCacheNewBoolean:
2559 * @ctxt: the XPath context
2560 * @val: the boolean value
2562 * This is the cached version of xmlXPathNewBoolean().
2563 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2565 * Returns the created or reused object.
2567 static xmlXPathObjectPtr
2568 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2570 if ((ctxt != NULL) && (ctxt->cache)) {
2571 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2573 if ((cache->booleanObjs != NULL) &&
2574 (cache->booleanObjs->number != 0))
2576 xmlXPathObjectPtr ret;
2578 ret = (xmlXPathObjectPtr)
2579 cache->booleanObjs->items[--cache->booleanObjs->number];
2580 ret->type = XPATH_BOOLEAN;
2581 ret->boolval = (val != 0);
2582 #ifdef XP_DEBUG_OBJ_USAGE
2583 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2586 } else if ((cache->miscObjs != NULL) &&
2587 (cache->miscObjs->number != 0))
2589 xmlXPathObjectPtr ret;
2591 ret = (xmlXPathObjectPtr)
2592 cache->miscObjs->items[--cache->miscObjs->number];
2594 ret->type = XPATH_BOOLEAN;
2595 ret->boolval = (val != 0);
2596 #ifdef XP_DEBUG_OBJ_USAGE
2597 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2602 return(xmlXPathNewBoolean(val));
2606 * xmlXPathCacheNewFloat:
2607 * @ctxt: the XPath context
2608 * @val: the double value
2610 * This is the cached version of xmlXPathNewFloat().
2611 * Acquires an xmlXPathObjectPtr of type double and of value @val
2613 * Returns the created or reused object.
2615 static xmlXPathObjectPtr
2616 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2618 if ((ctxt != NULL) && (ctxt->cache)) {
2619 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2621 if ((cache->numberObjs != NULL) &&
2622 (cache->numberObjs->number != 0))
2624 xmlXPathObjectPtr ret;
2626 ret = (xmlXPathObjectPtr)
2627 cache->numberObjs->items[--cache->numberObjs->number];
2628 ret->type = XPATH_NUMBER;
2629 ret->floatval = val;
2630 #ifdef XP_DEBUG_OBJ_USAGE
2631 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2634 } else if ((cache->miscObjs != NULL) &&
2635 (cache->miscObjs->number != 0))
2637 xmlXPathObjectPtr ret;
2639 ret = (xmlXPathObjectPtr)
2640 cache->miscObjs->items[--cache->miscObjs->number];
2642 ret->type = XPATH_NUMBER;
2643 ret->floatval = val;
2644 #ifdef XP_DEBUG_OBJ_USAGE
2645 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2650 return(xmlXPathNewFloat(val));
2654 * xmlXPathCacheConvertString:
2655 * @ctxt: the XPath context
2656 * @val: an XPath object
2658 * This is the cached version of xmlXPathConvertString().
2659 * Converts an existing object to its string() equivalent
2661 * Returns a created or reused object, the old one is freed (cached)
2662 * (or the operation is done directly on @val)
2665 static xmlXPathObjectPtr
2666 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2667 xmlChar *res = NULL;
2670 return(xmlXPathCacheNewCString(ctxt, ""));
2672 switch (val->type) {
2673 case XPATH_UNDEFINED:
2675 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2679 case XPATH_XSLT_TREE:
2680 res = xmlXPathCastNodeSetToString(val->nodesetval);
2685 res = xmlXPathCastBooleanToString(val->boolval);
2688 res = xmlXPathCastNumberToString(val->floatval);
2693 case XPATH_LOCATIONSET:
2697 xmlXPathReleaseObject(ctxt, val);
2699 return(xmlXPathCacheNewCString(ctxt, ""));
2700 return(xmlXPathCacheWrapString(ctxt, res));
2704 * xmlXPathCacheObjectCopy:
2705 * @ctxt: the XPath context
2706 * @val: the original object
2708 * This is the cached version of xmlXPathObjectCopy().
2709 * Acquire a copy of a given object
2711 * Returns a created or reused created object.
2713 static xmlXPathObjectPtr
2714 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2719 if (XP_HAS_CACHE(ctxt)) {
2720 switch (val->type) {
2722 return(xmlXPathCacheWrapNodeSet(ctxt,
2723 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2725 return(xmlXPathCacheNewString(ctxt, val->stringval));
2727 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2729 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2734 return(xmlXPathObjectCopy(val));
2738 * xmlXPathCacheConvertBoolean:
2739 * @ctxt: the XPath context
2740 * @val: an XPath object
2742 * This is the cached version of xmlXPathConvertBoolean().
2743 * Converts an existing object to its boolean() equivalent
2745 * Returns a created or reused object, the old one is freed (or the operation
2746 * is done directly on @val)
2748 static xmlXPathObjectPtr
2749 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2750 xmlXPathObjectPtr ret;
2753 return(xmlXPathCacheNewBoolean(ctxt, 0));
2754 if (val->type == XPATH_BOOLEAN)
2756 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2757 xmlXPathReleaseObject(ctxt, val);
2762 * xmlXPathCacheConvertNumber:
2763 * @ctxt: the XPath context
2764 * @val: an XPath object
2766 * This is the cached version of xmlXPathConvertNumber().
2767 * Converts an existing object to its number() equivalent
2769 * Returns a created or reused object, the old one is freed (or the operation
2770 * is done directly on @val)
2772 static xmlXPathObjectPtr
2773 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2774 xmlXPathObjectPtr ret;
2777 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2778 if (val->type == XPATH_NUMBER)
2780 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2781 xmlXPathReleaseObject(ctxt, val);
2785 /************************************************************************
2787 * Parser stacks related functions and macros *
2789 ************************************************************************/
2793 * @ctxt: an XPath parser context
2795 * Set the callee evaluation frame
2797 * Returns the previous frame value to be restored once done
2800 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2805 ret = ctxt->valueFrame;
2806 ctxt->valueFrame = ctxt->valueNr;
2812 * @ctxt: an XPath parser context
2813 * @frame: the previous frame value
2815 * Remove the callee evaluation frame
2818 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2821 if (ctxt->valueNr < ctxt->valueFrame) {
2822 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2824 ctxt->valueFrame = frame;
2829 * @ctxt: an XPath evaluation context
2831 * Pops the top XPath object from the value stack
2833 * Returns the XPath object just removed
2836 valuePop(xmlXPathParserContextPtr ctxt)
2838 xmlXPathObjectPtr ret;
2840 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2843 if (ctxt->valueNr <= ctxt->valueFrame) {
2844 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2849 if (ctxt->valueNr > 0)
2850 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2853 ret = ctxt->valueTab[ctxt->valueNr];
2854 ctxt->valueTab[ctxt->valueNr] = NULL;
2859 * @ctxt: an XPath evaluation context
2860 * @value: the XPath object
2862 * Pushes a new XPath object on top of the value stack
2864 * returns the number of items on the value stack
2867 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2869 if ((ctxt == NULL) || (value == NULL)) return(-1);
2870 if (ctxt->valueNr >= ctxt->valueMax) {
2871 xmlXPathObjectPtr *tmp;
2873 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2874 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2875 ctxt->error = XPATH_MEMORY_ERROR;
2878 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2879 2 * ctxt->valueMax *
2880 sizeof(ctxt->valueTab[0]));
2882 xmlXPathErrMemory(NULL, "pushing value\n");
2883 ctxt->error = XPATH_MEMORY_ERROR;
2886 ctxt->valueMax *= 2;
2887 ctxt->valueTab = tmp;
2889 ctxt->valueTab[ctxt->valueNr] = value;
2890 ctxt->value = value;
2891 return (ctxt->valueNr++);
2895 * xmlXPathPopBoolean:
2896 * @ctxt: an XPath parser context
2898 * Pops a boolean from the stack, handling conversion if needed.
2899 * Check error with #xmlXPathCheckError.
2901 * Returns the boolean
2904 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2905 xmlXPathObjectPtr obj;
2908 obj = valuePop(ctxt);
2910 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2913 if (obj->type != XPATH_BOOLEAN)
2914 ret = xmlXPathCastToBoolean(obj);
2917 xmlXPathReleaseObject(ctxt->context, obj);
2922 * xmlXPathPopNumber:
2923 * @ctxt: an XPath parser context
2925 * Pops a number from the stack, handling conversion if needed.
2926 * Check error with #xmlXPathCheckError.
2928 * Returns the number
2931 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2932 xmlXPathObjectPtr obj;
2935 obj = valuePop(ctxt);
2937 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2940 if (obj->type != XPATH_NUMBER)
2941 ret = xmlXPathCastToNumber(obj);
2943 ret = obj->floatval;
2944 xmlXPathReleaseObject(ctxt->context, obj);
2949 * xmlXPathPopString:
2950 * @ctxt: an XPath parser context
2952 * Pops a string from the stack, handling conversion if needed.
2953 * Check error with #xmlXPathCheckError.
2955 * Returns the string
2958 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2959 xmlXPathObjectPtr obj;
2962 obj = valuePop(ctxt);
2964 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2967 ret = xmlXPathCastToString(obj); /* this does required strdup */
2968 /* TODO: needs refactoring somewhere else */
2969 if (obj->stringval == ret)
2970 obj->stringval = NULL;
2971 xmlXPathReleaseObject(ctxt->context, obj);
2976 * xmlXPathPopNodeSet:
2977 * @ctxt: an XPath parser context
2979 * Pops a node-set from the stack, handling conversion if needed.
2980 * Check error with #xmlXPathCheckError.
2982 * Returns the node-set
2985 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2986 xmlXPathObjectPtr obj;
2989 if (ctxt == NULL) return(NULL);
2990 if (ctxt->value == NULL) {
2991 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2994 if (!xmlXPathStackIsNodeSet(ctxt)) {
2995 xmlXPathSetTypeError(ctxt);
2998 obj = valuePop(ctxt);
2999 ret = obj->nodesetval;
3001 /* to fix memory leak of not clearing obj->user */
3002 if (obj->boolval && obj->user != NULL)
3003 xmlFreeNodeList((xmlNodePtr) obj->user);
3005 obj->nodesetval = NULL;
3006 xmlXPathReleaseObject(ctxt->context, obj);
3011 * xmlXPathPopExternal:
3012 * @ctxt: an XPath parser context
3014 * Pops an external object from the stack, handling conversion if needed.
3015 * Check error with #xmlXPathCheckError.
3017 * Returns the object
3020 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3021 xmlXPathObjectPtr obj;
3024 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3025 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3028 if (ctxt->value->type != XPATH_USERS) {
3029 xmlXPathSetTypeError(ctxt);
3032 obj = valuePop(ctxt);
3035 xmlXPathReleaseObject(ctxt->context, obj);
3040 * Macros for accessing the content. Those should be used only by the parser,
3043 * Dirty macros, i.e. one need to make assumption on the context to use them
3045 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3046 * CUR returns the current xmlChar value, i.e. a 8 bit value
3047 * in ISO-Latin or UTF-8.
3048 * This should be used internally by the parser
3049 * only to compare to ASCII values otherwise it would break when
3050 * running with UTF-8 encoding.
3051 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3052 * to compare on ASCII based substring.
3053 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3054 * strings within the parser.
3055 * CURRENT Returns the current char value, with the full decoding of
3056 * UTF-8 if we are using this mode. It returns an int.
3057 * NEXT Skip to the next character, this does the proper decoding
3058 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3059 * It returns the pointer to the current xmlChar.
3062 #define CUR (*ctxt->cur)
3063 #define SKIP(val) ctxt->cur += (val)
3064 #define NXT(val) ctxt->cur[(val)]
3065 #define CUR_PTR ctxt->cur
3066 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3068 #define COPY_BUF(l,b,i,v) \
3069 if (l == 1) b[i++] = (xmlChar) v; \
3070 else i += xmlCopyChar(l,&b[i],v)
3072 #define NEXTL(l) ctxt->cur += l
3074 #define SKIP_BLANKS \
3075 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3077 #define CURRENT (*ctxt->cur)
3078 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3085 #define DBL_EPSILON 1E-9
3088 #define UPPER_DOUBLE 1E9
3089 #define LOWER_DOUBLE 1E-5
3090 #define LOWER_DOUBLE_EXP 5
3092 #define INTEGER_DIGITS DBL_DIG
3093 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3094 #define EXPONENT_DIGITS (3 + 2)
3097 * xmlXPathFormatNumber:
3098 * @number: number to format
3099 * @buffer: output buffer
3100 * @buffersize: size of output buffer
3102 * Convert the number into a string representation.
3105 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3107 switch (xmlXPathIsInf(number)) {
3109 if (buffersize > (int)sizeof("Infinity"))
3110 snprintf(buffer, buffersize, "Infinity");
3113 if (buffersize > (int)sizeof("-Infinity"))
3114 snprintf(buffer, buffersize, "-Infinity");
3117 if (xmlXPathIsNaN(number)) {
3118 if (buffersize > (int)sizeof("NaN"))
3119 snprintf(buffer, buffersize, "NaN");
3120 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3121 snprintf(buffer, buffersize, "0");
3122 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3123 (number == (int) number)) {
3126 int value = (int) number;
3132 snprintf(work, 29, "%d", value);
3134 while ((*cur) && (ptr - buffer < buffersize)) {
3138 if (ptr - buffer < buffersize) {
3140 } else if (buffersize > 0) {
3146 For the dimension of work,
3147 DBL_DIG is number of significant digits
3148 EXPONENT is only needed for "scientific notation"
3149 3 is sign, decimal point, and terminating zero
3150 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3151 Note that this dimension is slightly (a few characters)
3152 larger than actually necessary.
3154 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3155 int integer_place, fraction_place;
3157 char *after_fraction;
3158 double absolute_value;
3161 absolute_value = fabs(number);
3164 * First choose format - scientific or regular floating point.
3165 * In either case, result is in work, and after_fraction points
3166 * just past the fractional part.
3168 if ( ((absolute_value > UPPER_DOUBLE) ||
3169 (absolute_value < LOWER_DOUBLE)) &&
3170 (absolute_value != 0.0) ) {
3171 /* Use scientific notation */
3172 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3173 fraction_place = DBL_DIG - 1;
3174 size = snprintf(work, sizeof(work),"%*.*e",
3175 integer_place, fraction_place, number);
3176 while ((size > 0) && (work[size] != 'e')) size--;
3180 /* Use regular notation */
3181 if (absolute_value > 0.0) {
3182 integer_place = (int)log10(absolute_value);
3183 if (integer_place > 0)
3184 fraction_place = DBL_DIG - integer_place - 1;
3186 fraction_place = DBL_DIG - integer_place;
3190 size = snprintf(work, sizeof(work), "%0.*f",
3191 fraction_place, number);
3194 /* Remove leading spaces sometimes inserted by snprintf */
3195 while (work[0] == ' ') {
3196 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3200 /* Remove fractional trailing zeroes */
3201 after_fraction = work + size;
3202 ptr = after_fraction;
3203 while (*(--ptr) == '0')
3207 while ((*ptr++ = *after_fraction++) != 0);
3209 /* Finally copy result back to caller */
3210 size = strlen(work) + 1;
3211 if (size > buffersize) {
3212 work[buffersize - 1] = 0;
3215 memmove(buffer, work, size);
3222 /************************************************************************
3224 * Routines to handle NodeSets *
3226 ************************************************************************/
3229 * xmlXPathOrderDocElems:
3230 * @doc: an input document
3232 * Call this routine to speed up XPath computation on static documents.
3233 * This stamps all the element nodes with the document order
3234 * Like for line information, the order is kept in the element->content
3235 * field, the value stored is actually - the node number (starting at -1)
3236 * to be able to differentiate from line numbers.
3238 * Returns the number of elements found in the document or -1 in case
3242 xmlXPathOrderDocElems(xmlDocPtr doc) {
3243 ptrdiff_t count = 0;
3248 cur = doc->children;
3249 while (cur != NULL) {
3250 if (cur->type == XML_ELEMENT_NODE) {
3251 cur->content = (void *) (-(++count));
3252 if (cur->children != NULL) {
3253 cur = cur->children;
3257 if (cur->next != NULL) {
3265 if (cur == (xmlNodePtr) doc) {
3269 if (cur->next != NULL) {
3273 } while (cur != NULL);
3275 return((long) count);
3280 * @node1: the first node
3281 * @node2: the second node
3283 * Compare two nodes w.r.t document order
3285 * Returns -2 in case of error 1 if first point < second point, 0 if
3286 * it's the same node, -1 otherwise
3289 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3291 int attr1 = 0, attr2 = 0;
3292 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3293 xmlNodePtr cur, root;
3295 if ((node1 == NULL) || (node2 == NULL))
3298 * a couple of optimizations which will avoid computations in most cases
3300 if (node1 == node2) /* trivial case */
3302 if (node1->type == XML_ATTRIBUTE_NODE) {
3305 node1 = node1->parent;
3307 if (node2->type == XML_ATTRIBUTE_NODE) {
3310 node2 = node2->parent;
3312 if (node1 == node2) {
3313 if (attr1 == attr2) {
3314 /* not required, but we keep attributes in order */
3316 cur = attrNode2->prev;
3317 while (cur != NULL) {
3318 if (cur == attrNode1)
3330 if ((node1->type == XML_NAMESPACE_DECL) ||
3331 (node2->type == XML_NAMESPACE_DECL))
3333 if (node1 == node2->prev)
3335 if (node1 == node2->next)
3339 * Speedup using document order if availble.
3341 if ((node1->type == XML_ELEMENT_NODE) &&
3342 (node2->type == XML_ELEMENT_NODE) &&
3343 (0 > (ptrdiff_t) node1->content) &&
3344 (0 > (ptrdiff_t) node2->content) &&
3345 (node1->doc == node2->doc)) {
3348 l1 = -((ptrdiff_t) node1->content);
3349 l2 = -((ptrdiff_t) node2->content);
3357 * compute depth to root
3359 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3360 if (cur->parent == node1)
3365 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3366 if (cur->parent == node2)
3371 * Distinct document (or distinct entities :-( ) case.
3377 * get the nearest common ancestor.
3379 while (depth1 > depth2) {
3381 node1 = node1->parent;
3383 while (depth2 > depth1) {
3385 node2 = node2->parent;
3387 while (node1->parent != node2->parent) {
3388 node1 = node1->parent;
3389 node2 = node2->parent;
3390 /* should not happen but just in case ... */
3391 if ((node1 == NULL) || (node2 == NULL))
3397 if (node1 == node2->prev)
3399 if (node1 == node2->next)
3402 * Speedup using document order if availble.
3404 if ((node1->type == XML_ELEMENT_NODE) &&
3405 (node2->type == XML_ELEMENT_NODE) &&
3406 (0 > (ptrdiff_t) node1->content) &&
3407 (0 > (ptrdiff_t) node2->content) &&
3408 (node1->doc == node2->doc)) {
3411 l1 = -((ptrdiff_t) node1->content);
3412 l2 = -((ptrdiff_t) node2->content);
3419 for (cur = node1->next;cur != NULL;cur = cur->next)
3422 return(-1); /* assume there is no sibling list corruption */
3426 * xmlXPathNodeSetSort:
3427 * @set: the node set
3429 * Sort the node set in document order
3432 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3433 #ifndef WITH_TIM_SORT
3434 int i, j, incr, len;
3441 #ifndef WITH_TIM_SORT
3443 * Use the old Shell's sort implementation to sort the node-set
3444 * Timsort ought to be quite faster
3447 for (incr = len / 2; incr > 0; incr /= 2) {
3448 for (i = incr; i < len; i++) {
3451 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3452 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3453 set->nodeTab[j + incr]) == -1)
3455 if (xmlXPathCmpNodes(set->nodeTab[j],
3456 set->nodeTab[j + incr]) == -1)
3459 tmp = set->nodeTab[j];
3460 set->nodeTab[j] = set->nodeTab[j + incr];
3461 set->nodeTab[j + incr] = tmp;
3468 #else /* WITH_TIM_SORT */
3469 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3470 #endif /* WITH_TIM_SORT */
3473 #define XML_NODESET_DEFAULT 10
3475 * xmlXPathNodeSetDupNs:
3476 * @node: the parent node of the namespace XPath node
3477 * @ns: the libxml namespace declaration node.
3479 * Namespace node in libxml don't match the XPath semantic. In a node set
3480 * the namespace nodes are duplicated and the next pointer is set to the
3481 * parent node in the XPath semantic.
3483 * Returns the newly created object.
3486 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3489 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3491 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3492 return((xmlNodePtr) ns);
3495 * Allocate a new Namespace and fill the fields.
3497 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3499 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3502 memset(cur, 0, sizeof(xmlNs));
3503 cur->type = XML_NAMESPACE_DECL;
3504 if (ns->href != NULL)
3505 cur->href = xmlStrdup(ns->href);
3506 if (ns->prefix != NULL)
3507 cur->prefix = xmlStrdup(ns->prefix);
3508 cur->next = (xmlNsPtr) node;
3509 return((xmlNodePtr) cur);
3513 * xmlXPathNodeSetFreeNs:
3514 * @ns: the XPath namespace node found in a nodeset.
3516 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3517 * the namespace nodes are duplicated and the next pointer is set to the
3518 * parent node in the XPath semantic. Check if such a node needs to be freed
3521 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3522 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3525 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3526 if (ns->href != NULL)
3527 xmlFree((xmlChar *)ns->href);
3528 if (ns->prefix != NULL)
3529 xmlFree((xmlChar *)ns->prefix);
3535 * xmlXPathNodeSetCreate:
3536 * @val: an initial xmlNodePtr, or NULL
3538 * Create a new xmlNodeSetPtr of type double and of value @val
3540 * Returns the newly created object.
3543 xmlXPathNodeSetCreate(xmlNodePtr val) {
3546 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3548 xmlXPathErrMemory(NULL, "creating nodeset\n");
3551 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3553 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3554 sizeof(xmlNodePtr));
3555 if (ret->nodeTab == NULL) {
3556 xmlXPathErrMemory(NULL, "creating nodeset\n");
3560 memset(ret->nodeTab, 0 ,
3561 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3562 ret->nodeMax = XML_NODESET_DEFAULT;
3563 if (val->type == XML_NAMESPACE_DECL) {
3564 xmlNsPtr ns = (xmlNsPtr) val;
3566 ret->nodeTab[ret->nodeNr++] =
3567 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3569 ret->nodeTab[ret->nodeNr++] = val;
3575 * xmlXPathNodeSetCreateSize:
3576 * @size: the initial size of the set
3578 * Create a new xmlNodeSetPtr of type double and of value @val
3580 * Returns the newly created object.
3582 static xmlNodeSetPtr
3583 xmlXPathNodeSetCreateSize(int size) {
3586 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3588 xmlXPathErrMemory(NULL, "creating nodeset\n");
3591 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3592 if (size < XML_NODESET_DEFAULT)
3593 size = XML_NODESET_DEFAULT;
3594 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3595 if (ret->nodeTab == NULL) {
3596 xmlXPathErrMemory(NULL, "creating nodeset\n");
3600 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3601 ret->nodeMax = size;
3606 * xmlXPathNodeSetContains:
3607 * @cur: the node-set
3610 * checks whether @cur contains @val
3612 * Returns true (1) if @cur contains @val, false (0) otherwise
3615 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3618 if ((cur == NULL) || (val == NULL)) return(0);
3619 if (val->type == XML_NAMESPACE_DECL) {
3620 for (i = 0; i < cur->nodeNr; i++) {
3621 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3624 ns1 = (xmlNsPtr) val;
3625 ns2 = (xmlNsPtr) cur->nodeTab[i];
3628 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3629 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3634 for (i = 0; i < cur->nodeNr; i++) {
3635 if (cur->nodeTab[i] == val)
3643 * xmlXPathNodeSetAddNs:
3644 * @cur: the initial node set
3645 * @node: the hosting node
3646 * @ns: a the namespace node
3648 * add a new namespace node to an existing NodeSet
3650 * Returns 0 in case of success and -1 in case of error
3653 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3657 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3658 (ns->type != XML_NAMESPACE_DECL) ||
3659 (node->type != XML_ELEMENT_NODE))
3662 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3664 * prevent duplicates
3666 for (i = 0;i < cur->nodeNr;i++) {
3667 if ((cur->nodeTab[i] != NULL) &&
3668 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3669 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3670 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3675 * grow the nodeTab if needed
3677 if (cur->nodeMax == 0) {
3678 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3679 sizeof(xmlNodePtr));
3680 if (cur->nodeTab == NULL) {
3681 xmlXPathErrMemory(NULL, "growing nodeset\n");
3684 memset(cur->nodeTab, 0 ,
3685 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3686 cur->nodeMax = XML_NODESET_DEFAULT;
3687 } else if (cur->nodeNr == cur->nodeMax) {
3690 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3691 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3694 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3695 sizeof(xmlNodePtr));
3697 xmlXPathErrMemory(NULL, "growing nodeset\n");
3701 cur->nodeTab = temp;
3703 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3708 * xmlXPathNodeSetAdd:
3709 * @cur: the initial node set
3710 * @val: a new xmlNodePtr
3712 * add a new xmlNodePtr to an existing NodeSet
3714 * Returns 0 in case of success, and -1 in case of error
3717 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3720 if ((cur == NULL) || (val == NULL)) return(-1);
3722 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3724 * prevent duplicates
3726 for (i = 0;i < cur->nodeNr;i++)
3727 if (cur->nodeTab[i] == val) return(0);
3730 * grow the nodeTab if needed
3732 if (cur->nodeMax == 0) {
3733 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3734 sizeof(xmlNodePtr));
3735 if (cur->nodeTab == NULL) {
3736 xmlXPathErrMemory(NULL, "growing nodeset\n");
3739 memset(cur->nodeTab, 0 ,
3740 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3741 cur->nodeMax = XML_NODESET_DEFAULT;
3742 } else if (cur->nodeNr == cur->nodeMax) {
3745 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3746 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3749 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3750 sizeof(xmlNodePtr));
3752 xmlXPathErrMemory(NULL, "growing nodeset\n");
3756 cur->nodeTab = temp;
3758 if (val->type == XML_NAMESPACE_DECL) {
3759 xmlNsPtr ns = (xmlNsPtr) val;
3761 cur->nodeTab[cur->nodeNr++] =
3762 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3764 cur->nodeTab[cur->nodeNr++] = val;
3769 * xmlXPathNodeSetAddUnique:
3770 * @cur: the initial node set
3771 * @val: a new xmlNodePtr
3773 * add a new xmlNodePtr to an existing NodeSet, optimized version
3774 * when we are sure the node is not already in the set.
3776 * Returns 0 in case of success and -1 in case of failure
3779 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3780 if ((cur == NULL) || (val == NULL)) return(-1);
3782 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3784 * grow the nodeTab if needed
3786 if (cur->nodeMax == 0) {
3787 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3788 sizeof(xmlNodePtr));
3789 if (cur->nodeTab == NULL) {
3790 xmlXPathErrMemory(NULL, "growing nodeset\n");
3793 memset(cur->nodeTab, 0 ,
3794 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3795 cur->nodeMax = XML_NODESET_DEFAULT;
3796 } else if (cur->nodeNr == cur->nodeMax) {
3799 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3800 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3803 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3804 sizeof(xmlNodePtr));
3806 xmlXPathErrMemory(NULL, "growing nodeset\n");
3809 cur->nodeTab = temp;
3812 if (val->type == XML_NAMESPACE_DECL) {
3813 xmlNsPtr ns = (xmlNsPtr) val;
3815 cur->nodeTab[cur->nodeNr++] =
3816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3818 cur->nodeTab[cur->nodeNr++] = val;
3823 * xmlXPathNodeSetMerge:
3824 * @val1: the first NodeSet or NULL
3825 * @val2: the second NodeSet
3827 * Merges two nodesets, all nodes from @val2 are added to @val1
3828 * if @val1 is NULL, a new set is created and copied from @val2
3830 * Returns @val1 once extended or NULL in case of error.
3833 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3834 int i, j, initNr, skip;
3837 if (val2 == NULL) return(val1);
3839 val1 = xmlXPathNodeSetCreate(NULL);
3844 * TODO: The optimization won't work in every case, since
3845 * those nasty namespace nodes need to be added with
3846 * xmlXPathNodeSetDupNs() to the set; thus a pure
3847 * memcpy is not possible.
3848 * If there was a flag on the nodesetval, indicating that
3849 * some temporary nodes are in, that would be helpfull.
3852 * Optimization: Create an equally sized node-set
3853 * and memcpy the content.
3855 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3858 if (val2->nodeNr != 0) {
3859 if (val2->nodeNr == 1)
3860 *(val1->nodeTab) = *(val2->nodeTab);
3862 memcpy(val1->nodeTab, val2->nodeTab,
3863 val2->nodeNr * sizeof(xmlNodePtr));
3865 val1->nodeNr = val2->nodeNr;
3871 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3872 initNr = val1->nodeNr;
3874 for (i = 0;i < val2->nodeNr;i++) {
3875 n2 = val2->nodeTab[i];
3877 * check against duplicates
3880 for (j = 0; j < initNr; j++) {
3881 n1 = val1->nodeTab[j];
3885 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3886 (n2->type == XML_NAMESPACE_DECL)) {
3887 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3888 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3889 ((xmlNsPtr) n2)->prefix)))
3900 * grow the nodeTab if needed
3902 if (val1->nodeMax == 0) {
3903 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3904 sizeof(xmlNodePtr));
3905 if (val1->nodeTab == NULL) {
3906 xmlXPathErrMemory(NULL, "merging nodeset\n");
3909 memset(val1->nodeTab, 0 ,
3910 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3911 val1->nodeMax = XML_NODESET_DEFAULT;
3912 } else if (val1->nodeNr == val1->nodeMax) {
3915 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3916 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3919 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3920 sizeof(xmlNodePtr));
3922 xmlXPathErrMemory(NULL, "merging nodeset\n");
3925 val1->nodeTab = temp;
3928 if (n2->type == XML_NAMESPACE_DECL) {
3929 xmlNsPtr ns = (xmlNsPtr) n2;
3931 val1->nodeTab[val1->nodeNr++] =
3932 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3934 val1->nodeTab[val1->nodeNr++] = n2;
3942 * xmlXPathNodeSetMergeAndClear:
3943 * @set1: the first NodeSet or NULL
3944 * @set2: the second NodeSet
3945 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3947 * Merges two nodesets, all nodes from @set2 are added to @set1
3948 * if @set1 is NULL, a new set is created and copied from @set2.
3949 * Checks for duplicate nodes. Clears set2.
3951 * Returns @set1 once extended or NULL in case of error.
3953 static xmlNodeSetPtr
3954 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3957 if ((set1 == NULL) && (hasNullEntries == 0)) {
3959 * Note that doing a memcpy of the list, namespace nodes are
3960 * just assigned to set1, since set2 is cleared anyway.
3962 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3965 if (set2->nodeNr != 0) {
3966 memcpy(set1->nodeTab, set2->nodeTab,
3967 set2->nodeNr * sizeof(xmlNodePtr));
3968 set1->nodeNr = set2->nodeNr;
3971 int i, j, initNbSet1;
3975 set1 = xmlXPathNodeSetCreate(NULL);
3979 initNbSet1 = set1->nodeNr;
3980 for (i = 0;i < set2->nodeNr;i++) {
3981 n2 = set2->nodeTab[i];
3983 * Skip NULLed entries.
3990 for (j = 0; j < initNbSet1; j++) {
3991 n1 = set1->nodeTab[j];
3994 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3995 (n2->type == XML_NAMESPACE_DECL))
3997 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3998 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3999 ((xmlNsPtr) n2)->prefix)))
4002 * Free the namespace node.
4004 set2->nodeTab[i] = NULL;
4005 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4011 * grow the nodeTab if needed
4013 if (set1->nodeMax == 0) {
4014 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4015 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4016 if (set1->nodeTab == NULL) {
4017 xmlXPathErrMemory(NULL, "merging nodeset\n");
4020 memset(set1->nodeTab, 0,
4021 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4022 set1->nodeMax = XML_NODESET_DEFAULT;
4023 } else if (set1->nodeNr >= set1->nodeMax) {
4026 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4027 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4030 temp = (xmlNodePtr *) xmlRealloc(
4031 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4033 xmlXPathErrMemory(NULL, "merging nodeset\n");
4036 set1->nodeTab = temp;
4039 set1->nodeTab[set1->nodeNr++] = n2;
4049 * xmlXPathNodeSetMergeAndClearNoDupls:
4050 * @set1: the first NodeSet or NULL
4051 * @set2: the second NodeSet
4052 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4054 * Merges two nodesets, all nodes from @set2 are added to @set1
4055 * if @set1 is NULL, a new set is created and copied from @set2.
4056 * Doesn't chack for duplicate nodes. Clears set2.
4058 * Returns @set1 once extended or NULL in case of error.
4060 static xmlNodeSetPtr
4061 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4066 if ((set1 == NULL) && (hasNullEntries == 0)) {
4068 * Note that doing a memcpy of the list, namespace nodes are
4069 * just assigned to set1, since set2 is cleared anyway.
4071 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4074 if (set2->nodeNr != 0) {
4075 memcpy(set1->nodeTab, set2->nodeTab,
4076 set2->nodeNr * sizeof(xmlNodePtr));
4077 set1->nodeNr = set2->nodeNr;
4084 set1 = xmlXPathNodeSetCreate(NULL);
4088 for (i = 0;i < set2->nodeNr;i++) {
4089 n2 = set2->nodeTab[i];
4091 * Skip NULLed entries.
4095 if (set1->nodeMax == 0) {
4096 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4097 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4098 if (set1->nodeTab == NULL) {
4099 xmlXPathErrMemory(NULL, "merging nodeset\n");
4102 memset(set1->nodeTab, 0,
4103 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4104 set1->nodeMax = XML_NODESET_DEFAULT;
4105 } else if (set1->nodeNr >= set1->nodeMax) {
4108 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4109 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4112 temp = (xmlNodePtr *) xmlRealloc(
4113 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4115 xmlXPathErrMemory(NULL, "merging nodeset\n");
4118 set1->nodeTab = temp;
4121 set1->nodeTab[set1->nodeNr++] = n2;
4129 * xmlXPathNodeSetDel:
4130 * @cur: the initial node set
4131 * @val: an xmlNodePtr
4133 * Removes an xmlNodePtr from an existing NodeSet
4136 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4139 if (cur == NULL) return;
4140 if (val == NULL) return;
4143 * find node in nodeTab
4145 for (i = 0;i < cur->nodeNr;i++)
4146 if (cur->nodeTab[i] == val) break;
4148 if (i >= cur->nodeNr) { /* not found */
4150 xmlGenericError(xmlGenericErrorContext,
4151 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4156 if ((cur->nodeTab[i] != NULL) &&
4157 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4158 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4160 for (;i < cur->nodeNr;i++)
4161 cur->nodeTab[i] = cur->nodeTab[i + 1];
4162 cur->nodeTab[cur->nodeNr] = NULL;
4166 * xmlXPathNodeSetRemove:
4167 * @cur: the initial node set
4168 * @val: the index to remove
4170 * Removes an entry from an existing NodeSet list.
4173 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4174 if (cur == NULL) return;
4175 if (val >= cur->nodeNr) return;
4176 if ((cur->nodeTab[val] != NULL) &&
4177 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4178 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4180 for (;val < cur->nodeNr;val++)
4181 cur->nodeTab[val] = cur->nodeTab[val + 1];
4182 cur->nodeTab[cur->nodeNr] = NULL;
4186 * xmlXPathFreeNodeSet:
4187 * @obj: the xmlNodeSetPtr to free
4189 * Free the NodeSet compound (not the actual nodes !).
4192 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4193 if (obj == NULL) return;
4194 if (obj->nodeTab != NULL) {
4197 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4198 for (i = 0;i < obj->nodeNr;i++)
4199 if ((obj->nodeTab[i] != NULL) &&
4200 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4201 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4202 xmlFree(obj->nodeTab);
4208 * xmlXPathNodeSetClearFromPos:
4209 * @set: the node set to be cleared
4210 * @pos: the start position to clear from
4212 * Clears the list from temporary XPath objects (e.g. namespace nodes
4213 * are feed) starting with the entry at @pos, but does *not* free the list
4214 * itself. Sets the length of the list to @pos.
4217 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4219 if ((set == NULL) || (pos >= set->nodeNr))
4221 else if ((hasNsNodes)) {
4225 for (i = pos; i < set->nodeNr; i++) {
4226 node = set->nodeTab[i];
4227 if ((node != NULL) &&
4228 (node->type == XML_NAMESPACE_DECL))
4229 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4236 * xmlXPathNodeSetClear:
4237 * @set: the node set to clear
4239 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4240 * are feed), but does *not* free the list itself. Sets the length of the
4244 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4246 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4250 * xmlXPathNodeSetKeepLast:
4251 * @set: the node set to be cleared
4253 * Move the last node to the first position and clear temporary XPath objects
4254 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4258 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4263 if ((set == NULL) || (set->nodeNr <= 1))
4265 for (i = 0; i < set->nodeNr - 1; i++) {
4266 node = set->nodeTab[i];
4267 if ((node != NULL) &&
4268 (node->type == XML_NAMESPACE_DECL))
4269 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4271 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4276 * xmlXPathFreeValueTree:
4277 * @obj: the xmlNodeSetPtr to free
4279 * Free the NodeSet compound and the actual tree, this is different
4280 * from xmlXPathFreeNodeSet()
4283 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4286 if (obj == NULL) return;
4288 if (obj->nodeTab != NULL) {
4289 for (i = 0;i < obj->nodeNr;i++) {
4290 if (obj->nodeTab[i] != NULL) {
4291 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4292 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4294 xmlFreeNodeList(obj->nodeTab[i]);
4298 xmlFree(obj->nodeTab);
4303 #if defined(DEBUG) || defined(DEBUG_STEP)
4305 * xmlGenericErrorContextNodeSet:
4306 * @output: a FILE * for the output
4307 * @obj: the xmlNodeSetPtr to display
4309 * Quick display of a NodeSet
4312 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4315 if (output == NULL) output = xmlGenericErrorContext;
4317 fprintf(output, "NodeSet == NULL !\n");
4320 if (obj->nodeNr == 0) {
4321 fprintf(output, "NodeSet is empty\n");
4324 if (obj->nodeTab == NULL) {
4325 fprintf(output, " nodeTab == NULL !\n");
4328 for (i = 0; i < obj->nodeNr; i++) {
4329 if (obj->nodeTab[i] == NULL) {
4330 fprintf(output, " NULL !\n");
4333 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4334 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4335 fprintf(output, " /");
4336 else if (obj->nodeTab[i]->name == NULL)
4337 fprintf(output, " noname!");
4338 else fprintf(output, " %s", obj->nodeTab[i]->name);
4340 fprintf(output, "\n");
4345 * xmlXPathNewNodeSet:
4346 * @val: the NodePtr value
4348 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4349 * it with the single Node @val
4351 * Returns the newly created object.
4354 xmlXPathNewNodeSet(xmlNodePtr val) {
4355 xmlXPathObjectPtr ret;
4357 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4359 xmlXPathErrMemory(NULL, "creating nodeset\n");
4362 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4363 ret->type = XPATH_NODESET;
4365 ret->nodesetval = xmlXPathNodeSetCreate(val);
4366 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4367 #ifdef XP_DEBUG_OBJ_USAGE
4368 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4374 * xmlXPathNewValueTree:
4375 * @val: the NodePtr value
4377 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4378 * it with the tree root @val
4380 * Returns the newly created object.
4383 xmlXPathNewValueTree(xmlNodePtr val) {
4384 xmlXPathObjectPtr ret;
4386 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4388 xmlXPathErrMemory(NULL, "creating result value tree\n");
4391 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4392 ret->type = XPATH_XSLT_TREE;
4394 ret->user = (void *) val;
4395 ret->nodesetval = xmlXPathNodeSetCreate(val);
4396 #ifdef XP_DEBUG_OBJ_USAGE
4397 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4403 * xmlXPathNewNodeSetList:
4404 * @val: an existing NodeSet
4406 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4407 * it with the Nodeset @val
4409 * Returns the newly created object.
4412 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4414 xmlXPathObjectPtr ret;
4419 else if (val->nodeTab == NULL)
4420 ret = xmlXPathNewNodeSet(NULL);
4422 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4424 for (i = 1; i < val->nodeNr; ++i) {
4425 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4435 * xmlXPathWrapNodeSet:
4436 * @val: the NodePtr value
4438 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4440 * Returns the newly created object.
4443 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4444 xmlXPathObjectPtr ret;
4446 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4448 xmlXPathErrMemory(NULL, "creating node set object\n");
4451 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4452 ret->type = XPATH_NODESET;
4453 ret->nodesetval = val;
4454 #ifdef XP_DEBUG_OBJ_USAGE
4455 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4461 * xmlXPathFreeNodeSetList:
4462 * @obj: an existing NodeSetList object
4464 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4465 * the list contrary to xmlXPathFreeObject().
4468 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4469 if (obj == NULL) return;
4470 #ifdef XP_DEBUG_OBJ_USAGE
4471 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4477 * xmlXPathDifference:
4478 * @nodes1: a node-set
4479 * @nodes2: a node-set
4481 * Implements the EXSLT - Sets difference() function:
4482 * node-set set:difference (node-set, node-set)
4484 * Returns the difference between the two node sets, or nodes1 if
4488 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4493 if (xmlXPathNodeSetIsEmpty(nodes2))
4496 ret = xmlXPathNodeSetCreate(NULL);
4497 if (xmlXPathNodeSetIsEmpty(nodes1))
4500 l1 = xmlXPathNodeSetGetLength(nodes1);
4502 for (i = 0; i < l1; i++) {
4503 cur = xmlXPathNodeSetItem(nodes1, i);
4504 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4505 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4513 * xmlXPathIntersection:
4514 * @nodes1: a node-set
4515 * @nodes2: a node-set
4517 * Implements the EXSLT - Sets intersection() function:
4518 * node-set set:intersection (node-set, node-set)
4520 * Returns a node set comprising the nodes that are within both the
4521 * node sets passed as arguments
4524 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4525 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4531 if (xmlXPathNodeSetIsEmpty(nodes1))
4533 if (xmlXPathNodeSetIsEmpty(nodes2))
4536 l1 = xmlXPathNodeSetGetLength(nodes1);
4538 for (i = 0; i < l1; i++) {
4539 cur = xmlXPathNodeSetItem(nodes1, i);
4540 if (xmlXPathNodeSetContains(nodes2, cur)) {
4541 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4549 * xmlXPathDistinctSorted:
4550 * @nodes: a node-set, sorted by document order
4552 * Implements the EXSLT - Sets distinct() function:
4553 * node-set set:distinct (node-set)
4555 * Returns a subset of the nodes contained in @nodes, or @nodes if
4559 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4561 xmlHashTablePtr hash;
4566 if (xmlXPathNodeSetIsEmpty(nodes))
4569 ret = xmlXPathNodeSetCreate(NULL);
4572 l = xmlXPathNodeSetGetLength(nodes);
4573 hash = xmlHashCreate (l);
4574 for (i = 0; i < l; i++) {
4575 cur = xmlXPathNodeSetItem(nodes, i);
4576 strval = xmlXPathCastNodeToString(cur);
4577 if (xmlHashLookup(hash, strval) == NULL) {
4578 xmlHashAddEntry(hash, strval, strval);
4579 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4585 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4591 * @nodes: a node-set
4593 * Implements the EXSLT - Sets distinct() function:
4594 * node-set set:distinct (node-set)
4595 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4596 * is called with the sorted node-set
4598 * Returns a subset of the nodes contained in @nodes, or @nodes if
4602 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4603 if (xmlXPathNodeSetIsEmpty(nodes))
4606 xmlXPathNodeSetSort(nodes);
4607 return(xmlXPathDistinctSorted(nodes));
4611 * xmlXPathHasSameNodes:
4612 * @nodes1: a node-set
4613 * @nodes2: a node-set
4615 * Implements the EXSLT - Sets has-same-nodes function:
4616 * boolean set:has-same-node(node-set, node-set)
4618 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4622 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4626 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4627 xmlXPathNodeSetIsEmpty(nodes2))
4630 l = xmlXPathNodeSetGetLength(nodes1);
4631 for (i = 0; i < l; i++) {
4632 cur = xmlXPathNodeSetItem(nodes1, i);
4633 if (xmlXPathNodeSetContains(nodes2, cur))
4640 * xmlXPathNodeLeadingSorted:
4641 * @nodes: a node-set, sorted by document order
4644 * Implements the EXSLT - Sets leading() function:
4645 * node-set set:leading (node-set, node-set)
4647 * Returns the nodes in @nodes that precede @node in document order,
4648 * @nodes if @node is NULL or an empty node-set if @nodes
4649 * doesn't contain @node
4652 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4660 ret = xmlXPathNodeSetCreate(NULL);
4663 if (xmlXPathNodeSetIsEmpty(nodes) ||
4664 (!xmlXPathNodeSetContains(nodes, node)))
4667 l = xmlXPathNodeSetGetLength(nodes);
4668 for (i = 0; i < l; i++) {
4669 cur = xmlXPathNodeSetItem(nodes, i);
4672 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4679 * xmlXPathNodeLeading:
4680 * @nodes: a node-set
4683 * Implements the EXSLT - Sets leading() function:
4684 * node-set set:leading (node-set, node-set)
4685 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4688 * Returns the nodes in @nodes that precede @node in document order,
4689 * @nodes if @node is NULL or an empty node-set if @nodes
4690 * doesn't contain @node
4693 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4694 xmlXPathNodeSetSort(nodes);
4695 return(xmlXPathNodeLeadingSorted(nodes, node));
4699 * xmlXPathLeadingSorted:
4700 * @nodes1: a node-set, sorted by document order
4701 * @nodes2: a node-set, sorted by document order
4703 * Implements the EXSLT - Sets leading() function:
4704 * node-set set:leading (node-set, node-set)
4706 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707 * in document order, @nodes1 if @nodes2 is NULL or empty or
4708 * an empty node-set if @nodes1 doesn't contain @nodes2
4711 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4712 if (xmlXPathNodeSetIsEmpty(nodes2))
4714 return(xmlXPathNodeLeadingSorted(nodes1,
4715 xmlXPathNodeSetItem(nodes2, 1)));
4720 * @nodes1: a node-set
4721 * @nodes2: a node-set
4723 * Implements the EXSLT - Sets leading() function:
4724 * node-set set:leading (node-set, node-set)
4725 * @nodes1 and @nodes2 are sorted by document order, then
4726 * #exslSetsLeadingSorted is called.
4728 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4729 * in document order, @nodes1 if @nodes2 is NULL or empty or
4730 * an empty node-set if @nodes1 doesn't contain @nodes2
4733 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4734 if (xmlXPathNodeSetIsEmpty(nodes2))
4736 if (xmlXPathNodeSetIsEmpty(nodes1))
4737 return(xmlXPathNodeSetCreate(NULL));
4738 xmlXPathNodeSetSort(nodes1);
4739 xmlXPathNodeSetSort(nodes2);
4740 return(xmlXPathNodeLeadingSorted(nodes1,
4741 xmlXPathNodeSetItem(nodes2, 1)));
4745 * xmlXPathNodeTrailingSorted:
4746 * @nodes: a node-set, sorted by document order
4749 * Implements the EXSLT - Sets trailing() function:
4750 * node-set set:trailing (node-set, node-set)
4752 * Returns the nodes in @nodes that follow @node in document order,
4753 * @nodes if @node is NULL or an empty node-set if @nodes
4754 * doesn't contain @node
4757 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4765 ret = xmlXPathNodeSetCreate(NULL);
4768 if (xmlXPathNodeSetIsEmpty(nodes) ||
4769 (!xmlXPathNodeSetContains(nodes, node)))
4772 l = xmlXPathNodeSetGetLength(nodes);
4773 for (i = l - 1; i >= 0; i--) {
4774 cur = xmlXPathNodeSetItem(nodes, i);
4777 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4780 xmlXPathNodeSetSort(ret); /* bug 413451 */
4785 * xmlXPathNodeTrailing:
4786 * @nodes: a node-set
4789 * Implements the EXSLT - Sets trailing() function:
4790 * node-set set:trailing (node-set, node-set)
4791 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4794 * Returns the nodes in @nodes that follow @node in document order,
4795 * @nodes if @node is NULL or an empty node-set if @nodes
4796 * doesn't contain @node
4799 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4800 xmlXPathNodeSetSort(nodes);
4801 return(xmlXPathNodeTrailingSorted(nodes, node));
4805 * xmlXPathTrailingSorted:
4806 * @nodes1: a node-set, sorted by document order
4807 * @nodes2: a node-set, sorted by document order
4809 * Implements the EXSLT - Sets trailing() function:
4810 * node-set set:trailing (node-set, node-set)
4812 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813 * in document order, @nodes1 if @nodes2 is NULL or empty or
4814 * an empty node-set if @nodes1 doesn't contain @nodes2
4817 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4818 if (xmlXPathNodeSetIsEmpty(nodes2))
4820 return(xmlXPathNodeTrailingSorted(nodes1,
4821 xmlXPathNodeSetItem(nodes2, 0)));
4826 * @nodes1: a node-set
4827 * @nodes2: a node-set
4829 * Implements the EXSLT - Sets trailing() function:
4830 * node-set set:trailing (node-set, node-set)
4831 * @nodes1 and @nodes2 are sorted by document order, then
4832 * #xmlXPathTrailingSorted is called.
4834 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4835 * in document order, @nodes1 if @nodes2 is NULL or empty or
4836 * an empty node-set if @nodes1 doesn't contain @nodes2
4839 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4840 if (xmlXPathNodeSetIsEmpty(nodes2))
4842 if (xmlXPathNodeSetIsEmpty(nodes1))
4843 return(xmlXPathNodeSetCreate(NULL));
4844 xmlXPathNodeSetSort(nodes1);
4845 xmlXPathNodeSetSort(nodes2);
4846 return(xmlXPathNodeTrailingSorted(nodes1,
4847 xmlXPathNodeSetItem(nodes2, 0)));
4850 /************************************************************************
4852 * Routines to handle extra functions *
4854 ************************************************************************/
4857 * xmlXPathRegisterFunc:
4858 * @ctxt: the XPath context
4859 * @name: the function name
4860 * @f: the function implementation or NULL
4862 * Register a new function. If @f is NULL it unregisters the function
4864 * Returns 0 in case of success, -1 in case of error
4867 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4868 xmlXPathFunction f) {
4869 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4873 * xmlXPathRegisterFuncNS:
4874 * @ctxt: the XPath context
4875 * @name: the function name
4876 * @ns_uri: the function namespace URI
4877 * @f: the function implementation or NULL
4879 * Register a new function. If @f is NULL it unregisters the function
4881 * Returns 0 in case of success, -1 in case of error
4884 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4885 const xmlChar *ns_uri, xmlXPathFunction f) {
4891 if (ctxt->funcHash == NULL)
4892 ctxt->funcHash = xmlHashCreate(0);
4893 if (ctxt->funcHash == NULL)
4896 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4897 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4901 * xmlXPathRegisterFuncLookup:
4902 * @ctxt: the XPath context
4903 * @f: the lookup function
4904 * @funcCtxt: the lookup data
4906 * Registers an external mechanism to do function lookup.
4909 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4910 xmlXPathFuncLookupFunc f,
4914 ctxt->funcLookupFunc = f;
4915 ctxt->funcLookupData = funcCtxt;
4919 * xmlXPathFunctionLookup:
4920 * @ctxt: the XPath context
4921 * @name: the function name
4923 * Search in the Function array of the context for the given
4926 * Returns the xmlXPathFunction or NULL if not found
4929 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4933 if (ctxt->funcLookupFunc != NULL) {
4934 xmlXPathFunction ret;
4935 xmlXPathFuncLookupFunc f;
4937 f = ctxt->funcLookupFunc;
4938 ret = f(ctxt->funcLookupData, name, NULL);
4942 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4946 * xmlXPathFunctionLookupNS:
4947 * @ctxt: the XPath context
4948 * @name: the function name
4949 * @ns_uri: the function namespace URI
4951 * Search in the Function array of the context for the given
4954 * Returns the xmlXPathFunction or NULL if not found
4957 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4958 const xmlChar *ns_uri) {
4959 xmlXPathFunction ret;
4966 if (ctxt->funcLookupFunc != NULL) {
4967 xmlXPathFuncLookupFunc f;
4969 f = ctxt->funcLookupFunc;
4970 ret = f(ctxt->funcLookupData, name, ns_uri);
4975 if (ctxt->funcHash == NULL)
4978 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4983 * xmlXPathRegisteredFuncsCleanup:
4984 * @ctxt: the XPath context
4986 * Cleanup the XPath context data associated to registered functions
4989 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4993 xmlHashFree(ctxt->funcHash, NULL);
4994 ctxt->funcHash = NULL;
4997 /************************************************************************
4999 * Routines to handle Variables *
5001 ************************************************************************/
5004 * xmlXPathRegisterVariable:
5005 * @ctxt: the XPath context
5006 * @name: the variable name
5007 * @value: the variable value or NULL
5009 * Register a new variable value. If @value is NULL it unregisters
5012 * Returns 0 in case of success, -1 in case of error
5015 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5016 xmlXPathObjectPtr value) {
5017 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5021 * xmlXPathRegisterVariableNS:
5022 * @ctxt: the XPath context
5023 * @name: the variable name
5024 * @ns_uri: the variable namespace URI
5025 * @value: the variable value or NULL
5027 * Register a new variable value. If @value is NULL it unregisters
5030 * Returns 0 in case of success, -1 in case of error
5033 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5034 const xmlChar *ns_uri,
5035 xmlXPathObjectPtr value) {
5041 if (ctxt->varHash == NULL)
5042 ctxt->varHash = xmlHashCreate(0);
5043 if (ctxt->varHash == NULL)
5046 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5047 (xmlHashDeallocator)xmlXPathFreeObject));
5048 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5050 (xmlHashDeallocator)xmlXPathFreeObject));
5054 * xmlXPathRegisterVariableLookup:
5055 * @ctxt: the XPath context
5056 * @f: the lookup function
5057 * @data: the lookup data
5059 * register an external mechanism to do variable lookup
5062 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5063 xmlXPathVariableLookupFunc f, void *data) {
5066 ctxt->varLookupFunc = f;
5067 ctxt->varLookupData = data;
5071 * xmlXPathVariableLookup:
5072 * @ctxt: the XPath context
5073 * @name: the variable name
5075 * Search in the Variable array of the context for the given
5078 * Returns a copy of the value or NULL if not found
5081 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5085 if (ctxt->varLookupFunc != NULL) {
5086 xmlXPathObjectPtr ret;
5088 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5089 (ctxt->varLookupData, name, NULL);
5092 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5096 * xmlXPathVariableLookupNS:
5097 * @ctxt: the XPath context
5098 * @name: the variable name
5099 * @ns_uri: the variable namespace URI
5101 * Search in the Variable array of the context for the given
5104 * Returns the a copy of the value or NULL if not found
5107 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5108 const xmlChar *ns_uri) {
5112 if (ctxt->varLookupFunc != NULL) {
5113 xmlXPathObjectPtr ret;
5115 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5116 (ctxt->varLookupData, name, ns_uri);
5117 if (ret != NULL) return(ret);
5120 if (ctxt->varHash == NULL)
5125 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5126 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5130 * xmlXPathRegisteredVariablesCleanup:
5131 * @ctxt: the XPath context
5133 * Cleanup the XPath context data associated to registered variables
5136 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5140 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5141 ctxt->varHash = NULL;
5145 * xmlXPathRegisterNs:
5146 * @ctxt: the XPath context
5147 * @prefix: the namespace prefix cannot be NULL or empty string
5148 * @ns_uri: the namespace name
5150 * Register a new namespace. If @ns_uri is NULL it unregisters
5153 * Returns 0 in case of success, -1 in case of error
5156 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5157 const xmlChar *ns_uri) {
5165 if (ctxt->nsHash == NULL)
5166 ctxt->nsHash = xmlHashCreate(10);
5167 if (ctxt->nsHash == NULL)
5170 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5171 (xmlHashDeallocator)xmlFree));
5172 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5173 (xmlHashDeallocator)xmlFree));
5178 * @ctxt: the XPath context
5179 * @prefix: the namespace prefix value
5181 * Search in the namespace declaration array of the context for the given
5182 * namespace name associated to the given prefix
5184 * Returns the value or NULL if not found
5187 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5193 #ifdef XML_XML_NAMESPACE
5194 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5195 return(XML_XML_NAMESPACE);
5198 if (ctxt->namespaces != NULL) {
5201 for (i = 0;i < ctxt->nsNr;i++) {
5202 if ((ctxt->namespaces[i] != NULL) &&
5203 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5204 return(ctxt->namespaces[i]->href);
5208 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5212 * xmlXPathRegisteredNsCleanup:
5213 * @ctxt: the XPath context
5215 * Cleanup the XPath context data associated to registered variables
5218 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5222 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5223 ctxt->nsHash = NULL;
5226 /************************************************************************
5228 * Routines to handle Values *
5230 ************************************************************************/
5232 /* Allocations are terrible, one needs to optimize all this !!! */
5236 * @val: the double value
5238 * Create a new xmlXPathObjectPtr of type double and of value @val
5240 * Returns the newly created object.
5243 xmlXPathNewFloat(double val) {
5244 xmlXPathObjectPtr ret;
5246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5248 xmlXPathErrMemory(NULL, "creating float object\n");
5251 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5252 ret->type = XPATH_NUMBER;
5253 ret->floatval = val;
5254 #ifdef XP_DEBUG_OBJ_USAGE
5255 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5261 * xmlXPathNewBoolean:
5262 * @val: the boolean value
5264 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5266 * Returns the newly created object.
5269 xmlXPathNewBoolean(int val) {
5270 xmlXPathObjectPtr ret;
5272 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5274 xmlXPathErrMemory(NULL, "creating boolean object\n");
5277 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5278 ret->type = XPATH_BOOLEAN;
5279 ret->boolval = (val != 0);
5280 #ifdef XP_DEBUG_OBJ_USAGE
5281 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5287 * xmlXPathNewString:
5288 * @val: the xmlChar * value
5290 * Create a new xmlXPathObjectPtr of type string and of value @val
5292 * Returns the newly created object.
5295 xmlXPathNewString(const xmlChar *val) {
5296 xmlXPathObjectPtr ret;
5298 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5300 xmlXPathErrMemory(NULL, "creating string object\n");
5303 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5304 ret->type = XPATH_STRING;
5306 ret->stringval = xmlStrdup(val);
5308 ret->stringval = xmlStrdup((const xmlChar *)"");
5309 #ifdef XP_DEBUG_OBJ_USAGE
5310 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5316 * xmlXPathWrapString:
5317 * @val: the xmlChar * value
5319 * Wraps the @val string into an XPath object.
5321 * Returns the newly created object.
5324 xmlXPathWrapString (xmlChar *val) {
5325 xmlXPathObjectPtr ret;
5327 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5329 xmlXPathErrMemory(NULL, "creating string object\n");
5332 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5333 ret->type = XPATH_STRING;
5334 ret->stringval = val;
5335 #ifdef XP_DEBUG_OBJ_USAGE
5336 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5342 * xmlXPathNewCString:
5343 * @val: the char * value
5345 * Create a new xmlXPathObjectPtr of type string and of value @val
5347 * Returns the newly created object.
5350 xmlXPathNewCString(const char *val) {
5351 xmlXPathObjectPtr ret;
5353 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5355 xmlXPathErrMemory(NULL, "creating string object\n");
5358 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5359 ret->type = XPATH_STRING;
5360 ret->stringval = xmlStrdup(BAD_CAST val);
5361 #ifdef XP_DEBUG_OBJ_USAGE
5362 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5368 * xmlXPathWrapCString:
5369 * @val: the char * value
5371 * Wraps a string into an XPath object.
5373 * Returns the newly created object.
5376 xmlXPathWrapCString (char * val) {
5377 return(xmlXPathWrapString((xmlChar *)(val)));
5381 * xmlXPathWrapExternal:
5382 * @val: the user data
5384 * Wraps the @val data into an XPath object.
5386 * Returns the newly created object.
5389 xmlXPathWrapExternal (void *val) {
5390 xmlXPathObjectPtr ret;
5392 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5394 xmlXPathErrMemory(NULL, "creating user object\n");
5397 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5398 ret->type = XPATH_USERS;
5400 #ifdef XP_DEBUG_OBJ_USAGE
5401 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5407 * xmlXPathObjectCopy:
5408 * @val: the original object
5410 * allocate a new copy of a given object
5412 * Returns the newly created object.
5415 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5416 xmlXPathObjectPtr ret;
5421 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5423 xmlXPathErrMemory(NULL, "copying object\n");
5426 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5427 #ifdef XP_DEBUG_OBJ_USAGE
5428 xmlXPathDebugObjUsageRequested(NULL, val->type);
5430 switch (val->type) {
5437 ret->stringval = xmlStrdup(val->stringval);
5439 case XPATH_XSLT_TREE:
5442 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5443 this previous handling is no longer correct, and can cause some serious
5444 problems (ref. bug 145547)
5446 if ((val->nodesetval != NULL) &&
5447 (val->nodesetval->nodeTab != NULL)) {
5448 xmlNodePtr cur, tmp;
5452 top = xmlNewDoc(NULL);
5453 top->name = (char *)
5454 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5458 cur = val->nodesetval->nodeTab[0]->children;
5459 while (cur != NULL) {
5460 tmp = xmlDocCopyNode(cur, top, 1);
5461 xmlAddChild((xmlNodePtr) top, tmp);
5466 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5468 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5469 /* Deallocate the copied tree value */
5473 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5474 /* Do not deallocate the copied tree value */
5477 case XPATH_LOCATIONSET:
5478 #ifdef LIBXML_XPTR_ENABLED
5480 xmlLocationSetPtr loc = val->user;
5481 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5486 ret->user = val->user;
5488 case XPATH_UNDEFINED:
5489 xmlGenericError(xmlGenericErrorContext,
5490 "xmlXPathObjectCopy: unsupported type %d\n",
5498 * xmlXPathFreeObject:
5499 * @obj: the object to free
5501 * Free up an xmlXPathObjectPtr object.
5504 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5505 if (obj == NULL) return;
5506 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5509 if (obj->user != NULL) {
5510 xmlXPathFreeNodeSet(obj->nodesetval);
5511 xmlFreeNodeList((xmlNodePtr) obj->user);
5514 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5515 if (obj->nodesetval != NULL)
5516 xmlXPathFreeValueTree(obj->nodesetval);
5518 if (obj->nodesetval != NULL)
5519 xmlXPathFreeNodeSet(obj->nodesetval);
5521 #ifdef LIBXML_XPTR_ENABLED
5522 } else if (obj->type == XPATH_LOCATIONSET) {
5523 if (obj->user != NULL)
5524 xmlXPtrFreeLocationSet(obj->user);
5526 } else if (obj->type == XPATH_STRING) {
5527 if (obj->stringval != NULL)
5528 xmlFree(obj->stringval);
5530 #ifdef XP_DEBUG_OBJ_USAGE
5531 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5537 * xmlXPathReleaseObject:
5538 * @obj: the xmlXPathObjectPtr to free or to cache
5540 * Depending on the state of the cache this frees the given
5541 * XPath object or stores it in the cache.
5544 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5546 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5547 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5548 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5550 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5554 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5555 xmlXPathFreeObject(obj);
5557 xmlXPathContextCachePtr cache =
5558 (xmlXPathContextCachePtr) ctxt->cache;
5560 switch (obj->type) {
5562 case XPATH_XSLT_TREE:
5563 if (obj->nodesetval != NULL) {
5566 * It looks like the @boolval is used for
5567 * evaluation if this an XSLT Result Tree Fragment.
5568 * TODO: Check if this assumption is correct.
5570 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5571 xmlXPathFreeValueTree(obj->nodesetval);
5572 obj->nodesetval = NULL;
5573 } else if ((obj->nodesetval->nodeMax <= 40) &&
5574 (XP_CACHE_WANTS(cache->nodesetObjs,
5575 cache->maxNodeset)))
5577 XP_CACHE_ADD(cache->nodesetObjs, obj);
5580 xmlXPathFreeNodeSet(obj->nodesetval);
5581 obj->nodesetval = NULL;
5586 if (obj->stringval != NULL)
5587 xmlFree(obj->stringval);
5589 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5590 XP_CACHE_ADD(cache->stringObjs, obj);
5595 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5596 XP_CACHE_ADD(cache->booleanObjs, obj);
5601 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5602 XP_CACHE_ADD(cache->numberObjs, obj);
5606 #ifdef LIBXML_XPTR_ENABLED
5607 case XPATH_LOCATIONSET:
5608 if (obj->user != NULL) {
5609 xmlXPtrFreeLocationSet(obj->user);
5618 * Fallback to adding to the misc-objects slot.
5620 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5621 XP_CACHE_ADD(cache->miscObjs, obj);
5627 #ifdef XP_DEBUG_OBJ_USAGE
5628 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5631 if (obj->nodesetval != NULL) {
5632 xmlNodeSetPtr tmpset = obj->nodesetval;
5635 * TODO: Due to those nasty ns-nodes, we need to traverse
5636 * the list and free the ns-nodes.
5637 * URGENT TODO: Check if it's actually slowing things down.
5638 * Maybe we shouldn't try to preserve the list.
5640 if (tmpset->nodeNr > 1) {
5644 for (i = 0; i < tmpset->nodeNr; i++) {
5645 node = tmpset->nodeTab[i];
5646 if ((node != NULL) &&
5647 (node->type == XML_NAMESPACE_DECL))
5649 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5652 } else if (tmpset->nodeNr == 1) {
5653 if ((tmpset->nodeTab[0] != NULL) &&
5654 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5655 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5658 memset(obj, 0, sizeof(xmlXPathObject));
5659 obj->nodesetval = tmpset;
5661 memset(obj, 0, sizeof(xmlXPathObject));
5667 * Cache is full; free the object.
5669 if (obj->nodesetval != NULL)
5670 xmlXPathFreeNodeSet(obj->nodesetval);
5671 #ifdef XP_DEBUG_OBJ_USAGE
5672 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5680 /************************************************************************
5682 * Type Casting Routines *
5684 ************************************************************************/
5687 * xmlXPathCastBooleanToString:
5690 * Converts a boolean to its string value.
5692 * Returns a newly allocated string.
5695 xmlXPathCastBooleanToString (int val) {
5698 ret = xmlStrdup((const xmlChar *) "true");
5700 ret = xmlStrdup((const xmlChar *) "false");
5705 * xmlXPathCastNumberToString:
5708 * Converts a number to its string value.
5710 * Returns a newly allocated string.
5713 xmlXPathCastNumberToString (double val) {
5715 switch (xmlXPathIsInf(val)) {
5717 ret = xmlStrdup((const xmlChar *) "Infinity");
5720 ret = xmlStrdup((const xmlChar *) "-Infinity");
5723 if (xmlXPathIsNaN(val)) {
5724 ret = xmlStrdup((const xmlChar *) "NaN");
5725 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5726 ret = xmlStrdup((const xmlChar *) "0");
5728 /* could be improved */
5730 xmlXPathFormatNumber(val, buf, 99);
5732 ret = xmlStrdup((const xmlChar *) buf);
5739 * xmlXPathCastNodeToString:
5742 * Converts a node to its string value.
5744 * Returns a newly allocated string.
5747 xmlXPathCastNodeToString (xmlNodePtr node) {
5749 if ((ret = xmlNodeGetContent(node)) == NULL)
5750 ret = xmlStrdup((const xmlChar *) "");
5755 * xmlXPathCastNodeSetToString:
5758 * Converts a node-set to its string value.
5760 * Returns a newly allocated string.
5763 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5764 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5765 return(xmlStrdup((const xmlChar *) ""));
5768 xmlXPathNodeSetSort(ns);
5769 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5773 * xmlXPathCastToString:
5774 * @val: an XPath object
5776 * Converts an existing object to its string() equivalent
5778 * Returns the allocated string value of the object, NULL in case of error.
5779 * It's up to the caller to free the string memory with xmlFree().
5782 xmlXPathCastToString(xmlXPathObjectPtr val) {
5783 xmlChar *ret = NULL;
5786 return(xmlStrdup((const xmlChar *) ""));
5787 switch (val->type) {
5788 case XPATH_UNDEFINED:
5790 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5792 ret = xmlStrdup((const xmlChar *) "");
5795 case XPATH_XSLT_TREE:
5796 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5799 return(xmlStrdup(val->stringval));
5801 ret = xmlXPathCastBooleanToString(val->boolval);
5803 case XPATH_NUMBER: {
5804 ret = xmlXPathCastNumberToString(val->floatval);
5810 case XPATH_LOCATIONSET:
5812 ret = xmlStrdup((const xmlChar *) "");
5819 * xmlXPathConvertString:
5820 * @val: an XPath object
5822 * Converts an existing object to its string() equivalent
5824 * Returns the new object, the old one is freed (or the operation
5825 * is done directly on @val)
5828 xmlXPathConvertString(xmlXPathObjectPtr val) {
5829 xmlChar *res = NULL;
5832 return(xmlXPathNewCString(""));
5834 switch (val->type) {
5835 case XPATH_UNDEFINED:
5837 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5841 case XPATH_XSLT_TREE:
5842 res = xmlXPathCastNodeSetToString(val->nodesetval);
5847 res = xmlXPathCastBooleanToString(val->boolval);
5850 res = xmlXPathCastNumberToString(val->floatval);
5855 case XPATH_LOCATIONSET:
5859 xmlXPathFreeObject(val);
5861 return(xmlXPathNewCString(""));
5862 return(xmlXPathWrapString(res));
5866 * xmlXPathCastBooleanToNumber:
5869 * Converts a boolean to its number value
5871 * Returns the number value
5874 xmlXPathCastBooleanToNumber(int val) {
5881 * xmlXPathCastStringToNumber:
5884 * Converts a string to its number value
5886 * Returns the number value
5889 xmlXPathCastStringToNumber(const xmlChar * val) {
5890 return(xmlXPathStringEvalNumber(val));
5894 * xmlXPathCastNodeToNumber:
5897 * Converts a node to its number value
5899 * Returns the number value
5902 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5907 return(xmlXPathNAN);
5908 strval = xmlXPathCastNodeToString(node);
5910 return(xmlXPathNAN);
5911 ret = xmlXPathCastStringToNumber(strval);
5918 * xmlXPathCastNodeSetToNumber:
5921 * Converts a node-set to its number value
5923 * Returns the number value
5926 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5931 return(xmlXPathNAN);
5932 str = xmlXPathCastNodeSetToString(ns);
5933 ret = xmlXPathCastStringToNumber(str);
5939 * xmlXPathCastToNumber:
5940 * @val: an XPath object
5942 * Converts an XPath object to its number value
5944 * Returns the number value
5947 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5951 return(xmlXPathNAN);
5952 switch (val->type) {
5953 case XPATH_UNDEFINED:
5955 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5960 case XPATH_XSLT_TREE:
5961 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5964 ret = xmlXPathCastStringToNumber(val->stringval);
5967 ret = val->floatval;
5970 ret = xmlXPathCastBooleanToNumber(val->boolval);
5975 case XPATH_LOCATIONSET:
5984 * xmlXPathConvertNumber:
5985 * @val: an XPath object
5987 * Converts an existing object to its number() equivalent
5989 * Returns the new object, the old one is freed (or the operation
5990 * is done directly on @val)
5993 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5994 xmlXPathObjectPtr ret;
5997 return(xmlXPathNewFloat(0.0));
5998 if (val->type == XPATH_NUMBER)
6000 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6001 xmlXPathFreeObject(val);
6006 * xmlXPathCastNumberToBoolean:
6009 * Converts a number to its boolean value
6011 * Returns the boolean value
6014 xmlXPathCastNumberToBoolean (double val) {
6015 if (xmlXPathIsNaN(val) || (val == 0.0))
6021 * xmlXPathCastStringToBoolean:
6024 * Converts a string to its boolean value
6026 * Returns the boolean value
6029 xmlXPathCastStringToBoolean (const xmlChar *val) {
6030 if ((val == NULL) || (xmlStrlen(val) == 0))
6036 * xmlXPathCastNodeSetToBoolean:
6039 * Converts a node-set to its boolean value
6041 * Returns the boolean value
6044 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6045 if ((ns == NULL) || (ns->nodeNr == 0))
6051 * xmlXPathCastToBoolean:
6052 * @val: an XPath object
6054 * Converts an XPath object to its boolean value
6056 * Returns the boolean value
6059 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6064 switch (val->type) {
6065 case XPATH_UNDEFINED:
6067 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6072 case XPATH_XSLT_TREE:
6073 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6076 ret = xmlXPathCastStringToBoolean(val->stringval);
6079 ret = xmlXPathCastNumberToBoolean(val->floatval);
6087 case XPATH_LOCATIONSET:
6097 * xmlXPathConvertBoolean:
6098 * @val: an XPath object
6100 * Converts an existing object to its boolean() equivalent
6102 * Returns the new object, the old one is freed (or the operation
6103 * is done directly on @val)
6106 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6107 xmlXPathObjectPtr ret;
6110 return(xmlXPathNewBoolean(0));
6111 if (val->type == XPATH_BOOLEAN)
6113 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6114 xmlXPathFreeObject(val);
6118 /************************************************************************
6120 * Routines to handle XPath contexts *
6122 ************************************************************************/
6125 * xmlXPathNewContext:
6126 * @doc: the XML document
6128 * Create a new xmlXPathContext
6130 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6133 xmlXPathNewContext(xmlDocPtr doc) {
6134 xmlXPathContextPtr ret;
6136 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6138 xmlXPathErrMemory(NULL, "creating context\n");
6141 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6145 ret->varHash = NULL;
6151 ret->funcHash = xmlHashCreate(0);
6160 ret->contextSize = -1;
6161 ret->proximityPosition = -1;
6163 #ifdef XP_DEFAULT_CACHE_ON
6164 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6165 xmlXPathFreeContext(ret);
6170 xmlXPathRegisterAllFunctions(ret);
6176 * xmlXPathFreeContext:
6177 * @ctxt: the context to free
6179 * Free up an xmlXPathContext
6182 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6183 if (ctxt == NULL) return;
6185 if (ctxt->cache != NULL)
6186 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6187 xmlXPathRegisteredNsCleanup(ctxt);
6188 xmlXPathRegisteredFuncsCleanup(ctxt);
6189 xmlXPathRegisteredVariablesCleanup(ctxt);
6190 xmlResetError(&ctxt->lastError);
6194 /************************************************************************
6196 * Routines to handle XPath parser contexts *
6198 ************************************************************************/
6200 #define CHECK_CTXT(ctxt) \
6201 if (ctxt == NULL) { \
6202 __xmlRaiseError(NULL, NULL, NULL, \
6203 NULL, NULL, XML_FROM_XPATH, \
6204 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6205 __FILE__, __LINE__, \
6206 NULL, NULL, NULL, 0, 0, \
6207 "NULL context pointer\n"); \
6211 #define CHECK_CTXT_NEG(ctxt) \
6212 if (ctxt == NULL) { \
6213 __xmlRaiseError(NULL, NULL, NULL, \
6214 NULL, NULL, XML_FROM_XPATH, \
6215 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6216 __FILE__, __LINE__, \
6217 NULL, NULL, NULL, 0, 0, \
6218 "NULL context pointer\n"); \
6223 #define CHECK_CONTEXT(ctxt) \
6224 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6225 (ctxt->doc->children == NULL)) { \
6226 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6232 * xmlXPathNewParserContext:
6233 * @str: the XPath expression
6234 * @ctxt: the XPath context
6236 * Create a new xmlXPathParserContext
6238 * Returns the xmlXPathParserContext just allocated.
6240 xmlXPathParserContextPtr
6241 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6242 xmlXPathParserContextPtr ret;
6244 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6246 xmlXPathErrMemory(ctxt, "creating parser context\n");
6249 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6250 ret->cur = ret->base = str;
6251 ret->context = ctxt;
6253 ret->comp = xmlXPathNewCompExpr();
6254 if (ret->comp == NULL) {
6255 xmlFree(ret->valueTab);
6259 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6260 ret->comp->dict = ctxt->dict;
6261 xmlDictReference(ret->comp->dict);
6268 * xmlXPathCompParserContext:
6269 * @comp: the XPath compiled expression
6270 * @ctxt: the XPath context
6272 * Create a new xmlXPathParserContext when processing a compiled expression
6274 * Returns the xmlXPathParserContext just allocated.
6276 static xmlXPathParserContextPtr
6277 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6278 xmlXPathParserContextPtr ret;
6280 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6282 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6285 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6287 /* Allocate the value stack */
6288 ret->valueTab = (xmlXPathObjectPtr *)
6289 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6290 if (ret->valueTab == NULL) {
6292 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6298 ret->valueFrame = 0;
6300 ret->context = ctxt;
6307 * xmlXPathFreeParserContext:
6308 * @ctxt: the context to free
6310 * Free up an xmlXPathParserContext
6313 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6316 if (ctxt->valueTab != NULL) {
6317 for (i = 0; i < ctxt->valueNr; i++) {
6319 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6321 xmlXPathFreeObject(ctxt->valueTab[i]);
6323 xmlFree(ctxt->valueTab);
6325 if (ctxt->comp != NULL) {
6326 #ifdef XPATH_STREAMING
6327 if (ctxt->comp->stream != NULL) {
6328 xmlFreePatternList(ctxt->comp->stream);
6329 ctxt->comp->stream = NULL;
6332 xmlXPathFreeCompExpr(ctxt->comp);
6337 /************************************************************************
6339 * The implicit core function library *
6341 ************************************************************************/
6344 * xmlXPathNodeValHash:
6345 * @node: a node pointer
6347 * Function computing the beginning of the string value of the node,
6348 * used to speed up comparisons
6350 * Returns an int usable as a hash
6353 xmlXPathNodeValHash(xmlNodePtr node) {
6355 const xmlChar * string = NULL;
6356 xmlNodePtr tmp = NULL;
6357 unsigned int ret = 0;
6362 if (node->type == XML_DOCUMENT_NODE) {
6363 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6365 node = node->children;
6373 switch (node->type) {
6374 case XML_COMMENT_NODE:
6376 case XML_CDATA_SECTION_NODE:
6378 string = node->content;
6383 return(((unsigned int) string[0]) +
6384 (((unsigned int) string[1]) << 8));
6385 case XML_NAMESPACE_DECL:
6386 string = ((xmlNsPtr)node)->href;
6391 return(((unsigned int) string[0]) +
6392 (((unsigned int) string[1]) << 8));
6393 case XML_ATTRIBUTE_NODE:
6394 tmp = ((xmlAttrPtr) node)->children;
6396 case XML_ELEMENT_NODE:
6397 tmp = node->children;
6402 while (tmp != NULL) {
6403 switch (tmp->type) {
6404 case XML_CDATA_SECTION_NODE:
6406 string = tmp->content;
6412 if ((string != NULL) && (string[0] != 0)) {
6414 return(ret + (((unsigned int) string[0]) << 8));
6416 if (string[1] == 0) {
6418 ret = (unsigned int) string[0];
6420 return(((unsigned int) string[0]) +
6421 (((unsigned int) string[1]) << 8));
6427 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6428 if (tmp->children->type != XML_ENTITY_DECL) {
6429 tmp = tmp->children;
6436 if (tmp->next != NULL) {
6449 if (tmp->next != NULL) {
6453 } while (tmp != NULL);
6459 * xmlXPathStringHash:
6462 * Function computing the beginning of the string value of the node,
6463 * used to speed up comparisons
6465 * Returns an int usable as a hash
6468 xmlXPathStringHash(const xmlChar * string) {
6470 return((unsigned int) 0);
6473 return(((unsigned int) string[0]) +
6474 (((unsigned int) string[1]) << 8));
6478 * xmlXPathCompareNodeSetFloat:
6479 * @ctxt: the XPath Parser context
6480 * @inf: less than (1) or greater than (0)
6481 * @strict: is the comparison strict
6482 * @arg: the node set
6485 * Implement the compare operation between a nodeset and a number
6486 * @ns < @val (1, 1, ...
6487 * @ns <= @val (1, 0, ...
6488 * @ns > @val (0, 1, ...
6489 * @ns >= @val (0, 0, ...
6491 * If one object to be compared is a node-set and the other is a number,
6492 * then the comparison will be true if and only if there is a node in the
6493 * node-set such that the result of performing the comparison on the number
6494 * to be compared and on the result of converting the string-value of that
6495 * node to a number using the number function is true.
6497 * Returns 0 or 1 depending on the results of the test.
6500 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6501 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6506 if ((f == NULL) || (arg == NULL) ||
6507 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6508 xmlXPathReleaseObject(ctxt->context, arg);
6509 xmlXPathReleaseObject(ctxt->context, f);
6512 ns = arg->nodesetval;
6514 for (i = 0;i < ns->nodeNr;i++) {
6515 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6518 xmlXPathCacheNewString(ctxt->context, str2));
6520 xmlXPathNumberFunction(ctxt, 1);
6521 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6522 ret = xmlXPathCompareValues(ctxt, inf, strict);
6528 xmlXPathReleaseObject(ctxt->context, arg);
6529 xmlXPathReleaseObject(ctxt->context, f);
6534 * xmlXPathCompareNodeSetString:
6535 * @ctxt: the XPath Parser context
6536 * @inf: less than (1) or greater than (0)
6537 * @strict: is the comparison strict
6538 * @arg: the node set
6541 * Implement the compare operation between a nodeset and a string
6542 * @ns < @val (1, 1, ...
6543 * @ns <= @val (1, 0, ...
6544 * @ns > @val (0, 1, ...
6545 * @ns >= @val (0, 0, ...
6547 * If one object to be compared is a node-set and the other is a string,
6548 * then the comparison will be true if and only if there is a node in
6549 * the node-set such that the result of performing the comparison on the
6550 * string-value of the node and the other string is true.
6552 * Returns 0 or 1 depending on the results of the test.
6555 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6556 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6561 if ((s == NULL) || (arg == NULL) ||
6562 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6563 xmlXPathReleaseObject(ctxt->context, arg);
6564 xmlXPathReleaseObject(ctxt->context, s);
6567 ns = arg->nodesetval;
6569 for (i = 0;i < ns->nodeNr;i++) {
6570 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6573 xmlXPathCacheNewString(ctxt->context, str2));
6575 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6576 ret = xmlXPathCompareValues(ctxt, inf, strict);
6582 xmlXPathReleaseObject(ctxt->context, arg);
6583 xmlXPathReleaseObject(ctxt->context, s);
6588 * xmlXPathCompareNodeSets:
6589 * @inf: less than (1) or greater than (0)
6590 * @strict: is the comparison strict
6591 * @arg1: the first node set object
6592 * @arg2: the second node set object
6594 * Implement the compare operation on nodesets:
6596 * If both objects to be compared are node-sets, then the comparison
6597 * will be true if and only if there is a node in the first node-set
6598 * and a node in the second node-set such that the result of performing
6599 * the comparison on the string-values of the two nodes is true.
6601 * When neither object to be compared is a node-set and the operator
6602 * is <=, <, >= or >, then the objects are compared by converting both
6603 * objects to numbers and comparing the numbers according to IEEE 754.
6605 * The number function converts its argument to a number as follows:
6606 * - a string that consists of optional whitespace followed by an
6607 * optional minus sign followed by a Number followed by whitespace
6608 * is converted to the IEEE 754 number that is nearest (according
6609 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6610 * represented by the string; any other string is converted to NaN
6612 * Conclusion all nodes need to be converted first to their string value
6613 * and then the comparison must be done when possible
6616 xmlXPathCompareNodeSets(int inf, int strict,
6617 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6625 if ((arg1 == NULL) ||
6626 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6627 xmlXPathFreeObject(arg2);
6630 if ((arg2 == NULL) ||
6631 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6632 xmlXPathFreeObject(arg1);
6633 xmlXPathFreeObject(arg2);
6637 ns1 = arg1->nodesetval;
6638 ns2 = arg2->nodesetval;
6640 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6641 xmlXPathFreeObject(arg1);
6642 xmlXPathFreeObject(arg2);
6645 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6646 xmlXPathFreeObject(arg1);
6647 xmlXPathFreeObject(arg2);
6651 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6652 if (values2 == NULL) {
6653 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6654 xmlXPathFreeObject(arg1);
6655 xmlXPathFreeObject(arg2);
6658 for (i = 0;i < ns1->nodeNr;i++) {
6659 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6660 if (xmlXPathIsNaN(val1))
6662 for (j = 0;j < ns2->nodeNr;j++) {
6664 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6666 if (xmlXPathIsNaN(values2[j]))
6669 ret = (val1 < values2[j]);
6670 else if (inf && !strict)
6671 ret = (val1 <= values2[j]);
6672 else if (!inf && strict)
6673 ret = (val1 > values2[j]);
6674 else if (!inf && !strict)
6675 ret = (val1 >= values2[j]);
6684 xmlXPathFreeObject(arg1);
6685 xmlXPathFreeObject(arg2);
6690 * xmlXPathCompareNodeSetValue:
6691 * @ctxt: the XPath Parser context
6692 * @inf: less than (1) or greater than (0)
6693 * @strict: is the comparison strict
6694 * @arg: the node set
6697 * Implement the compare operation between a nodeset and a value
6698 * @ns < @val (1, 1, ...
6699 * @ns <= @val (1, 0, ...
6700 * @ns > @val (0, 1, ...
6701 * @ns >= @val (0, 0, ...
6703 * If one object to be compared is a node-set and the other is a boolean,
6704 * then the comparison will be true if and only if the result of performing
6705 * the comparison on the boolean and on the result of converting
6706 * the node-set to a boolean using the boolean function is true.
6708 * Returns 0 or 1 depending on the results of the test.
6711 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6712 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6713 if ((val == NULL) || (arg == NULL) ||
6714 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6719 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6721 case XPATH_XSLT_TREE:
6722 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6724 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6726 valuePush(ctxt, arg);
6727 xmlXPathBooleanFunction(ctxt, 1);
6728 valuePush(ctxt, val);
6729 return(xmlXPathCompareValues(ctxt, inf, strict));
6731 xmlGenericError(xmlGenericErrorContext,
6732 "xmlXPathCompareNodeSetValue: Can't compare node set "
6733 "and object of type %d\n",
6735 xmlXPathReleaseObject(ctxt->context, arg);
6736 xmlXPathReleaseObject(ctxt->context, val);
6737 XP_ERROR0(XPATH_INVALID_TYPE);
6743 * xmlXPathEqualNodeSetString:
6744 * @arg: the nodeset object argument
6745 * @str: the string to compare to.
6746 * @neq: flag to show whether for '=' (0) or '!=' (1)
6748 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6749 * If one object to be compared is a node-set and the other is a string,
6750 * then the comparison will be true if and only if there is a node in
6751 * the node-set such that the result of performing the comparison on the
6752 * string-value of the node and the other string is true.
6754 * Returns 0 or 1 depending on the results of the test.
6757 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6764 if ((str == NULL) || (arg == NULL) ||
6765 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6767 ns = arg->nodesetval;
6769 * A NULL nodeset compared with a string is always false
6770 * (since there is no node equal, and no node not equal)
6772 if ((ns == NULL) || (ns->nodeNr <= 0) )
6774 hash = xmlXPathStringHash(str);
6775 for (i = 0; i < ns->nodeNr; i++) {
6776 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6777 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6778 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6783 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6801 * xmlXPathEqualNodeSetFloat:
6802 * @arg: the nodeset object argument
6803 * @f: the float to compare to
6804 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6806 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6807 * If one object to be compared is a node-set and the other is a number,
6808 * then the comparison will be true if and only if there is a node in
6809 * the node-set such that the result of performing the comparison on the
6810 * number to be compared and on the result of converting the string-value
6811 * of that node to a number using the number function is true.
6813 * Returns 0 or 1 depending on the results of the test.
6816 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6817 xmlXPathObjectPtr arg, double f, int neq) {
6821 xmlXPathObjectPtr val;
6824 if ((arg == NULL) ||
6825 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6828 ns = arg->nodesetval;
6830 for (i=0;i<ns->nodeNr;i++) {
6831 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6833 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6835 xmlXPathNumberFunction(ctxt, 1);
6836 val = valuePop(ctxt);
6838 xmlXPathReleaseObject(ctxt->context, val);
6839 if (!xmlXPathIsNaN(v)) {
6840 if ((!neq) && (v==f)) {
6843 } else if ((neq) && (v!=f)) {
6847 } else { /* NaN is unequal to any value */
6860 * xmlXPathEqualNodeSets:
6861 * @arg1: first nodeset object argument
6862 * @arg2: second nodeset object argument
6863 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6865 * Implement the equal / not equal operation on XPath nodesets:
6866 * @arg1 == @arg2 or @arg1 != @arg2
6867 * If both objects to be compared are node-sets, then the comparison
6868 * will be true if and only if there is a node in the first node-set and
6869 * a node in the second node-set such that the result of performing the
6870 * comparison on the string-values of the two nodes is true.
6872 * (needless to say, this is a costly operation)
6874 * Returns 0 or 1 depending on the results of the test.
6877 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6879 unsigned int *hashs1;
6880 unsigned int *hashs2;
6887 if ((arg1 == NULL) ||
6888 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6890 if ((arg2 == NULL) ||
6891 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6894 ns1 = arg1->nodesetval;
6895 ns2 = arg2->nodesetval;
6897 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6899 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6903 * for equal, check if there is a node pertaining to both sets
6906 for (i = 0;i < ns1->nodeNr;i++)
6907 for (j = 0;j < ns2->nodeNr;j++)
6908 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6911 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6912 if (values1 == NULL) {
6913 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6916 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6917 if (hashs1 == NULL) {
6918 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6922 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6923 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6924 if (values2 == NULL) {
6925 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6930 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6931 if (hashs2 == NULL) {
6932 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6938 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6939 for (i = 0;i < ns1->nodeNr;i++) {
6940 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6941 for (j = 0;j < ns2->nodeNr;j++) {
6943 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6944 if (hashs1[i] != hashs2[j]) {
6951 if (values1[i] == NULL)
6952 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6953 if (values2[j] == NULL)
6954 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6955 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6963 for (i = 0;i < ns1->nodeNr;i++)
6964 if (values1[i] != NULL)
6965 xmlFree(values1[i]);
6966 for (j = 0;j < ns2->nodeNr;j++)
6967 if (values2[j] != NULL)
6968 xmlFree(values2[j]);
6977 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6978 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6981 *At this point we are assured neither arg1 nor arg2
6982 *is a nodeset, so we can just pick the appropriate routine.
6984 switch (arg1->type) {
6985 case XPATH_UNDEFINED:
6987 xmlGenericError(xmlGenericErrorContext,
6988 "Equal: undefined\n");
6992 switch (arg2->type) {
6993 case XPATH_UNDEFINED:
6995 xmlGenericError(xmlGenericErrorContext,
6996 "Equal: undefined\n");
7001 xmlGenericError(xmlGenericErrorContext,
7002 "Equal: %d boolean %d \n",
7003 arg1->boolval, arg2->boolval);
7005 ret = (arg1->boolval == arg2->boolval);
7008 ret = (arg1->boolval ==
7009 xmlXPathCastNumberToBoolean(arg2->floatval));
7012 if ((arg2->stringval == NULL) ||
7013 (arg2->stringval[0] == 0)) ret = 0;
7016 ret = (arg1->boolval == ret);
7021 case XPATH_LOCATIONSET:
7025 case XPATH_XSLT_TREE:
7030 switch (arg2->type) {
7031 case XPATH_UNDEFINED:
7033 xmlGenericError(xmlGenericErrorContext,
7034 "Equal: undefined\n");
7038 ret = (arg2->boolval==
7039 xmlXPathCastNumberToBoolean(arg1->floatval));
7042 valuePush(ctxt, arg2);
7043 xmlXPathNumberFunction(ctxt, 1);
7044 arg2 = valuePop(ctxt);
7045 /* Falls through. */
7047 /* Hand check NaN and Infinity equalities */
7048 if (xmlXPathIsNaN(arg1->floatval) ||
7049 xmlXPathIsNaN(arg2->floatval)) {
7051 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7052 if (xmlXPathIsInf(arg2->floatval) == 1)
7056 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7057 if (xmlXPathIsInf(arg2->floatval) == -1)
7061 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7062 if (xmlXPathIsInf(arg1->floatval) == 1)
7066 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7067 if (xmlXPathIsInf(arg1->floatval) == -1)
7072 ret = (arg1->floatval == arg2->floatval);
7078 case XPATH_LOCATIONSET:
7082 case XPATH_XSLT_TREE:
7087 switch (arg2->type) {
7088 case XPATH_UNDEFINED:
7090 xmlGenericError(xmlGenericErrorContext,
7091 "Equal: undefined\n");
7095 if ((arg1->stringval == NULL) ||
7096 (arg1->stringval[0] == 0)) ret = 0;
7099 ret = (arg2->boolval == ret);
7102 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7105 valuePush(ctxt, arg1);
7106 xmlXPathNumberFunction(ctxt, 1);
7107 arg1 = valuePop(ctxt);
7108 /* Hand check NaN and Infinity equalities */
7109 if (xmlXPathIsNaN(arg1->floatval) ||
7110 xmlXPathIsNaN(arg2->floatval)) {
7112 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7113 if (xmlXPathIsInf(arg2->floatval) == 1)
7117 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7118 if (xmlXPathIsInf(arg2->floatval) == -1)
7122 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7123 if (xmlXPathIsInf(arg1->floatval) == 1)
7127 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7128 if (xmlXPathIsInf(arg1->floatval) == -1)
7133 ret = (arg1->floatval == arg2->floatval);
7139 case XPATH_LOCATIONSET:
7143 case XPATH_XSLT_TREE:
7150 case XPATH_LOCATIONSET:
7154 case XPATH_XSLT_TREE:
7157 xmlXPathReleaseObject(ctxt->context, arg1);
7158 xmlXPathReleaseObject(ctxt->context, arg2);
7163 * xmlXPathEqualValues:
7164 * @ctxt: the XPath Parser context
7166 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7168 * Returns 0 or 1 depending on the results of the test.
7171 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7172 xmlXPathObjectPtr arg1, arg2, argtmp;
7175 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7176 arg2 = valuePop(ctxt);
7177 arg1 = valuePop(ctxt);
7178 if ((arg1 == NULL) || (arg2 == NULL)) {
7180 xmlXPathReleaseObject(ctxt->context, arg1);
7182 xmlXPathReleaseObject(ctxt->context, arg2);
7183 XP_ERROR0(XPATH_INVALID_OPERAND);
7188 xmlGenericError(xmlGenericErrorContext,
7189 "Equal: by pointer\n");
7191 xmlXPathFreeObject(arg1);
7196 *If either argument is a nodeset, it's a 'special case'
7198 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7199 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7201 *Hack it to assure arg1 is the nodeset
7203 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7208 switch (arg2->type) {
7209 case XPATH_UNDEFINED:
7211 xmlGenericError(xmlGenericErrorContext,
7212 "Equal: undefined\n");
7216 case XPATH_XSLT_TREE:
7217 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7220 if ((arg1->nodesetval == NULL) ||
7221 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7224 ret = (ret == arg2->boolval);
7227 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7230 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7235 case XPATH_LOCATIONSET:
7239 xmlXPathReleaseObject(ctxt->context, arg1);
7240 xmlXPathReleaseObject(ctxt->context, arg2);
7244 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7248 * xmlXPathNotEqualValues:
7249 * @ctxt: the XPath Parser context
7251 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7253 * Returns 0 or 1 depending on the results of the test.
7256 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7257 xmlXPathObjectPtr arg1, arg2, argtmp;
7260 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7261 arg2 = valuePop(ctxt);
7262 arg1 = valuePop(ctxt);
7263 if ((arg1 == NULL) || (arg2 == NULL)) {
7265 xmlXPathReleaseObject(ctxt->context, arg1);
7267 xmlXPathReleaseObject(ctxt->context, arg2);
7268 XP_ERROR0(XPATH_INVALID_OPERAND);
7273 xmlGenericError(xmlGenericErrorContext,
7274 "NotEqual: by pointer\n");
7276 xmlXPathReleaseObject(ctxt->context, arg1);
7281 *If either argument is a nodeset, it's a 'special case'
7283 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7284 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7286 *Hack it to assure arg1 is the nodeset
7288 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7293 switch (arg2->type) {
7294 case XPATH_UNDEFINED:
7296 xmlGenericError(xmlGenericErrorContext,
7297 "NotEqual: undefined\n");
7301 case XPATH_XSLT_TREE:
7302 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7305 if ((arg1->nodesetval == NULL) ||
7306 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7309 ret = (ret != arg2->boolval);
7312 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7315 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7320 case XPATH_LOCATIONSET:
7324 xmlXPathReleaseObject(ctxt->context, arg1);
7325 xmlXPathReleaseObject(ctxt->context, arg2);
7329 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7333 * xmlXPathCompareValues:
7334 * @ctxt: the XPath Parser context
7335 * @inf: less than (1) or greater than (0)
7336 * @strict: is the comparison strict
7338 * Implement the compare operation on XPath objects:
7339 * @arg1 < @arg2 (1, 1, ...
7340 * @arg1 <= @arg2 (1, 0, ...
7341 * @arg1 > @arg2 (0, 1, ...
7342 * @arg1 >= @arg2 (0, 0, ...
7344 * When neither object to be compared is a node-set and the operator is
7345 * <=, <, >=, >, then the objects are compared by converted both objects
7346 * to numbers and comparing the numbers according to IEEE 754. The <
7347 * comparison will be true if and only if the first number is less than the
7348 * second number. The <= comparison will be true if and only if the first
7349 * number is less than or equal to the second number. The > comparison
7350 * will be true if and only if the first number is greater than the second
7351 * number. The >= comparison will be true if and only if the first number
7352 * is greater than or equal to the second number.
7354 * Returns 1 if the comparison succeeded, 0 if it failed
7357 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7358 int ret = 0, arg1i = 0, arg2i = 0;
7359 xmlXPathObjectPtr arg1, arg2;
7361 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7362 arg2 = valuePop(ctxt);
7363 arg1 = valuePop(ctxt);
7364 if ((arg1 == NULL) || (arg2 == NULL)) {
7366 xmlXPathReleaseObject(ctxt->context, arg1);
7368 xmlXPathReleaseObject(ctxt->context, arg2);
7369 XP_ERROR0(XPATH_INVALID_OPERAND);
7372 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7373 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7375 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7376 * are not freed from within this routine; they will be freed from the
7377 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7379 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7380 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7381 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7383 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7384 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7387 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7394 if (arg1->type != XPATH_NUMBER) {
7395 valuePush(ctxt, arg1);
7396 xmlXPathNumberFunction(ctxt, 1);
7397 arg1 = valuePop(ctxt);
7399 if (arg1->type != XPATH_NUMBER) {
7400 xmlXPathFreeObject(arg1);
7401 xmlXPathFreeObject(arg2);
7402 XP_ERROR0(XPATH_INVALID_OPERAND);
7404 if (arg2->type != XPATH_NUMBER) {
7405 valuePush(ctxt, arg2);
7406 xmlXPathNumberFunction(ctxt, 1);
7407 arg2 = valuePop(ctxt);
7409 if (arg2->type != XPATH_NUMBER) {
7410 xmlXPathReleaseObject(ctxt->context, arg1);
7411 xmlXPathReleaseObject(ctxt->context, arg2);
7412 XP_ERROR0(XPATH_INVALID_OPERAND);
7415 * Add tests for infinity and nan
7416 * => feedback on 3.4 for Inf and NaN
7418 /* Hand check NaN and Infinity comparisons */
7419 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7422 arg1i=xmlXPathIsInf(arg1->floatval);
7423 arg2i=xmlXPathIsInf(arg2->floatval);
7424 if (inf && strict) {
7425 if ((arg1i == -1 && arg2i != -1) ||
7426 (arg2i == 1 && arg1i != 1)) {
7428 } else if (arg1i == 0 && arg2i == 0) {
7429 ret = (arg1->floatval < arg2->floatval);
7434 else if (inf && !strict) {
7435 if (arg1i == -1 || arg2i == 1) {
7437 } else if (arg1i == 0 && arg2i == 0) {
7438 ret = (arg1->floatval <= arg2->floatval);
7443 else if (!inf && strict) {
7444 if ((arg1i == 1 && arg2i != 1) ||
7445 (arg2i == -1 && arg1i != -1)) {
7447 } else if (arg1i == 0 && arg2i == 0) {
7448 ret = (arg1->floatval > arg2->floatval);
7453 else if (!inf && !strict) {
7454 if (arg1i == 1 || arg2i == -1) {
7456 } else if (arg1i == 0 && arg2i == 0) {
7457 ret = (arg1->floatval >= arg2->floatval);
7463 xmlXPathReleaseObject(ctxt->context, arg1);
7464 xmlXPathReleaseObject(ctxt->context, arg2);
7469 * xmlXPathValueFlipSign:
7470 * @ctxt: the XPath Parser context
7472 * Implement the unary - operation on an XPath object
7473 * The numeric operators convert their operands to numbers as if
7474 * by calling the number function.
7477 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7478 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7480 CHECK_TYPE(XPATH_NUMBER);
7481 if (xmlXPathIsNaN(ctxt->value->floatval))
7482 ctxt->value->floatval=xmlXPathNAN;
7483 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7484 ctxt->value->floatval=xmlXPathNINF;
7485 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7486 ctxt->value->floatval=xmlXPathPINF;
7487 else if (ctxt->value->floatval == 0) {
7488 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7489 ctxt->value->floatval = xmlXPathNZERO;
7491 ctxt->value->floatval = 0;
7494 ctxt->value->floatval = - ctxt->value->floatval;
7498 * xmlXPathAddValues:
7499 * @ctxt: the XPath Parser context
7501 * Implement the add operation on XPath objects:
7502 * The numeric operators convert their operands to numbers as if
7503 * by calling the number function.
7506 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7507 xmlXPathObjectPtr arg;
7510 arg = valuePop(ctxt);
7512 XP_ERROR(XPATH_INVALID_OPERAND);
7513 val = xmlXPathCastToNumber(arg);
7514 xmlXPathReleaseObject(ctxt->context, arg);
7516 CHECK_TYPE(XPATH_NUMBER);
7517 ctxt->value->floatval += val;
7521 * xmlXPathSubValues:
7522 * @ctxt: the XPath Parser context
7524 * Implement the subtraction operation on XPath objects:
7525 * The numeric operators convert their operands to numbers as if
7526 * by calling the number function.
7529 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7530 xmlXPathObjectPtr arg;
7533 arg = valuePop(ctxt);
7535 XP_ERROR(XPATH_INVALID_OPERAND);
7536 val = xmlXPathCastToNumber(arg);
7537 xmlXPathReleaseObject(ctxt->context, arg);
7539 CHECK_TYPE(XPATH_NUMBER);
7540 ctxt->value->floatval -= val;
7544 * xmlXPathMultValues:
7545 * @ctxt: the XPath Parser context
7547 * Implement the multiply operation on XPath objects:
7548 * The numeric operators convert their operands to numbers as if
7549 * by calling the number function.
7552 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7553 xmlXPathObjectPtr arg;
7556 arg = valuePop(ctxt);
7558 XP_ERROR(XPATH_INVALID_OPERAND);
7559 val = xmlXPathCastToNumber(arg);
7560 xmlXPathReleaseObject(ctxt->context, arg);
7562 CHECK_TYPE(XPATH_NUMBER);
7563 ctxt->value->floatval *= val;
7567 * xmlXPathDivValues:
7568 * @ctxt: the XPath Parser context
7570 * Implement the div operation on XPath objects @arg1 / @arg2:
7571 * The numeric operators convert their operands to numbers as if
7572 * by calling the number function.
7575 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7576 xmlXPathObjectPtr arg;
7579 arg = valuePop(ctxt);
7581 XP_ERROR(XPATH_INVALID_OPERAND);
7582 val = xmlXPathCastToNumber(arg);
7583 xmlXPathReleaseObject(ctxt->context, arg);
7585 CHECK_TYPE(XPATH_NUMBER);
7586 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7587 ctxt->value->floatval = xmlXPathNAN;
7588 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7589 if (ctxt->value->floatval == 0)
7590 ctxt->value->floatval = xmlXPathNAN;
7591 else if (ctxt->value->floatval > 0)
7592 ctxt->value->floatval = xmlXPathNINF;
7593 else if (ctxt->value->floatval < 0)
7594 ctxt->value->floatval = xmlXPathPINF;
7596 else if (val == 0) {
7597 if (ctxt->value->floatval == 0)
7598 ctxt->value->floatval = xmlXPathNAN;
7599 else if (ctxt->value->floatval > 0)
7600 ctxt->value->floatval = xmlXPathPINF;
7601 else if (ctxt->value->floatval < 0)
7602 ctxt->value->floatval = xmlXPathNINF;
7604 ctxt->value->floatval /= val;
7608 * xmlXPathModValues:
7609 * @ctxt: the XPath Parser context
7611 * Implement the mod operation on XPath objects: @arg1 / @arg2
7612 * The numeric operators convert their operands to numbers as if
7613 * by calling the number function.
7616 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7617 xmlXPathObjectPtr arg;
7620 arg = valuePop(ctxt);
7622 XP_ERROR(XPATH_INVALID_OPERAND);
7623 arg2 = xmlXPathCastToNumber(arg);
7624 xmlXPathReleaseObject(ctxt->context, arg);
7626 CHECK_TYPE(XPATH_NUMBER);
7627 arg1 = ctxt->value->floatval;
7629 ctxt->value->floatval = xmlXPathNAN;
7631 ctxt->value->floatval = fmod(arg1, arg2);
7635 /************************************************************************
7637 * The traversal functions *
7639 ************************************************************************/
7642 * A traversal function enumerates nodes along an axis.
7643 * Initially it must be called with NULL, and it indicates
7644 * termination on the axis by returning NULL.
7646 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7647 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7650 * xmlXPathTraversalFunctionExt:
7651 * A traversal function enumerates nodes along an axis.
7652 * Initially it must be called with NULL, and it indicates
7653 * termination on the axis by returning NULL.
7654 * The context node of the traversal is specified via @contextNode.
7656 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7657 (xmlNodePtr cur, xmlNodePtr contextNode);
7660 * xmlXPathNodeSetMergeFunction:
7661 * Used for merging node sets in xmlXPathCollectAndTest().
7663 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7664 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7669 * @ctxt: the XPath Parser context
7670 * @cur: the current node in the traversal
7672 * Traversal function for the "self" direction
7673 * The self axis contains just the context node itself
7675 * Returns the next element following that axis
7678 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7679 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7681 return(ctxt->context->node);
7686 * xmlXPathNextChild:
7687 * @ctxt: the XPath Parser context
7688 * @cur: the current node in the traversal
7690 * Traversal function for the "child" direction
7691 * The child axis contains the children of the context node in document order.
7693 * Returns the next element following that axis
7696 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7697 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7699 if (ctxt->context->node == NULL) return(NULL);
7700 switch (ctxt->context->node->type) {
7701 case XML_ELEMENT_NODE:
7703 case XML_CDATA_SECTION_NODE:
7704 case XML_ENTITY_REF_NODE:
7705 case XML_ENTITY_NODE:
7707 case XML_COMMENT_NODE:
7708 case XML_NOTATION_NODE:
7710 return(ctxt->context->node->children);
7711 case XML_DOCUMENT_NODE:
7712 case XML_DOCUMENT_TYPE_NODE:
7713 case XML_DOCUMENT_FRAG_NODE:
7714 case XML_HTML_DOCUMENT_NODE:
7715 #ifdef LIBXML_DOCB_ENABLED
7716 case XML_DOCB_DOCUMENT_NODE:
7718 return(((xmlDocPtr) ctxt->context->node)->children);
7719 case XML_ELEMENT_DECL:
7720 case XML_ATTRIBUTE_DECL:
7721 case XML_ENTITY_DECL:
7722 case XML_ATTRIBUTE_NODE:
7723 case XML_NAMESPACE_DECL:
7724 case XML_XINCLUDE_START:
7725 case XML_XINCLUDE_END:
7730 if ((cur->type == XML_DOCUMENT_NODE) ||
7731 (cur->type == XML_HTML_DOCUMENT_NODE))
7737 * xmlXPathNextChildElement:
7738 * @ctxt: the XPath Parser context
7739 * @cur: the current node in the traversal
7741 * Traversal function for the "child" direction and nodes of type element.
7742 * The child axis contains the children of the context node in document order.
7744 * Returns the next element following that axis
7747 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7750 cur = ctxt->context->node;
7751 if (cur == NULL) return(NULL);
7753 * Get the first element child.
7755 switch (cur->type) {
7756 case XML_ELEMENT_NODE:
7757 case XML_DOCUMENT_FRAG_NODE:
7758 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7759 case XML_ENTITY_NODE:
7760 cur = cur->children;
7762 if (cur->type == XML_ELEMENT_NODE)
7766 } while ((cur != NULL) &&
7767 (cur->type != XML_ELEMENT_NODE));
7771 case XML_DOCUMENT_NODE:
7772 case XML_HTML_DOCUMENT_NODE:
7773 #ifdef LIBXML_DOCB_ENABLED
7774 case XML_DOCB_DOCUMENT_NODE:
7776 return(xmlDocGetRootElement((xmlDocPtr) cur));
7783 * Get the next sibling element node.
7785 switch (cur->type) {
7786 case XML_ELEMENT_NODE:
7788 case XML_ENTITY_REF_NODE:
7789 case XML_ENTITY_NODE:
7790 case XML_CDATA_SECTION_NODE:
7792 case XML_COMMENT_NODE:
7793 case XML_XINCLUDE_END:
7795 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7799 if (cur->next != NULL) {
7800 if (cur->next->type == XML_ELEMENT_NODE)
7805 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7813 * xmlXPathNextDescendantOrSelfElemParent:
7814 * @ctxt: the XPath Parser context
7815 * @cur: the current node in the traversal
7817 * Traversal function for the "descendant-or-self" axis.
7818 * Additionally it returns only nodes which can be parents of
7822 * Returns the next element following that axis
7825 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7826 xmlNodePtr contextNode)
7829 if (contextNode == NULL)
7831 switch (contextNode->type) {
7832 case XML_ELEMENT_NODE:
7833 case XML_XINCLUDE_START:
7834 case XML_DOCUMENT_FRAG_NODE:
7835 case XML_DOCUMENT_NODE:
7836 #ifdef LIBXML_DOCB_ENABLED
7837 case XML_DOCB_DOCUMENT_NODE:
7839 case XML_HTML_DOCUMENT_NODE:
7840 return(contextNode);
7846 xmlNodePtr start = cur;
7848 while (cur != NULL) {
7849 switch (cur->type) {
7850 case XML_ELEMENT_NODE:
7851 /* TODO: OK to have XInclude here? */
7852 case XML_XINCLUDE_START:
7853 case XML_DOCUMENT_FRAG_NODE:
7856 if (cur->children != NULL) {
7857 cur = cur->children;
7861 /* Not sure if we need those here. */
7862 case XML_DOCUMENT_NODE:
7863 #ifdef LIBXML_DOCB_ENABLED
7864 case XML_DOCB_DOCUMENT_NODE:
7866 case XML_HTML_DOCUMENT_NODE:
7869 return(xmlDocGetRootElement((xmlDocPtr) cur));
7875 if ((cur == NULL) || (cur == contextNode))
7877 if (cur->next != NULL) {
7890 * xmlXPathNextDescendant:
7891 * @ctxt: the XPath Parser context
7892 * @cur: the current node in the traversal
7894 * Traversal function for the "descendant" direction
7895 * the descendant axis contains the descendants of the context node in document
7896 * order; a descendant is a child or a child of a child and so on.
7898 * Returns the next element following that axis
7901 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7902 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7904 if (ctxt->context->node == NULL)
7906 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7907 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7910 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7911 return(ctxt->context->doc->children);
7912 return(ctxt->context->node->children);
7915 if (cur->type == XML_NAMESPACE_DECL)
7917 if (cur->children != NULL) {
7919 * Do not descend on entities declarations
7921 if (cur->children->type != XML_ENTITY_DECL) {
7922 cur = cur->children;
7926 if (cur->type != XML_DTD_NODE)
7931 if (cur == ctxt->context->node) return(NULL);
7933 while (cur->next != NULL) {
7935 if ((cur->type != XML_ENTITY_DECL) &&
7936 (cur->type != XML_DTD_NODE))
7942 if (cur == NULL) break;
7943 if (cur == ctxt->context->node) return(NULL);
7944 if (cur->next != NULL) {
7948 } while (cur != NULL);
7953 * xmlXPathNextDescendantOrSelf:
7954 * @ctxt: the XPath Parser context
7955 * @cur: the current node in the traversal
7957 * Traversal function for the "descendant-or-self" direction
7958 * the descendant-or-self axis contains the context node and the descendants
7959 * of the context node in document order; thus the context node is the first
7960 * node on the axis, and the first child of the context node is the second node
7963 * Returns the next element following that axis
7966 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7967 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7969 return(ctxt->context->node);
7971 if (ctxt->context->node == NULL)
7973 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7974 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7977 return(xmlXPathNextDescendant(ctxt, cur));
7981 * xmlXPathNextParent:
7982 * @ctxt: the XPath Parser context
7983 * @cur: the current node in the traversal
7985 * Traversal function for the "parent" direction
7986 * The parent axis contains the parent of the context node, if there is one.
7988 * Returns the next element following that axis
7991 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7992 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7994 * the parent of an attribute or namespace node is the element
7995 * to which the attribute or namespace node is attached
7996 * Namespace handling !!!
7999 if (ctxt->context->node == NULL) return(NULL);
8000 switch (ctxt->context->node->type) {
8001 case XML_ELEMENT_NODE:
8003 case XML_CDATA_SECTION_NODE:
8004 case XML_ENTITY_REF_NODE:
8005 case XML_ENTITY_NODE:
8007 case XML_COMMENT_NODE:
8008 case XML_NOTATION_NODE:
8010 case XML_ELEMENT_DECL:
8011 case XML_ATTRIBUTE_DECL:
8012 case XML_XINCLUDE_START:
8013 case XML_XINCLUDE_END:
8014 case XML_ENTITY_DECL:
8015 if (ctxt->context->node->parent == NULL)
8016 return((xmlNodePtr) ctxt->context->doc);
8017 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8018 ((ctxt->context->node->parent->name[0] == ' ') ||
8019 (xmlStrEqual(ctxt->context->node->parent->name,
8020 BAD_CAST "fake node libxslt"))))
8022 return(ctxt->context->node->parent);
8023 case XML_ATTRIBUTE_NODE: {
8024 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8026 return(att->parent);
8028 case XML_DOCUMENT_NODE:
8029 case XML_DOCUMENT_TYPE_NODE:
8030 case XML_DOCUMENT_FRAG_NODE:
8031 case XML_HTML_DOCUMENT_NODE:
8032 #ifdef LIBXML_DOCB_ENABLED
8033 case XML_DOCB_DOCUMENT_NODE:
8036 case XML_NAMESPACE_DECL: {
8037 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8039 if ((ns->next != NULL) &&
8040 (ns->next->type != XML_NAMESPACE_DECL))
8041 return((xmlNodePtr) ns->next);
8050 * xmlXPathNextAncestor:
8051 * @ctxt: the XPath Parser context
8052 * @cur: the current node in the traversal
8054 * Traversal function for the "ancestor" direction
8055 * the ancestor axis contains the ancestors of the context node; the ancestors
8056 * of the context node consist of the parent of context node and the parent's
8057 * parent and so on; the nodes are ordered in reverse document order; thus the
8058 * parent is the first node on the axis, and the parent's parent is the second
8061 * Returns the next element following that axis
8064 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8065 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8067 * the parent of an attribute or namespace node is the element
8068 * to which the attribute or namespace node is attached
8072 if (ctxt->context->node == NULL) return(NULL);
8073 switch (ctxt->context->node->type) {
8074 case XML_ELEMENT_NODE:
8076 case XML_CDATA_SECTION_NODE:
8077 case XML_ENTITY_REF_NODE:
8078 case XML_ENTITY_NODE:
8080 case XML_COMMENT_NODE:
8082 case XML_ELEMENT_DECL:
8083 case XML_ATTRIBUTE_DECL:
8084 case XML_ENTITY_DECL:
8085 case XML_NOTATION_NODE:
8086 case XML_XINCLUDE_START:
8087 case XML_XINCLUDE_END:
8088 if (ctxt->context->node->parent == NULL)
8089 return((xmlNodePtr) ctxt->context->doc);
8090 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8091 ((ctxt->context->node->parent->name[0] == ' ') ||
8092 (xmlStrEqual(ctxt->context->node->parent->name,
8093 BAD_CAST "fake node libxslt"))))
8095 return(ctxt->context->node->parent);
8096 case XML_ATTRIBUTE_NODE: {
8097 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8099 return(tmp->parent);
8101 case XML_DOCUMENT_NODE:
8102 case XML_DOCUMENT_TYPE_NODE:
8103 case XML_DOCUMENT_FRAG_NODE:
8104 case XML_HTML_DOCUMENT_NODE:
8105 #ifdef LIBXML_DOCB_ENABLED
8106 case XML_DOCB_DOCUMENT_NODE:
8109 case XML_NAMESPACE_DECL: {
8110 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8112 if ((ns->next != NULL) &&
8113 (ns->next->type != XML_NAMESPACE_DECL))
8114 return((xmlNodePtr) ns->next);
8115 /* Bad, how did that namespace end up here ? */
8121 if (cur == ctxt->context->doc->children)
8122 return((xmlNodePtr) ctxt->context->doc);
8123 if (cur == (xmlNodePtr) ctxt->context->doc)
8125 switch (cur->type) {
8126 case XML_ELEMENT_NODE:
8128 case XML_CDATA_SECTION_NODE:
8129 case XML_ENTITY_REF_NODE:
8130 case XML_ENTITY_NODE:
8132 case XML_COMMENT_NODE:
8133 case XML_NOTATION_NODE:
8135 case XML_ELEMENT_DECL:
8136 case XML_ATTRIBUTE_DECL:
8137 case XML_ENTITY_DECL:
8138 case XML_XINCLUDE_START:
8139 case XML_XINCLUDE_END:
8140 if (cur->parent == NULL)
8142 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8143 ((cur->parent->name[0] == ' ') ||
8144 (xmlStrEqual(cur->parent->name,
8145 BAD_CAST "fake node libxslt"))))
8147 return(cur->parent);
8148 case XML_ATTRIBUTE_NODE: {
8149 xmlAttrPtr att = (xmlAttrPtr) cur;
8151 return(att->parent);
8153 case XML_NAMESPACE_DECL: {
8154 xmlNsPtr ns = (xmlNsPtr) cur;
8156 if ((ns->next != NULL) &&
8157 (ns->next->type != XML_NAMESPACE_DECL))
8158 return((xmlNodePtr) ns->next);
8159 /* Bad, how did that namespace end up here ? */
8162 case XML_DOCUMENT_NODE:
8163 case XML_DOCUMENT_TYPE_NODE:
8164 case XML_DOCUMENT_FRAG_NODE:
8165 case XML_HTML_DOCUMENT_NODE:
8166 #ifdef LIBXML_DOCB_ENABLED
8167 case XML_DOCB_DOCUMENT_NODE:
8175 * xmlXPathNextAncestorOrSelf:
8176 * @ctxt: the XPath Parser context
8177 * @cur: the current node in the traversal
8179 * Traversal function for the "ancestor-or-self" direction
8180 * he ancestor-or-self axis contains the context node and ancestors of
8181 * the context node in reverse document order; thus the context node is
8182 * the first node on the axis, and the context node's parent the second;
8183 * parent here is defined the same as with the parent axis.
8185 * Returns the next element following that axis
8188 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8189 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8191 return(ctxt->context->node);
8192 return(xmlXPathNextAncestor(ctxt, cur));
8196 * xmlXPathNextFollowingSibling:
8197 * @ctxt: the XPath Parser context
8198 * @cur: the current node in the traversal
8200 * Traversal function for the "following-sibling" direction
8201 * The following-sibling axis contains the following siblings of the context
8202 * node in document order.
8204 * Returns the next element following that axis
8207 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8208 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8209 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8210 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8212 if (cur == (xmlNodePtr) ctxt->context->doc)
8215 return(ctxt->context->node->next);
8220 * xmlXPathNextPrecedingSibling:
8221 * @ctxt: the XPath Parser context
8222 * @cur: the current node in the traversal
8224 * Traversal function for the "preceding-sibling" direction
8225 * The preceding-sibling axis contains the preceding siblings of the context
8226 * node in reverse document order; the first preceding sibling is first on the
8227 * axis; the sibling preceding that node is the second on the axis and so on.
8229 * Returns the next element following that axis
8232 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8233 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8234 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8235 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8237 if (cur == (xmlNodePtr) ctxt->context->doc)
8240 return(ctxt->context->node->prev);
8241 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8244 return(ctxt->context->node->prev);
8250 * xmlXPathNextFollowing:
8251 * @ctxt: the XPath Parser context
8252 * @cur: the current node in the traversal
8254 * Traversal function for the "following" direction
8255 * The following axis contains all nodes in the same document as the context
8256 * node that are after the context node in document order, excluding any
8257 * descendants and excluding attribute nodes and namespace nodes; the nodes
8258 * are ordered in document order
8260 * Returns the next element following that axis
8263 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8264 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8265 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8266 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8267 return(cur->children);
8270 cur = ctxt->context->node;
8271 if (cur->type == XML_ATTRIBUTE_NODE) {
8273 } else if (cur->type == XML_NAMESPACE_DECL) {
8274 xmlNsPtr ns = (xmlNsPtr) cur;
8276 if ((ns->next == NULL) ||
8277 (ns->next->type == XML_NAMESPACE_DECL))
8279 cur = (xmlNodePtr) ns->next;
8282 if (cur == NULL) return(NULL) ; /* ERROR */
8283 if (cur->next != NULL) return(cur->next) ;
8286 if (cur == NULL) break;
8287 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8288 if (cur->next != NULL) return(cur->next);
8289 } while (cur != NULL);
8294 * xmlXPathIsAncestor:
8295 * @ancestor: the ancestor node
8296 * @node: the current node
8298 * Check that @ancestor is a @node's ancestor
8300 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8303 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8304 if ((ancestor == NULL) || (node == NULL)) return(0);
8305 if (node->type == XML_NAMESPACE_DECL)
8307 if (ancestor->type == XML_NAMESPACE_DECL)
8309 /* nodes need to be in the same document */
8310 if (ancestor->doc != node->doc) return(0);
8311 /* avoid searching if ancestor or node is the root node */
8312 if (ancestor == (xmlNodePtr) node->doc) return(1);
8313 if (node == (xmlNodePtr) ancestor->doc) return(0);
8314 while (node->parent != NULL) {
8315 if (node->parent == ancestor)
8317 node = node->parent;
8323 * xmlXPathNextPreceding:
8324 * @ctxt: the XPath Parser context
8325 * @cur: the current node in the traversal
8327 * Traversal function for the "preceding" direction
8328 * the preceding axis contains all nodes in the same document as the context
8329 * node that are before the context node in document order, excluding any
8330 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8331 * ordered in reverse document order
8333 * Returns the next element following that axis
8336 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8338 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8340 cur = ctxt->context->node;
8341 if (cur->type == XML_ATTRIBUTE_NODE) {
8343 } else if (cur->type == XML_NAMESPACE_DECL) {
8344 xmlNsPtr ns = (xmlNsPtr) cur;
8346 if ((ns->next == NULL) ||
8347 (ns->next->type == XML_NAMESPACE_DECL))
8349 cur = (xmlNodePtr) ns->next;
8352 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8354 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8357 if (cur->prev != NULL) {
8358 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8365 if (cur == ctxt->context->doc->children)
8367 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8372 * xmlXPathNextPrecedingInternal:
8373 * @ctxt: the XPath Parser context
8374 * @cur: the current node in the traversal
8376 * Traversal function for the "preceding" direction
8377 * the preceding axis contains all nodes in the same document as the context
8378 * node that are before the context node in document order, excluding any
8379 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8380 * ordered in reverse document order
8381 * This is a faster implementation but internal only since it requires a
8382 * state kept in the parser context: ctxt->ancestor.
8384 * Returns the next element following that axis
8387 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8390 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8392 cur = ctxt->context->node;
8395 if (cur->type == XML_ATTRIBUTE_NODE) {
8397 } else if (cur->type == XML_NAMESPACE_DECL) {
8398 xmlNsPtr ns = (xmlNsPtr) cur;
8400 if ((ns->next == NULL) ||
8401 (ns->next->type == XML_NAMESPACE_DECL))
8403 cur = (xmlNodePtr) ns->next;
8405 ctxt->ancestor = cur->parent;
8407 if (cur->type == XML_NAMESPACE_DECL)
8409 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8411 while (cur->prev == NULL) {
8415 if (cur == ctxt->context->doc->children)
8417 if (cur != ctxt->ancestor)
8419 ctxt->ancestor = cur->parent;
8422 while (cur->last != NULL)
8428 * xmlXPathNextNamespace:
8429 * @ctxt: the XPath Parser context
8430 * @cur: the current attribute in the traversal
8432 * Traversal function for the "namespace" direction
8433 * the namespace axis contains the namespace nodes of the context node;
8434 * the order of nodes on this axis is implementation-defined; the axis will
8435 * be empty unless the context node is an element
8437 * We keep the XML namespace node at the end of the list.
8439 * Returns the next element following that axis
8442 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8443 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8444 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8446 if (ctxt->context->tmpNsList != NULL)
8447 xmlFree(ctxt->context->tmpNsList);
8448 ctxt->context->tmpNsList =
8449 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8450 ctxt->context->tmpNsNr = 0;
8451 if (ctxt->context->tmpNsList != NULL) {
8452 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8453 ctxt->context->tmpNsNr++;
8456 return((xmlNodePtr) xmlXPathXMLNamespace);
8458 if (ctxt->context->tmpNsNr > 0) {
8459 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8461 if (ctxt->context->tmpNsList != NULL)
8462 xmlFree(ctxt->context->tmpNsList);
8463 ctxt->context->tmpNsList = NULL;
8469 * xmlXPathNextAttribute:
8470 * @ctxt: the XPath Parser context
8471 * @cur: the current attribute in the traversal
8473 * Traversal function for the "attribute" direction
8474 * TODO: support DTD inherited default attributes
8476 * Returns the next element following that axis
8479 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8480 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8481 if (ctxt->context->node == NULL)
8483 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8486 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8488 return((xmlNodePtr)ctxt->context->node->properties);
8490 return((xmlNodePtr)cur->next);
8493 /************************************************************************
8495 * NodeTest Functions *
8497 ************************************************************************/
8499 #define IS_FUNCTION 200
8502 /************************************************************************
8504 * Implicit tree core function library *
8506 ************************************************************************/
8510 * @ctxt: the XPath Parser context
8512 * Initialize the context to the root of the document
8515 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8516 if ((ctxt == NULL) || (ctxt->context == NULL))
8518 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8519 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8520 ctxt->context->node));
8523 /************************************************************************
8525 * The explicit core function library *
8526 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8528 ************************************************************************/
8532 * xmlXPathLastFunction:
8533 * @ctxt: the XPath Parser context
8534 * @nargs: the number of arguments
8536 * Implement the last() XPath function
8538 * The last function returns the number of nodes in the context node list.
8541 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8543 if (ctxt->context->contextSize >= 0) {
8545 xmlXPathCacheNewFloat(ctxt->context,
8546 (double) ctxt->context->contextSize));
8548 xmlGenericError(xmlGenericErrorContext,
8549 "last() : %d\n", ctxt->context->contextSize);
8552 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8557 * xmlXPathPositionFunction:
8558 * @ctxt: the XPath Parser context
8559 * @nargs: the number of arguments
8561 * Implement the position() XPath function
8563 * The position function returns the position of the context node in the
8564 * context node list. The first position is 1, and so the last position
8565 * will be equal to last().
8568 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8570 if (ctxt->context->proximityPosition >= 0) {
8572 xmlXPathCacheNewFloat(ctxt->context,
8573 (double) ctxt->context->proximityPosition));
8575 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8576 ctxt->context->proximityPosition);
8579 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8584 * xmlXPathCountFunction:
8585 * @ctxt: the XPath Parser context
8586 * @nargs: the number of arguments
8588 * Implement the count() XPath function
8589 * number count(node-set)
8592 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8593 xmlXPathObjectPtr cur;
8596 if ((ctxt->value == NULL) ||
8597 ((ctxt->value->type != XPATH_NODESET) &&
8598 (ctxt->value->type != XPATH_XSLT_TREE)))
8599 XP_ERROR(XPATH_INVALID_TYPE);
8600 cur = valuePop(ctxt);
8602 if ((cur == NULL) || (cur->nodesetval == NULL))
8603 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8604 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8605 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8606 (double) cur->nodesetval->nodeNr));
8608 if ((cur->nodesetval->nodeNr != 1) ||
8609 (cur->nodesetval->nodeTab == NULL)) {
8610 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8615 tmp = cur->nodesetval->nodeTab[0];
8616 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8617 tmp = tmp->children;
8618 while (tmp != NULL) {
8623 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8626 xmlXPathReleaseObject(ctxt->context, cur);
8630 * xmlXPathGetElementsByIds:
8631 * @doc: the document
8632 * @ids: a whitespace separated list of IDs
8634 * Selects elements by their unique ID.
8636 * Returns a node-set of selected elements.
8638 static xmlNodeSetPtr
8639 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8641 const xmlChar *cur = ids;
8644 xmlNodePtr elem = NULL;
8646 if (ids == NULL) return(NULL);
8648 ret = xmlXPathNodeSetCreate(NULL);
8652 while (IS_BLANK_CH(*cur)) cur++;
8654 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8657 ID = xmlStrndup(ids, cur - ids);
8660 * We used to check the fact that the value passed
8661 * was an NCName, but this generated much troubles for
8662 * me and Aleksey Sanin, people blatantly violated that
8663 * constaint, like Visa3D spec.
8664 * if (xmlValidateNCName(ID, 1) == 0)
8666 attr = xmlGetID(doc, ID);
8668 if (attr->type == XML_ATTRIBUTE_NODE)
8669 elem = attr->parent;
8670 else if (attr->type == XML_ELEMENT_NODE)
8671 elem = (xmlNodePtr) attr;
8675 xmlXPathNodeSetAdd(ret, elem);
8680 while (IS_BLANK_CH(*cur)) cur++;
8687 * xmlXPathIdFunction:
8688 * @ctxt: the XPath Parser context
8689 * @nargs: the number of arguments
8691 * Implement the id() XPath function
8692 * node-set id(object)
8693 * The id function selects elements by their unique ID
8694 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8695 * then the result is the union of the result of applying id to the
8696 * string value of each of the nodes in the argument node-set. When the
8697 * argument to id is of any other type, the argument is converted to a
8698 * string as if by a call to the string function; the string is split
8699 * into a whitespace-separated list of tokens (whitespace is any sequence
8700 * of characters matching the production S); the result is a node-set
8701 * containing the elements in the same document as the context node that
8702 * have a unique ID equal to any of the tokens in the list.
8705 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8708 xmlXPathObjectPtr obj;
8711 obj = valuePop(ctxt);
8712 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8713 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8717 ret = xmlXPathNodeSetCreate(NULL);
8719 * FIXME -- in an out-of-memory condition this will behave badly.
8720 * The solution is not clear -- we already popped an item from
8721 * ctxt, so the object is in a corrupt state.
8724 if (obj->nodesetval != NULL) {
8725 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8727 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8728 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8729 ret = xmlXPathNodeSetMerge(ret, ns);
8730 xmlXPathFreeNodeSet(ns);
8735 xmlXPathReleaseObject(ctxt->context, obj);
8736 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8739 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8740 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8741 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8742 xmlXPathReleaseObject(ctxt->context, obj);
8747 * xmlXPathLocalNameFunction:
8748 * @ctxt: the XPath Parser context
8749 * @nargs: the number of arguments
8751 * Implement the local-name() XPath function
8752 * string local-name(node-set?)
8753 * The local-name function returns a string containing the local part
8754 * of the name of the node in the argument node-set that is first in
8755 * document order. If the node-set is empty or the first node has no
8756 * name, an empty string is returned. If the argument is omitted it
8757 * defaults to the context node.
8760 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8761 xmlXPathObjectPtr cur;
8763 if (ctxt == NULL) return;
8766 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8767 ctxt->context->node));
8772 if ((ctxt->value == NULL) ||
8773 ((ctxt->value->type != XPATH_NODESET) &&
8774 (ctxt->value->type != XPATH_XSLT_TREE)))
8775 XP_ERROR(XPATH_INVALID_TYPE);
8776 cur = valuePop(ctxt);
8778 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8779 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8781 int i = 0; /* Should be first in document order !!!!! */
8782 switch (cur->nodesetval->nodeTab[i]->type) {
8783 case XML_ELEMENT_NODE:
8784 case XML_ATTRIBUTE_NODE:
8786 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8787 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8790 xmlXPathCacheNewString(ctxt->context,
8791 cur->nodesetval->nodeTab[i]->name));
8793 case XML_NAMESPACE_DECL:
8794 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8795 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8798 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8801 xmlXPathReleaseObject(ctxt->context, cur);
8805 * xmlXPathNamespaceURIFunction:
8806 * @ctxt: the XPath Parser context
8807 * @nargs: the number of arguments
8809 * Implement the namespace-uri() XPath function
8810 * string namespace-uri(node-set?)
8811 * The namespace-uri function returns a string containing the
8812 * namespace URI of the expanded name of the node in the argument
8813 * node-set that is first in document order. If the node-set is empty,
8814 * the first node has no name, or the expanded name has no namespace
8815 * URI, an empty string is returned. If the argument is omitted it
8816 * defaults to the context node.
8819 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8820 xmlXPathObjectPtr cur;
8822 if (ctxt == NULL) return;
8825 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8826 ctxt->context->node));
8830 if ((ctxt->value == NULL) ||
8831 ((ctxt->value->type != XPATH_NODESET) &&
8832 (ctxt->value->type != XPATH_XSLT_TREE)))
8833 XP_ERROR(XPATH_INVALID_TYPE);
8834 cur = valuePop(ctxt);
8836 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8837 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8839 int i = 0; /* Should be first in document order !!!!! */
8840 switch (cur->nodesetval->nodeTab[i]->type) {
8841 case XML_ELEMENT_NODE:
8842 case XML_ATTRIBUTE_NODE:
8843 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8844 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8846 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8847 cur->nodesetval->nodeTab[i]->ns->href));
8850 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8853 xmlXPathReleaseObject(ctxt->context, cur);
8857 * xmlXPathNameFunction:
8858 * @ctxt: the XPath Parser context
8859 * @nargs: the number of arguments
8861 * Implement the name() XPath function
8862 * string name(node-set?)
8863 * The name function returns a string containing a QName representing
8864 * the name of the node in the argument node-set that is first in document
8865 * order. The QName must represent the name with respect to the namespace
8866 * declarations in effect on the node whose name is being represented.
8867 * Typically, this will be the form in which the name occurred in the XML
8868 * source. This need not be the case if there are namespace declarations
8869 * in effect on the node that associate multiple prefixes with the same
8870 * namespace. However, an implementation may include information about
8871 * the original prefix in its representation of nodes; in this case, an
8872 * implementation can ensure that the returned string is always the same
8873 * as the QName used in the XML source. If the argument it omitted it
8874 * defaults to the context node.
8875 * Libxml keep the original prefix so the "real qualified name" used is
8879 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8881 xmlXPathObjectPtr cur;
8884 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8885 ctxt->context->node));
8890 if ((ctxt->value == NULL) ||
8891 ((ctxt->value->type != XPATH_NODESET) &&
8892 (ctxt->value->type != XPATH_XSLT_TREE)))
8893 XP_ERROR(XPATH_INVALID_TYPE);
8894 cur = valuePop(ctxt);
8896 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8897 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8899 int i = 0; /* Should be first in document order !!!!! */
8901 switch (cur->nodesetval->nodeTab[i]->type) {
8902 case XML_ELEMENT_NODE:
8903 case XML_ATTRIBUTE_NODE:
8904 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8906 xmlXPathCacheNewCString(ctxt->context, ""));
8907 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8908 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8910 xmlXPathCacheNewString(ctxt->context,
8911 cur->nodesetval->nodeTab[i]->name));
8915 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8916 cur->nodesetval->nodeTab[i]->ns->prefix,
8918 if (fullname == cur->nodesetval->nodeTab[i]->name)
8919 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8920 if (fullname == NULL) {
8921 XP_ERROR(XPATH_MEMORY_ERROR);
8923 valuePush(ctxt, xmlXPathCacheWrapString(
8924 ctxt->context, fullname));
8928 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8929 cur->nodesetval->nodeTab[i]));
8930 xmlXPathLocalNameFunction(ctxt, 1);
8933 xmlXPathReleaseObject(ctxt->context, cur);
8938 * xmlXPathStringFunction:
8939 * @ctxt: the XPath Parser context
8940 * @nargs: the number of arguments
8942 * Implement the string() XPath function
8943 * string string(object?)
8944 * The string function converts an object to a string as follows:
8945 * - A node-set is converted to a string by returning the value of
8946 * the node in the node-set that is first in document order.
8947 * If the node-set is empty, an empty string is returned.
8948 * - A number is converted to a string as follows
8949 * + NaN is converted to the string NaN
8950 * + positive zero is converted to the string 0
8951 * + negative zero is converted to the string 0
8952 * + positive infinity is converted to the string Infinity
8953 * + negative infinity is converted to the string -Infinity
8954 * + if the number is an integer, the number is represented in
8955 * decimal form as a Number with no decimal point and no leading
8956 * zeros, preceded by a minus sign (-) if the number is negative
8957 * + otherwise, the number is represented in decimal form as a
8958 * Number including a decimal point with at least one digit
8959 * before the decimal point and at least one digit after the
8960 * decimal point, preceded by a minus sign (-) if the number
8961 * is negative; there must be no leading zeros before the decimal
8962 * point apart possibly from the one required digit immediately
8963 * before the decimal point; beyond the one required digit
8964 * after the decimal point there must be as many, but only as
8965 * many, more digits as are needed to uniquely distinguish the
8966 * number from all other IEEE 754 numeric values.
8967 * - The boolean false value is converted to the string false.
8968 * The boolean true value is converted to the string true.
8970 * If the argument is omitted, it defaults to a node-set with the
8971 * context node as its only member.
8974 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8975 xmlXPathObjectPtr cur;
8977 if (ctxt == NULL) return;
8980 xmlXPathCacheWrapString(ctxt->context,
8981 xmlXPathCastNodeToString(ctxt->context->node)));
8986 cur = valuePop(ctxt);
8987 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8988 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8992 * xmlXPathStringLengthFunction:
8993 * @ctxt: the XPath Parser context
8994 * @nargs: the number of arguments
8996 * Implement the string-length() XPath function
8997 * number string-length(string?)
8998 * The string-length returns the number of characters in the string
8999 * (see [3.6 Strings]). If the argument is omitted, it defaults to
9000 * the context node converted to a string, in other words the value
9001 * of the context node.
9004 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9005 xmlXPathObjectPtr cur;
9008 if ((ctxt == NULL) || (ctxt->context == NULL))
9010 if (ctxt->context->node == NULL) {
9011 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9015 content = xmlXPathCastNodeToString(ctxt->context->node);
9016 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9017 xmlUTF8Strlen(content)));
9024 CHECK_TYPE(XPATH_STRING);
9025 cur = valuePop(ctxt);
9026 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9027 xmlUTF8Strlen(cur->stringval)));
9028 xmlXPathReleaseObject(ctxt->context, cur);
9032 * xmlXPathConcatFunction:
9033 * @ctxt: the XPath Parser context
9034 * @nargs: the number of arguments
9036 * Implement the concat() XPath function
9037 * string concat(string, string, string*)
9038 * The concat function returns the concatenation of its arguments.
9041 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9042 xmlXPathObjectPtr cur, newobj;
9045 if (ctxt == NULL) return;
9051 cur = valuePop(ctxt);
9052 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9053 xmlXPathReleaseObject(ctxt->context, cur);
9060 newobj = valuePop(ctxt);
9061 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9062 xmlXPathReleaseObject(ctxt->context, newobj);
9063 xmlXPathReleaseObject(ctxt->context, cur);
9064 XP_ERROR(XPATH_INVALID_TYPE);
9066 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9067 newobj->stringval = cur->stringval;
9068 cur->stringval = tmp;
9069 xmlXPathReleaseObject(ctxt->context, newobj);
9072 valuePush(ctxt, cur);
9076 * xmlXPathContainsFunction:
9077 * @ctxt: the XPath Parser context
9078 * @nargs: the number of arguments
9080 * Implement the contains() XPath function
9081 * boolean contains(string, string)
9082 * The contains function returns true if the first argument string
9083 * contains the second argument string, and otherwise returns false.
9086 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9087 xmlXPathObjectPtr hay, needle;
9091 CHECK_TYPE(XPATH_STRING);
9092 needle = valuePop(ctxt);
9094 hay = valuePop(ctxt);
9096 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9097 xmlXPathReleaseObject(ctxt->context, hay);
9098 xmlXPathReleaseObject(ctxt->context, needle);
9099 XP_ERROR(XPATH_INVALID_TYPE);
9101 if (xmlStrstr(hay->stringval, needle->stringval))
9102 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9104 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9105 xmlXPathReleaseObject(ctxt->context, hay);
9106 xmlXPathReleaseObject(ctxt->context, needle);
9110 * xmlXPathStartsWithFunction:
9111 * @ctxt: the XPath Parser context
9112 * @nargs: the number of arguments
9114 * Implement the starts-with() XPath function
9115 * boolean starts-with(string, string)
9116 * The starts-with function returns true if the first argument string
9117 * starts with the second argument string, and otherwise returns false.
9120 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9121 xmlXPathObjectPtr hay, needle;
9126 CHECK_TYPE(XPATH_STRING);
9127 needle = valuePop(ctxt);
9129 hay = valuePop(ctxt);
9131 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9132 xmlXPathReleaseObject(ctxt->context, hay);
9133 xmlXPathReleaseObject(ctxt->context, needle);
9134 XP_ERROR(XPATH_INVALID_TYPE);
9136 n = xmlStrlen(needle->stringval);
9137 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9138 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9140 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9141 xmlXPathReleaseObject(ctxt->context, hay);
9142 xmlXPathReleaseObject(ctxt->context, needle);
9146 * xmlXPathSubstringFunction:
9147 * @ctxt: the XPath Parser context
9148 * @nargs: the number of arguments
9150 * Implement the substring() XPath function
9151 * string substring(string, number, number?)
9152 * The substring function returns the substring of the first argument
9153 * starting at the position specified in the second argument with
9154 * length specified in the third argument. For example,
9155 * substring("12345",2,3) returns "234". If the third argument is not
9156 * specified, it returns the substring starting at the position specified
9157 * in the second argument and continuing to the end of the string. For
9158 * example, substring("12345",2) returns "2345". More precisely, each
9159 * character in the string (see [3.6 Strings]) is considered to have a
9160 * numeric position: the position of the first character is 1, the position
9161 * of the second character is 2 and so on. The returned substring contains
9162 * those characters for which the position of the character is greater than
9163 * or equal to the second argument and, if the third argument is specified,
9164 * less than the sum of the second and third arguments; the comparisons
9165 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9166 * - substring("12345", 1.5, 2.6) returns "234"
9167 * - substring("12345", 0, 3) returns "12"
9168 * - substring("12345", 0 div 0, 3) returns ""
9169 * - substring("12345", 1, 0 div 0) returns ""
9170 * - substring("12345", -42, 1 div 0) returns "12345"
9171 * - substring("12345", -1 div 0, 1 div 0) returns ""
9174 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9175 xmlXPathObjectPtr str, start, len;
9187 * take care of possible last (position) argument
9191 CHECK_TYPE(XPATH_NUMBER);
9192 len = valuePop(ctxt);
9194 xmlXPathReleaseObject(ctxt->context, len);
9198 CHECK_TYPE(XPATH_NUMBER);
9199 start = valuePop(ctxt);
9200 in = start->floatval;
9201 xmlXPathReleaseObject(ctxt->context, start);
9203 CHECK_TYPE(XPATH_STRING);
9204 str = valuePop(ctxt);
9205 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9208 * If last pos not present, calculate last position
9216 /* Need to check for the special cases where either
9217 * the index is NaN, the length is NaN, or both
9218 * arguments are infinity (relying on Inf + -Inf = NaN)
9220 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9222 * To meet the requirements of the spec, the arguments
9223 * must be converted to integer format before
9224 * initial index calculations are done
9226 * First we go to integer form, rounding up
9227 * and checking for special cases
9230 if (((double)i)+0.5 <= in) i++;
9232 if (xmlXPathIsInf(le) == 1) {
9237 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9241 if (((double)l)+0.5 <= le) l++;
9244 /* Now we normalize inidices */
9252 /* number of chars to copy */
9255 ret = xmlUTF8Strsub(str->stringval, i, l);
9261 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9263 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9266 xmlXPathReleaseObject(ctxt->context, str);
9270 * xmlXPathSubstringBeforeFunction:
9271 * @ctxt: the XPath Parser context
9272 * @nargs: the number of arguments
9274 * Implement the substring-before() XPath function
9275 * string substring-before(string, string)
9276 * The substring-before function returns the substring of the first
9277 * argument string that precedes the first occurrence of the second
9278 * argument string in the first argument string, or the empty string
9279 * if the first argument string does not contain the second argument
9280 * string. For example, substring-before("1999/04/01","/") returns 1999.
9283 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9284 xmlXPathObjectPtr str;
9285 xmlXPathObjectPtr find;
9287 const xmlChar *point;
9292 find = valuePop(ctxt);
9294 str = valuePop(ctxt);
9296 target = xmlBufCreate();
9298 point = xmlStrstr(str->stringval, find->stringval);
9300 offset = (int)(point - str->stringval);
9301 xmlBufAdd(target, str->stringval, offset);
9303 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9304 xmlBufContent(target)));
9307 xmlXPathReleaseObject(ctxt->context, str);
9308 xmlXPathReleaseObject(ctxt->context, find);
9312 * xmlXPathSubstringAfterFunction:
9313 * @ctxt: the XPath Parser context
9314 * @nargs: the number of arguments
9316 * Implement the substring-after() XPath function
9317 * string substring-after(string, string)
9318 * The substring-after function returns the substring of the first
9319 * argument string that follows the first occurrence of the second
9320 * argument string in the first argument string, or the empty stringi
9321 * if the first argument string does not contain the second argument
9322 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9323 * and substring-after("1999/04/01","19") returns 99/04/01.
9326 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9327 xmlXPathObjectPtr str;
9328 xmlXPathObjectPtr find;
9330 const xmlChar *point;
9335 find = valuePop(ctxt);
9337 str = valuePop(ctxt);
9339 target = xmlBufCreate();
9341 point = xmlStrstr(str->stringval, find->stringval);
9343 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9344 xmlBufAdd(target, &str->stringval[offset],
9345 xmlStrlen(str->stringval) - offset);
9347 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9348 xmlBufContent(target)));
9351 xmlXPathReleaseObject(ctxt->context, str);
9352 xmlXPathReleaseObject(ctxt->context, find);
9356 * xmlXPathNormalizeFunction:
9357 * @ctxt: the XPath Parser context
9358 * @nargs: the number of arguments
9360 * Implement the normalize-space() XPath function
9361 * string normalize-space(string?)
9362 * The normalize-space function returns the argument string with white
9363 * space normalized by stripping leading and trailing whitespace
9364 * and replacing sequences of whitespace characters by a single
9365 * space. Whitespace characters are the same allowed by the S production
9366 * in XML. If the argument is omitted, it defaults to the context
9367 * node converted to a string, in other words the value of the context node.
9370 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9371 xmlXPathObjectPtr obj = NULL;
9372 xmlChar *source = NULL;
9376 if (ctxt == NULL) return;
9378 /* Use current context node */
9380 xmlXPathCacheWrapString(ctxt->context,
9381 xmlXPathCastNodeToString(ctxt->context->node)));
9387 CHECK_TYPE(XPATH_STRING);
9388 obj = valuePop(ctxt);
9389 source = obj->stringval;
9391 target = xmlBufCreate();
9392 if (target && source) {
9394 /* Skip leading whitespaces */
9395 while (IS_BLANK_CH(*source))
9398 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9401 if (IS_BLANK_CH(*source)) {
9405 xmlBufAdd(target, &blank, 1);
9408 xmlBufAdd(target, source, 1);
9412 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9413 xmlBufContent(target)));
9416 xmlXPathReleaseObject(ctxt->context, obj);
9420 * xmlXPathTranslateFunction:
9421 * @ctxt: the XPath Parser context
9422 * @nargs: the number of arguments
9424 * Implement the translate() XPath function
9425 * string translate(string, string, string)
9426 * The translate function returns the first argument string with
9427 * occurrences of characters in the second argument string replaced
9428 * by the character at the corresponding position in the third argument
9429 * string. For example, translate("bar","abc","ABC") returns the string
9430 * BAr. If there is a character in the second argument string with no
9431 * character at a corresponding position in the third argument string
9432 * (because the second argument string is longer than the third argument
9433 * string), then occurrences of that character in the first argument
9434 * string are removed. For example, translate("--aaa--","abc-","ABC")
9435 * returns "AAA". If a character occurs more than once in second
9436 * argument string, then the first occurrence determines the replacement
9437 * character. If the third argument string is longer than the second
9438 * argument string, then excess characters are ignored.
9441 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9442 xmlXPathObjectPtr str;
9443 xmlXPathObjectPtr from;
9444 xmlXPathObjectPtr to;
9448 const xmlChar *point;
9454 to = valuePop(ctxt);
9456 from = valuePop(ctxt);
9458 str = valuePop(ctxt);
9460 target = xmlBufCreate();
9462 max = xmlUTF8Strlen(to->stringval);
9463 for (cptr = str->stringval; (ch=*cptr); ) {
9464 offset = xmlUTF8Strloc(from->stringval, cptr);
9467 point = xmlUTF8Strpos(to->stringval, offset);
9469 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9472 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9474 /* Step to next character in input */
9477 /* if not simple ascii, verify proper format */
9478 if ( (ch & 0xc0) != 0xc0 ) {
9479 xmlGenericError(xmlGenericErrorContext,
9480 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9481 /* not asserting an XPath error is probably better */
9484 /* then skip over remaining bytes for this char */
9485 while ( (ch <<= 1) & 0x80 )
9486 if ( (*cptr++ & 0xc0) != 0x80 ) {
9487 xmlGenericError(xmlGenericErrorContext,
9488 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9489 /* not asserting an XPath error is probably better */
9492 if (ch & 0x80) /* must have had error encountered */
9497 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9498 xmlBufContent(target)));
9500 xmlXPathReleaseObject(ctxt->context, str);
9501 xmlXPathReleaseObject(ctxt->context, from);
9502 xmlXPathReleaseObject(ctxt->context, to);
9506 * xmlXPathBooleanFunction:
9507 * @ctxt: the XPath Parser context
9508 * @nargs: the number of arguments
9510 * Implement the boolean() XPath function
9511 * boolean boolean(object)
9512 * The boolean function converts its argument to a boolean as follows:
9513 * - a number is true if and only if it is neither positive or
9514 * negative zero nor NaN
9515 * - a node-set is true if and only if it is non-empty
9516 * - a string is true if and only if its length is non-zero
9519 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9520 xmlXPathObjectPtr cur;
9523 cur = valuePop(ctxt);
9524 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9525 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9526 valuePush(ctxt, cur);
9530 * xmlXPathNotFunction:
9531 * @ctxt: the XPath Parser context
9532 * @nargs: the number of arguments
9534 * Implement the not() XPath function
9535 * boolean not(boolean)
9536 * The not function returns true if its argument is false,
9537 * and false otherwise.
9540 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9543 CHECK_TYPE(XPATH_BOOLEAN);
9544 ctxt->value->boolval = ! ctxt->value->boolval;
9548 * xmlXPathTrueFunction:
9549 * @ctxt: the XPath Parser context
9550 * @nargs: the number of arguments
9552 * Implement the true() XPath function
9556 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9558 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9562 * xmlXPathFalseFunction:
9563 * @ctxt: the XPath Parser context
9564 * @nargs: the number of arguments
9566 * Implement the false() XPath function
9570 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9572 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9576 * xmlXPathLangFunction:
9577 * @ctxt: the XPath Parser context
9578 * @nargs: the number of arguments
9580 * Implement the lang() XPath function
9581 * boolean lang(string)
9582 * The lang function returns true or false depending on whether the
9583 * language of the context node as specified by xml:lang attributes
9584 * is the same as or is a sublanguage of the language specified by
9585 * the argument string. The language of the context node is determined
9586 * by the value of the xml:lang attribute on the context node, or, if
9587 * the context node has no xml:lang attribute, by the value of the
9588 * xml:lang attribute on the nearest ancestor of the context node that
9589 * has an xml:lang attribute. If there is no such attribute, then lang
9590 * returns false. If there is such an attribute, then lang returns
9591 * true if the attribute value is equal to the argument ignoring case,
9592 * or if there is some suffix starting with - such that the attribute
9593 * value is equal to the argument ignoring that suffix of the attribute
9594 * value and ignoring case.
9597 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9598 xmlXPathObjectPtr val = NULL;
9599 const xmlChar *theLang = NULL;
9600 const xmlChar *lang;
9606 CHECK_TYPE(XPATH_STRING);
9607 val = valuePop(ctxt);
9608 lang = val->stringval;
9609 theLang = xmlNodeGetLang(ctxt->context->node);
9610 if ((theLang != NULL) && (lang != NULL)) {
9611 for (i = 0;lang[i] != 0;i++)
9612 if (toupper(lang[i]) != toupper(theLang[i]))
9614 if ((theLang[i] == 0) || (theLang[i] == '-'))
9618 if (theLang != NULL)
9619 xmlFree((void *)theLang);
9621 xmlXPathReleaseObject(ctxt->context, val);
9622 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9626 * xmlXPathNumberFunction:
9627 * @ctxt: the XPath Parser context
9628 * @nargs: the number of arguments
9630 * Implement the number() XPath function
9631 * number number(object?)
9634 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9635 xmlXPathObjectPtr cur;
9638 if (ctxt == NULL) return;
9640 if (ctxt->context->node == NULL) {
9641 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9643 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9645 res = xmlXPathStringEvalNumber(content);
9646 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9653 cur = valuePop(ctxt);
9654 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9658 * xmlXPathSumFunction:
9659 * @ctxt: the XPath Parser context
9660 * @nargs: the number of arguments
9662 * Implement the sum() XPath function
9663 * number sum(node-set)
9664 * The sum function returns the sum of the values of the nodes in
9665 * the argument node-set.
9668 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9669 xmlXPathObjectPtr cur;
9674 if ((ctxt->value == NULL) ||
9675 ((ctxt->value->type != XPATH_NODESET) &&
9676 (ctxt->value->type != XPATH_XSLT_TREE)))
9677 XP_ERROR(XPATH_INVALID_TYPE);
9678 cur = valuePop(ctxt);
9680 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9681 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9682 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9685 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9686 xmlXPathReleaseObject(ctxt->context, cur);
9690 * xmlXPathFloorFunction:
9691 * @ctxt: the XPath Parser context
9692 * @nargs: the number of arguments
9694 * Implement the floor() XPath function
9695 * number floor(number)
9696 * The floor function returns the largest (closest to positive infinity)
9697 * number that is not greater than the argument and that is an integer.
9700 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9703 CHECK_TYPE(XPATH_NUMBER);
9705 ctxt->value->floatval = floor(ctxt->value->floatval);
9709 * xmlXPathCeilingFunction:
9710 * @ctxt: the XPath Parser context
9711 * @nargs: the number of arguments
9713 * Implement the ceiling() XPath function
9714 * number ceiling(number)
9715 * The ceiling function returns the smallest (closest to negative infinity)
9716 * number that is not less than the argument and that is an integer.
9719 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9722 CHECK_TYPE(XPATH_NUMBER);
9724 ctxt->value->floatval = ceil(ctxt->value->floatval);
9728 * xmlXPathRoundFunction:
9729 * @ctxt: the XPath Parser context
9730 * @nargs: the number of arguments
9732 * Implement the round() XPath function
9733 * number round(number)
9734 * The round function returns the number that is closest to the
9735 * argument and that is an integer. If there are two such numbers,
9736 * then the one that is closest to positive infinity is returned.
9739 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9744 CHECK_TYPE(XPATH_NUMBER);
9746 f = ctxt->value->floatval;
9748 /* Test for zero to keep negative zero unchanged. */
9749 if ((xmlXPathIsNaN(f)) || (f == 0.0))
9752 if ((f >= -0.5) && (f < 0.0)) {
9753 /* Negative zero. */
9754 ctxt->value->floatval = xmlXPathNZERO;
9757 double rounded = floor(f);
9758 if (f - rounded >= 0.5)
9760 ctxt->value->floatval = rounded;
9764 /************************************************************************
9768 ************************************************************************/
9771 * a few forward declarations since we use a recursive call based
9774 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9775 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9776 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9777 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9778 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9782 * xmlXPathCurrentChar:
9783 * @ctxt: the XPath parser context
9784 * @cur: pointer to the beginning of the char
9785 * @len: pointer to the length of the char read
9787 * The current char value, if using UTF-8 this may actually span multiple
9788 * bytes in the input buffer.
9790 * Returns the current char value and its length
9794 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9804 * We are supposed to handle UTF8, check it's valid
9805 * From rfc2044: encoding of the Unicode values on UTF-8:
9807 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9808 * 0000 0000-0000 007F 0xxxxxxx
9809 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9810 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9812 * Check for the 0x110000 limit too
9816 if ((cur[1] & 0xc0) != 0x80)
9817 goto encoding_error;
9818 if ((c & 0xe0) == 0xe0) {
9820 if ((cur[2] & 0xc0) != 0x80)
9821 goto encoding_error;
9822 if ((c & 0xf0) == 0xf0) {
9823 if (((c & 0xf8) != 0xf0) ||
9824 ((cur[3] & 0xc0) != 0x80))
9825 goto encoding_error;
9828 val = (cur[0] & 0x7) << 18;
9829 val |= (cur[1] & 0x3f) << 12;
9830 val |= (cur[2] & 0x3f) << 6;
9831 val |= cur[3] & 0x3f;
9835 val = (cur[0] & 0xf) << 12;
9836 val |= (cur[1] & 0x3f) << 6;
9837 val |= cur[2] & 0x3f;
9842 val = (cur[0] & 0x1f) << 6;
9843 val |= cur[1] & 0x3f;
9845 if (!IS_CHAR(val)) {
9846 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9856 * If we detect an UTF8 error that probably means that the
9857 * input encoding didn't get properly advertised in the
9858 * declaration header. Report the error and switch the encoding
9859 * to ISO-Latin-1 (if you don't like this policy, just declare the
9863 XP_ERROR0(XPATH_ENCODING_ERROR);
9867 * xmlXPathParseNCName:
9868 * @ctxt: the XPath Parser context
9870 * parse an XML namespace non qualified name.
9872 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9874 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9875 * CombiningChar | Extender
9877 * Returns the namespace name or NULL
9881 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9886 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9888 * Accelerator for simple ASCII names
9891 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9892 ((*in >= 0x41) && (*in <= 0x5A)) ||
9895 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9896 ((*in >= 0x41) && (*in <= 0x5A)) ||
9897 ((*in >= 0x30) && (*in <= 0x39)) ||
9898 (*in == '_') || (*in == '.') ||
9901 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9902 (*in == '[') || (*in == ']') || (*in == ':') ||
9903 (*in == '@') || (*in == '*')) {
9904 count = in - ctxt->cur;
9907 ret = xmlStrndup(ctxt->cur, count);
9912 return(xmlXPathParseNameComplex(ctxt, 0));
9917 * xmlXPathParseQName:
9918 * @ctxt: the XPath Parser context
9919 * @prefix: a xmlChar **
9921 * parse an XML qualified name
9923 * [NS 5] QName ::= (Prefix ':')? LocalPart
9925 * [NS 6] Prefix ::= NCName
9927 * [NS 7] LocalPart ::= NCName
9929 * Returns the function returns the local part, and prefix is updated
9930 * to get the Prefix if any.
9934 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9935 xmlChar *ret = NULL;
9938 ret = xmlXPathParseNCName(ctxt);
9939 if (ret && CUR == ':') {
9942 ret = xmlXPathParseNCName(ctxt);
9948 * xmlXPathParseName:
9949 * @ctxt: the XPath Parser context
9953 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9954 * CombiningChar | Extender
9956 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9958 * Returns the namespace name or NULL
9962 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9967 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9969 * Accelerator for simple ASCII names
9972 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9973 ((*in >= 0x41) && (*in <= 0x5A)) ||
9974 (*in == '_') || (*in == ':')) {
9976 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9977 ((*in >= 0x41) && (*in <= 0x5A)) ||
9978 ((*in >= 0x30) && (*in <= 0x39)) ||
9979 (*in == '_') || (*in == '-') ||
9980 (*in == ':') || (*in == '.'))
9982 if ((*in > 0) && (*in < 0x80)) {
9983 count = in - ctxt->cur;
9984 if (count > XML_MAX_NAME_LENGTH) {
9986 XP_ERRORNULL(XPATH_EXPR_ERROR);
9988 ret = xmlStrndup(ctxt->cur, count);
9993 return(xmlXPathParseNameComplex(ctxt, 1));
9997 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9998 xmlChar buf[XML_MAX_NAMELEN + 5];
10003 * Handler for more complex cases
10006 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10007 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10008 (c == '*') || /* accelerators */
10009 (!IS_LETTER(c) && (c != '_') &&
10010 ((!qualified) || (c != ':')))) {
10014 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10015 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10016 (c == '.') || (c == '-') ||
10017 (c == '_') || ((qualified) && (c == ':')) ||
10018 (IS_COMBINING(c)) ||
10019 (IS_EXTENDER(c)))) {
10020 COPY_BUF(l,buf,len,c);
10023 if (len >= XML_MAX_NAMELEN) {
10025 * Okay someone managed to make a huge name, so he's ready to pay
10026 * for the processing speed.
10031 if (len > XML_MAX_NAME_LENGTH) {
10032 XP_ERRORNULL(XPATH_EXPR_ERROR);
10034 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10035 if (buffer == NULL) {
10036 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10038 memcpy(buffer, buf, len);
10039 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10040 (c == '.') || (c == '-') ||
10041 (c == '_') || ((qualified) && (c == ':')) ||
10042 (IS_COMBINING(c)) ||
10043 (IS_EXTENDER(c))) {
10044 if (len + 10 > max) {
10045 if (max > XML_MAX_NAME_LENGTH) {
10046 XP_ERRORNULL(XPATH_EXPR_ERROR);
10049 buffer = (xmlChar *) xmlRealloc(buffer,
10050 max * sizeof(xmlChar));
10051 if (buffer == NULL) {
10052 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10055 COPY_BUF(l,buffer,len,c);
10065 return(xmlStrndup(buf, len));
10068 #define MAX_FRAC 20
10071 * xmlXPathStringEvalNumber:
10072 * @str: A string to scan
10074 * [30a] Float ::= Number ('e' Digits?)?
10076 * [30] Number ::= Digits ('.' Digits?)?
10078 * [31] Digits ::= [0-9]+
10080 * Compile a Number in the string
10081 * In complement of the Number expression, this function also handles
10082 * negative values : '-' Number.
10084 * Returns the double value.
10087 xmlXPathStringEvalNumber(const xmlChar *str) {
10088 const xmlChar *cur = str;
10093 int is_exponent_negative = 0;
10095 unsigned long tmp = 0;
10098 if (cur == NULL) return(0);
10099 while (IS_BLANK_CH(*cur)) cur++;
10100 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10101 return(xmlXPathNAN);
10110 * tmp/temp is a workaround against a gcc compiler bug
10111 * http://veillard.com/gcc.bug
10114 while ((*cur >= '0') && (*cur <= '9')) {
10116 tmp = (*cur - '0');
10119 temp = (double) tmp;
10124 while ((*cur >= '0') && (*cur <= '9')) {
10125 ret = ret * 10 + (*cur - '0');
10132 int v, frac = 0, max;
10133 double fraction = 0;
10136 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10137 return(xmlXPathNAN);
10139 while (*cur == '0') {
10143 max = frac + MAX_FRAC;
10144 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10146 fraction = fraction * 10 + v;
10150 fraction /= pow(10.0, frac);
10151 ret = ret + fraction;
10152 while ((*cur >= '0') && (*cur <= '9'))
10155 if ((*cur == 'e') || (*cur == 'E')) {
10158 is_exponent_negative = 1;
10160 } else if (*cur == '+') {
10163 while ((*cur >= '0') && (*cur <= '9')) {
10164 if (exponent < 1000000)
10165 exponent = exponent * 10 + (*cur - '0');
10169 while (IS_BLANK_CH(*cur)) cur++;
10170 if (*cur != 0) return(xmlXPathNAN);
10171 if (isneg) ret = -ret;
10172 if (is_exponent_negative) exponent = -exponent;
10173 ret *= pow(10.0, (double)exponent);
10178 * xmlXPathCompNumber:
10179 * @ctxt: the XPath Parser context
10181 * [30] Number ::= Digits ('.' Digits?)?
10183 * [31] Digits ::= [0-9]+
10185 * Compile a Number, then push it on the stack
10189 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10194 int is_exponent_negative = 0;
10196 unsigned long tmp = 0;
10201 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10202 XP_ERROR(XPATH_NUMBER_ERROR);
10206 * tmp/temp is a workaround against a gcc compiler bug
10207 * http://veillard.com/gcc.bug
10210 while ((CUR >= '0') && (CUR <= '9')) {
10215 temp = (double) tmp;
10220 while ((CUR >= '0') && (CUR <= '9')) {
10221 ret = ret * 10 + (CUR - '0');
10227 int v, frac = 0, max;
10228 double fraction = 0;
10231 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10232 XP_ERROR(XPATH_NUMBER_ERROR);
10234 while (CUR == '0') {
10238 max = frac + MAX_FRAC;
10239 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10241 fraction = fraction * 10 + v;
10245 fraction /= pow(10.0, frac);
10246 ret = ret + fraction;
10247 while ((CUR >= '0') && (CUR <= '9'))
10250 if ((CUR == 'e') || (CUR == 'E')) {
10253 is_exponent_negative = 1;
10255 } else if (CUR == '+') {
10258 while ((CUR >= '0') && (CUR <= '9')) {
10259 if (exponent < 1000000)
10260 exponent = exponent * 10 + (CUR - '0');
10263 if (is_exponent_negative)
10264 exponent = -exponent;
10265 ret *= pow(10.0, (double) exponent);
10267 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10268 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10272 * xmlXPathParseLiteral:
10273 * @ctxt: the XPath Parser context
10277 * [29] Literal ::= '"' [^"]* '"'
10280 * Returns the value found or NULL in case of error
10283 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10285 xmlChar *ret = NULL;
10290 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10292 if (!IS_CHAR_CH(CUR)) {
10293 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10295 ret = xmlStrndup(q, CUR_PTR - q);
10298 } else if (CUR == '\'') {
10301 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10303 if (!IS_CHAR_CH(CUR)) {
10304 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10306 ret = xmlStrndup(q, CUR_PTR - q);
10310 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10316 * xmlXPathCompLiteral:
10317 * @ctxt: the XPath Parser context
10319 * Parse a Literal and push it on the stack.
10321 * [29] Literal ::= '"' [^"]* '"'
10324 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10327 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10329 xmlChar *ret = NULL;
10334 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10336 if (!IS_CHAR_CH(CUR)) {
10337 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10339 ret = xmlStrndup(q, CUR_PTR - q);
10342 } else if (CUR == '\'') {
10345 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10347 if (!IS_CHAR_CH(CUR)) {
10348 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10350 ret = xmlStrndup(q, CUR_PTR - q);
10354 XP_ERROR(XPATH_START_LITERAL_ERROR);
10356 if (ret == NULL) return;
10357 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10358 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10363 * xmlXPathCompVariableReference:
10364 * @ctxt: the XPath Parser context
10366 * Parse a VariableReference, evaluate it and push it on the stack.
10368 * The variable bindings consist of a mapping from variable names
10369 * to variable values. The value of a variable is an object, which can be
10370 * of any of the types that are possible for the value of an expression,
10371 * and may also be of additional types not specified here.
10373 * Early evaluation is possible since:
10374 * The variable bindings [...] used to evaluate a subexpression are
10375 * always the same as those used to evaluate the containing expression.
10377 * [36] VariableReference ::= '$' QName
10380 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10386 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10389 name = xmlXPathParseQName(ctxt, &prefix);
10390 if (name == NULL) {
10392 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10394 ctxt->comp->last = -1;
10395 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10398 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10399 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10404 * xmlXPathIsNodeType:
10405 * @name: a name string
10407 * Is the name given a NodeType one.
10409 * [38] NodeType ::= 'comment'
10411 * | 'processing-instruction'
10414 * Returns 1 if true 0 otherwise
10417 xmlXPathIsNodeType(const xmlChar *name) {
10421 if (xmlStrEqual(name, BAD_CAST "node"))
10423 if (xmlStrEqual(name, BAD_CAST "text"))
10425 if (xmlStrEqual(name, BAD_CAST "comment"))
10427 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10433 * xmlXPathCompFunctionCall:
10434 * @ctxt: the XPath Parser context
10436 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10437 * [17] Argument ::= Expr
10439 * Compile a function call, the evaluation of all arguments are
10440 * pushed on the stack
10443 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10449 name = xmlXPathParseQName(ctxt, &prefix);
10450 if (name == NULL) {
10452 XP_ERROR(XPATH_EXPR_ERROR);
10456 if (prefix == NULL)
10457 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10460 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10467 XP_ERROR(XPATH_EXPR_ERROR);
10473 * Optimization for count(): we don't need the node-set to be sorted.
10475 if ((prefix == NULL) && (name[0] == 'c') &&
10476 xmlStrEqual(name, BAD_CAST "count"))
10480 ctxt->comp->last = -1;
10483 int op1 = ctxt->comp->last;
10484 ctxt->comp->last = -1;
10485 xmlXPathCompileExpr(ctxt, sort);
10486 if (ctxt->error != XPATH_EXPRESSION_OK) {
10491 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10493 if (CUR == ')') break;
10497 XP_ERROR(XPATH_EXPR_ERROR);
10503 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10510 * xmlXPathCompPrimaryExpr:
10511 * @ctxt: the XPath Parser context
10513 * [15] PrimaryExpr ::= VariableReference
10519 * Compile a primary expression.
10522 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10524 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10525 else if (CUR == '(') {
10528 xmlXPathCompileExpr(ctxt, 1);
10531 XP_ERROR(XPATH_EXPR_ERROR);
10535 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10536 xmlXPathCompNumber(ctxt);
10537 } else if ((CUR == '\'') || (CUR == '"')) {
10538 xmlXPathCompLiteral(ctxt);
10540 xmlXPathCompFunctionCall(ctxt);
10546 * xmlXPathCompFilterExpr:
10547 * @ctxt: the XPath Parser context
10549 * [20] FilterExpr ::= PrimaryExpr
10550 * | FilterExpr Predicate
10552 * Compile a filter expression.
10553 * Square brackets are used to filter expressions in the same way that
10554 * they are used in location paths. It is an error if the expression to
10555 * be filtered does not evaluate to a node-set. The context node list
10556 * used for evaluating the expression in square brackets is the node-set
10557 * to be filtered listed in document order.
10561 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10562 xmlXPathCompPrimaryExpr(ctxt);
10566 while (CUR == '[') {
10567 xmlXPathCompPredicate(ctxt, 1);
10575 * xmlXPathScanName:
10576 * @ctxt: the XPath Parser context
10578 * Trickery: parse an XML name but without consuming the input flow
10579 * Needed to avoid insanity in the parser state.
10581 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10582 * CombiningChar | Extender
10584 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10586 * [6] Names ::= Name (S Name)*
10588 * Returns the Name parsed or NULL
10592 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10595 const xmlChar *cur;
10601 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10602 (!IS_LETTER(c) && (c != '_') &&
10607 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10608 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10609 (c == '.') || (c == '-') ||
10610 (c == '_') || (c == ':') ||
10611 (IS_COMBINING(c)) ||
10612 (IS_EXTENDER(c)))) {
10617 ret = xmlStrndup(cur, ctxt->cur - cur);
10623 * xmlXPathCompPathExpr:
10624 * @ctxt: the XPath Parser context
10626 * [19] PathExpr ::= LocationPath
10628 * | FilterExpr '/' RelativeLocationPath
10629 * | FilterExpr '//' RelativeLocationPath
10631 * Compile a path expression.
10632 * The / operator and // operators combine an arbitrary expression
10633 * and a relative location path. It is an error if the expression
10634 * does not evaluate to a node-set.
10635 * The / operator does composition in the same way as when / is
10636 * used in a location path. As in location paths, // is short for
10637 * /descendant-or-self::node()/.
10641 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10642 int lc = 1; /* Should we branch to LocationPath ? */
10643 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10646 if ((CUR == '$') || (CUR == '(') ||
10647 (IS_ASCII_DIGIT(CUR)) ||
10648 (CUR == '\'') || (CUR == '"') ||
10649 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10651 } else if (CUR == '*') {
10652 /* relative or absolute location path */
10654 } else if (CUR == '/') {
10655 /* relative or absolute location path */
10657 } else if (CUR == '@') {
10658 /* relative abbreviated attribute location path */
10660 } else if (CUR == '.') {
10661 /* relative abbreviated attribute location path */
10665 * Problem is finding if we have a name here whether it's:
10667 * - a function call in which case it's followed by '('
10668 * - an axis in which case it's followed by ':'
10670 * We do an a priori analysis here rather than having to
10671 * maintain parsed token content through the recursive function
10672 * calls. This looks uglier but makes the code easier to
10673 * read/write/debug.
10676 name = xmlXPathScanName(ctxt);
10677 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10679 xmlGenericError(xmlGenericErrorContext,
10680 "PathExpr: Axis\n");
10684 } else if (name != NULL) {
10685 int len =xmlStrlen(name);
10688 while (NXT(len) != 0) {
10689 if (NXT(len) == '/') {
10692 xmlGenericError(xmlGenericErrorContext,
10693 "PathExpr: AbbrRelLocation\n");
10697 } else if (IS_BLANK_CH(NXT(len))) {
10698 /* ignore blanks */
10700 } else if (NXT(len) == ':') {
10702 xmlGenericError(xmlGenericErrorContext,
10703 "PathExpr: AbbrRelLocation\n");
10707 } else if ((NXT(len) == '(')) {
10708 /* Node Type or Function */
10709 if (xmlXPathIsNodeType(name)) {
10711 xmlGenericError(xmlGenericErrorContext,
10712 "PathExpr: Type search\n");
10715 #ifdef LIBXML_XPTR_ENABLED
10716 } else if (ctxt->xptr &&
10717 xmlStrEqual(name, BAD_CAST "range-to")) {
10722 xmlGenericError(xmlGenericErrorContext,
10723 "PathExpr: function call\n");
10728 } else if ((NXT(len) == '[')) {
10731 xmlGenericError(xmlGenericErrorContext,
10732 "PathExpr: AbbrRelLocation\n");
10736 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10737 (NXT(len) == '=')) {
10746 if (NXT(len) == 0) {
10748 xmlGenericError(xmlGenericErrorContext,
10749 "PathExpr: AbbrRelLocation\n");
10756 /* make sure all cases are covered explicitly */
10757 XP_ERROR(XPATH_EXPR_ERROR);
10763 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10765 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10767 xmlXPathCompLocationPath(ctxt);
10769 xmlXPathCompFilterExpr(ctxt);
10771 if ((CUR == '/') && (NXT(1) == '/')) {
10775 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10776 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10777 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10779 xmlXPathCompRelativeLocationPath(ctxt);
10780 } else if (CUR == '/') {
10781 xmlXPathCompRelativeLocationPath(ctxt);
10788 * xmlXPathCompUnionExpr:
10789 * @ctxt: the XPath Parser context
10791 * [18] UnionExpr ::= PathExpr
10792 * | UnionExpr '|' PathExpr
10794 * Compile an union expression.
10798 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10799 xmlXPathCompPathExpr(ctxt);
10802 while (CUR == '|') {
10803 int op1 = ctxt->comp->last;
10804 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10808 xmlXPathCompPathExpr(ctxt);
10810 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10817 * xmlXPathCompUnaryExpr:
10818 * @ctxt: the XPath Parser context
10820 * [27] UnaryExpr ::= UnionExpr
10823 * Compile an unary expression.
10827 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10832 while (CUR == '-') {
10839 xmlXPathCompUnionExpr(ctxt);
10843 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10845 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10850 * xmlXPathCompMultiplicativeExpr:
10851 * @ctxt: the XPath Parser context
10853 * [26] MultiplicativeExpr ::= UnaryExpr
10854 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10855 * | MultiplicativeExpr 'div' UnaryExpr
10856 * | MultiplicativeExpr 'mod' UnaryExpr
10857 * [34] MultiplyOperator ::= '*'
10859 * Compile an Additive expression.
10863 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10864 xmlXPathCompUnaryExpr(ctxt);
10867 while ((CUR == '*') ||
10868 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10869 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10871 int op1 = ctxt->comp->last;
10876 } else if (CUR == 'd') {
10879 } else if (CUR == 'm') {
10884 xmlXPathCompUnaryExpr(ctxt);
10886 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10892 * xmlXPathCompAdditiveExpr:
10893 * @ctxt: the XPath Parser context
10895 * [25] AdditiveExpr ::= MultiplicativeExpr
10896 * | AdditiveExpr '+' MultiplicativeExpr
10897 * | AdditiveExpr '-' MultiplicativeExpr
10899 * Compile an Additive expression.
10903 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10905 xmlXPathCompMultiplicativeExpr(ctxt);
10908 while ((CUR == '+') || (CUR == '-')) {
10910 int op1 = ctxt->comp->last;
10912 if (CUR == '+') plus = 1;
10916 xmlXPathCompMultiplicativeExpr(ctxt);
10918 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10924 * xmlXPathCompRelationalExpr:
10925 * @ctxt: the XPath Parser context
10927 * [24] RelationalExpr ::= AdditiveExpr
10928 * | RelationalExpr '<' AdditiveExpr
10929 * | RelationalExpr '>' AdditiveExpr
10930 * | RelationalExpr '<=' AdditiveExpr
10931 * | RelationalExpr '>=' AdditiveExpr
10933 * A <= B > C is allowed ? Answer from James, yes with
10934 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10935 * which is basically what got implemented.
10937 * Compile a Relational expression, then push the result
10942 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10943 xmlXPathCompAdditiveExpr(ctxt);
10946 while ((CUR == '<') ||
10948 ((CUR == '<') && (NXT(1) == '=')) ||
10949 ((CUR == '>') && (NXT(1) == '='))) {
10951 int op1 = ctxt->comp->last;
10953 if (CUR == '<') inf = 1;
10955 if (NXT(1) == '=') strict = 0;
10960 xmlXPathCompAdditiveExpr(ctxt);
10962 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10968 * xmlXPathCompEqualityExpr:
10969 * @ctxt: the XPath Parser context
10971 * [23] EqualityExpr ::= RelationalExpr
10972 * | EqualityExpr '=' RelationalExpr
10973 * | EqualityExpr '!=' RelationalExpr
10975 * A != B != C is allowed ? Answer from James, yes with
10976 * (RelationalExpr = RelationalExpr) = RelationalExpr
10977 * (RelationalExpr != RelationalExpr) != RelationalExpr
10978 * which is basically what got implemented.
10980 * Compile an Equality expression.
10984 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10985 xmlXPathCompRelationalExpr(ctxt);
10988 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10990 int op1 = ctxt->comp->last;
10992 if (CUR == '=') eq = 1;
10997 xmlXPathCompRelationalExpr(ctxt);
10999 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
11005 * xmlXPathCompAndExpr:
11006 * @ctxt: the XPath Parser context
11008 * [22] AndExpr ::= EqualityExpr
11009 * | AndExpr 'and' EqualityExpr
11011 * Compile an AND expression.
11015 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11016 xmlXPathCompEqualityExpr(ctxt);
11019 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11020 int op1 = ctxt->comp->last;
11023 xmlXPathCompEqualityExpr(ctxt);
11025 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11031 * xmlXPathCompileExpr:
11032 * @ctxt: the XPath Parser context
11034 * [14] Expr ::= OrExpr
11035 * [21] OrExpr ::= AndExpr
11036 * | OrExpr 'or' AndExpr
11038 * Parse and compile an expression
11041 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11042 xmlXPathCompAndExpr(ctxt);
11045 while ((CUR == 'o') && (NXT(1) == 'r')) {
11046 int op1 = ctxt->comp->last;
11049 xmlXPathCompAndExpr(ctxt);
11051 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11054 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11055 /* more ops could be optimized too */
11057 * This is the main place to eliminate sorting for
11058 * operations which don't require a sorted node-set.
11061 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11066 * xmlXPathCompPredicate:
11067 * @ctxt: the XPath Parser context
11068 * @filter: act as a filter
11070 * [8] Predicate ::= '[' PredicateExpr ']'
11071 * [9] PredicateExpr ::= Expr
11073 * Compile a predicate expression
11076 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11077 int op1 = ctxt->comp->last;
11081 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11086 ctxt->comp->last = -1;
11088 * This call to xmlXPathCompileExpr() will deactivate sorting
11089 * of the predicate result.
11090 * TODO: Sorting is still activated for filters, since I'm not
11091 * sure if needed. Normally sorting should not be needed, since
11092 * a filter can only diminish the number of items in a sequence,
11093 * but won't change its order; so if the initial sequence is sorted,
11094 * subsequent sorting is not needed.
11097 xmlXPathCompileExpr(ctxt, 0);
11099 xmlXPathCompileExpr(ctxt, 1);
11103 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11107 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11109 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11116 * xmlXPathCompNodeTest:
11117 * @ctxt: the XPath Parser context
11118 * @test: pointer to a xmlXPathTestVal
11119 * @type: pointer to a xmlXPathTypeVal
11120 * @prefix: placeholder for a possible name prefix
11122 * [7] NodeTest ::= NameTest
11123 * | NodeType '(' ')'
11124 * | 'processing-instruction' '(' Literal ')'
11126 * [37] NameTest ::= '*'
11129 * [38] NodeType ::= 'comment'
11131 * | 'processing-instruction'
11134 * Returns the name found and updates @test, @type and @prefix appropriately
11137 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11138 xmlXPathTypeVal *type, const xmlChar **prefix,
11142 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11146 *type = (xmlXPathTypeVal) 0;
11147 *test = (xmlXPathTestVal) 0;
11151 if ((name == NULL) && (CUR == '*')) {
11156 *test = NODE_TEST_ALL;
11161 name = xmlXPathParseNCName(ctxt);
11162 if (name == NULL) {
11163 XP_ERRORNULL(XPATH_EXPR_ERROR);
11166 blanks = IS_BLANK_CH(CUR);
11171 * NodeType or PI search
11173 if (xmlStrEqual(name, BAD_CAST "comment"))
11174 *type = NODE_TYPE_COMMENT;
11175 else if (xmlStrEqual(name, BAD_CAST "node"))
11176 *type = NODE_TYPE_NODE;
11177 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11178 *type = NODE_TYPE_PI;
11179 else if (xmlStrEqual(name, BAD_CAST "text"))
11180 *type = NODE_TYPE_TEXT;
11184 XP_ERRORNULL(XPATH_EXPR_ERROR);
11187 *test = NODE_TEST_TYPE;
11190 if (*type == NODE_TYPE_PI) {
11192 * Specific case: search a PI by name.
11198 name = xmlXPathParseLiteral(ctxt);
11200 *test = NODE_TEST_PI;
11207 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11212 *test = NODE_TEST_NAME;
11213 if ((!blanks) && (CUR == ':')) {
11217 * Since currently the parser context don't have a
11218 * namespace list associated:
11219 * The namespace name for this prefix can be computed
11220 * only at evaluation time. The compilation is done
11221 * outside of any context.
11224 *prefix = xmlXPathNsLookup(ctxt->context, name);
11227 if (*prefix == NULL) {
11228 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11239 *test = NODE_TEST_ALL;
11243 name = xmlXPathParseNCName(ctxt);
11244 if (name == NULL) {
11245 XP_ERRORNULL(XPATH_EXPR_ERROR);
11252 * xmlXPathIsAxisName:
11253 * @name: a preparsed name token
11255 * [6] AxisName ::= 'ancestor'
11256 * | 'ancestor-or-self'
11260 * | 'descendant-or-self'
11262 * | 'following-sibling'
11266 * | 'preceding-sibling'
11269 * Returns the axis or 0
11271 static xmlXPathAxisVal
11272 xmlXPathIsAxisName(const xmlChar *name) {
11273 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11276 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11277 ret = AXIS_ANCESTOR;
11278 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11279 ret = AXIS_ANCESTOR_OR_SELF;
11280 if (xmlStrEqual(name, BAD_CAST "attribute"))
11281 ret = AXIS_ATTRIBUTE;
11284 if (xmlStrEqual(name, BAD_CAST "child"))
11288 if (xmlStrEqual(name, BAD_CAST "descendant"))
11289 ret = AXIS_DESCENDANT;
11290 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11291 ret = AXIS_DESCENDANT_OR_SELF;
11294 if (xmlStrEqual(name, BAD_CAST "following"))
11295 ret = AXIS_FOLLOWING;
11296 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11297 ret = AXIS_FOLLOWING_SIBLING;
11300 if (xmlStrEqual(name, BAD_CAST "namespace"))
11301 ret = AXIS_NAMESPACE;
11304 if (xmlStrEqual(name, BAD_CAST "parent"))
11306 if (xmlStrEqual(name, BAD_CAST "preceding"))
11307 ret = AXIS_PRECEDING;
11308 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11309 ret = AXIS_PRECEDING_SIBLING;
11312 if (xmlStrEqual(name, BAD_CAST "self"))
11320 * xmlXPathCompStep:
11321 * @ctxt: the XPath Parser context
11323 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11324 * | AbbreviatedStep
11326 * [12] AbbreviatedStep ::= '.' | '..'
11328 * [5] AxisSpecifier ::= AxisName '::'
11329 * | AbbreviatedAxisSpecifier
11331 * [13] AbbreviatedAxisSpecifier ::= '@'?
11333 * Modified for XPtr range support as:
11335 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11336 * | AbbreviatedStep
11337 * | 'range-to' '(' Expr ')' Predicate*
11339 * Compile one step in a Location Path
11340 * A location step of . is short for self::node(). This is
11341 * particularly useful in conjunction with //. For example, the
11342 * location path .//para is short for
11343 * self::node()/descendant-or-self::node()/child::para
11344 * and so will select all para descendant elements of the context
11346 * Similarly, a location step of .. is short for parent::node().
11347 * For example, ../title is short for parent::node()/child::title
11348 * and so will select the title children of the parent of the context
11352 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11353 #ifdef LIBXML_XPTR_ENABLED
11359 if ((CUR == '.') && (NXT(1) == '.')) {
11362 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11363 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11364 } else if (CUR == '.') {
11368 xmlChar *name = NULL;
11369 const xmlChar *prefix = NULL;
11370 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11371 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11372 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11376 * The modification needed for XPointer change to the production
11378 #ifdef LIBXML_XPTR_ENABLED
11380 name = xmlXPathParseNCName(ctxt);
11381 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11382 op2 = ctxt->comp->last;
11386 XP_ERROR(XPATH_EXPR_ERROR);
11391 xmlXPathCompileExpr(ctxt, 1);
11392 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11397 XP_ERROR(XPATH_EXPR_ERROR);
11401 goto eval_predicates;
11409 name = xmlXPathParseNCName(ctxt);
11410 if (name != NULL) {
11411 axis = xmlXPathIsAxisName(name);
11414 if ((CUR == ':') && (NXT(1) == ':')) {
11419 /* an element name can conflict with an axis one :-\ */
11425 } else if (CUR == '@') {
11427 axis = AXIS_ATTRIBUTE;
11433 if (ctxt->error != XPATH_EXPRESSION_OK) {
11438 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11442 if ((prefix != NULL) && (ctxt->context != NULL) &&
11443 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11444 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11445 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11449 xmlGenericError(xmlGenericErrorContext,
11450 "Basis : computing new set\n");
11454 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11455 if (ctxt->value == NULL)
11456 xmlGenericError(xmlGenericErrorContext, "no value\n");
11457 else if (ctxt->value->nodesetval == NULL)
11458 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11460 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11463 #ifdef LIBXML_XPTR_ENABLED
11466 op1 = ctxt->comp->last;
11467 ctxt->comp->last = -1;
11470 while (CUR == '[') {
11471 xmlXPathCompPredicate(ctxt, 0);
11474 #ifdef LIBXML_XPTR_ENABLED
11476 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11479 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11480 test, type, (void *)prefix, (void *)name);
11484 xmlGenericError(xmlGenericErrorContext, "Step : ");
11485 if (ctxt->value == NULL)
11486 xmlGenericError(xmlGenericErrorContext, "no value\n");
11487 else if (ctxt->value->nodesetval == NULL)
11488 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11490 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11491 ctxt->value->nodesetval);
11496 * xmlXPathCompRelativeLocationPath:
11497 * @ctxt: the XPath Parser context
11499 * [3] RelativeLocationPath ::= Step
11500 * | RelativeLocationPath '/' Step
11501 * | AbbreviatedRelativeLocationPath
11502 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11504 * Compile a relative location path.
11507 xmlXPathCompRelativeLocationPath
11508 (xmlXPathParserContextPtr ctxt) {
11510 if ((CUR == '/') && (NXT(1) == '/')) {
11513 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11514 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11515 } else if (CUR == '/') {
11519 xmlXPathCompStep(ctxt);
11522 while (CUR == '/') {
11523 if ((CUR == '/') && (NXT(1) == '/')) {
11526 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11527 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11528 xmlXPathCompStep(ctxt);
11529 } else if (CUR == '/') {
11532 xmlXPathCompStep(ctxt);
11539 * xmlXPathCompLocationPath:
11540 * @ctxt: the XPath Parser context
11542 * [1] LocationPath ::= RelativeLocationPath
11543 * | AbsoluteLocationPath
11544 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11545 * | AbbreviatedAbsoluteLocationPath
11546 * [10] AbbreviatedAbsoluteLocationPath ::=
11547 * '//' RelativeLocationPath
11549 * Compile a location path
11551 * // is short for /descendant-or-self::node()/. For example,
11552 * //para is short for /descendant-or-self::node()/child::para and
11553 * so will select any para element in the document (even a para element
11554 * that is a document element will be selected by //para since the
11555 * document element node is a child of the root node); div//para is
11556 * short for div/descendant-or-self::node()/child::para and so will
11557 * select all para descendants of div children.
11560 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11563 xmlXPathCompRelativeLocationPath(ctxt);
11565 while (CUR == '/') {
11566 if ((CUR == '/') && (NXT(1) == '/')) {
11569 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11570 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11571 xmlXPathCompRelativeLocationPath(ctxt);
11572 } else if (CUR == '/') {
11576 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11577 (CUR == '@') || (CUR == '*')))
11578 xmlXPathCompRelativeLocationPath(ctxt);
11585 /************************************************************************
11587 * XPath precompiled expression evaluation *
11589 ************************************************************************/
11592 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11596 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11599 xmlGenericError(xmlGenericErrorContext, "new step : ");
11600 switch (op->value) {
11601 case AXIS_ANCESTOR:
11602 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11604 case AXIS_ANCESTOR_OR_SELF:
11605 xmlGenericError(xmlGenericErrorContext,
11606 "axis 'ancestors-or-self' ");
11608 case AXIS_ATTRIBUTE:
11609 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11612 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11614 case AXIS_DESCENDANT:
11615 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11617 case AXIS_DESCENDANT_OR_SELF:
11618 xmlGenericError(xmlGenericErrorContext,
11619 "axis 'descendant-or-self' ");
11621 case AXIS_FOLLOWING:
11622 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11624 case AXIS_FOLLOWING_SIBLING:
11625 xmlGenericError(xmlGenericErrorContext,
11626 "axis 'following-siblings' ");
11628 case AXIS_NAMESPACE:
11629 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11632 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11634 case AXIS_PRECEDING:
11635 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11637 case AXIS_PRECEDING_SIBLING:
11638 xmlGenericError(xmlGenericErrorContext,
11639 "axis 'preceding-sibling' ");
11642 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11645 xmlGenericError(xmlGenericErrorContext,
11646 " context contains %d nodes\n", nbNodes);
11647 switch (op->value2) {
11648 case NODE_TEST_NONE:
11649 xmlGenericError(xmlGenericErrorContext,
11650 " searching for none !!!\n");
11652 case NODE_TEST_TYPE:
11653 xmlGenericError(xmlGenericErrorContext,
11654 " searching for type %d\n", op->value3);
11657 xmlGenericError(xmlGenericErrorContext,
11658 " searching for PI !!!\n");
11660 case NODE_TEST_ALL:
11661 xmlGenericError(xmlGenericErrorContext,
11662 " searching for *\n");
11665 xmlGenericError(xmlGenericErrorContext,
11666 " searching for namespace %s\n",
11669 case NODE_TEST_NAME:
11670 xmlGenericError(xmlGenericErrorContext,
11671 " searching for name %s\n", op->value5);
11673 xmlGenericError(xmlGenericErrorContext,
11674 " with namespace %s\n", op->value4);
11677 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11679 #endif /* DEBUG_STEP */
11682 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11683 xmlXPathStepOpPtr op,
11688 if (op->ch1 != -1) {
11689 xmlXPathCompExprPtr comp = ctxt->comp;
11691 * Process inner predicates first.
11693 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11695 * TODO: raise an internal error.
11698 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11699 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11701 if (contextSize <= 0)
11704 if (op->ch2 != -1) {
11705 xmlXPathContextPtr xpctxt = ctxt->context;
11706 xmlNodePtr contextNode, oldContextNode;
11707 xmlDocPtr oldContextDoc;
11708 int i, res, contextPos = 0, newContextSize;
11709 xmlXPathStepOpPtr exprOp;
11710 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11712 #ifdef LIBXML_XPTR_ENABLED
11714 * URGENT TODO: Check the following:
11715 * We don't expect location sets if evaluating prediates, right?
11716 * Only filters should expect location sets, right?
11721 * "For each node in the node-set to be filtered, the
11722 * PredicateExpr is evaluated with that node as the
11723 * context node, with the number of nodes in the
11724 * node-set as the context size, and with the proximity
11725 * position of the node in the node-set with respect to
11726 * the axis as the context position;"
11727 * @oldset is the node-set" to be filtered.
11730 * "only predicates change the context position and
11731 * context size (see [2.4 Predicates])."
11733 * node-set context pos
11737 * After applying predicate [position() > 1] :
11738 * node-set context pos
11742 oldContextNode = xpctxt->node;
11743 oldContextDoc = xpctxt->doc;
11745 * Get the expression of this predicate.
11747 exprOp = &ctxt->comp->steps[op->ch2];
11748 newContextSize = 0;
11749 for (i = 0; i < set->nodeNr; i++) {
11750 if (set->nodeTab[i] == NULL)
11753 contextNode = set->nodeTab[i];
11754 xpctxt->node = contextNode;
11755 xpctxt->contextSize = contextSize;
11756 xpctxt->proximityPosition = ++contextPos;
11759 * Also set the xpath document in case things like
11760 * key() are evaluated in the predicate.
11762 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11763 (contextNode->doc != NULL))
11764 xpctxt->doc = contextNode->doc;
11766 * Evaluate the predicate expression with 1 context node
11767 * at a time; this node is packaged into a node set; this
11768 * node set is handed over to the evaluation mechanism.
11770 if (contextObj == NULL)
11771 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11773 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11774 contextNode) < 0) {
11775 ctxt->error = XPATH_MEMORY_ERROR;
11776 goto evaluation_exit;
11780 valuePush(ctxt, contextObj);
11782 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11784 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11785 xmlXPathNodeSetClear(set, hasNsNodes);
11786 newContextSize = 0;
11787 goto evaluation_exit;
11794 * Remove the entry from the initial node set.
11796 set->nodeTab[i] = NULL;
11797 if (contextNode->type == XML_NAMESPACE_DECL)
11798 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11800 if (ctxt->value == contextObj) {
11802 * Don't free the temporary XPath object holding the
11803 * context node, in order to avoid massive recreation
11804 * inside this loop.
11807 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11810 * TODO: The object was lost in the evaluation machinery.
11811 * Can this happen? Maybe in internal-error cases.
11817 if (contextObj != NULL) {
11818 if (ctxt->value == contextObj)
11820 xmlXPathReleaseObject(xpctxt, contextObj);
11823 if (exprRes != NULL)
11824 xmlXPathReleaseObject(ctxt->context, exprRes);
11826 * Reset/invalidate the context.
11828 xpctxt->node = oldContextNode;
11829 xpctxt->doc = oldContextDoc;
11830 xpctxt->contextSize = -1;
11831 xpctxt->proximityPosition = -1;
11832 return(newContextSize);
11834 return(contextSize);
11838 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11839 xmlXPathStepOpPtr op,
11846 if (op->ch1 != -1) {
11847 xmlXPathCompExprPtr comp = ctxt->comp;
11848 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11850 * TODO: raise an internal error.
11853 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11854 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11856 if (contextSize <= 0)
11860 * Check if the node set contains a sufficient number of nodes for
11861 * the requested range.
11863 if (contextSize < minPos) {
11864 xmlXPathNodeSetClear(set, hasNsNodes);
11867 if (op->ch2 == -1) {
11869 * TODO: Can this ever happen?
11871 return (contextSize);
11873 xmlDocPtr oldContextDoc;
11874 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11875 xmlXPathStepOpPtr exprOp;
11876 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11877 xmlNodePtr oldContextNode, contextNode = NULL;
11878 xmlXPathContextPtr xpctxt = ctxt->context;
11881 #ifdef LIBXML_XPTR_ENABLED
11883 * URGENT TODO: Check the following:
11884 * We don't expect location sets if evaluating prediates, right?
11885 * Only filters should expect location sets, right?
11887 #endif /* LIBXML_XPTR_ENABLED */
11890 * Save old context.
11892 oldContextNode = xpctxt->node;
11893 oldContextDoc = xpctxt->doc;
11895 * Get the expression of this predicate.
11897 exprOp = &ctxt->comp->steps[op->ch2];
11898 for (i = 0; i < set->nodeNr; i++) {
11899 xmlXPathObjectPtr tmp;
11901 if (set->nodeTab[i] == NULL)
11904 contextNode = set->nodeTab[i];
11905 xpctxt->node = contextNode;
11906 xpctxt->contextSize = contextSize;
11907 xpctxt->proximityPosition = ++contextPos;
11910 * Initialize the new set.
11911 * Also set the xpath document in case things like
11912 * key() evaluation are attempted on the predicate
11914 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11915 (contextNode->doc != NULL))
11916 xpctxt->doc = contextNode->doc;
11918 * Evaluate the predicate expression with 1 context node
11919 * at a time; this node is packaged into a node set; this
11920 * node set is handed over to the evaluation mechanism.
11922 if (contextObj == NULL)
11923 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11925 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11926 contextNode) < 0) {
11927 ctxt->error = XPATH_MEMORY_ERROR;
11928 goto evaluation_exit;
11932 valuePush(ctxt, contextObj);
11933 frame = xmlXPathSetFrame(ctxt);
11934 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11935 xmlXPathPopFrame(ctxt, frame);
11936 tmp = valuePop(ctxt);
11938 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11939 while (tmp != contextObj) {
11941 * Free up the result
11942 * then pop off contextObj, which will be freed later
11944 xmlXPathReleaseObject(xpctxt, tmp);
11945 tmp = valuePop(ctxt);
11947 goto evaluation_error;
11949 /* push the result back onto the stack */
11950 valuePush(ctxt, tmp);
11955 if (res && (pos >= minPos) && (pos <= maxPos)) {
11957 * Fits in the requested range.
11960 if (minPos == maxPos) {
11962 * Only 1 node was requested.
11964 if (contextNode->type == XML_NAMESPACE_DECL) {
11966 * As always: take care of those nasty
11969 set->nodeTab[i] = NULL;
11971 xmlXPathNodeSetClear(set, hasNsNodes);
11973 set->nodeTab[0] = contextNode;
11974 goto evaluation_exit;
11976 if (pos == maxPos) {
11980 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11981 goto evaluation_exit;
11985 * Remove the entry from the initial node set.
11987 set->nodeTab[i] = NULL;
11988 if (contextNode->type == XML_NAMESPACE_DECL)
11989 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11991 if (exprRes != NULL) {
11992 xmlXPathReleaseObject(ctxt->context, exprRes);
11995 if (ctxt->value == contextObj) {
11997 * Don't free the temporary XPath object holding the
11998 * context node, in order to avoid massive recreation
11999 * inside this loop.
12002 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
12005 * The object was lost in the evaluation machinery.
12006 * Can this happen? Maybe in case of internal-errors.
12011 goto evaluation_exit;
12014 xmlXPathNodeSetClear(set, hasNsNodes);
12015 newContextSize = 0;
12018 if (contextObj != NULL) {
12019 if (ctxt->value == contextObj)
12021 xmlXPathReleaseObject(xpctxt, contextObj);
12023 if (exprRes != NULL)
12024 xmlXPathReleaseObject(ctxt->context, exprRes);
12026 * Reset/invalidate the context.
12028 xpctxt->node = oldContextNode;
12029 xpctxt->doc = oldContextDoc;
12030 xpctxt->contextSize = -1;
12031 xpctxt->proximityPosition = -1;
12032 return(newContextSize);
12034 return(contextSize);
12038 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12039 xmlXPathStepOpPtr op,
12043 xmlXPathStepOpPtr exprOp;
12046 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12050 * If not -1, then ch1 will point to:
12051 * 1) For predicates (XPATH_OP_PREDICATE):
12052 * - an inner predicate operator
12053 * 2) For filters (XPATH_OP_FILTER):
12054 * - an inner filter operater OR
12055 * - an expression selecting the node set.
12056 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12058 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12061 if (op->ch2 != -1) {
12062 exprOp = &ctxt->comp->steps[op->ch2];
12066 if ((exprOp != NULL) &&
12067 (exprOp->op == XPATH_OP_VALUE) &&
12068 (exprOp->value4 != NULL) &&
12069 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12071 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12074 * We have a "[n]" predicate here.
12075 * TODO: Unfortunately this simplistic test here is not
12076 * able to detect a position() predicate in compound
12077 * expressions like "[@attr = 'a" and position() = 1],
12078 * and even not the usage of position() in
12079 * "[position() = 1]"; thus - obviously - a position-range,
12080 * like it "[position() < 5]", is also not detected.
12081 * Maybe we could rewrite the AST to ease the optimization.
12084 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12085 *maxPos = (int) floatval;
12086 if (floatval == (double) *maxPos)
12094 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12095 xmlXPathStepOpPtr op,
12096 xmlNodePtr * first, xmlNodePtr * last,
12100 #define XP_TEST_HIT \
12101 if (hasAxisRange != 0) { \
12102 if (++pos == maxPos) { \
12103 if (addNode(seq, cur) < 0) \
12104 ctxt->error = XPATH_MEMORY_ERROR; \
12105 goto axis_range_end; } \
12107 if (addNode(seq, cur) < 0) \
12108 ctxt->error = XPATH_MEMORY_ERROR; \
12109 if (breakOnFirstHit) goto first_hit; }
12111 #define XP_TEST_HIT_NS \
12112 if (hasAxisRange != 0) { \
12113 if (++pos == maxPos) { \
12115 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12116 ctxt->error = XPATH_MEMORY_ERROR; \
12117 goto axis_range_end; } \
12120 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12121 ctxt->error = XPATH_MEMORY_ERROR; \
12122 if (breakOnFirstHit) goto first_hit; }
12124 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12125 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12126 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12127 const xmlChar *prefix = op->value4;
12128 const xmlChar *name = op->value5;
12129 const xmlChar *URI = NULL;
12132 int nbMatches = 0, prevMatches = 0;
12134 int total = 0, hasNsNodes = 0;
12135 /* The popped object holding the context nodes */
12136 xmlXPathObjectPtr obj;
12137 /* The set of context nodes for the node tests */
12138 xmlNodeSetPtr contextSeq;
12140 xmlNodePtr contextNode;
12141 /* The final resulting node set wrt to all context nodes */
12142 xmlNodeSetPtr outSeq;
12144 * The temporary resulting node set wrt 1 context node.
12145 * Used to feed predicate evaluation.
12149 /* First predicate operator */
12150 xmlXPathStepOpPtr predOp;
12151 int maxPos; /* The requested position() (when a "[n]" predicate) */
12152 int hasPredicateRange, hasAxisRange, pos, size, newSize;
12153 int breakOnFirstHit;
12155 xmlXPathTraversalFunction next = NULL;
12156 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12157 xmlXPathNodeSetMergeFunction mergeAndClear;
12158 xmlNodePtr oldContextNode;
12159 xmlXPathContextPtr xpctxt = ctxt->context;
12162 CHECK_TYPE0(XPATH_NODESET);
12163 obj = valuePop(ctxt);
12165 * Setup namespaces.
12167 if (prefix != NULL) {
12168 URI = xmlXPathNsLookup(xpctxt, prefix);
12170 xmlXPathReleaseObject(xpctxt, obj);
12171 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12177 * MAYBE FUTURE TODO: merging optimizations:
12178 * - If the nodes to be traversed wrt to the initial nodes and
12179 * the current axis cannot overlap, then we could avoid searching
12180 * for duplicates during the merge.
12181 * But the question is how/when to evaluate if they cannot overlap.
12182 * Example: if we know that for two initial nodes, the one is
12183 * not in the ancestor-or-self axis of the other, then we could safely
12184 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12185 * the descendant-or-self axis.
12187 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12189 case AXIS_ANCESTOR:
12191 next = xmlXPathNextAncestor;
12193 case AXIS_ANCESTOR_OR_SELF:
12195 next = xmlXPathNextAncestorOrSelf;
12197 case AXIS_ATTRIBUTE:
12200 next = xmlXPathNextAttribute;
12201 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12205 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12206 (type == NODE_TYPE_NODE))
12209 * Optimization if an element node type is 'element'.
12211 next = xmlXPathNextChildElement;
12213 next = xmlXPathNextChild;
12214 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12216 case AXIS_DESCENDANT:
12218 next = xmlXPathNextDescendant;
12220 case AXIS_DESCENDANT_OR_SELF:
12222 next = xmlXPathNextDescendantOrSelf;
12224 case AXIS_FOLLOWING:
12226 next = xmlXPathNextFollowing;
12228 case AXIS_FOLLOWING_SIBLING:
12230 next = xmlXPathNextFollowingSibling;
12232 case AXIS_NAMESPACE:
12235 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12236 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12240 next = xmlXPathNextParent;
12242 case AXIS_PRECEDING:
12244 next = xmlXPathNextPrecedingInternal;
12246 case AXIS_PRECEDING_SIBLING:
12248 next = xmlXPathNextPrecedingSibling;
12253 next = xmlXPathNextSelf;
12254 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12259 xmlXPathDebugDumpStepAxis(op,
12260 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12263 if (next == NULL) {
12264 xmlXPathReleaseObject(xpctxt, obj);
12267 contextSeq = obj->nodesetval;
12268 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12269 xmlXPathReleaseObject(xpctxt, obj);
12270 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12274 * Predicate optimization ---------------------------------------------
12275 * If this step has a last predicate, which contains a position(),
12276 * then we'll optimize (although not exactly "position()", but only
12277 * the short-hand form, i.e., "[n]".
12279 * Example - expression "/foo[parent::bar][1]":
12281 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12283 * PREDICATE -- op->ch2 (predOp)
12284 * PREDICATE -- predOp->ch1 = [parent::bar]
12286 * COLLECT 'parent' 'name' 'node' bar
12288 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12293 hasPredicateRange = 0;
12295 if (op->ch2 != -1) {
12297 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12299 predOp = &ctxt->comp->steps[op->ch2];
12300 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12301 if (predOp->ch1 != -1) {
12303 * Use the next inner predicate operator.
12305 predOp = &ctxt->comp->steps[predOp->ch1];
12306 hasPredicateRange = 1;
12309 * There's no other predicate than the [n] predicate.
12316 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12318 * Axis traversal -----------------------------------------------------
12322 * - For the attribute axis, the principal node type is attribute.
12323 * - For the namespace axis, the principal node type is namespace.
12324 * - For other axes, the principal node type is element.
12326 * A node test * is true for any node of the
12327 * principal node type. For example, child::* will
12328 * select all element children of the context node
12330 oldContextNode = xpctxt->node;
12331 addNode = xmlXPathNodeSetAddUnique;
12334 contextNode = NULL;
12338 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12339 (ctxt->error == XPATH_EXPRESSION_OK)) {
12340 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12343 seq = xmlXPathNodeSetCreate(NULL);
12350 * Traverse the axis and test the nodes.
12356 cur = next(ctxt, cur);
12361 * QUESTION TODO: What does the "first" and "last" stuff do?
12363 if ((first != NULL) && (*first != NULL)) {
12366 if (((total % 256) == 0) &&
12367 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12368 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12370 (xmlXPathCmpNodes(*first, cur) >= 0))
12376 if ((last != NULL) && (*last != NULL)) {
12379 if (((total % 256) == 0) &&
12380 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12381 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12383 (xmlXPathCmpNodes(cur, *last) >= 0))
12393 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12397 case NODE_TEST_NONE:
12401 case NODE_TEST_TYPE:
12402 if (type == NODE_TYPE_NODE) {
12403 switch (cur->type) {
12404 case XML_DOCUMENT_NODE:
12405 case XML_HTML_DOCUMENT_NODE:
12406 #ifdef LIBXML_DOCB_ENABLED
12407 case XML_DOCB_DOCUMENT_NODE:
12409 case XML_ELEMENT_NODE:
12410 case XML_ATTRIBUTE_NODE:
12412 case XML_COMMENT_NODE:
12413 case XML_CDATA_SECTION_NODE:
12414 case XML_TEXT_NODE:
12417 case XML_NAMESPACE_DECL: {
12418 if (axis == AXIS_NAMESPACE) {
12429 } else if (cur->type == type) {
12430 if (cur->type == XML_NAMESPACE_DECL)
12434 } else if ((type == NODE_TYPE_TEXT) &&
12435 (cur->type == XML_CDATA_SECTION_NODE))
12441 if ((cur->type == XML_PI_NODE) &&
12442 ((name == NULL) || xmlStrEqual(name, cur->name)))
12447 case NODE_TEST_ALL:
12448 if (axis == AXIS_ATTRIBUTE) {
12449 if (cur->type == XML_ATTRIBUTE_NODE)
12451 if (prefix == NULL)
12454 } else if ((cur->ns != NULL) &&
12455 (xmlStrEqual(URI, cur->ns->href)))
12460 } else if (axis == AXIS_NAMESPACE) {
12461 if (cur->type == XML_NAMESPACE_DECL)
12466 if (cur->type == XML_ELEMENT_NODE) {
12467 if (prefix == NULL)
12471 } else if ((cur->ns != NULL) &&
12472 (xmlStrEqual(URI, cur->ns->href)))
12479 case NODE_TEST_NS:{
12483 case NODE_TEST_NAME:
12484 if (axis == AXIS_ATTRIBUTE) {
12485 if (cur->type != XML_ATTRIBUTE_NODE)
12487 } else if (axis == AXIS_NAMESPACE) {
12488 if (cur->type != XML_NAMESPACE_DECL)
12491 if (cur->type != XML_ELEMENT_NODE)
12494 switch (cur->type) {
12495 case XML_ELEMENT_NODE:
12496 if (xmlStrEqual(name, cur->name)) {
12497 if (prefix == NULL) {
12498 if (cur->ns == NULL)
12503 if ((cur->ns != NULL) &&
12504 (xmlStrEqual(URI, cur->ns->href)))
12511 case XML_ATTRIBUTE_NODE:{
12512 xmlAttrPtr attr = (xmlAttrPtr) cur;
12514 if (xmlStrEqual(name, attr->name)) {
12515 if (prefix == NULL) {
12516 if ((attr->ns == NULL) ||
12517 (attr->ns->prefix == NULL))
12522 if ((attr->ns != NULL) &&
12532 case XML_NAMESPACE_DECL:
12533 if (cur->type == XML_NAMESPACE_DECL) {
12534 xmlNsPtr ns = (xmlNsPtr) cur;
12536 if ((ns->prefix != NULL) && (name != NULL)
12537 && (xmlStrEqual(ns->prefix, name)))
12547 } /* switch(test) */
12548 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12550 goto apply_predicates;
12552 axis_range_end: /* ----------------------------------------------------- */
12554 * We have a "/foo[n]", and position() = n was reached.
12555 * Note that we can have as well "/foo/::parent::foo[1]", so
12556 * a duplicate-aware merge is still needed.
12557 * Merge with the result.
12559 if (outSeq == NULL) {
12563 outSeq = mergeAndClear(outSeq, seq, 0);
12565 * Break if only a true/false result was requested.
12571 first_hit: /* ---------------------------------------------------------- */
12573 * Break if only a true/false result was requested and
12574 * no predicates existed and a node test succeeded.
12576 if (outSeq == NULL) {
12580 outSeq = mergeAndClear(outSeq, seq, 0);
12585 nbMatches += seq->nodeNr;
12588 apply_predicates: /* --------------------------------------------------- */
12589 if (ctxt->error != XPATH_EXPRESSION_OK)
12593 * Apply predicates.
12595 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12597 * E.g. when we have a "/foo[some expression][n]".
12600 * QUESTION TODO: The old predicate evaluation took into
12601 * account location-sets.
12602 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12603 * Do we expect such a set here?
12604 * All what I learned now from the evaluation semantics
12605 * does not indicate that a location-set will be processed
12606 * here, so this looks OK.
12609 * Iterate over all predicates, starting with the outermost
12611 * TODO: Problem: we cannot execute the inner predicates first
12612 * since we cannot go back *up* the operator tree!
12614 * 1) Use of recursive functions (like is it currently done
12615 * via xmlXPathCompOpEval())
12616 * 2) Add a predicate evaluation information stack to the
12618 * 3) Change the way the operators are linked; we need a
12619 * "parent" field on xmlXPathStepOp
12621 * For the moment, I'll try to solve this with a recursive
12622 * function: xmlXPathCompOpEvalPredicate().
12624 size = seq->nodeNr;
12625 if (hasPredicateRange != 0)
12626 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12627 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12629 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12630 predOp, seq, size, hasNsNodes);
12632 if (ctxt->error != XPATH_EXPRESSION_OK) {
12637 * Add the filtered set of nodes to the result node set.
12639 if (newSize == 0) {
12641 * The predicates filtered all nodes out.
12643 xmlXPathNodeSetClear(seq, hasNsNodes);
12644 } else if (seq->nodeNr > 0) {
12646 * Add to result set.
12648 if (outSeq == NULL) {
12649 if (size != newSize) {
12651 * We need to merge and clear here, since
12652 * the sequence will contained NULLed entries.
12654 outSeq = mergeAndClear(NULL, seq, 1);
12660 outSeq = mergeAndClear(outSeq, seq,
12661 (size != newSize) ? 1: 0);
12663 * Break if only a true/false result was requested.
12668 } else if (seq->nodeNr > 0) {
12670 * Add to result set.
12672 if (outSeq == NULL) {
12676 outSeq = mergeAndClear(outSeq, seq, 0);
12682 if ((obj->boolval) && (obj->user != NULL)) {
12684 * QUESTION TODO: What does this do and why?
12685 * TODO: Do we have to do this also for the "error"
12686 * cleanup further down?
12688 ctxt->value->boolval = 1;
12689 ctxt->value->user = obj->user;
12693 xmlXPathReleaseObject(xpctxt, obj);
12696 * Ensure we return at least an emtpy set.
12698 if (outSeq == NULL) {
12699 if ((seq != NULL) && (seq->nodeNr == 0))
12702 outSeq = xmlXPathNodeSetCreate(NULL);
12703 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12705 if ((seq != NULL) && (seq != outSeq)) {
12706 xmlXPathFreeNodeSet(seq);
12709 * Hand over the result. Better to push the set also in
12712 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12714 * Reset the context node.
12716 xpctxt->node = oldContextNode;
12718 * When traversing the namespace axis in "toBool" mode, it's
12719 * possible that tmpNsList wasn't freed.
12721 if (xpctxt->tmpNsList != NULL) {
12722 xmlFree(xpctxt->tmpNsList);
12723 xpctxt->tmpNsList = NULL;
12727 xmlGenericError(xmlGenericErrorContext,
12728 "\nExamined %d nodes, found %d nodes at that step\n",
12736 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12737 xmlXPathStepOpPtr op, xmlNodePtr * first);
12740 * xmlXPathCompOpEvalFirst:
12741 * @ctxt: the XPath parser context with the compiled expression
12742 * @op: an XPath compiled operation
12743 * @first: the first elem found so far
12745 * Evaluate the Precompiled XPath operation searching only the first
12746 * element in document order
12748 * Returns the number of examined objects.
12751 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12752 xmlXPathStepOpPtr op, xmlNodePtr * first)
12754 int total = 0, cur;
12755 xmlXPathCompExprPtr comp;
12756 xmlXPathObjectPtr arg1, arg2;
12763 case XPATH_OP_UNION:
12765 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12768 if ((ctxt->value != NULL)
12769 && (ctxt->value->type == XPATH_NODESET)
12770 && (ctxt->value->nodesetval != NULL)
12771 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12773 * limit tree traversing to first node in the result
12776 * OPTIMIZE TODO: This implicitely sorts
12777 * the result, even if not needed. E.g. if the argument
12778 * of the count() function, no sorting is needed.
12779 * OPTIMIZE TODO: How do we know if the node-list wasn't
12782 if (ctxt->value->nodesetval->nodeNr > 1)
12783 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12784 *first = ctxt->value->nodesetval->nodeTab[0];
12787 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12791 arg2 = valuePop(ctxt);
12792 arg1 = valuePop(ctxt);
12793 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12794 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12795 xmlXPathReleaseObject(ctxt->context, arg1);
12796 xmlXPathReleaseObject(ctxt->context, arg2);
12797 XP_ERROR0(XPATH_INVALID_TYPE);
12800 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12802 valuePush(ctxt, arg1);
12803 xmlXPathReleaseObject(ctxt->context, arg2);
12806 xmlXPathCompSwap(op);
12807 return (total + cur);
12808 case XPATH_OP_ROOT:
12809 xmlXPathRoot(ctxt);
12811 case XPATH_OP_NODE:
12813 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12818 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12819 ctxt->context->node));
12821 case XPATH_OP_RESET:
12823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12828 ctxt->context->node = NULL;
12830 case XPATH_OP_COLLECT:{
12834 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12837 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12840 case XPATH_OP_VALUE:
12842 xmlXPathCacheObjectCopy(ctxt->context,
12843 (xmlXPathObjectPtr) op->value4));
12845 case XPATH_OP_SORT:
12848 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12851 if ((ctxt->value != NULL)
12852 && (ctxt->value->type == XPATH_NODESET)
12853 && (ctxt->value->nodesetval != NULL)
12854 && (ctxt->value->nodesetval->nodeNr > 1))
12855 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12857 #ifdef XP_OPTIMIZED_FILTER_FIRST
12858 case XPATH_OP_FILTER:
12859 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12863 return (xmlXPathCompOpEval(ctxt, op));
12868 * xmlXPathCompOpEvalLast:
12869 * @ctxt: the XPath parser context with the compiled expression
12870 * @op: an XPath compiled operation
12871 * @last: the last elem found so far
12873 * Evaluate the Precompiled XPath operation searching only the last
12874 * element in document order
12876 * Returns the number of nodes traversed
12879 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12882 int total = 0, cur;
12883 xmlXPathCompExprPtr comp;
12884 xmlXPathObjectPtr arg1, arg2;
12895 case XPATH_OP_UNION:
12896 bakd = ctxt->context->doc;
12897 bak = ctxt->context->node;
12898 pp = ctxt->context->proximityPosition;
12899 cs = ctxt->context->contextSize;
12901 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12903 if ((ctxt->value != NULL)
12904 && (ctxt->value->type == XPATH_NODESET)
12905 && (ctxt->value->nodesetval != NULL)
12906 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12908 * limit tree traversing to first node in the result
12910 if (ctxt->value->nodesetval->nodeNr > 1)
12911 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12913 ctxt->value->nodesetval->nodeTab[ctxt->value->
12914 nodesetval->nodeNr -
12917 ctxt->context->doc = bakd;
12918 ctxt->context->node = bak;
12919 ctxt->context->proximityPosition = pp;
12920 ctxt->context->contextSize = cs;
12922 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12924 if ((ctxt->value != NULL)
12925 && (ctxt->value->type == XPATH_NODESET)
12926 && (ctxt->value->nodesetval != NULL)
12927 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12930 arg2 = valuePop(ctxt);
12931 arg1 = valuePop(ctxt);
12932 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12933 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12934 xmlXPathReleaseObject(ctxt->context, arg1);
12935 xmlXPathReleaseObject(ctxt->context, arg2);
12936 XP_ERROR0(XPATH_INVALID_TYPE);
12939 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12941 valuePush(ctxt, arg1);
12942 xmlXPathReleaseObject(ctxt->context, arg2);
12945 xmlXPathCompSwap(op);
12946 return (total + cur);
12947 case XPATH_OP_ROOT:
12948 xmlXPathRoot(ctxt);
12950 case XPATH_OP_NODE:
12952 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12957 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12958 ctxt->context->node));
12960 case XPATH_OP_RESET:
12962 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12967 ctxt->context->node = NULL;
12969 case XPATH_OP_COLLECT:{
12973 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12976 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12979 case XPATH_OP_VALUE:
12981 xmlXPathCacheObjectCopy(ctxt->context,
12982 (xmlXPathObjectPtr) op->value4));
12984 case XPATH_OP_SORT:
12987 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12990 if ((ctxt->value != NULL)
12991 && (ctxt->value->type == XPATH_NODESET)
12992 && (ctxt->value->nodesetval != NULL)
12993 && (ctxt->value->nodesetval->nodeNr > 1))
12994 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12997 return (xmlXPathCompOpEval(ctxt, op));
13001 #ifdef XP_OPTIMIZED_FILTER_FIRST
13003 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13004 xmlXPathStepOpPtr op, xmlNodePtr * first)
13007 xmlXPathCompExprPtr comp;
13008 xmlXPathObjectPtr res;
13009 xmlXPathObjectPtr obj;
13010 xmlNodeSetPtr oldset;
13011 xmlNodePtr oldnode;
13018 * Optimization for ()[last()] selection i.e. the last elem
13020 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13021 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13022 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13023 int f = comp->steps[op->ch2].ch1;
13026 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13027 (comp->steps[f].value5 == NULL) &&
13028 (comp->steps[f].value == 0) &&
13029 (comp->steps[f].value4 != NULL) &&
13031 (comp->steps[f].value4, BAD_CAST "last"))) {
13032 xmlNodePtr last = NULL;
13035 xmlXPathCompOpEvalLast(ctxt,
13036 &comp->steps[op->ch1],
13040 * The nodeset should be in document order,
13041 * Keep only the last value
13043 if ((ctxt->value != NULL) &&
13044 (ctxt->value->type == XPATH_NODESET) &&
13045 (ctxt->value->nodesetval != NULL) &&
13046 (ctxt->value->nodesetval->nodeTab != NULL) &&
13047 (ctxt->value->nodesetval->nodeNr > 1)) {
13048 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13049 *first = *(ctxt->value->nodesetval->nodeTab);
13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13060 if (ctxt->value == NULL)
13063 #ifdef LIBXML_XPTR_ENABLED
13064 oldnode = ctxt->context->node;
13066 * Hum are we filtering the result of an XPointer expression
13068 if (ctxt->value->type == XPATH_LOCATIONSET) {
13069 xmlXPathObjectPtr tmp = NULL;
13070 xmlLocationSetPtr newlocset = NULL;
13071 xmlLocationSetPtr oldlocset;
13074 * Extract the old locset, and then evaluate the result of the
13075 * expression for all the element in the locset. use it to grow
13078 CHECK_TYPE0(XPATH_LOCATIONSET);
13079 obj = valuePop(ctxt);
13080 oldlocset = obj->user;
13081 ctxt->context->node = NULL;
13083 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13084 ctxt->context->contextSize = 0;
13085 ctxt->context->proximityPosition = 0;
13087 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13088 res = valuePop(ctxt);
13090 xmlXPathReleaseObject(ctxt->context, res);
13092 valuePush(ctxt, obj);
13096 newlocset = xmlXPtrLocationSetCreate(NULL);
13098 for (i = 0; i < oldlocset->locNr; i++) {
13100 * Run the evaluation with a node list made of a
13101 * single item in the nodelocset.
13103 ctxt->context->node = oldlocset->locTab[i]->user;
13104 ctxt->context->contextSize = oldlocset->locNr;
13105 ctxt->context->proximityPosition = i + 1;
13107 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13108 ctxt->context->node);
13110 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13111 ctxt->context->node) < 0) {
13112 ctxt->error = XPATH_MEMORY_ERROR;
13115 valuePush(ctxt, tmp);
13117 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13118 if (ctxt->error != XPATH_EXPRESSION_OK) {
13119 xmlXPathFreeObject(obj);
13123 * The result of the evaluation need to be tested to
13124 * decided whether the filter succeeded or not
13126 res = valuePop(ctxt);
13127 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13128 xmlXPtrLocationSetAdd(newlocset,
13129 xmlXPathCacheObjectCopy(ctxt->context,
13130 oldlocset->locTab[i]));
13136 xmlXPathReleaseObject(ctxt->context, res);
13138 if (ctxt->value == tmp) {
13140 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13142 * REVISIT TODO: Don't create a temporary nodeset
13143 * for everly iteration.
13145 /* OLD: xmlXPathFreeObject(res); */
13148 ctxt->context->node = NULL;
13150 * Only put the first node in the result, then leave.
13152 if (newlocset->locNr > 0) {
13153 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13158 xmlXPathReleaseObject(ctxt->context, tmp);
13161 * The result is used as the new evaluation locset.
13163 xmlXPathReleaseObject(ctxt->context, obj);
13164 ctxt->context->node = NULL;
13165 ctxt->context->contextSize = -1;
13166 ctxt->context->proximityPosition = -1;
13167 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13168 ctxt->context->node = oldnode;
13171 #endif /* LIBXML_XPTR_ENABLED */
13174 * Extract the old set, and then evaluate the result of the
13175 * expression for all the element in the set. use it to grow
13178 CHECK_TYPE0(XPATH_NODESET);
13179 obj = valuePop(ctxt);
13180 oldset = obj->nodesetval;
13182 oldnode = ctxt->context->node;
13183 oldDoc = ctxt->context->doc;
13184 ctxt->context->node = NULL;
13186 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13187 ctxt->context->contextSize = 0;
13188 ctxt->context->proximityPosition = 0;
13189 /* QUESTION TODO: Why was this code commented out?
13192 xmlXPathCompOpEval(ctxt,
13193 &comp->steps[op->ch2]);
13195 res = valuePop(ctxt);
13197 xmlXPathFreeObject(res);
13199 valuePush(ctxt, obj);
13200 ctxt->context->node = oldnode;
13203 xmlNodeSetPtr newset;
13204 xmlXPathObjectPtr tmp = NULL;
13206 * Initialize the new set.
13207 * Also set the xpath document in case things like
13208 * key() evaluation are attempted on the predicate
13210 newset = xmlXPathNodeSetCreate(NULL);
13211 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13213 for (i = 0; i < oldset->nodeNr; i++) {
13215 * Run the evaluation with a node list made of
13216 * a single item in the nodeset.
13218 ctxt->context->node = oldset->nodeTab[i];
13219 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13220 (oldset->nodeTab[i]->doc != NULL))
13221 ctxt->context->doc = oldset->nodeTab[i]->doc;
13223 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13224 ctxt->context->node);
13226 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13227 ctxt->context->node) < 0) {
13228 ctxt->error = XPATH_MEMORY_ERROR;
13231 valuePush(ctxt, tmp);
13232 ctxt->context->contextSize = oldset->nodeNr;
13233 ctxt->context->proximityPosition = i + 1;
13235 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13236 if (ctxt->error != XPATH_EXPRESSION_OK) {
13237 xmlXPathFreeNodeSet(newset);
13238 xmlXPathFreeObject(obj);
13242 * The result of the evaluation needs to be tested to
13243 * decide whether the filter succeeded or not
13245 res = valuePop(ctxt);
13246 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13247 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13248 ctxt->error = XPATH_MEMORY_ERROR;
13254 xmlXPathReleaseObject(ctxt->context, res);
13256 if (ctxt->value == tmp) {
13259 * Don't free the temporary nodeset
13260 * in order to avoid massive recreation inside this
13263 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13266 ctxt->context->node = NULL;
13268 * Only put the first node in the result, then leave.
13270 if (newset->nodeNr > 0) {
13271 *first = *(newset->nodeTab);
13276 xmlXPathReleaseObject(ctxt->context, tmp);
13279 * The result is used as the new evaluation set.
13281 xmlXPathReleaseObject(ctxt->context, obj);
13282 ctxt->context->node = NULL;
13283 ctxt->context->contextSize = -1;
13284 ctxt->context->proximityPosition = -1;
13285 /* may want to move this past the '}' later */
13286 ctxt->context->doc = oldDoc;
13287 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13289 ctxt->context->node = oldnode;
13292 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13295 * xmlXPathCompOpEval:
13296 * @ctxt: the XPath parser context with the compiled expression
13297 * @op: an XPath compiled operation
13299 * Evaluate the Precompiled XPath operation
13300 * Returns the number of nodes traversed
13303 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13307 xmlXPathCompExprPtr comp;
13308 xmlXPathObjectPtr arg1, arg2;
13320 bakd = ctxt->context->doc;
13321 bak = ctxt->context->node;
13322 pp = ctxt->context->proximityPosition;
13323 cs = ctxt->context->contextSize;
13324 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13326 xmlXPathBooleanFunction(ctxt, 1);
13327 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13329 arg2 = valuePop(ctxt);
13330 ctxt->context->doc = bakd;
13331 ctxt->context->node = bak;
13332 ctxt->context->proximityPosition = pp;
13333 ctxt->context->contextSize = cs;
13334 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13336 xmlXPathFreeObject(arg2);
13339 xmlXPathBooleanFunction(ctxt, 1);
13340 arg1 = valuePop(ctxt);
13341 arg1->boolval &= arg2->boolval;
13342 valuePush(ctxt, arg1);
13343 xmlXPathReleaseObject(ctxt->context, arg2);
13346 bakd = ctxt->context->doc;
13347 bak = ctxt->context->node;
13348 pp = ctxt->context->proximityPosition;
13349 cs = ctxt->context->contextSize;
13350 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13352 xmlXPathBooleanFunction(ctxt, 1);
13353 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13355 arg2 = valuePop(ctxt);
13356 ctxt->context->doc = bakd;
13357 ctxt->context->node = bak;
13358 ctxt->context->proximityPosition = pp;
13359 ctxt->context->contextSize = cs;
13360 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13362 xmlXPathFreeObject(arg2);
13365 xmlXPathBooleanFunction(ctxt, 1);
13366 arg1 = valuePop(ctxt);
13367 arg1->boolval |= arg2->boolval;
13368 valuePush(ctxt, arg1);
13369 xmlXPathReleaseObject(ctxt->context, arg2);
13371 case XPATH_OP_EQUAL:
13372 bakd = ctxt->context->doc;
13373 bak = ctxt->context->node;
13374 pp = ctxt->context->proximityPosition;
13375 cs = ctxt->context->contextSize;
13376 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13378 ctxt->context->doc = bakd;
13379 ctxt->context->node = bak;
13380 ctxt->context->proximityPosition = pp;
13381 ctxt->context->contextSize = cs;
13382 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13385 equal = xmlXPathEqualValues(ctxt);
13387 equal = xmlXPathNotEqualValues(ctxt);
13388 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13391 bakd = ctxt->context->doc;
13392 bak = ctxt->context->node;
13393 pp = ctxt->context->proximityPosition;
13394 cs = ctxt->context->contextSize;
13395 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13397 ctxt->context->doc = bakd;
13398 ctxt->context->node = bak;
13399 ctxt->context->proximityPosition = pp;
13400 ctxt->context->contextSize = cs;
13401 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13403 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13404 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13406 case XPATH_OP_PLUS:
13407 bakd = ctxt->context->doc;
13408 bak = ctxt->context->node;
13409 pp = ctxt->context->proximityPosition;
13410 cs = ctxt->context->contextSize;
13411 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13413 if (op->ch2 != -1) {
13414 ctxt->context->doc = bakd;
13415 ctxt->context->node = bak;
13416 ctxt->context->proximityPosition = pp;
13417 ctxt->context->contextSize = cs;
13418 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13421 if (op->value == 0)
13422 xmlXPathSubValues(ctxt);
13423 else if (op->value == 1)
13424 xmlXPathAddValues(ctxt);
13425 else if (op->value == 2)
13426 xmlXPathValueFlipSign(ctxt);
13427 else if (op->value == 3) {
13429 CHECK_TYPE0(XPATH_NUMBER);
13432 case XPATH_OP_MULT:
13433 bakd = ctxt->context->doc;
13434 bak = ctxt->context->node;
13435 pp = ctxt->context->proximityPosition;
13436 cs = ctxt->context->contextSize;
13437 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13439 ctxt->context->doc = bakd;
13440 ctxt->context->node = bak;
13441 ctxt->context->proximityPosition = pp;
13442 ctxt->context->contextSize = cs;
13443 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13445 if (op->value == 0)
13446 xmlXPathMultValues(ctxt);
13447 else if (op->value == 1)
13448 xmlXPathDivValues(ctxt);
13449 else if (op->value == 2)
13450 xmlXPathModValues(ctxt);
13452 case XPATH_OP_UNION:
13453 bakd = ctxt->context->doc;
13454 bak = ctxt->context->node;
13455 pp = ctxt->context->proximityPosition;
13456 cs = ctxt->context->contextSize;
13457 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13459 ctxt->context->doc = bakd;
13460 ctxt->context->node = bak;
13461 ctxt->context->proximityPosition = pp;
13462 ctxt->context->contextSize = cs;
13463 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13466 arg2 = valuePop(ctxt);
13467 arg1 = valuePop(ctxt);
13468 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13469 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13470 xmlXPathReleaseObject(ctxt->context, arg1);
13471 xmlXPathReleaseObject(ctxt->context, arg2);
13472 XP_ERROR0(XPATH_INVALID_TYPE);
13475 if ((arg1->nodesetval == NULL) ||
13476 ((arg2->nodesetval != NULL) &&
13477 (arg2->nodesetval->nodeNr != 0)))
13479 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13483 valuePush(ctxt, arg1);
13484 xmlXPathReleaseObject(ctxt->context, arg2);
13486 case XPATH_OP_ROOT:
13487 xmlXPathRoot(ctxt);
13489 case XPATH_OP_NODE:
13491 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13494 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13496 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13497 ctxt->context->node));
13499 case XPATH_OP_RESET:
13501 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13504 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13506 ctxt->context->node = NULL;
13508 case XPATH_OP_COLLECT:{
13512 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13515 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13518 case XPATH_OP_VALUE:
13520 xmlXPathCacheObjectCopy(ctxt->context,
13521 (xmlXPathObjectPtr) op->value4));
13523 case XPATH_OP_VARIABLE:{
13524 xmlXPathObjectPtr val;
13528 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13529 if (op->value5 == NULL) {
13530 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13532 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13533 valuePush(ctxt, val);
13535 const xmlChar *URI;
13537 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13539 xmlGenericError(xmlGenericErrorContext,
13540 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13541 (char *) op->value4, (char *)op->value5);
13542 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13545 val = xmlXPathVariableLookupNS(ctxt->context,
13548 XP_ERROR0(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"