2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
9 * http://www.w3.org/TR/xpath
11 * See Copyright for the status of this software
13 * Author: daniel@veillard.com
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
58 #ifdef LIBXML_PATTERN_ENABLED
59 #define XPATH_STREAMING
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
68 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
69 * If defined, this will use xmlXPathCmpNodesExt() instead of
70 * xmlXPathCmpNodes(). The new function is optimized comparison of
71 * non-element nodes; actually it will speed up comparison only if
72 * xmlXPathOrderDocElems() was called in order to index the elements of
73 * a tree in document order; Libxslt does such an indexing, thus it will
74 * benefit from this optimization.
76 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
79 * XP_OPTIMIZED_FILTER_FIRST:
80 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
81 * in a way, that it stop evaluation at the first node.
83 #define XP_OPTIMIZED_FILTER_FIRST
87 * Internal flag to enable tracking of how much XPath objects have been
90 /* #define XP_DEBUG_OBJ_USAGE */
94 * There are a few spots where some tests are done which depend upon ascii
95 * data. These should be enhanced for full UTF8 support (see particularly
96 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
99 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
101 /************************************************************************
103 * Floating point stuff *
105 ************************************************************************/
107 #ifndef TRIO_REPLACE_STDIO
108 #define TRIO_PUBLIC static
113 * The lack of portability of this section of the libc is annoying !
115 double xmlXPathNAN = 0;
116 double xmlXPathPINF = 1;
117 double xmlXPathNINF = -1;
118 static double xmlXPathNZERO = 0; /* not exported from headers */
119 static int xmlXPathInitialized = 0;
124 * Initialize the XPath environment
128 if (xmlXPathInitialized) return;
130 xmlXPathPINF = trio_pinf();
131 xmlXPathNINF = trio_ninf();
132 xmlXPathNAN = trio_nan();
133 xmlXPathNZERO = trio_nzero();
135 xmlXPathInitialized = 1;
140 * @val: a double value
142 * Provides a portable isnan() function to detect whether a double
143 * is a NotaNumber. Based on trio code
144 * http://sourceforge.net/projects/ctrio/
146 * Returns 1 if the value is a NaN, 0 otherwise
149 xmlXPathIsNaN(double val) {
150 return(trio_isnan(val));
155 * @val: a double value
157 * Provides a portable isinf() function to detect whether a double
158 * is a +Infinite or -Infinite. Based on trio code
159 * http://sourceforge.net/projects/ctrio/
161 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
164 xmlXPathIsInf(double val) {
165 return(trio_isinf(val));
168 #endif /* SCHEMAS or XPATH */
169 #ifdef LIBXML_XPATH_ENABLED
172 * @val: a double value
174 * Provides a portable function to detect the sign of a double
175 * Modified from trio code
176 * http://sourceforge.net/projects/ctrio/
178 * Returns 1 if the value is Negative, 0 if positive
181 xmlXPathGetSign(double val) {
182 return(trio_signbit(val));
187 * TODO: when compatibility allows remove all "fake node libxslt" strings
188 * the test should just be name[0] = ' '
191 /* #define DEBUG_STEP */
192 /* #define DEBUG_STEP_NTH */
193 /* #define DEBUG_EXPR */
194 /* #define DEBUG_EVAL_COUNTS */
196 static xmlNs xmlXPathXMLNamespaceStruct = {
203 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
204 #ifndef LIBXML_THREAD_ENABLED
206 * Optimizer is disabled only when threaded apps are detected while
207 * the library ain't compiled for thread safety.
209 static int xmlXPathDisableOptimizer = 0;
212 /************************************************************************
214 * Error handling routines *
216 ************************************************************************/
222 * Macro to raise an XPath error and return NULL.
224 #define XP_ERRORNULL(X) \
225 { xmlXPathErr(ctxt, X); return(NULL); }
228 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
230 static const char *xmlXPathErrorMessages[] = {
233 "Unfinished literal\n",
234 "Start of literal\n",
235 "Expected $ for variable reference\n",
236 "Undefined variable\n",
237 "Invalid predicate\n",
238 "Invalid expression\n",
239 "Missing closing curly brace\n",
240 "Unregistered function\n",
243 "Invalid number of arguments\n",
244 "Invalid context size\n",
245 "Invalid context position\n",
246 "Memory allocation error\n",
249 "Sub resource error\n",
250 "Undefined namespace prefix\n",
252 "Char out of XML range\n",
253 "Invalid or incomplete context\n",
254 "?? Unknown error ??\n" /* Must be last in the list! */
256 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
257 sizeof(xmlXPathErrorMessages[0])) - 1)
260 * @ctxt: an XPath context
261 * @extra: extra informations
263 * Handle a redefinition of attribute error
266 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
272 xmlStrPrintf(buf, 200,
273 BAD_CAST "Memory allocation failed : %s\n",
275 ctxt->lastError.message = (char *) xmlStrdup(buf);
277 ctxt->lastError.message = (char *)
278 xmlStrdup(BAD_CAST "Memory allocation failed\n");
280 ctxt->lastError.domain = XML_FROM_XPATH;
281 ctxt->lastError.code = XML_ERR_NO_MEMORY;
282 if (ctxt->error != NULL)
283 ctxt->error(ctxt->userData, &ctxt->lastError);
286 __xmlRaiseError(NULL, NULL, NULL,
287 NULL, NULL, XML_FROM_XPATH,
288 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
289 extra, NULL, NULL, 0, 0,
290 "Memory allocation failed : %s\n", extra);
292 __xmlRaiseError(NULL, NULL, NULL,
293 NULL, NULL, XML_FROM_XPATH,
294 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
295 NULL, NULL, NULL, 0, 0,
296 "Memory allocation failed\n");
301 * xmlXPathPErrMemory:
302 * @ctxt: an XPath parser context
303 * @extra: extra informations
305 * Handle a redefinition of attribute error
308 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
311 xmlXPathErrMemory(NULL, extra);
313 ctxt->error = XPATH_MEMORY_ERROR;
314 xmlXPathErrMemory(ctxt->context, extra);
320 * @ctxt: a XPath parser context
321 * @error: the error code
323 * Handle an XPath error
326 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
328 if ((error < 0) || (error > MAXERRNO))
331 __xmlRaiseError(NULL, NULL, NULL,
332 NULL, NULL, XML_FROM_XPATH,
333 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
334 XML_ERR_ERROR, NULL, 0,
335 NULL, NULL, NULL, 0, 0,
336 xmlXPathErrorMessages[error]);
340 if (ctxt->context == NULL) {
341 __xmlRaiseError(NULL, NULL, NULL,
342 NULL, NULL, XML_FROM_XPATH,
343 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
344 XML_ERR_ERROR, NULL, 0,
345 (const char *) ctxt->base, NULL, NULL,
346 ctxt->cur - ctxt->base, 0,
347 xmlXPathErrorMessages[error]);
351 /* cleanup current last error */
352 xmlResetError(&ctxt->context->lastError);
354 ctxt->context->lastError.domain = XML_FROM_XPATH;
355 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
357 ctxt->context->lastError.level = XML_ERR_ERROR;
358 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
359 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
360 ctxt->context->lastError.node = ctxt->context->debugNode;
361 if (ctxt->context->error != NULL) {
362 ctxt->context->error(ctxt->context->userData,
363 &ctxt->context->lastError);
365 __xmlRaiseError(NULL, NULL, NULL,
366 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
367 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
368 XML_ERR_ERROR, NULL, 0,
369 (const char *) ctxt->base, NULL, NULL,
370 ctxt->cur - ctxt->base, 0,
371 xmlXPathErrorMessages[error]);
378 * @ctxt: the XPath Parser context
379 * @file: the file name
380 * @line: the line number
381 * @no: the error number
383 * Formats an error message.
386 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
387 int line ATTRIBUTE_UNUSED, int no) {
388 xmlXPathErr(ctxt, no);
391 /************************************************************************
395 ************************************************************************/
400 * Pointer-list for various purposes.
402 typedef struct _xmlPointerList xmlPointerList;
403 typedef xmlPointerList *xmlPointerListPtr;
404 struct _xmlPointerList {
410 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
411 * and here, we should make the functions public.
414 xmlPointerListAddSize(xmlPointerListPtr list,
418 if (list->items == NULL) {
419 if (initialSize <= 0)
421 list->items = (void **) xmlMalloc(
422 initialSize * sizeof(void *));
423 if (list->items == NULL) {
424 xmlXPathErrMemory(NULL,
425 "xmlPointerListCreate: allocating item\n");
429 list->size = initialSize;
430 } else if (list->size <= list->number) {
432 list->items = (void **) xmlRealloc(list->items,
433 list->size * sizeof(void *));
434 if (list->items == NULL) {
435 xmlXPathErrMemory(NULL,
436 "xmlPointerListCreate: re-allocating item\n");
441 list->items[list->number++] = item;
446 * xsltPointerListCreate:
448 * Creates an xsltPointerList structure.
450 * Returns a xsltPointerList structure or NULL in case of an error.
452 static xmlPointerListPtr
453 xmlPointerListCreate(int initialSize)
455 xmlPointerListPtr ret;
457 ret = xmlMalloc(sizeof(xmlPointerList));
459 xmlXPathErrMemory(NULL,
460 "xmlPointerListCreate: allocating item\n");
463 memset(ret, 0, sizeof(xmlPointerList));
464 if (initialSize > 0) {
465 xmlPointerListAddSize(ret, NULL, initialSize);
472 * xsltPointerListFree:
474 * Frees the xsltPointerList structure. This does not free
475 * the content of the list.
478 xmlPointerListFree(xmlPointerListPtr list)
482 if (list->items != NULL)
483 xmlFree(list->items);
487 /************************************************************************
491 ************************************************************************/
508 XPATH_OP_RESET, /* 10 */
510 XPATH_OP_VALUE, /* 12 */
515 XPATH_OP_FILTER, /* 17 */
516 XPATH_OP_SORT /* 18 */
517 #ifdef LIBXML_XPTR_ENABLED
524 AXIS_ANCESTOR_OR_SELF,
528 AXIS_DESCENDANT_OR_SELF,
530 AXIS_FOLLOWING_SIBLING,
534 AXIS_PRECEDING_SIBLING,
549 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
550 NODE_TYPE_TEXT = XML_TEXT_NODE,
551 NODE_TYPE_PI = XML_PI_NODE
554 #define XP_REWRITE_DOS_CHILD_ELEM 1
556 typedef struct _xmlXPathStepOp xmlXPathStepOp;
557 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
558 struct _xmlXPathStepOp {
559 xmlXPathOp op; /* The identifier of the operation */
560 int ch1; /* First child */
561 int ch2; /* Second child */
572 struct _xmlXPathCompExpr {
573 int nbStep; /* Number of steps in this expression */
574 int maxStep; /* Maximum number of steps allocated */
575 xmlXPathStepOp *steps; /* ops for computation of this expression */
576 int last; /* index of last step in expression */
577 xmlChar *expr; /* the expression being computed */
578 xmlDictPtr dict; /* the dictionnary to use if any */
579 #ifdef DEBUG_EVAL_COUNTS
583 #ifdef XPATH_STREAMING
584 xmlPatternPtr stream;
588 /************************************************************************
590 * Forward declarations *
592 ************************************************************************/
594 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
596 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
598 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
599 xmlXPathStepOpPtr op, xmlNodePtr *first);
601 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
602 xmlXPathStepOpPtr op,
605 /************************************************************************
607 * Parser Type functions *
609 ************************************************************************/
612 * xmlXPathNewCompExpr:
614 * Create a new Xpath component
616 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
618 static xmlXPathCompExprPtr
619 xmlXPathNewCompExpr(void) {
620 xmlXPathCompExprPtr cur;
622 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
624 xmlXPathErrMemory(NULL, "allocating component\n");
627 memset(cur, 0, sizeof(xmlXPathCompExpr));
630 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
631 sizeof(xmlXPathStepOp));
632 if (cur->steps == NULL) {
633 xmlXPathErrMemory(NULL, "allocating steps\n");
637 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
639 #ifdef DEBUG_EVAL_COUNTS
646 * xmlXPathFreeCompExpr:
647 * @comp: an XPATH comp
649 * Free up the memory allocated by @comp
652 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
654 xmlXPathStepOpPtr op;
659 if (comp->dict == NULL) {
660 for (i = 0; i < comp->nbStep; i++) {
661 op = &comp->steps[i];
662 if (op->value4 != NULL) {
663 if (op->op == XPATH_OP_VALUE)
664 xmlXPathFreeObject(op->value4);
668 if (op->value5 != NULL)
672 for (i = 0; i < comp->nbStep; i++) {
673 op = &comp->steps[i];
674 if (op->value4 != NULL) {
675 if (op->op == XPATH_OP_VALUE)
676 xmlXPathFreeObject(op->value4);
679 xmlDictFree(comp->dict);
681 if (comp->steps != NULL) {
682 xmlFree(comp->steps);
684 #ifdef DEBUG_EVAL_COUNTS
685 if (comp->string != NULL) {
686 xmlFree(comp->string);
689 #ifdef XPATH_STREAMING
690 if (comp->stream != NULL) {
691 xmlFreePatternList(comp->stream);
694 if (comp->expr != NULL) {
702 * xmlXPathCompExprAdd:
703 * @comp: the compiled expression
704 * @ch1: first child index
705 * @ch2: second child index
707 * @value: the first int value
708 * @value2: the second int value
709 * @value3: the third int value
710 * @value4: the first string value
711 * @value5: the second string value
713 * Add a step to an XPath Compiled Expression
715 * Returns -1 in case of failure, the index otherwise
718 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
719 xmlXPathOp op, int value,
720 int value2, int value3, void *value4, void *value5) {
721 if (comp->nbStep >= comp->maxStep) {
722 xmlXPathStepOp *real;
725 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
726 comp->maxStep * sizeof(xmlXPathStepOp));
729 xmlXPathErrMemory(NULL, "adding step\n");
734 comp->last = comp->nbStep;
735 comp->steps[comp->nbStep].rewriteType = 0;
736 comp->steps[comp->nbStep].ch1 = ch1;
737 comp->steps[comp->nbStep].ch2 = ch2;
738 comp->steps[comp->nbStep].op = op;
739 comp->steps[comp->nbStep].value = value;
740 comp->steps[comp->nbStep].value2 = value2;
741 comp->steps[comp->nbStep].value3 = value3;
742 if ((comp->dict != NULL) &&
743 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
744 (op == XPATH_OP_COLLECT))) {
745 if (value4 != NULL) {
746 comp->steps[comp->nbStep].value4 = (xmlChar *)
747 (void *)xmlDictLookup(comp->dict, value4, -1);
750 comp->steps[comp->nbStep].value4 = NULL;
751 if (value5 != NULL) {
752 comp->steps[comp->nbStep].value5 = (xmlChar *)
753 (void *)xmlDictLookup(comp->dict, value5, -1);
756 comp->steps[comp->nbStep].value5 = NULL;
758 comp->steps[comp->nbStep].value4 = value4;
759 comp->steps[comp->nbStep].value5 = value5;
761 comp->steps[comp->nbStep].cache = NULL;
762 return(comp->nbStep++);
767 * @comp: the compiled expression
768 * @op: operation index
770 * Swaps 2 operations in the compiled expression
773 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
776 #ifndef LIBXML_THREAD_ENABLED
778 * Since this manipulates possibly shared variables, this is
779 * disabled if one detects that the library is used in a multithreaded
782 if (xmlXPathDisableOptimizer)
791 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
792 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
793 (op), (val), (val2), (val3), (val4), (val5))
794 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
795 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
796 (op), (val), (val2), (val3), (val4), (val5))
798 #define PUSH_LEAVE_EXPR(op, val, val2) \
799 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
801 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
802 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
804 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
805 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
806 (val), (val2), 0 ,NULL ,NULL)
808 /************************************************************************
810 * XPath object cache structures *
812 ************************************************************************/
814 /* #define XP_DEFAULT_CACHE_ON */
816 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
818 typedef struct _xmlXPathContextCache xmlXPathContextCache;
819 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
820 struct _xmlXPathContextCache {
821 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
822 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
831 #ifdef XP_DEBUG_OBJ_USAGE
833 int dbgCachedNodeset;
841 int dbgCachedXSLTTree;
842 int dbgCachedUndefined;
846 int dbgReusedNodeset;
854 int dbgReusedXSLTTree;
855 int dbgReusedUndefined;
860 /************************************************************************
862 * Debugging related functions *
864 ************************************************************************/
867 xmlGenericError(xmlGenericErrorContext, \
868 "Internal error at %s:%d\n", \
871 #ifdef LIBXML_DEBUG_ENABLED
873 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
877 for (i = 0;((i < depth) && (i < 25));i++)
878 shift[2 * i] = shift[2 * i + 1] = ' ';
879 shift[2 * i] = shift[2 * i + 1] = 0;
881 fprintf(output, shift);
882 fprintf(output, "Node is NULL !\n");
887 if ((cur->type == XML_DOCUMENT_NODE) ||
888 (cur->type == XML_HTML_DOCUMENT_NODE)) {
889 fprintf(output, shift);
890 fprintf(output, " /\n");
891 } else if (cur->type == XML_ATTRIBUTE_NODE)
892 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
894 xmlDebugDumpOneNode(output, cur, depth);
897 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
902 for (i = 0;((i < depth) && (i < 25));i++)
903 shift[2 * i] = shift[2 * i + 1] = ' ';
904 shift[2 * i] = shift[2 * i + 1] = 0;
906 fprintf(output, shift);
907 fprintf(output, "Node is NULL !\n");
912 while (cur != NULL) {
915 xmlDebugDumpOneNode(output, tmp, depth);
920 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
924 for (i = 0;((i < depth) && (i < 25));i++)
925 shift[2 * i] = shift[2 * i + 1] = ' ';
926 shift[2 * i] = shift[2 * i + 1] = 0;
929 fprintf(output, shift);
930 fprintf(output, "NodeSet is NULL !\n");
936 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
937 for (i = 0;i < cur->nodeNr;i++) {
938 fprintf(output, shift);
939 fprintf(output, "%d", i + 1);
940 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
946 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
950 for (i = 0;((i < depth) && (i < 25));i++)
951 shift[2 * i] = shift[2 * i + 1] = ' ';
952 shift[2 * i] = shift[2 * i + 1] = 0;
954 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
955 fprintf(output, shift);
956 fprintf(output, "Value Tree is NULL !\n");
961 fprintf(output, shift);
962 fprintf(output, "%d", i + 1);
963 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
965 #if defined(LIBXML_XPTR_ENABLED)
967 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
971 for (i = 0;((i < depth) && (i < 25));i++)
972 shift[2 * i] = shift[2 * i + 1] = ' ';
973 shift[2 * i] = shift[2 * i + 1] = 0;
976 fprintf(output, shift);
977 fprintf(output, "LocationSet is NULL !\n");
982 for (i = 0;i < cur->locNr;i++) {
983 fprintf(output, shift);
984 fprintf(output, "%d : ", i + 1);
985 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
988 #endif /* LIBXML_XPTR_ENABLED */
991 * xmlXPathDebugDumpObject:
992 * @output: the FILE * to dump the output
993 * @cur: the object to inspect
994 * @depth: indentation level
996 * Dump the content of the object for debugging purposes
999 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1003 if (output == NULL) return;
1005 for (i = 0;((i < depth) && (i < 25));i++)
1006 shift[2 * i] = shift[2 * i + 1] = ' ';
1007 shift[2 * i] = shift[2 * i + 1] = 0;
1010 fprintf(output, shift);
1013 fprintf(output, "Object is empty (NULL)\n");
1017 case XPATH_UNDEFINED:
1018 fprintf(output, "Object is uninitialized\n");
1021 fprintf(output, "Object is a Node Set :\n");
1022 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1024 case XPATH_XSLT_TREE:
1025 fprintf(output, "Object is an XSLT value tree :\n");
1026 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1029 fprintf(output, "Object is a Boolean : ");
1030 if (cur->boolval) fprintf(output, "true\n");
1031 else fprintf(output, "false\n");
1034 switch (xmlXPathIsInf(cur->floatval)) {
1036 fprintf(output, "Object is a number : Infinity\n");
1039 fprintf(output, "Object is a number : -Infinity\n");
1042 if (xmlXPathIsNaN(cur->floatval)) {
1043 fprintf(output, "Object is a number : NaN\n");
1044 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1045 fprintf(output, "Object is a number : 0\n");
1047 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1052 fprintf(output, "Object is a string : ");
1053 xmlDebugDumpString(output, cur->stringval);
1054 fprintf(output, "\n");
1057 fprintf(output, "Object is a point : index %d in node", cur->index);
1058 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1059 fprintf(output, "\n");
1062 if ((cur->user2 == NULL) ||
1063 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1064 fprintf(output, "Object is a collapsed range :\n");
1065 fprintf(output, shift);
1066 if (cur->index >= 0)
1067 fprintf(output, "index %d in ", cur->index);
1068 fprintf(output, "node\n");
1069 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1072 fprintf(output, "Object is a range :\n");
1073 fprintf(output, shift);
1074 fprintf(output, "From ");
1075 if (cur->index >= 0)
1076 fprintf(output, "index %d in ", cur->index);
1077 fprintf(output, "node\n");
1078 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1080 fprintf(output, shift);
1081 fprintf(output, "To ");
1082 if (cur->index2 >= 0)
1083 fprintf(output, "index %d in ", cur->index2);
1084 fprintf(output, "node\n");
1085 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1087 fprintf(output, "\n");
1090 case XPATH_LOCATIONSET:
1091 #if defined(LIBXML_XPTR_ENABLED)
1092 fprintf(output, "Object is a Location Set:\n");
1093 xmlXPathDebugDumpLocationSet(output,
1094 (xmlLocationSetPtr) cur->user, depth);
1098 fprintf(output, "Object is user defined\n");
1104 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1105 xmlXPathStepOpPtr op, int depth) {
1109 for (i = 0;((i < depth) && (i < 25));i++)
1110 shift[2 * i] = shift[2 * i + 1] = ' ';
1111 shift[2 * i] = shift[2 * i + 1] = 0;
1113 fprintf(output, shift);
1115 fprintf(output, "Step is NULL\n");
1120 fprintf(output, "END"); break;
1122 fprintf(output, "AND"); break;
1124 fprintf(output, "OR"); break;
1125 case XPATH_OP_EQUAL:
1127 fprintf(output, "EQUAL =");
1129 fprintf(output, "EQUAL !=");
1133 fprintf(output, "CMP <");
1135 fprintf(output, "CMP >");
1137 fprintf(output, "=");
1141 fprintf(output, "PLUS -");
1142 else if (op->value == 1)
1143 fprintf(output, "PLUS +");
1144 else if (op->value == 2)
1145 fprintf(output, "PLUS unary -");
1146 else if (op->value == 3)
1147 fprintf(output, "PLUS unary - -");
1151 fprintf(output, "MULT *");
1152 else if (op->value == 1)
1153 fprintf(output, "MULT div");
1155 fprintf(output, "MULT mod");
1157 case XPATH_OP_UNION:
1158 fprintf(output, "UNION"); break;
1160 fprintf(output, "ROOT"); break;
1162 fprintf(output, "NODE"); break;
1163 case XPATH_OP_RESET:
1164 fprintf(output, "RESET"); break;
1166 fprintf(output, "SORT"); break;
1167 case XPATH_OP_COLLECT: {
1168 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1169 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1170 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1171 const xmlChar *prefix = op->value4;
1172 const xmlChar *name = op->value5;
1174 fprintf(output, "COLLECT ");
1177 fprintf(output, " 'ancestors' "); break;
1178 case AXIS_ANCESTOR_OR_SELF:
1179 fprintf(output, " 'ancestors-or-self' "); break;
1180 case AXIS_ATTRIBUTE:
1181 fprintf(output, " 'attributes' "); break;
1183 fprintf(output, " 'child' "); break;
1184 case AXIS_DESCENDANT:
1185 fprintf(output, " 'descendant' "); break;
1186 case AXIS_DESCENDANT_OR_SELF:
1187 fprintf(output, " 'descendant-or-self' "); break;
1188 case AXIS_FOLLOWING:
1189 fprintf(output, " 'following' "); break;
1190 case AXIS_FOLLOWING_SIBLING:
1191 fprintf(output, " 'following-siblings' "); break;
1192 case AXIS_NAMESPACE:
1193 fprintf(output, " 'namespace' "); break;
1195 fprintf(output, " 'parent' "); break;
1196 case AXIS_PRECEDING:
1197 fprintf(output, " 'preceding' "); break;
1198 case AXIS_PRECEDING_SIBLING:
1199 fprintf(output, " 'preceding-sibling' "); break;
1201 fprintf(output, " 'self' "); break;
1204 case NODE_TEST_NONE:
1205 fprintf(output, "'none' "); break;
1206 case NODE_TEST_TYPE:
1207 fprintf(output, "'type' "); break;
1209 fprintf(output, "'PI' "); break;
1211 fprintf(output, "'all' "); break;
1213 fprintf(output, "'namespace' "); break;
1214 case NODE_TEST_NAME:
1215 fprintf(output, "'name' "); break;
1218 case NODE_TYPE_NODE:
1219 fprintf(output, "'node' "); break;
1220 case NODE_TYPE_COMMENT:
1221 fprintf(output, "'comment' "); break;
1222 case NODE_TYPE_TEXT:
1223 fprintf(output, "'text' "); break;
1225 fprintf(output, "'PI' "); break;
1228 fprintf(output, "%s:", prefix);
1230 fprintf(output, "%s", (const char *) name);
1234 case XPATH_OP_VALUE: {
1235 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1237 fprintf(output, "ELEM ");
1238 xmlXPathDebugDumpObject(output, object, 0);
1241 case XPATH_OP_VARIABLE: {
1242 const xmlChar *prefix = op->value5;
1243 const xmlChar *name = op->value4;
1246 fprintf(output, "VARIABLE %s:%s", prefix, name);
1248 fprintf(output, "VARIABLE %s", name);
1251 case XPATH_OP_FUNCTION: {
1252 int nbargs = op->value;
1253 const xmlChar *prefix = op->value5;
1254 const xmlChar *name = op->value4;
1257 fprintf(output, "FUNCTION %s:%s(%d args)",
1258 prefix, name, nbargs);
1260 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1263 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1264 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1265 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1266 #ifdef LIBXML_XPTR_ENABLED
1267 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1270 fprintf(output, "UNKNOWN %d\n", op->op); return;
1272 fprintf(output, "\n");
1275 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1281 * xmlXPathDebugDumpCompExpr:
1282 * @output: the FILE * for the output
1283 * @comp: the precompiled XPath expression
1284 * @depth: the indentation level.
1286 * Dumps the tree of the compiled XPath expression.
1289 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1294 if ((output == NULL) || (comp == NULL)) return;
1296 for (i = 0;((i < depth) && (i < 25));i++)
1297 shift[2 * i] = shift[2 * i + 1] = ' ';
1298 shift[2 * i] = shift[2 * i + 1] = 0;
1300 fprintf(output, shift);
1302 fprintf(output, "Compiled Expression : %d elements\n",
1305 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1308 #ifdef XP_DEBUG_OBJ_USAGE
1311 * XPath object usage related debugging variables.
1313 static int xmlXPathDebugObjCounterUndefined = 0;
1314 static int xmlXPathDebugObjCounterNodeset = 0;
1315 static int xmlXPathDebugObjCounterBool = 0;
1316 static int xmlXPathDebugObjCounterNumber = 0;
1317 static int xmlXPathDebugObjCounterString = 0;
1318 static int xmlXPathDebugObjCounterPoint = 0;
1319 static int xmlXPathDebugObjCounterRange = 0;
1320 static int xmlXPathDebugObjCounterLocset = 0;
1321 static int xmlXPathDebugObjCounterUsers = 0;
1322 static int xmlXPathDebugObjCounterXSLTTree = 0;
1323 static int xmlXPathDebugObjCounterAll = 0;
1325 static int xmlXPathDebugObjTotalUndefined = 0;
1326 static int xmlXPathDebugObjTotalNodeset = 0;
1327 static int xmlXPathDebugObjTotalBool = 0;
1328 static int xmlXPathDebugObjTotalNumber = 0;
1329 static int xmlXPathDebugObjTotalString = 0;
1330 static int xmlXPathDebugObjTotalPoint = 0;
1331 static int xmlXPathDebugObjTotalRange = 0;
1332 static int xmlXPathDebugObjTotalLocset = 0;
1333 static int xmlXPathDebugObjTotalUsers = 0;
1334 static int xmlXPathDebugObjTotalXSLTTree = 0;
1335 static int xmlXPathDebugObjTotalAll = 0;
1337 static int xmlXPathDebugObjMaxUndefined = 0;
1338 static int xmlXPathDebugObjMaxNodeset = 0;
1339 static int xmlXPathDebugObjMaxBool = 0;
1340 static int xmlXPathDebugObjMaxNumber = 0;
1341 static int xmlXPathDebugObjMaxString = 0;
1342 static int xmlXPathDebugObjMaxPoint = 0;
1343 static int xmlXPathDebugObjMaxRange = 0;
1344 static int xmlXPathDebugObjMaxLocset = 0;
1345 static int xmlXPathDebugObjMaxUsers = 0;
1346 static int xmlXPathDebugObjMaxXSLTTree = 0;
1347 static int xmlXPathDebugObjMaxAll = 0;
1349 /* REVISIT TODO: Make this static when committing */
1351 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1354 if (ctxt->cache != NULL) {
1355 xmlXPathContextCachePtr cache =
1356 (xmlXPathContextCachePtr) ctxt->cache;
1358 cache->dbgCachedAll = 0;
1359 cache->dbgCachedNodeset = 0;
1360 cache->dbgCachedString = 0;
1361 cache->dbgCachedBool = 0;
1362 cache->dbgCachedNumber = 0;
1363 cache->dbgCachedPoint = 0;
1364 cache->dbgCachedRange = 0;
1365 cache->dbgCachedLocset = 0;
1366 cache->dbgCachedUsers = 0;
1367 cache->dbgCachedXSLTTree = 0;
1368 cache->dbgCachedUndefined = 0;
1370 cache->dbgReusedAll = 0;
1371 cache->dbgReusedNodeset = 0;
1372 cache->dbgReusedString = 0;
1373 cache->dbgReusedBool = 0;
1374 cache->dbgReusedNumber = 0;
1375 cache->dbgReusedPoint = 0;
1376 cache->dbgReusedRange = 0;
1377 cache->dbgReusedLocset = 0;
1378 cache->dbgReusedUsers = 0;
1379 cache->dbgReusedXSLTTree = 0;
1380 cache->dbgReusedUndefined = 0;
1384 xmlXPathDebugObjCounterUndefined = 0;
1385 xmlXPathDebugObjCounterNodeset = 0;
1386 xmlXPathDebugObjCounterBool = 0;
1387 xmlXPathDebugObjCounterNumber = 0;
1388 xmlXPathDebugObjCounterString = 0;
1389 xmlXPathDebugObjCounterPoint = 0;
1390 xmlXPathDebugObjCounterRange = 0;
1391 xmlXPathDebugObjCounterLocset = 0;
1392 xmlXPathDebugObjCounterUsers = 0;
1393 xmlXPathDebugObjCounterXSLTTree = 0;
1394 xmlXPathDebugObjCounterAll = 0;
1396 xmlXPathDebugObjTotalUndefined = 0;
1397 xmlXPathDebugObjTotalNodeset = 0;
1398 xmlXPathDebugObjTotalBool = 0;
1399 xmlXPathDebugObjTotalNumber = 0;
1400 xmlXPathDebugObjTotalString = 0;
1401 xmlXPathDebugObjTotalPoint = 0;
1402 xmlXPathDebugObjTotalRange = 0;
1403 xmlXPathDebugObjTotalLocset = 0;
1404 xmlXPathDebugObjTotalUsers = 0;
1405 xmlXPathDebugObjTotalXSLTTree = 0;
1406 xmlXPathDebugObjTotalAll = 0;
1408 xmlXPathDebugObjMaxUndefined = 0;
1409 xmlXPathDebugObjMaxNodeset = 0;
1410 xmlXPathDebugObjMaxBool = 0;
1411 xmlXPathDebugObjMaxNumber = 0;
1412 xmlXPathDebugObjMaxString = 0;
1413 xmlXPathDebugObjMaxPoint = 0;
1414 xmlXPathDebugObjMaxRange = 0;
1415 xmlXPathDebugObjMaxLocset = 0;
1416 xmlXPathDebugObjMaxUsers = 0;
1417 xmlXPathDebugObjMaxXSLTTree = 0;
1418 xmlXPathDebugObjMaxAll = 0;
1423 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1424 xmlXPathObjectType objType)
1429 if (ctxt->cache != NULL) {
1430 xmlXPathContextCachePtr cache =
1431 (xmlXPathContextCachePtr) ctxt->cache;
1435 cache->dbgReusedAll++;
1437 case XPATH_UNDEFINED:
1438 cache->dbgReusedUndefined++;
1441 cache->dbgReusedNodeset++;
1444 cache->dbgReusedBool++;
1447 cache->dbgReusedNumber++;
1450 cache->dbgReusedString++;
1453 cache->dbgReusedPoint++;
1456 cache->dbgReusedRange++;
1458 case XPATH_LOCATIONSET:
1459 cache->dbgReusedLocset++;
1462 cache->dbgReusedUsers++;
1464 case XPATH_XSLT_TREE:
1465 cache->dbgReusedXSLTTree++;
1474 case XPATH_UNDEFINED:
1476 xmlXPathDebugObjTotalUndefined++;
1477 xmlXPathDebugObjCounterUndefined++;
1478 if (xmlXPathDebugObjCounterUndefined >
1479 xmlXPathDebugObjMaxUndefined)
1480 xmlXPathDebugObjMaxUndefined =
1481 xmlXPathDebugObjCounterUndefined;
1485 xmlXPathDebugObjTotalNodeset++;
1486 xmlXPathDebugObjCounterNodeset++;
1487 if (xmlXPathDebugObjCounterNodeset >
1488 xmlXPathDebugObjMaxNodeset)
1489 xmlXPathDebugObjMaxNodeset =
1490 xmlXPathDebugObjCounterNodeset;
1494 xmlXPathDebugObjTotalBool++;
1495 xmlXPathDebugObjCounterBool++;
1496 if (xmlXPathDebugObjCounterBool >
1497 xmlXPathDebugObjMaxBool)
1498 xmlXPathDebugObjMaxBool =
1499 xmlXPathDebugObjCounterBool;
1503 xmlXPathDebugObjTotalNumber++;
1504 xmlXPathDebugObjCounterNumber++;
1505 if (xmlXPathDebugObjCounterNumber >
1506 xmlXPathDebugObjMaxNumber)
1507 xmlXPathDebugObjMaxNumber =
1508 xmlXPathDebugObjCounterNumber;
1512 xmlXPathDebugObjTotalString++;
1513 xmlXPathDebugObjCounterString++;
1514 if (xmlXPathDebugObjCounterString >
1515 xmlXPathDebugObjMaxString)
1516 xmlXPathDebugObjMaxString =
1517 xmlXPathDebugObjCounterString;
1521 xmlXPathDebugObjTotalPoint++;
1522 xmlXPathDebugObjCounterPoint++;
1523 if (xmlXPathDebugObjCounterPoint >
1524 xmlXPathDebugObjMaxPoint)
1525 xmlXPathDebugObjMaxPoint =
1526 xmlXPathDebugObjCounterPoint;
1530 xmlXPathDebugObjTotalRange++;
1531 xmlXPathDebugObjCounterRange++;
1532 if (xmlXPathDebugObjCounterRange >
1533 xmlXPathDebugObjMaxRange)
1534 xmlXPathDebugObjMaxRange =
1535 xmlXPathDebugObjCounterRange;
1537 case XPATH_LOCATIONSET:
1539 xmlXPathDebugObjTotalLocset++;
1540 xmlXPathDebugObjCounterLocset++;
1541 if (xmlXPathDebugObjCounterLocset >
1542 xmlXPathDebugObjMaxLocset)
1543 xmlXPathDebugObjMaxLocset =
1544 xmlXPathDebugObjCounterLocset;
1548 xmlXPathDebugObjTotalUsers++;
1549 xmlXPathDebugObjCounterUsers++;
1550 if (xmlXPathDebugObjCounterUsers >
1551 xmlXPathDebugObjMaxUsers)
1552 xmlXPathDebugObjMaxUsers =
1553 xmlXPathDebugObjCounterUsers;
1555 case XPATH_XSLT_TREE:
1557 xmlXPathDebugObjTotalXSLTTree++;
1558 xmlXPathDebugObjCounterXSLTTree++;
1559 if (xmlXPathDebugObjCounterXSLTTree >
1560 xmlXPathDebugObjMaxXSLTTree)
1561 xmlXPathDebugObjMaxXSLTTree =
1562 xmlXPathDebugObjCounterXSLTTree;
1568 xmlXPathDebugObjTotalAll++;
1569 xmlXPathDebugObjCounterAll++;
1570 if (xmlXPathDebugObjCounterAll >
1571 xmlXPathDebugObjMaxAll)
1572 xmlXPathDebugObjMaxAll =
1573 xmlXPathDebugObjCounterAll;
1577 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1578 xmlXPathObjectType objType)
1583 if (ctxt->cache != NULL) {
1584 xmlXPathContextCachePtr cache =
1585 (xmlXPathContextCachePtr) ctxt->cache;
1589 cache->dbgCachedAll++;
1591 case XPATH_UNDEFINED:
1592 cache->dbgCachedUndefined++;
1595 cache->dbgCachedNodeset++;
1598 cache->dbgCachedBool++;
1601 cache->dbgCachedNumber++;
1604 cache->dbgCachedString++;
1607 cache->dbgCachedPoint++;
1610 cache->dbgCachedRange++;
1612 case XPATH_LOCATIONSET:
1613 cache->dbgCachedLocset++;
1616 cache->dbgCachedUsers++;
1618 case XPATH_XSLT_TREE:
1619 cache->dbgCachedXSLTTree++;
1628 case XPATH_UNDEFINED:
1629 xmlXPathDebugObjCounterUndefined--;
1632 xmlXPathDebugObjCounterNodeset--;
1635 xmlXPathDebugObjCounterBool--;
1638 xmlXPathDebugObjCounterNumber--;
1641 xmlXPathDebugObjCounterString--;
1644 xmlXPathDebugObjCounterPoint--;
1647 xmlXPathDebugObjCounterRange--;
1649 case XPATH_LOCATIONSET:
1650 xmlXPathDebugObjCounterLocset--;
1653 xmlXPathDebugObjCounterUsers--;
1655 case XPATH_XSLT_TREE:
1656 xmlXPathDebugObjCounterXSLTTree--;
1661 xmlXPathDebugObjCounterAll--;
1664 /* REVISIT TODO: Make this static when committing */
1666 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1668 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1669 reqXSLTTree, reqUndefined;
1670 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1671 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1672 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1673 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1674 int leftObjs = xmlXPathDebugObjCounterAll;
1676 reqAll = xmlXPathDebugObjTotalAll;
1677 reqNodeset = xmlXPathDebugObjTotalNodeset;
1678 reqString = xmlXPathDebugObjTotalString;
1679 reqBool = xmlXPathDebugObjTotalBool;
1680 reqNumber = xmlXPathDebugObjTotalNumber;
1681 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1682 reqUndefined = xmlXPathDebugObjTotalUndefined;
1684 printf("# XPath object usage:\n");
1687 if (ctxt->cache != NULL) {
1688 xmlXPathContextCachePtr cache =
1689 (xmlXPathContextCachePtr) ctxt->cache;
1691 reAll = cache->dbgReusedAll;
1693 reNodeset = cache->dbgReusedNodeset;
1694 reqNodeset += reNodeset;
1695 reString = cache->dbgReusedString;
1696 reqString += reString;
1697 reBool = cache->dbgReusedBool;
1699 reNumber = cache->dbgReusedNumber;
1700 reqNumber += reNumber;
1701 reXSLTTree = cache->dbgReusedXSLTTree;
1702 reqXSLTTree += reXSLTTree;
1703 reUndefined = cache->dbgReusedUndefined;
1704 reqUndefined += reUndefined;
1706 caAll = cache->dbgCachedAll;
1707 caBool = cache->dbgCachedBool;
1708 caNodeset = cache->dbgCachedNodeset;
1709 caString = cache->dbgCachedString;
1710 caNumber = cache->dbgCachedNumber;
1711 caXSLTTree = cache->dbgCachedXSLTTree;
1712 caUndefined = cache->dbgCachedUndefined;
1714 if (cache->nodesetObjs)
1715 leftObjs -= cache->nodesetObjs->number;
1716 if (cache->stringObjs)
1717 leftObjs -= cache->stringObjs->number;
1718 if (cache->booleanObjs)
1719 leftObjs -= cache->booleanObjs->number;
1720 if (cache->numberObjs)
1721 leftObjs -= cache->numberObjs->number;
1722 if (cache->miscObjs)
1723 leftObjs -= cache->miscObjs->number;
1728 printf("# total : %d\n", reqAll);
1729 printf("# left : %d\n", leftObjs);
1730 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1731 printf("# reused : %d\n", reAll);
1732 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1734 printf("# node-sets\n");
1735 printf("# total : %d\n", reqNodeset);
1736 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1737 printf("# reused : %d\n", reNodeset);
1738 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1740 printf("# strings\n");
1741 printf("# total : %d\n", reqString);
1742 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1743 printf("# reused : %d\n", reString);
1744 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1746 printf("# booleans\n");
1747 printf("# total : %d\n", reqBool);
1748 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1749 printf("# reused : %d\n", reBool);
1750 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1752 printf("# numbers\n");
1753 printf("# total : %d\n", reqNumber);
1754 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1755 printf("# reused : %d\n", reNumber);
1756 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1758 printf("# XSLT result tree fragments\n");
1759 printf("# total : %d\n", reqXSLTTree);
1760 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1761 printf("# reused : %d\n", reXSLTTree);
1762 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1764 printf("# undefined\n");
1765 printf("# total : %d\n", reqUndefined);
1766 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1767 printf("# reused : %d\n", reUndefined);
1768 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1772 #endif /* XP_DEBUG_OBJ_USAGE */
1774 #endif /* LIBXML_DEBUG_ENABLED */
1776 /************************************************************************
1778 * XPath object caching *
1780 ************************************************************************/
1785 * Create a new object cache
1787 * Returns the xmlXPathCache just allocated.
1789 static xmlXPathContextCachePtr
1790 xmlXPathNewCache(void)
1792 xmlXPathContextCachePtr ret;
1794 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1796 xmlXPathErrMemory(NULL, "creating object cache\n");
1799 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1800 ret->maxNodeset = 100;
1801 ret->maxString = 100;
1802 ret->maxBoolean = 100;
1803 ret->maxNumber = 100;
1809 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1812 xmlXPathObjectPtr obj;
1817 for (i = 0; i < list->number; i++) {
1818 obj = list->items[i];
1820 * Note that it is already assured that we don't need to
1821 * look out for namespace nodes in the node-set.
1823 if (obj->nodesetval != NULL) {
1824 if (obj->nodesetval->nodeTab != NULL)
1825 xmlFree(obj->nodesetval->nodeTab);
1826 xmlFree(obj->nodesetval);
1829 #ifdef XP_DEBUG_OBJ_USAGE
1830 xmlXPathDebugObjCounterAll--;
1833 xmlPointerListFree(list);
1837 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1841 if (cache->nodesetObjs)
1842 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1843 if (cache->stringObjs)
1844 xmlXPathCacheFreeObjectList(cache->stringObjs);
1845 if (cache->booleanObjs)
1846 xmlXPathCacheFreeObjectList(cache->booleanObjs);
1847 if (cache->numberObjs)
1848 xmlXPathCacheFreeObjectList(cache->numberObjs);
1849 if (cache->miscObjs)
1850 xmlXPathCacheFreeObjectList(cache->miscObjs);
1855 * xmlXPathContextSetCache:
1857 * @ctxt: the XPath context
1858 * @active: enables/disables (creates/frees) the cache
1859 * @value: a value with semantics dependant on @options
1860 * @options: options (currently only the value 0 is used)
1862 * Creates/frees an object cache on the XPath context.
1863 * If activates XPath objects (xmlXPathObject) will be cached internally
1866 * 0: This will set the XPath object caching:
1868 * This will set the maximum number of XPath objects
1869 * to be cached per slot
1870 * There are 5 slots for: node-set, string, number, boolean, and
1871 * misc objects. Use <0 for the default number (100).
1872 * Other values for @options have currently no effect.
1874 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1877 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1885 xmlXPathContextCachePtr cache;
1887 if (ctxt->cache == NULL) {
1888 ctxt->cache = xmlXPathNewCache();
1889 if (ctxt->cache == NULL)
1892 cache = (xmlXPathContextCachePtr) ctxt->cache;
1896 cache->maxNodeset = value;
1897 cache->maxString = value;
1898 cache->maxNumber = value;
1899 cache->maxBoolean = value;
1900 cache->maxMisc = value;
1902 } else if (ctxt->cache != NULL) {
1903 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1910 * xmlXPathCacheWrapNodeSet:
1911 * @ctxt: the XPath context
1912 * @val: the NodePtr value
1914 * This is the cached version of xmlXPathWrapNodeSet().
1915 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1917 * Returns the created or reused object.
1919 static xmlXPathObjectPtr
1920 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1922 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1923 xmlXPathContextCachePtr cache =
1924 (xmlXPathContextCachePtr) ctxt->cache;
1926 if ((cache->miscObjs != NULL) &&
1927 (cache->miscObjs->number != 0))
1929 xmlXPathObjectPtr ret;
1931 ret = (xmlXPathObjectPtr)
1932 cache->miscObjs->items[--cache->miscObjs->number];
1933 ret->type = XPATH_NODESET;
1934 ret->nodesetval = val;
1935 #ifdef XP_DEBUG_OBJ_USAGE
1936 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1942 return(xmlXPathWrapNodeSet(val));
1947 * xmlXPathCacheWrapString:
1948 * @ctxt: the XPath context
1949 * @val: the xmlChar * value
1951 * This is the cached version of xmlXPathWrapString().
1952 * Wraps the @val string into an XPath object.
1954 * Returns the created or reused object.
1956 static xmlXPathObjectPtr
1957 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1959 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1960 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1962 if ((cache->stringObjs != NULL) &&
1963 (cache->stringObjs->number != 0))
1966 xmlXPathObjectPtr ret;
1968 ret = (xmlXPathObjectPtr)
1969 cache->stringObjs->items[--cache->stringObjs->number];
1970 ret->type = XPATH_STRING;
1971 ret->stringval = val;
1972 #ifdef XP_DEBUG_OBJ_USAGE
1973 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1976 } else if ((cache->miscObjs != NULL) &&
1977 (cache->miscObjs->number != 0))
1979 xmlXPathObjectPtr ret;
1981 * Fallback to misc-cache.
1983 ret = (xmlXPathObjectPtr)
1984 cache->miscObjs->items[--cache->miscObjs->number];
1986 ret->type = XPATH_STRING;
1987 ret->stringval = val;
1988 #ifdef XP_DEBUG_OBJ_USAGE
1989 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1994 return(xmlXPathWrapString(val));
1998 * xmlXPathCacheNewNodeSet:
1999 * @ctxt: the XPath context
2000 * @val: the NodePtr value
2002 * This is the cached version of xmlXPathNewNodeSet().
2003 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2004 * it with the single Node @val
2006 * Returns the created or reused object.
2008 static xmlXPathObjectPtr
2009 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2011 if ((ctxt != NULL) && (ctxt->cache)) {
2012 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2014 if ((cache->nodesetObjs != NULL) &&
2015 (cache->nodesetObjs->number != 0))
2017 xmlXPathObjectPtr ret;
2019 * Use the nodset-cache.
2021 ret = (xmlXPathObjectPtr)
2022 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2023 ret->type = XPATH_NODESET;
2026 if ((ret->nodesetval->nodeMax == 0) ||
2027 (val->type == XML_NAMESPACE_DECL))
2029 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2031 ret->nodesetval->nodeTab[0] = val;
2032 ret->nodesetval->nodeNr = 1;
2035 #ifdef XP_DEBUG_OBJ_USAGE
2036 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2039 } else if ((cache->miscObjs != NULL) &&
2040 (cache->miscObjs->number != 0))
2042 xmlXPathObjectPtr ret;
2044 * Fallback to misc-cache.
2047 ret = (xmlXPathObjectPtr)
2048 cache->miscObjs->items[--cache->miscObjs->number];
2050 ret->type = XPATH_NODESET;
2052 ret->nodesetval = xmlXPathNodeSetCreate(val);
2053 #ifdef XP_DEBUG_OBJ_USAGE
2054 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2059 return(xmlXPathNewNodeSet(val));
2063 * xmlXPathCacheNewCString:
2064 * @ctxt: the XPath context
2065 * @val: the char * value
2067 * This is the cached version of xmlXPathNewCString().
2068 * Acquire an xmlXPathObjectPtr of type string and of value @val
2070 * Returns the created or reused object.
2072 static xmlXPathObjectPtr
2073 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2075 if ((ctxt != NULL) && (ctxt->cache)) {
2076 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2078 if ((cache->stringObjs != NULL) &&
2079 (cache->stringObjs->number != 0))
2081 xmlXPathObjectPtr ret;
2083 ret = (xmlXPathObjectPtr)
2084 cache->stringObjs->items[--cache->stringObjs->number];
2086 ret->type = XPATH_STRING;
2087 ret->stringval = xmlStrdup(BAD_CAST val);
2088 #ifdef XP_DEBUG_OBJ_USAGE
2089 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2092 } else if ((cache->miscObjs != NULL) &&
2093 (cache->miscObjs->number != 0))
2095 xmlXPathObjectPtr ret;
2097 ret = (xmlXPathObjectPtr)
2098 cache->miscObjs->items[--cache->miscObjs->number];
2100 ret->type = XPATH_STRING;
2101 ret->stringval = xmlStrdup(BAD_CAST val);
2102 #ifdef XP_DEBUG_OBJ_USAGE
2103 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2108 return(xmlXPathNewCString(val));
2112 * xmlXPathCacheNewString:
2113 * @ctxt: the XPath context
2114 * @val: the xmlChar * value
2116 * This is the cached version of xmlXPathNewString().
2117 * Acquire an xmlXPathObjectPtr of type string and of value @val
2119 * Returns the created or reused object.
2121 static xmlXPathObjectPtr
2122 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2124 if ((ctxt != NULL) && (ctxt->cache)) {
2125 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2127 if ((cache->stringObjs != NULL) &&
2128 (cache->stringObjs->number != 0))
2130 xmlXPathObjectPtr ret;
2132 ret = (xmlXPathObjectPtr)
2133 cache->stringObjs->items[--cache->stringObjs->number];
2134 ret->type = XPATH_STRING;
2136 ret->stringval = xmlStrdup(val);
2138 ret->stringval = xmlStrdup((const xmlChar *)"");
2139 #ifdef XP_DEBUG_OBJ_USAGE
2140 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2143 } else if ((cache->miscObjs != NULL) &&
2144 (cache->miscObjs->number != 0))
2146 xmlXPathObjectPtr ret;
2148 ret = (xmlXPathObjectPtr)
2149 cache->miscObjs->items[--cache->miscObjs->number];
2151 ret->type = XPATH_STRING;
2153 ret->stringval = xmlStrdup(val);
2155 ret->stringval = xmlStrdup((const xmlChar *)"");
2156 #ifdef XP_DEBUG_OBJ_USAGE
2157 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2162 return(xmlXPathNewString(val));
2166 * xmlXPathCacheNewBoolean:
2167 * @ctxt: the XPath context
2168 * @val: the boolean value
2170 * This is the cached version of xmlXPathNewBoolean().
2171 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2173 * Returns the created or reused object.
2175 static xmlXPathObjectPtr
2176 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2178 if ((ctxt != NULL) && (ctxt->cache)) {
2179 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2181 if ((cache->booleanObjs != NULL) &&
2182 (cache->booleanObjs->number != 0))
2184 xmlXPathObjectPtr ret;
2186 ret = (xmlXPathObjectPtr)
2187 cache->booleanObjs->items[--cache->booleanObjs->number];
2188 ret->type = XPATH_BOOLEAN;
2189 ret->boolval = (val != 0);
2190 #ifdef XP_DEBUG_OBJ_USAGE
2191 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2194 } else if ((cache->miscObjs != NULL) &&
2195 (cache->miscObjs->number != 0))
2197 xmlXPathObjectPtr ret;
2199 ret = (xmlXPathObjectPtr)
2200 cache->miscObjs->items[--cache->miscObjs->number];
2202 ret->type = XPATH_BOOLEAN;
2203 ret->boolval = (val != 0);
2204 #ifdef XP_DEBUG_OBJ_USAGE
2205 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2210 return(xmlXPathNewBoolean(val));
2214 * xmlXPathCacheNewFloat:
2215 * @ctxt: the XPath context
2216 * @val: the double value
2218 * This is the cached version of xmlXPathNewFloat().
2219 * Acquires an xmlXPathObjectPtr of type double and of value @val
2221 * Returns the created or reused object.
2223 static xmlXPathObjectPtr
2224 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2226 if ((ctxt != NULL) && (ctxt->cache)) {
2227 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2229 if ((cache->numberObjs != NULL) &&
2230 (cache->numberObjs->number != 0))
2232 xmlXPathObjectPtr ret;
2234 ret = (xmlXPathObjectPtr)
2235 cache->numberObjs->items[--cache->numberObjs->number];
2236 ret->type = XPATH_NUMBER;
2237 ret->floatval = val;
2238 #ifdef XP_DEBUG_OBJ_USAGE
2239 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2242 } else if ((cache->miscObjs != NULL) &&
2243 (cache->miscObjs->number != 0))
2245 xmlXPathObjectPtr ret;
2247 ret = (xmlXPathObjectPtr)
2248 cache->miscObjs->items[--cache->miscObjs->number];
2250 ret->type = XPATH_NUMBER;
2251 ret->floatval = val;
2252 #ifdef XP_DEBUG_OBJ_USAGE
2253 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2258 return(xmlXPathNewFloat(val));
2262 * xmlXPathCacheConvertString:
2263 * @ctxt: the XPath context
2264 * @val: an XPath object
2266 * This is the cached version of xmlXPathConvertString().
2267 * Converts an existing object to its string() equivalent
2269 * Returns a created or reused object, the old one is freed (cached)
2270 * (or the operation is done directly on @val)
2273 static xmlXPathObjectPtr
2274 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2275 xmlChar *res = NULL;
2278 return(xmlXPathCacheNewCString(ctxt, ""));
2280 switch (val->type) {
2281 case XPATH_UNDEFINED:
2283 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2287 case XPATH_XSLT_TREE:
2288 res = xmlXPathCastNodeSetToString(val->nodesetval);
2293 res = xmlXPathCastBooleanToString(val->boolval);
2296 res = xmlXPathCastNumberToString(val->floatval);
2301 case XPATH_LOCATIONSET:
2305 xmlXPathReleaseObject(ctxt, val);
2307 return(xmlXPathCacheNewCString(ctxt, ""));
2308 return(xmlXPathCacheWrapString(ctxt, res));
2312 * xmlXPathCacheObjectCopy:
2313 * @ctxt: the XPath context
2314 * @val: the original object
2316 * This is the cached version of xmlXPathObjectCopy().
2317 * Acquire a copy of a given object
2319 * Returns a created or reused created object.
2321 static xmlXPathObjectPtr
2322 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2327 if (XP_HAS_CACHE(ctxt)) {
2328 switch (val->type) {
2330 return(xmlXPathCacheWrapNodeSet(ctxt,
2331 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2333 return(xmlXPathCacheNewString(ctxt, val->stringval));
2335 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2337 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2342 return(xmlXPathObjectCopy(val));
2346 * xmlXPathCacheConvertBoolean:
2347 * @ctxt: the XPath context
2348 * @val: an XPath object
2350 * This is the cached version of xmlXPathConvertBoolean().
2351 * Converts an existing object to its boolean() equivalent
2353 * Returns a created or reused object, the old one is freed (or the operation
2354 * is done directly on @val)
2356 static xmlXPathObjectPtr
2357 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2358 xmlXPathObjectPtr ret;
2361 return(xmlXPathCacheNewBoolean(ctxt, 0));
2362 if (val->type == XPATH_BOOLEAN)
2364 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2365 xmlXPathReleaseObject(ctxt, val);
2370 * xmlXPathCacheConvertNumber:
2371 * @ctxt: the XPath context
2372 * @val: an XPath object
2374 * This is the cached version of xmlXPathConvertNumber().
2375 * Converts an existing object to its number() equivalent
2377 * Returns a created or reused object, the old one is freed (or the operation
2378 * is done directly on @val)
2380 static xmlXPathObjectPtr
2381 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2382 xmlXPathObjectPtr ret;
2385 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2386 if (val->type == XPATH_NUMBER)
2388 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2389 xmlXPathReleaseObject(ctxt, val);
2393 /************************************************************************
2395 * Parser stacks related functions and macros *
2397 ************************************************************************/
2401 * @ctxt: an XPath evaluation context
2403 * Pops the top XPath object from the value stack
2405 * Returns the XPath object just removed
2408 valuePop(xmlXPathParserContextPtr ctxt)
2410 xmlXPathObjectPtr ret;
2412 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2415 if (ctxt->valueNr > 0)
2416 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2419 ret = ctxt->valueTab[ctxt->valueNr];
2420 ctxt->valueTab[ctxt->valueNr] = NULL;
2425 * @ctxt: an XPath evaluation context
2426 * @value: the XPath object
2428 * Pushes a new XPath object on top of the value stack
2430 * returns the number of items on the value stack
2433 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2435 if ((ctxt == NULL) || (value == NULL)) return(-1);
2436 if (ctxt->valueNr >= ctxt->valueMax) {
2437 xmlXPathObjectPtr *tmp;
2439 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2440 2 * ctxt->valueMax *
2441 sizeof(ctxt->valueTab[0]));
2443 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2446 ctxt->valueMax *= 2;
2447 ctxt->valueTab = tmp;
2449 ctxt->valueTab[ctxt->valueNr] = value;
2450 ctxt->value = value;
2451 return (ctxt->valueNr++);
2455 * xmlXPathPopBoolean:
2456 * @ctxt: an XPath parser context
2458 * Pops a boolean from the stack, handling conversion if needed.
2459 * Check error with #xmlXPathCheckError.
2461 * Returns the boolean
2464 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2465 xmlXPathObjectPtr obj;
2468 obj = valuePop(ctxt);
2470 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2473 if (obj->type != XPATH_BOOLEAN)
2474 ret = xmlXPathCastToBoolean(obj);
2477 xmlXPathReleaseObject(ctxt->context, obj);
2482 * xmlXPathPopNumber:
2483 * @ctxt: an XPath parser context
2485 * Pops a number from the stack, handling conversion if needed.
2486 * Check error with #xmlXPathCheckError.
2488 * Returns the number
2491 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2492 xmlXPathObjectPtr obj;
2495 obj = valuePop(ctxt);
2497 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2500 if (obj->type != XPATH_NUMBER)
2501 ret = xmlXPathCastToNumber(obj);
2503 ret = obj->floatval;
2504 xmlXPathReleaseObject(ctxt->context, obj);
2509 * xmlXPathPopString:
2510 * @ctxt: an XPath parser context
2512 * Pops a string from the stack, handling conversion if needed.
2513 * Check error with #xmlXPathCheckError.
2515 * Returns the string
2518 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2519 xmlXPathObjectPtr obj;
2522 obj = valuePop(ctxt);
2524 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2527 ret = xmlXPathCastToString(obj); /* this does required strdup */
2528 /* TODO: needs refactoring somewhere else */
2529 if (obj->stringval == ret)
2530 obj->stringval = NULL;
2531 xmlXPathReleaseObject(ctxt->context, obj);
2536 * xmlXPathPopNodeSet:
2537 * @ctxt: an XPath parser context
2539 * Pops a node-set from the stack, handling conversion if needed.
2540 * Check error with #xmlXPathCheckError.
2542 * Returns the node-set
2545 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2546 xmlXPathObjectPtr obj;
2549 if (ctxt == NULL) return(NULL);
2550 if (ctxt->value == NULL) {
2551 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2554 if (!xmlXPathStackIsNodeSet(ctxt)) {
2555 xmlXPathSetTypeError(ctxt);
2558 obj = valuePop(ctxt);
2559 ret = obj->nodesetval;
2561 /* to fix memory leak of not clearing obj->user */
2562 if (obj->boolval && obj->user != NULL)
2563 xmlFreeNodeList((xmlNodePtr) obj->user);
2565 obj->nodesetval = NULL;
2566 xmlXPathReleaseObject(ctxt->context, obj);
2571 * xmlXPathPopExternal:
2572 * @ctxt: an XPath parser context
2574 * Pops an external object from the stack, handling conversion if needed.
2575 * Check error with #xmlXPathCheckError.
2577 * Returns the object
2580 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2581 xmlXPathObjectPtr obj;
2584 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2585 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2588 if (ctxt->value->type != XPATH_USERS) {
2589 xmlXPathSetTypeError(ctxt);
2592 obj = valuePop(ctxt);
2595 xmlXPathReleaseObject(ctxt->context, obj);
2600 * Macros for accessing the content. Those should be used only by the parser,
2603 * Dirty macros, i.e. one need to make assumption on the context to use them
2605 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2606 * CUR returns the current xmlChar value, i.e. a 8 bit value
2607 * in ISO-Latin or UTF-8.
2608 * This should be used internally by the parser
2609 * only to compare to ASCII values otherwise it would break when
2610 * running with UTF-8 encoding.
2611 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2612 * to compare on ASCII based substring.
2613 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2614 * strings within the parser.
2615 * CURRENT Returns the current char value, with the full decoding of
2616 * UTF-8 if we are using this mode. It returns an int.
2617 * NEXT Skip to the next character, this does the proper decoding
2618 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2619 * It returns the pointer to the current xmlChar.
2622 #define CUR (*ctxt->cur)
2623 #define SKIP(val) ctxt->cur += (val)
2624 #define NXT(val) ctxt->cur[(val)]
2625 #define CUR_PTR ctxt->cur
2626 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2628 #define COPY_BUF(l,b,i,v) \
2629 if (l == 1) b[i++] = (xmlChar) v; \
2630 else i += xmlCopyChar(l,&b[i],v)
2632 #define NEXTL(l) ctxt->cur += l
2634 #define SKIP_BLANKS \
2635 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2637 #define CURRENT (*ctxt->cur)
2638 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2645 #define DBL_EPSILON 1E-9
2648 #define UPPER_DOUBLE 1E9
2649 #define LOWER_DOUBLE 1E-5
2651 #define INTEGER_DIGITS DBL_DIG
2652 #define FRACTION_DIGITS (DBL_DIG + 1)
2653 #define EXPONENT_DIGITS (3 + 2)
2656 * xmlXPathFormatNumber:
2657 * @number: number to format
2658 * @buffer: output buffer
2659 * @buffersize: size of output buffer
2661 * Convert the number into a string representation.
2664 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2666 switch (xmlXPathIsInf(number)) {
2668 if (buffersize > (int)sizeof("Infinity"))
2669 snprintf(buffer, buffersize, "Infinity");
2672 if (buffersize > (int)sizeof("-Infinity"))
2673 snprintf(buffer, buffersize, "-Infinity");
2676 if (xmlXPathIsNaN(number)) {
2677 if (buffersize > (int)sizeof("NaN"))
2678 snprintf(buffer, buffersize, "NaN");
2679 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2680 snprintf(buffer, buffersize, "0");
2681 } else if (number == ((int) number)) {
2684 int value = (int) number;
2690 snprintf(work, 29, "%d", value);
2692 while ((*cur) && (ptr - buffer < buffersize)) {
2696 if (ptr - buffer < buffersize) {
2698 } else if (buffersize > 0) {
2703 /* 3 is sign, decimal point, and terminating zero */
2704 char work[DBL_DIG + EXPONENT_DIGITS + 3];
2705 int integer_place, fraction_place;
2707 char *after_fraction;
2708 double absolute_value;
2711 absolute_value = fabs(number);
2714 * First choose format - scientific or regular floating point.
2715 * In either case, result is in work, and after_fraction points
2716 * just past the fractional part.
2718 if ( ((absolute_value > UPPER_DOUBLE) ||
2719 (absolute_value < LOWER_DOUBLE)) &&
2720 (absolute_value != 0.0) ) {
2721 /* Use scientific notation */
2722 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2723 fraction_place = DBL_DIG - 1;
2724 size = snprintf(work, sizeof(work),"%*.*e",
2725 integer_place, fraction_place, number);
2726 while ((size > 0) && (work[size] != 'e')) size--;
2727 after_fraction = work + size;
2731 /* Use regular notation */
2732 if (absolute_value > 0.0)
2733 integer_place = 1 + (int)log10(absolute_value);
2736 fraction_place = (integer_place > 0)
2737 ? DBL_DIG - integer_place
2739 size = snprintf(work, sizeof(work), "%0.*f",
2740 fraction_place, number);
2741 after_fraction = work + size;
2744 /* Remove fractional trailing zeroes */
2745 ptr = after_fraction;
2746 while (*(--ptr) == '0')
2750 while ((*ptr++ = *after_fraction++) != 0);
2752 /* Finally copy result back to caller */
2753 size = strlen(work) + 1;
2754 if (size > buffersize) {
2755 work[buffersize - 1] = 0;
2758 memmove(buffer, work, size);
2765 /************************************************************************
2767 * Routines to handle NodeSets *
2769 ************************************************************************/
2772 * xmlXPathOrderDocElems:
2773 * @doc: an input document
2775 * Call this routine to speed up XPath computation on static documents.
2776 * This stamps all the element nodes with the document order
2777 * Like for line information, the order is kept in the element->content
2778 * field, the value stored is actually - the node number (starting at -1)
2779 * to be able to differentiate from line numbers.
2781 * Returns the number of elements found in the document or -1 in case
2785 xmlXPathOrderDocElems(xmlDocPtr doc) {
2791 cur = doc->children;
2792 while (cur != NULL) {
2793 if (cur->type == XML_ELEMENT_NODE) {
2794 cur->content = (void *) (-(++count));
2795 if (cur->children != NULL) {
2796 cur = cur->children;
2800 if (cur->next != NULL) {
2808 if (cur == (xmlNodePtr) doc) {
2812 if (cur->next != NULL) {
2816 } while (cur != NULL);
2823 * @node1: the first node
2824 * @node2: the second node
2826 * Compare two nodes w.r.t document order
2828 * Returns -2 in case of error 1 if first point < second point, 0 if
2829 * it's the same node, -1 otherwise
2832 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2834 int attr1 = 0, attr2 = 0;
2835 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2836 xmlNodePtr cur, root;
2838 if ((node1 == NULL) || (node2 == NULL))
2841 * a couple of optimizations which will avoid computations in most cases
2843 if (node1->type == XML_ATTRIBUTE_NODE) {
2846 node1 = node1->parent;
2848 if (node2->type == XML_ATTRIBUTE_NODE) {
2851 node2 = node2->parent;
2853 if (node1 == node2) {
2854 if (attr1 == attr2) {
2855 /* not required, but we keep attributes in order */
2857 cur = attrNode2->prev;
2858 while (cur != NULL) {
2859 if (cur == attrNode1)
2871 if ((node1->type == XML_NAMESPACE_DECL) ||
2872 (node2->type == XML_NAMESPACE_DECL))
2874 if (node1 == node2->prev)
2876 if (node1 == node2->next)
2880 * Speedup using document order if availble.
2882 if ((node1->type == XML_ELEMENT_NODE) &&
2883 (node2->type == XML_ELEMENT_NODE) &&
2884 (0 > (long) node1->content) &&
2885 (0 > (long) node2->content) &&
2886 (node1->doc == node2->doc)) {
2889 l1 = -((long) node1->content);
2890 l2 = -((long) node2->content);
2898 * compute depth to root
2900 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2906 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2912 * Distinct document (or distinct entities :-( ) case.
2918 * get the nearest common ancestor.
2920 while (depth1 > depth2) {
2922 node1 = node1->parent;
2924 while (depth2 > depth1) {
2926 node2 = node2->parent;
2928 while (node1->parent != node2->parent) {
2929 node1 = node1->parent;
2930 node2 = node2->parent;
2931 /* should not happen but just in case ... */
2932 if ((node1 == NULL) || (node2 == NULL))
2938 if (node1 == node2->prev)
2940 if (node1 == node2->next)
2943 * Speedup using document order if availble.
2945 if ((node1->type == XML_ELEMENT_NODE) &&
2946 (node2->type == XML_ELEMENT_NODE) &&
2947 (0 > (long) node1->content) &&
2948 (0 > (long) node2->content) &&
2949 (node1->doc == node2->doc)) {
2952 l1 = -((long) node1->content);
2953 l2 = -((long) node2->content);
2960 for (cur = node1->next;cur != NULL;cur = cur->next)
2963 return(-1); /* assume there is no sibling list corruption */
2966 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2968 * xmlXPathCmpNodesExt:
2969 * @node1: the first node
2970 * @node2: the second node
2972 * Compare two nodes w.r.t document order.
2973 * This one is optimized for handling of non-element nodes.
2975 * Returns -2 in case of error 1 if first point < second point, 0 if
2976 * it's the same node, -1 otherwise
2979 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2981 int misc = 0, precedence1 = 0, precedence2 = 0;
2982 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2983 xmlNodePtr cur, root;
2986 if ((node1 == NULL) || (node2 == NULL))
2993 * a couple of optimizations which will avoid computations in most cases
2995 switch (node1->type) {
2996 case XML_ELEMENT_NODE:
2997 if (node2->type == XML_ELEMENT_NODE) {
2998 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
2999 (0 > (long) node2->content) &&
3000 (node1->doc == node2->doc))
3002 l1 = -((long) node1->content);
3003 l2 = -((long) node2->content);
3009 goto turtle_comparison;
3012 case XML_ATTRIBUTE_NODE:
3013 precedence1 = 1; /* element is owner */
3015 node1 = node1->parent;
3019 case XML_CDATA_SECTION_NODE:
3020 case XML_COMMENT_NODE:
3024 * Find nearest element node.
3026 if (node1->prev != NULL) {
3028 node1 = node1->prev;
3029 if (node1->type == XML_ELEMENT_NODE) {
3030 precedence1 = 3; /* element in prev-sibl axis */
3033 if (node1->prev == NULL) {
3034 precedence1 = 2; /* element is parent */
3036 * URGENT TODO: Are there any cases, where the
3037 * parent of such a node is not an element node?
3039 node1 = node1->parent;
3044 precedence1 = 2; /* element is parent */
3045 node1 = node1->parent;
3047 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE)) {
3049 * Fallback for whatever case.
3057 case XML_NAMESPACE_DECL:
3059 * TODO: why do we return 1 for namespace nodes?
3065 switch (node2->type) {
3066 case XML_ELEMENT_NODE:
3068 case XML_ATTRIBUTE_NODE:
3069 precedence2 = 1; /* element is owner */
3071 node2 = node2->parent;
3075 case XML_CDATA_SECTION_NODE:
3076 case XML_COMMENT_NODE:
3079 if (node2->prev != NULL) {
3081 node2 = node2->prev;
3082 if (node2->type == XML_ELEMENT_NODE) {
3083 precedence2 = 3; /* element in prev-sibl axis */
3086 if (node2->prev == NULL) {
3087 precedence2 = 2; /* element is parent */
3088 node2 = node2->parent;
3093 precedence2 = 2; /* element is parent */
3094 node2 = node2->parent;
3096 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3097 (0 <= (long) node1->content))
3105 case XML_NAMESPACE_DECL:
3111 if (node1 == node2) {
3112 if (precedence1 == precedence2) {
3114 * The ugly case; but normally there aren't many
3115 * adjacent non-element nodes around.
3117 cur = miscNode2->prev;
3118 while (cur != NULL) {
3119 if (cur == miscNode1)
3121 if (cur->type == XML_ELEMENT_NODE)
3128 * Evaluate based on higher precedence wrt to the element.
3129 * TODO: This assumes attributes are sorted before content.
3130 * Is this 100% correct?
3132 if (precedence1 < precedence2)
3139 * Special case: One of the helper-elements is contained by the other.
3142 * <node1>Text-1(precedence1 == 2)</node1>
3144 * Text-6(precedence2 == 3)
3147 if ((precedence2 == 3) && (precedence1 > 1)) {
3148 cur = node1->parent;
3155 if ((precedence1 == 3) && (precedence2 > 1)) {
3156 cur = node2->parent;
3166 * Speedup using document order if availble.
3168 if ((node1->type == XML_ELEMENT_NODE) &&
3169 (node2->type == XML_ELEMENT_NODE) &&
3170 (0 > (long) node1->content) &&
3171 (0 > (long) node2->content) &&
3172 (node1->doc == node2->doc)) {
3174 l1 = -((long) node1->content);
3175 l2 = -((long) node2->content);
3184 if (node1 == node2->prev)
3186 if (node1 == node2->next)
3189 * compute depth to root
3191 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3197 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3203 * Distinct document (or distinct entities :-( ) case.
3209 * get the nearest common ancestor.
3211 while (depth1 > depth2) {
3213 node1 = node1->parent;
3215 while (depth2 > depth1) {
3217 node2 = node2->parent;
3219 while (node1->parent != node2->parent) {
3220 node1 = node1->parent;
3221 node2 = node2->parent;
3222 /* should not happen but just in case ... */
3223 if ((node1 == NULL) || (node2 == NULL))
3229 if (node1 == node2->prev)
3231 if (node1 == node2->next)
3234 * Speedup using document order if availble.
3236 if ((node1->type == XML_ELEMENT_NODE) &&
3237 (node2->type == XML_ELEMENT_NODE) &&
3238 (0 > (long) node1->content) &&
3239 (0 > (long) node2->content) &&
3240 (node1->doc == node2->doc)) {
3242 l1 = -((long) node1->content);
3243 l2 = -((long) node2->content);
3250 for (cur = node1->next;cur != NULL;cur = cur->next)
3253 return(-1); /* assume there is no sibling list corruption */
3255 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3258 * xmlXPathNodeSetSort:
3259 * @set: the node set
3261 * Sort the node set in document order
3264 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3265 int i, j, incr, len;
3271 /* Use Shell's sort to sort the node-set */
3273 for (incr = len / 2; incr > 0; incr /= 2) {
3274 for (i = incr; i < len; i++) {
3277 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3278 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3279 set->nodeTab[j + incr]) == -1)
3281 if (xmlXPathCmpNodes(set->nodeTab[j],
3282 set->nodeTab[j + incr]) == -1)
3285 tmp = set->nodeTab[j];
3286 set->nodeTab[j] = set->nodeTab[j + incr];
3287 set->nodeTab[j + incr] = tmp;
3296 #define XML_NODESET_DEFAULT 10
3298 * xmlXPathNodeSetDupNs:
3299 * @node: the parent node of the namespace XPath node
3300 * @ns: the libxml namespace declaration node.
3302 * Namespace node in libxml don't match the XPath semantic. In a node set
3303 * the namespace nodes are duplicated and the next pointer is set to the
3304 * parent node in the XPath semantic.
3306 * Returns the newly created object.
3309 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3312 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3314 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3315 return((xmlNodePtr) ns);
3318 * Allocate a new Namespace and fill the fields.
3320 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3322 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3325 memset(cur, 0, sizeof(xmlNs));
3326 cur->type = XML_NAMESPACE_DECL;
3327 if (ns->href != NULL)
3328 cur->href = xmlStrdup(ns->href);
3329 if (ns->prefix != NULL)
3330 cur->prefix = xmlStrdup(ns->prefix);
3331 cur->next = (xmlNsPtr) node;
3332 return((xmlNodePtr) cur);
3336 * xmlXPathNodeSetFreeNs:
3337 * @ns: the XPath namespace node found in a nodeset.
3339 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3340 * the namespace nodes are duplicated and the next pointer is set to the
3341 * parent node in the XPath semantic. Check if such a node needs to be freed
3344 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3345 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3348 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3349 if (ns->href != NULL)
3350 xmlFree((xmlChar *)ns->href);
3351 if (ns->prefix != NULL)
3352 xmlFree((xmlChar *)ns->prefix);
3358 * xmlXPathNodeSetCreate:
3359 * @val: an initial xmlNodePtr, or NULL
3361 * Create a new xmlNodeSetPtr of type double and of value @val
3363 * Returns the newly created object.
3366 xmlXPathNodeSetCreate(xmlNodePtr val) {
3369 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3371 xmlXPathErrMemory(NULL, "creating nodeset\n");
3374 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3376 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3377 sizeof(xmlNodePtr));
3378 if (ret->nodeTab == NULL) {
3379 xmlXPathErrMemory(NULL, "creating nodeset\n");
3383 memset(ret->nodeTab, 0 ,
3384 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3385 ret->nodeMax = XML_NODESET_DEFAULT;
3386 if (val->type == XML_NAMESPACE_DECL) {
3387 xmlNsPtr ns = (xmlNsPtr) val;
3389 ret->nodeTab[ret->nodeNr++] =
3390 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3392 ret->nodeTab[ret->nodeNr++] = val;
3398 * xmlXPathNodeSetCreateSize:
3399 * @size: the initial size of the set
3401 * Create a new xmlNodeSetPtr of type double and of value @val
3403 * Returns the newly created object.
3405 static xmlNodeSetPtr
3406 xmlXPathNodeSetCreateSize(int size) {
3409 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3411 xmlXPathErrMemory(NULL, "creating nodeset\n");
3414 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3415 if (size < XML_NODESET_DEFAULT)
3416 size = XML_NODESET_DEFAULT;
3417 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3418 if (ret->nodeTab == NULL) {
3419 xmlXPathErrMemory(NULL, "creating nodeset\n");
3423 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3424 ret->nodeMax = size;
3429 * xmlXPathNodeSetContains:
3430 * @cur: the node-set
3433 * checks whether @cur contains @val
3435 * Returns true (1) if @cur contains @val, false (0) otherwise
3438 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3441 if ((cur == NULL) || (val == NULL)) return(0);
3442 if (val->type == XML_NAMESPACE_DECL) {
3443 for (i = 0; i < cur->nodeNr; i++) {
3444 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3447 ns1 = (xmlNsPtr) val;
3448 ns2 = (xmlNsPtr) cur->nodeTab[i];
3451 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3452 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3457 for (i = 0; i < cur->nodeNr; i++) {
3458 if (cur->nodeTab[i] == val)
3466 * xmlXPathNodeSetAddNs:
3467 * @cur: the initial node set
3468 * @node: the hosting node
3469 * @ns: a the namespace node
3471 * add a new namespace node to an existing NodeSet
3474 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3478 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3479 (ns->type != XML_NAMESPACE_DECL) ||
3480 (node->type != XML_ELEMENT_NODE))
3483 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3485 * prevent duplicates
3487 for (i = 0;i < cur->nodeNr;i++) {
3488 if ((cur->nodeTab[i] != NULL) &&
3489 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3490 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3491 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3496 * grow the nodeTab if needed
3498 if (cur->nodeMax == 0) {
3499 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3500 sizeof(xmlNodePtr));
3501 if (cur->nodeTab == NULL) {
3502 xmlXPathErrMemory(NULL, "growing nodeset\n");
3505 memset(cur->nodeTab, 0 ,
3506 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3507 cur->nodeMax = XML_NODESET_DEFAULT;
3508 } else if (cur->nodeNr == cur->nodeMax) {
3512 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3513 sizeof(xmlNodePtr));
3515 xmlXPathErrMemory(NULL, "growing nodeset\n");
3518 cur->nodeTab = temp;
3520 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3524 * xmlXPathNodeSetAdd:
3525 * @cur: the initial node set
3526 * @val: a new xmlNodePtr
3528 * add a new xmlNodePtr to an existing NodeSet
3531 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3534 if ((cur == NULL) || (val == NULL)) return;
3537 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3538 return; /* an XSLT fake node */
3541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3545 for (i = 0;i < cur->nodeNr;i++)
3546 if (cur->nodeTab[i] == val) return;
3549 * grow the nodeTab if needed
3551 if (cur->nodeMax == 0) {
3552 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553 sizeof(xmlNodePtr));
3554 if (cur->nodeTab == NULL) {
3555 xmlXPathErrMemory(NULL, "growing nodeset\n");
3558 memset(cur->nodeTab, 0 ,
3559 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3560 cur->nodeMax = XML_NODESET_DEFAULT;
3561 } else if (cur->nodeNr == cur->nodeMax) {
3565 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3566 sizeof(xmlNodePtr));
3568 xmlXPathErrMemory(NULL, "growing nodeset\n");
3571 cur->nodeTab = temp;
3573 if (val->type == XML_NAMESPACE_DECL) {
3574 xmlNsPtr ns = (xmlNsPtr) val;
3576 cur->nodeTab[cur->nodeNr++] =
3577 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3579 cur->nodeTab[cur->nodeNr++] = val;
3583 * xmlXPathNodeSetAddUnique:
3584 * @cur: the initial node set
3585 * @val: a new xmlNodePtr
3587 * add a new xmlNodePtr to an existing NodeSet, optimized version
3588 * when we are sure the node is not already in the set.
3591 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3592 if ((cur == NULL) || (val == NULL)) return;
3595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596 return; /* an XSLT fake node */
3599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3601 * grow the nodeTab if needed
3603 if (cur->nodeMax == 0) {
3604 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3605 sizeof(xmlNodePtr));
3606 if (cur->nodeTab == NULL) {
3607 xmlXPathErrMemory(NULL, "growing nodeset\n");
3610 memset(cur->nodeTab, 0 ,
3611 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3612 cur->nodeMax = XML_NODESET_DEFAULT;
3613 } else if (cur->nodeNr == cur->nodeMax) {
3617 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3618 sizeof(xmlNodePtr));
3620 xmlXPathErrMemory(NULL, "growing nodeset\n");
3623 cur->nodeTab = temp;
3625 if (val->type == XML_NAMESPACE_DECL) {
3626 xmlNsPtr ns = (xmlNsPtr) val;
3628 cur->nodeTab[cur->nodeNr++] =
3629 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3631 cur->nodeTab[cur->nodeNr++] = val;
3635 * xmlXPathNodeSetMerge:
3636 * @val1: the first NodeSet or NULL
3637 * @val2: the second NodeSet
3639 * Merges two nodesets, all nodes from @val2 are added to @val1
3640 * if @val1 is NULL, a new set is created and copied from @val2
3642 * Returns @val1 once extended or NULL in case of error.
3645 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3646 int i, j, initNr, skip;
3649 if (val2 == NULL) return(val1);
3651 val1 = xmlXPathNodeSetCreate(NULL);
3654 * TODO: The optimization won't work in every case, since
3655 * those nasty namespace nodes need to be added with
3656 * xmlXPathNodeSetDupNs() to the set; thus a pure
3657 * memcpy is not possible.
3658 * If there was a flag on the nodesetval, indicating that
3659 * some temporary nodes are in, that would be helpfull.
3662 * Optimization: Create an equally sized node-set
3663 * and memcpy the content.
3665 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3668 if (val2->nodeNr != 0) {
3669 if (val2->nodeNr == 1)
3670 *(val1->nodeTab) = *(val2->nodeTab);
3672 memcpy(val1->nodeTab, val2->nodeTab,
3673 val2->nodeNr * sizeof(xmlNodePtr));
3675 val1->nodeNr = val2->nodeNr;
3681 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3682 initNr = val1->nodeNr;
3684 for (i = 0;i < val2->nodeNr;i++) {
3685 n2 = val2->nodeTab[i];
3687 * check against duplicates
3690 for (j = 0; j < initNr; j++) {
3691 n1 = val1->nodeTab[j];
3695 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3696 (n2->type == XML_NAMESPACE_DECL)) {
3697 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3698 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3699 ((xmlNsPtr) n2)->prefix)))
3710 * grow the nodeTab if needed
3712 if (val1->nodeMax == 0) {
3713 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3714 sizeof(xmlNodePtr));
3715 if (val1->nodeTab == NULL) {
3716 xmlXPathErrMemory(NULL, "merging nodeset\n");
3719 memset(val1->nodeTab, 0 ,
3720 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3721 val1->nodeMax = XML_NODESET_DEFAULT;
3722 } else if (val1->nodeNr == val1->nodeMax) {
3726 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3727 sizeof(xmlNodePtr));
3729 xmlXPathErrMemory(NULL, "merging nodeset\n");
3732 val1->nodeTab = temp;
3734 if (n2->type == XML_NAMESPACE_DECL) {
3735 xmlNsPtr ns = (xmlNsPtr) n2;
3737 val1->nodeTab[val1->nodeNr++] =
3738 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3740 val1->nodeTab[val1->nodeNr++] = n2;
3746 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3748 * xmlXPathNodeSetMergeUnique:
3749 * @val1: the first NodeSet or NULL
3750 * @val2: the second NodeSet
3752 * Merges two nodesets, all nodes from @val2 are added to @val1
3753 * if @val1 is NULL, a new set is created and copied from @val2
3755 * Returns @val1 once extended or NULL in case of error.
3757 static xmlNodeSetPtr
3758 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3761 if (val2 == NULL) return(val1);
3763 val1 = xmlXPathNodeSetCreate(NULL);
3766 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3768 for (i = 0;i < val2->nodeNr;i++) {
3770 * grow the nodeTab if needed
3772 if (val1->nodeMax == 0) {
3773 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 sizeof(xmlNodePtr));
3775 if (val1->nodeTab == NULL) {
3776 xmlXPathErrMemory(NULL, "merging nodeset\n");
3779 memset(val1->nodeTab, 0 ,
3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781 val1->nodeMax = XML_NODESET_DEFAULT;
3782 } else if (val1->nodeNr == val1->nodeMax) {
3786 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3787 sizeof(xmlNodePtr));
3789 xmlXPathErrMemory(NULL, "merging nodeset\n");
3792 val1->nodeTab = temp;
3794 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3795 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3797 val1->nodeTab[val1->nodeNr++] =
3798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3800 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3805 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3808 * xmlXPathNodeSetMergeAndClear:
3809 * @set1: the first NodeSet or NULL
3810 * @set2: the second NodeSet
3811 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3813 * Merges two nodesets, all nodes from @set2 are added to @set1
3814 * if @set1 is NULL, a new set is created and copied from @set2.
3815 * Checks for duplicate nodes. Clears set2.
3817 * Returns @set1 once extended or NULL in case of error.
3819 static xmlNodeSetPtr
3820 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3823 if ((set1 == NULL) && (hasNullEntries == 0)) {
3825 * Note that doing a memcpy of the list, namespace nodes are
3826 * just assigned to set1, since set2 is cleared anyway.
3828 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3831 if (set2->nodeNr != 0) {
3832 memcpy(set1->nodeTab, set2->nodeTab,
3833 set2->nodeNr * sizeof(xmlNodePtr));
3834 set1->nodeNr = set2->nodeNr;
3837 int i, j, initNbSet1;
3841 set1 = xmlXPathNodeSetCreate(NULL);
3843 initNbSet1 = set1->nodeNr;
3844 for (i = 0;i < set2->nodeNr;i++) {
3845 n2 = set2->nodeTab[i];
3847 * Skip NULLed entries.
3854 for (j = 0; j < initNbSet1; j++) {
3855 n1 = set1->nodeTab[j];
3858 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3859 (n2->type == XML_NAMESPACE_DECL))
3861 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3862 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3863 ((xmlNsPtr) n2)->prefix)))
3866 * Free the namespace node.
3868 set2->nodeTab[i] = NULL;
3869 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3875 * grow the nodeTab if needed
3877 if (set1->nodeMax == 0) {
3878 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3879 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3880 if (set1->nodeTab == NULL) {
3881 xmlXPathErrMemory(NULL, "merging nodeset\n");
3884 memset(set1->nodeTab, 0,
3885 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3886 set1->nodeMax = XML_NODESET_DEFAULT;
3887 } else if (set1->nodeNr >= set1->nodeMax) {
3891 temp = (xmlNodePtr *) xmlRealloc(
3892 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3894 xmlXPathErrMemory(NULL, "merging nodeset\n");
3897 set1->nodeTab = temp;
3899 if (n2->type == XML_NAMESPACE_DECL) {
3900 xmlNsPtr ns = (xmlNsPtr) n2;
3902 set1->nodeTab[set1->nodeNr++] =
3903 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3905 set1->nodeTab[set1->nodeNr++] = n2;
3915 * xmlXPathNodeSetMergeAndClearNoDupls:
3916 * @set1: the first NodeSet or NULL
3917 * @set2: the second NodeSet
3918 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3920 * Merges two nodesets, all nodes from @set2 are added to @set1
3921 * if @set1 is NULL, a new set is created and copied from @set2.
3922 * Doesn't chack for duplicate nodes. Clears set2.
3924 * Returns @set1 once extended or NULL in case of error.
3926 static xmlNodeSetPtr
3927 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3932 if ((set1 == NULL) && (hasNullEntries == 0)) {
3934 * Note that doing a memcpy of the list, namespace nodes are
3935 * just assigned to set1, since set2 is cleared anyway.
3937 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3940 if (set2->nodeNr != 0) {
3941 memcpy(set1->nodeTab, set2->nodeTab,
3942 set2->nodeNr * sizeof(xmlNodePtr));
3943 set1->nodeNr = set2->nodeNr;
3950 set1 = xmlXPathNodeSetCreate(NULL);
3952 for (i = 0;i < set2->nodeNr;i++) {
3953 n2 = set2->nodeTab[i];
3955 * Skip NULLed entries.
3959 if (set1->nodeMax == 0) {
3960 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3961 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3962 if (set1->nodeTab == NULL) {
3963 xmlXPathErrMemory(NULL, "merging nodeset\n");
3966 memset(set1->nodeTab, 0,
3967 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3968 set1->nodeMax = XML_NODESET_DEFAULT;
3969 } else if (set1->nodeNr >= set1->nodeMax) {
3973 temp = (xmlNodePtr *) xmlRealloc(
3974 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3976 xmlXPathErrMemory(NULL, "merging nodeset\n");
3979 set1->nodeTab = temp;
3981 set1->nodeTab[set1->nodeNr++] = n2;
3989 * xmlXPathNodeSetDel:
3990 * @cur: the initial node set
3991 * @val: an xmlNodePtr
3993 * Removes an xmlNodePtr from an existing NodeSet
3996 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3999 if (cur == NULL) return;
4000 if (val == NULL) return;
4003 * find node in nodeTab
4005 for (i = 0;i < cur->nodeNr;i++)
4006 if (cur->nodeTab[i] == val) break;
4008 if (i >= cur->nodeNr) { /* not found */
4010 xmlGenericError(xmlGenericErrorContext,
4011 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4016 if ((cur->nodeTab[i] != NULL) &&
4017 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4018 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4020 for (;i < cur->nodeNr;i++)
4021 cur->nodeTab[i] = cur->nodeTab[i + 1];
4022 cur->nodeTab[cur->nodeNr] = NULL;
4026 * xmlXPathNodeSetRemove:
4027 * @cur: the initial node set
4028 * @val: the index to remove
4030 * Removes an entry from an existing NodeSet list.
4033 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4034 if (cur == NULL) return;
4035 if (val >= cur->nodeNr) return;
4036 if ((cur->nodeTab[val] != NULL) &&
4037 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4038 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4040 for (;val < cur->nodeNr;val++)
4041 cur->nodeTab[val] = cur->nodeTab[val + 1];
4042 cur->nodeTab[cur->nodeNr] = NULL;
4046 * xmlXPathFreeNodeSet:
4047 * @obj: the xmlNodeSetPtr to free
4049 * Free the NodeSet compound (not the actual nodes !).
4052 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4053 if (obj == NULL) return;
4054 if (obj->nodeTab != NULL) {
4057 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4058 for (i = 0;i < obj->nodeNr;i++)
4059 if ((obj->nodeTab[i] != NULL) &&
4060 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4061 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4062 xmlFree(obj->nodeTab);
4068 * xmlXPathNodeSetClear:
4069 * @set: the node set to clear
4071 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4072 * are feed), but does *not* free the list itself. Sets the length of the
4076 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4078 if ((set == NULL) || (set->nodeNr <= 0))
4080 else if (hasNsNodes) {
4084 for (i = 0; i < set->nodeNr; i++) {
4085 node = set->nodeTab[i];
4086 if ((node != NULL) &&
4087 (node->type == XML_NAMESPACE_DECL))
4088 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4095 * xmlXPathNodeSetClearFromPos:
4096 * @set: the node set to be cleared
4097 * @pos: the start position to clear from
4099 * Clears the list from temporary XPath objects (e.g. namespace nodes
4100 * are feed) starting with the entry at @pos, but does *not* free the list
4101 * itself. Sets the length of the list to @pos.
4104 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4106 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4108 else if ((hasNsNodes)) {
4112 for (i = pos; i < set->nodeNr; i++) {
4113 node = set->nodeTab[i];
4114 if ((node != NULL) &&
4115 (node->type == XML_NAMESPACE_DECL))
4116 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4123 * xmlXPathFreeValueTree:
4124 * @obj: the xmlNodeSetPtr to free
4126 * Free the NodeSet compound and the actual tree, this is different
4127 * from xmlXPathFreeNodeSet()
4130 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4133 if (obj == NULL) return;
4135 if (obj->nodeTab != NULL) {
4136 for (i = 0;i < obj->nodeNr;i++) {
4137 if (obj->nodeTab[i] != NULL) {
4138 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4139 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4141 xmlFreeNodeList(obj->nodeTab[i]);
4145 xmlFree(obj->nodeTab);
4150 #if defined(DEBUG) || defined(DEBUG_STEP)
4152 * xmlGenericErrorContextNodeSet:
4153 * @output: a FILE * for the output
4154 * @obj: the xmlNodeSetPtr to display
4156 * Quick display of a NodeSet
4159 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4162 if (output == NULL) output = xmlGenericErrorContext;
4164 fprintf(output, "NodeSet == NULL !\n");
4167 if (obj->nodeNr == 0) {
4168 fprintf(output, "NodeSet is empty\n");
4171 if (obj->nodeTab == NULL) {
4172 fprintf(output, " nodeTab == NULL !\n");
4175 for (i = 0; i < obj->nodeNr; i++) {
4176 if (obj->nodeTab[i] == NULL) {
4177 fprintf(output, " NULL !\n");
4180 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4181 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4182 fprintf(output, " /");
4183 else if (obj->nodeTab[i]->name == NULL)
4184 fprintf(output, " noname!");
4185 else fprintf(output, " %s", obj->nodeTab[i]->name);
4187 fprintf(output, "\n");
4192 * xmlXPathNewNodeSet:
4193 * @val: the NodePtr value
4195 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4196 * it with the single Node @val
4198 * Returns the newly created object.
4201 xmlXPathNewNodeSet(xmlNodePtr val) {
4202 xmlXPathObjectPtr ret;
4204 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4206 xmlXPathErrMemory(NULL, "creating nodeset\n");
4209 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4210 ret->type = XPATH_NODESET;
4212 ret->nodesetval = xmlXPathNodeSetCreate(val);
4213 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4214 #ifdef XP_DEBUG_OBJ_USAGE
4215 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4221 * xmlXPathNewValueTree:
4222 * @val: the NodePtr value
4224 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4225 * it with the tree root @val
4227 * Returns the newly created object.
4230 xmlXPathNewValueTree(xmlNodePtr val) {
4231 xmlXPathObjectPtr ret;
4233 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4235 xmlXPathErrMemory(NULL, "creating result value tree\n");
4238 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4239 ret->type = XPATH_XSLT_TREE;
4241 ret->user = (void *) val;
4242 ret->nodesetval = xmlXPathNodeSetCreate(val);
4243 #ifdef XP_DEBUG_OBJ_USAGE
4244 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4250 * xmlXPathNewNodeSetList:
4251 * @val: an existing NodeSet
4253 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4254 * it with the Nodeset @val
4256 * Returns the newly created object.
4259 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4261 xmlXPathObjectPtr ret;
4266 else if (val->nodeTab == NULL)
4267 ret = xmlXPathNewNodeSet(NULL);
4269 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4270 for (i = 1; i < val->nodeNr; ++i)
4271 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4278 * xmlXPathWrapNodeSet:
4279 * @val: the NodePtr value
4281 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4283 * Returns the newly created object.
4286 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4287 xmlXPathObjectPtr ret;
4289 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4291 xmlXPathErrMemory(NULL, "creating node set object\n");
4294 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4295 ret->type = XPATH_NODESET;
4296 ret->nodesetval = val;
4297 #ifdef XP_DEBUG_OBJ_USAGE
4298 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4304 * xmlXPathFreeNodeSetList:
4305 * @obj: an existing NodeSetList object
4307 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4308 * the list contrary to xmlXPathFreeObject().
4311 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4312 if (obj == NULL) return;
4313 #ifdef XP_DEBUG_OBJ_USAGE
4314 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4320 * xmlXPathDifference:
4321 * @nodes1: a node-set
4322 * @nodes2: a node-set
4324 * Implements the EXSLT - Sets difference() function:
4325 * node-set set:difference (node-set, node-set)
4327 * Returns the difference between the two node sets, or nodes1 if
4331 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4336 if (xmlXPathNodeSetIsEmpty(nodes2))
4339 ret = xmlXPathNodeSetCreate(NULL);
4340 if (xmlXPathNodeSetIsEmpty(nodes1))
4343 l1 = xmlXPathNodeSetGetLength(nodes1);
4345 for (i = 0; i < l1; i++) {
4346 cur = xmlXPathNodeSetItem(nodes1, i);
4347 if (!xmlXPathNodeSetContains(nodes2, cur))
4348 xmlXPathNodeSetAddUnique(ret, cur);
4354 * xmlXPathIntersection:
4355 * @nodes1: a node-set
4356 * @nodes2: a node-set
4358 * Implements the EXSLT - Sets intersection() function:
4359 * node-set set:intersection (node-set, node-set)
4361 * Returns a node set comprising the nodes that are within both the
4362 * node sets passed as arguments
4365 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4366 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4370 if (xmlXPathNodeSetIsEmpty(nodes1))
4372 if (xmlXPathNodeSetIsEmpty(nodes2))
4375 l1 = xmlXPathNodeSetGetLength(nodes1);
4377 for (i = 0; i < l1; i++) {
4378 cur = xmlXPathNodeSetItem(nodes1, i);
4379 if (xmlXPathNodeSetContains(nodes2, cur))
4380 xmlXPathNodeSetAddUnique(ret, cur);
4386 * xmlXPathDistinctSorted:
4387 * @nodes: a node-set, sorted by document order
4389 * Implements the EXSLT - Sets distinct() function:
4390 * node-set set:distinct (node-set)
4392 * Returns a subset of the nodes contained in @nodes, or @nodes if
4396 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4398 xmlHashTablePtr hash;
4403 if (xmlXPathNodeSetIsEmpty(nodes))
4406 ret = xmlXPathNodeSetCreate(NULL);
4407 l = xmlXPathNodeSetGetLength(nodes);
4408 hash = xmlHashCreate (l);
4409 for (i = 0; i < l; i++) {
4410 cur = xmlXPathNodeSetItem(nodes, i);
4411 strval = xmlXPathCastNodeToString(cur);
4412 if (xmlHashLookup(hash, strval) == NULL) {
4413 xmlHashAddEntry(hash, strval, strval);
4414 xmlXPathNodeSetAddUnique(ret, cur);
4419 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4425 * @nodes: a node-set
4427 * Implements the EXSLT - Sets distinct() function:
4428 * node-set set:distinct (node-set)
4429 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4430 * is called with the sorted node-set
4432 * Returns a subset of the nodes contained in @nodes, or @nodes if
4436 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4437 if (xmlXPathNodeSetIsEmpty(nodes))
4440 xmlXPathNodeSetSort(nodes);
4441 return(xmlXPathDistinctSorted(nodes));
4445 * xmlXPathHasSameNodes:
4446 * @nodes1: a node-set
4447 * @nodes2: a node-set
4449 * Implements the EXSLT - Sets has-same-nodes function:
4450 * boolean set:has-same-node(node-set, node-set)
4452 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4456 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4460 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4461 xmlXPathNodeSetIsEmpty(nodes2))
4464 l = xmlXPathNodeSetGetLength(nodes1);
4465 for (i = 0; i < l; i++) {
4466 cur = xmlXPathNodeSetItem(nodes1, i);
4467 if (xmlXPathNodeSetContains(nodes2, cur))
4474 * xmlXPathNodeLeadingSorted:
4475 * @nodes: a node-set, sorted by document order
4478 * Implements the EXSLT - Sets leading() function:
4479 * node-set set:leading (node-set, node-set)
4481 * Returns the nodes in @nodes that precede @node in document order,
4482 * @nodes if @node is NULL or an empty node-set if @nodes
4483 * doesn't contain @node
4486 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4494 ret = xmlXPathNodeSetCreate(NULL);
4495 if (xmlXPathNodeSetIsEmpty(nodes) ||
4496 (!xmlXPathNodeSetContains(nodes, node)))
4499 l = xmlXPathNodeSetGetLength(nodes);
4500 for (i = 0; i < l; i++) {
4501 cur = xmlXPathNodeSetItem(nodes, i);
4504 xmlXPathNodeSetAddUnique(ret, cur);
4510 * xmlXPathNodeLeading:
4511 * @nodes: a node-set
4514 * Implements the EXSLT - Sets leading() function:
4515 * node-set set:leading (node-set, node-set)
4516 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4519 * Returns the nodes in @nodes that precede @node in document order,
4520 * @nodes if @node is NULL or an empty node-set if @nodes
4521 * doesn't contain @node
4524 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4525 xmlXPathNodeSetSort(nodes);
4526 return(xmlXPathNodeLeadingSorted(nodes, node));
4530 * xmlXPathLeadingSorted:
4531 * @nodes1: a node-set, sorted by document order
4532 * @nodes2: a node-set, sorted by document order
4534 * Implements the EXSLT - Sets leading() function:
4535 * node-set set:leading (node-set, node-set)
4537 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4538 * in document order, @nodes1 if @nodes2 is NULL or empty or
4539 * an empty node-set if @nodes1 doesn't contain @nodes2
4542 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4543 if (xmlXPathNodeSetIsEmpty(nodes2))
4545 return(xmlXPathNodeLeadingSorted(nodes1,
4546 xmlXPathNodeSetItem(nodes2, 1)));
4551 * @nodes1: a node-set
4552 * @nodes2: a node-set
4554 * Implements the EXSLT - Sets leading() function:
4555 * node-set set:leading (node-set, node-set)
4556 * @nodes1 and @nodes2 are sorted by document order, then
4557 * #exslSetsLeadingSorted is called.
4559 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4560 * in document order, @nodes1 if @nodes2 is NULL or empty or
4561 * an empty node-set if @nodes1 doesn't contain @nodes2
4564 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4565 if (xmlXPathNodeSetIsEmpty(nodes2))
4567 if (xmlXPathNodeSetIsEmpty(nodes1))
4568 return(xmlXPathNodeSetCreate(NULL));
4569 xmlXPathNodeSetSort(nodes1);
4570 xmlXPathNodeSetSort(nodes2);
4571 return(xmlXPathNodeLeadingSorted(nodes1,
4572 xmlXPathNodeSetItem(nodes2, 1)));
4576 * xmlXPathNodeTrailingSorted:
4577 * @nodes: a node-set, sorted by document order
4580 * Implements the EXSLT - Sets trailing() function:
4581 * node-set set:trailing (node-set, node-set)
4583 * Returns the nodes in @nodes that follow @node in document order,
4584 * @nodes if @node is NULL or an empty node-set if @nodes
4585 * doesn't contain @node
4588 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4596 ret = xmlXPathNodeSetCreate(NULL);
4597 if (xmlXPathNodeSetIsEmpty(nodes) ||
4598 (!xmlXPathNodeSetContains(nodes, node)))
4601 l = xmlXPathNodeSetGetLength(nodes);
4602 for (i = l; i > 0; i--) {
4603 cur = xmlXPathNodeSetItem(nodes, i);
4606 xmlXPathNodeSetAddUnique(ret, cur);
4612 * xmlXPathNodeTrailing:
4613 * @nodes: a node-set
4616 * Implements the EXSLT - Sets trailing() function:
4617 * node-set set:trailing (node-set, node-set)
4618 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4621 * Returns the nodes in @nodes that follow @node in document order,
4622 * @nodes if @node is NULL or an empty node-set if @nodes
4623 * doesn't contain @node
4626 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4627 xmlXPathNodeSetSort(nodes);
4628 return(xmlXPathNodeTrailingSorted(nodes, node));
4632 * xmlXPathTrailingSorted:
4633 * @nodes1: a node-set, sorted by document order
4634 * @nodes2: a node-set, sorted by document order
4636 * Implements the EXSLT - Sets trailing() function:
4637 * node-set set:trailing (node-set, node-set)
4639 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4640 * in document order, @nodes1 if @nodes2 is NULL or empty or
4641 * an empty node-set if @nodes1 doesn't contain @nodes2
4644 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4645 if (xmlXPathNodeSetIsEmpty(nodes2))
4647 return(xmlXPathNodeTrailingSorted(nodes1,
4648 xmlXPathNodeSetItem(nodes2, 0)));
4653 * @nodes1: a node-set
4654 * @nodes2: a node-set
4656 * Implements the EXSLT - Sets trailing() function:
4657 * node-set set:trailing (node-set, node-set)
4658 * @nodes1 and @nodes2 are sorted by document order, then
4659 * #xmlXPathTrailingSorted is called.
4661 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4662 * in document order, @nodes1 if @nodes2 is NULL or empty or
4663 * an empty node-set if @nodes1 doesn't contain @nodes2
4666 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4667 if (xmlXPathNodeSetIsEmpty(nodes2))
4669 if (xmlXPathNodeSetIsEmpty(nodes1))
4670 return(xmlXPathNodeSetCreate(NULL));
4671 xmlXPathNodeSetSort(nodes1);
4672 xmlXPathNodeSetSort(nodes2);
4673 return(xmlXPathNodeTrailingSorted(nodes1,
4674 xmlXPathNodeSetItem(nodes2, 0)));
4677 /************************************************************************
4679 * Routines to handle extra functions *
4681 ************************************************************************/
4684 * xmlXPathRegisterFunc:
4685 * @ctxt: the XPath context
4686 * @name: the function name
4687 * @f: the function implementation or NULL
4689 * Register a new function. If @f is NULL it unregisters the function
4691 * Returns 0 in case of success, -1 in case of error
4694 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4695 xmlXPathFunction f) {
4696 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4700 * xmlXPathRegisterFuncNS:
4701 * @ctxt: the XPath context
4702 * @name: the function name
4703 * @ns_uri: the function namespace URI
4704 * @f: the function implementation or NULL
4706 * Register a new function. If @f is NULL it unregisters the function
4708 * Returns 0 in case of success, -1 in case of error
4711 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4712 const xmlChar *ns_uri, xmlXPathFunction f) {
4718 if (ctxt->funcHash == NULL)
4719 ctxt->funcHash = xmlHashCreate(0);
4720 if (ctxt->funcHash == NULL)
4723 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4724 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4728 * xmlXPathRegisterFuncLookup:
4729 * @ctxt: the XPath context
4730 * @f: the lookup function
4731 * @funcCtxt: the lookup data
4733 * Registers an external mechanism to do function lookup.
4736 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4737 xmlXPathFuncLookupFunc f,
4741 ctxt->funcLookupFunc = f;
4742 ctxt->funcLookupData = funcCtxt;
4746 * xmlXPathFunctionLookup:
4747 * @ctxt: the XPath context
4748 * @name: the function name
4750 * Search in the Function array of the context for the given
4753 * Returns the xmlXPathFunction or NULL if not found
4756 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4760 if (ctxt->funcLookupFunc != NULL) {
4761 xmlXPathFunction ret;
4762 xmlXPathFuncLookupFunc f;
4764 f = ctxt->funcLookupFunc;
4765 ret = f(ctxt->funcLookupData, name, NULL);
4769 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4773 * xmlXPathFunctionLookupNS:
4774 * @ctxt: the XPath context
4775 * @name: the function name
4776 * @ns_uri: the function namespace URI
4778 * Search in the Function array of the context for the given
4781 * Returns the xmlXPathFunction or NULL if not found
4784 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4785 const xmlChar *ns_uri) {
4786 xmlXPathFunction ret;
4793 if (ctxt->funcLookupFunc != NULL) {
4794 xmlXPathFuncLookupFunc f;
4796 f = ctxt->funcLookupFunc;
4797 ret = f(ctxt->funcLookupData, name, ns_uri);
4802 if (ctxt->funcHash == NULL)
4805 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4810 * xmlXPathRegisteredFuncsCleanup:
4811 * @ctxt: the XPath context
4813 * Cleanup the XPath context data associated to registered functions
4816 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4820 xmlHashFree(ctxt->funcHash, NULL);
4821 ctxt->funcHash = NULL;
4824 /************************************************************************
4826 * Routines to handle Variables *
4828 ************************************************************************/
4831 * xmlXPathRegisterVariable:
4832 * @ctxt: the XPath context
4833 * @name: the variable name
4834 * @value: the variable value or NULL
4836 * Register a new variable value. If @value is NULL it unregisters
4839 * Returns 0 in case of success, -1 in case of error
4842 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4843 xmlXPathObjectPtr value) {
4844 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4848 * xmlXPathRegisterVariableNS:
4849 * @ctxt: the XPath context
4850 * @name: the variable name
4851 * @ns_uri: the variable namespace URI
4852 * @value: the variable value or NULL
4854 * Register a new variable value. If @value is NULL it unregisters
4857 * Returns 0 in case of success, -1 in case of error
4860 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861 const xmlChar *ns_uri,
4862 xmlXPathObjectPtr value) {
4868 if (ctxt->varHash == NULL)
4869 ctxt->varHash = xmlHashCreate(0);
4870 if (ctxt->varHash == NULL)
4873 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4874 (xmlHashDeallocator)xmlXPathFreeObject));
4875 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4877 (xmlHashDeallocator)xmlXPathFreeObject));
4881 * xmlXPathRegisterVariableLookup:
4882 * @ctxt: the XPath context
4883 * @f: the lookup function
4884 * @data: the lookup data
4886 * register an external mechanism to do variable lookup
4889 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4890 xmlXPathVariableLookupFunc f, void *data) {
4893 ctxt->varLookupFunc = f;
4894 ctxt->varLookupData = data;
4898 * xmlXPathVariableLookup:
4899 * @ctxt: the XPath context
4900 * @name: the variable name
4902 * Search in the Variable array of the context for the given
4905 * Returns a copy of the value or NULL if not found
4908 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4912 if (ctxt->varLookupFunc != NULL) {
4913 xmlXPathObjectPtr ret;
4915 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4916 (ctxt->varLookupData, name, NULL);
4919 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4923 * xmlXPathVariableLookupNS:
4924 * @ctxt: the XPath context
4925 * @name: the variable name
4926 * @ns_uri: the variable namespace URI
4928 * Search in the Variable array of the context for the given
4931 * Returns the a copy of the value or NULL if not found
4934 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4935 const xmlChar *ns_uri) {
4939 if (ctxt->varLookupFunc != NULL) {
4940 xmlXPathObjectPtr ret;
4942 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4943 (ctxt->varLookupData, name, ns_uri);
4944 if (ret != NULL) return(ret);
4947 if (ctxt->varHash == NULL)
4952 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4953 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4957 * xmlXPathRegisteredVariablesCleanup:
4958 * @ctxt: the XPath context
4960 * Cleanup the XPath context data associated to registered variables
4963 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4967 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
4968 ctxt->varHash = NULL;
4972 * xmlXPathRegisterNs:
4973 * @ctxt: the XPath context
4974 * @prefix: the namespace prefix
4975 * @ns_uri: the namespace name
4977 * Register a new namespace. If @ns_uri is NULL it unregisters
4980 * Returns 0 in case of success, -1 in case of error
4983 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4984 const xmlChar *ns_uri) {
4990 if (ctxt->nsHash == NULL)
4991 ctxt->nsHash = xmlHashCreate(10);
4992 if (ctxt->nsHash == NULL)
4995 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4996 (xmlHashDeallocator)xmlFree));
4997 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
4998 (xmlHashDeallocator)xmlFree));
5003 * @ctxt: the XPath context
5004 * @prefix: the namespace prefix value
5006 * Search in the namespace declaration array of the context for the given
5007 * namespace name associated to the given prefix
5009 * Returns the value or NULL if not found
5012 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5018 #ifdef XML_XML_NAMESPACE
5019 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5020 return(XML_XML_NAMESPACE);
5023 if (ctxt->namespaces != NULL) {
5026 for (i = 0;i < ctxt->nsNr;i++) {
5027 if ((ctxt->namespaces[i] != NULL) &&
5028 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5029 return(ctxt->namespaces[i]->href);
5033 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5037 * xmlXPathRegisteredNsCleanup:
5038 * @ctxt: the XPath context
5040 * Cleanup the XPath context data associated to registered variables
5043 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5047 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5048 ctxt->nsHash = NULL;
5051 /************************************************************************
5053 * Routines to handle Values *
5055 ************************************************************************/
5057 /* Allocations are terrible, one needs to optimize all this !!! */
5061 * @val: the double value
5063 * Create a new xmlXPathObjectPtr of type double and of value @val
5065 * Returns the newly created object.
5068 xmlXPathNewFloat(double val) {
5069 xmlXPathObjectPtr ret;
5071 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5073 xmlXPathErrMemory(NULL, "creating float object\n");
5076 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5077 ret->type = XPATH_NUMBER;
5078 ret->floatval = val;
5079 #ifdef XP_DEBUG_OBJ_USAGE
5080 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5086 * xmlXPathNewBoolean:
5087 * @val: the boolean value
5089 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5091 * Returns the newly created object.
5094 xmlXPathNewBoolean(int val) {
5095 xmlXPathObjectPtr ret;
5097 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5099 xmlXPathErrMemory(NULL, "creating boolean object\n");
5102 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5103 ret->type = XPATH_BOOLEAN;
5104 ret->boolval = (val != 0);
5105 #ifdef XP_DEBUG_OBJ_USAGE
5106 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5112 * xmlXPathNewString:
5113 * @val: the xmlChar * value
5115 * Create a new xmlXPathObjectPtr of type string and of value @val
5117 * Returns the newly created object.
5120 xmlXPathNewString(const xmlChar *val) {
5121 xmlXPathObjectPtr ret;
5123 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5125 xmlXPathErrMemory(NULL, "creating string object\n");
5128 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5129 ret->type = XPATH_STRING;
5131 ret->stringval = xmlStrdup(val);
5133 ret->stringval = xmlStrdup((const xmlChar *)"");
5134 #ifdef XP_DEBUG_OBJ_USAGE
5135 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5141 * xmlXPathWrapString:
5142 * @val: the xmlChar * value
5144 * Wraps the @val string into an XPath object.
5146 * Returns the newly created object.
5149 xmlXPathWrapString (xmlChar *val) {
5150 xmlXPathObjectPtr ret;
5152 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5154 xmlXPathErrMemory(NULL, "creating string object\n");
5157 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5158 ret->type = XPATH_STRING;
5159 ret->stringval = val;
5160 #ifdef XP_DEBUG_OBJ_USAGE
5161 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5167 * xmlXPathNewCString:
5168 * @val: the char * value
5170 * Create a new xmlXPathObjectPtr of type string and of value @val
5172 * Returns the newly created object.
5175 xmlXPathNewCString(const char *val) {
5176 xmlXPathObjectPtr ret;
5178 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5180 xmlXPathErrMemory(NULL, "creating string object\n");
5183 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5184 ret->type = XPATH_STRING;
5185 ret->stringval = xmlStrdup(BAD_CAST val);
5186 #ifdef XP_DEBUG_OBJ_USAGE
5187 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5193 * xmlXPathWrapCString:
5194 * @val: the char * value
5196 * Wraps a string into an XPath object.
5198 * Returns the newly created object.
5201 xmlXPathWrapCString (char * val) {
5202 return(xmlXPathWrapString((xmlChar *)(val)));
5206 * xmlXPathWrapExternal:
5207 * @val: the user data
5209 * Wraps the @val data into an XPath object.
5211 * Returns the newly created object.
5214 xmlXPathWrapExternal (void *val) {
5215 xmlXPathObjectPtr ret;
5217 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5219 xmlXPathErrMemory(NULL, "creating user object\n");
5222 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5223 ret->type = XPATH_USERS;
5225 #ifdef XP_DEBUG_OBJ_USAGE
5226 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5232 * xmlXPathObjectCopy:
5233 * @val: the original object
5235 * allocate a new copy of a given object
5237 * Returns the newly created object.
5240 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5241 xmlXPathObjectPtr ret;
5246 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5248 xmlXPathErrMemory(NULL, "copying object\n");
5251 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5252 #ifdef XP_DEBUG_OBJ_USAGE
5253 xmlXPathDebugObjUsageRequested(NULL, val->type);
5255 switch (val->type) {
5262 ret->stringval = xmlStrdup(val->stringval);
5264 case XPATH_XSLT_TREE:
5267 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5268 this previous handling is no longer correct, and can cause some serious
5269 problems (ref. bug 145547)
5271 if ((val->nodesetval != NULL) &&
5272 (val->nodesetval->nodeTab != NULL)) {
5273 xmlNodePtr cur, tmp;
5277 top = xmlNewDoc(NULL);
5278 top->name = (char *)
5279 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5283 cur = val->nodesetval->nodeTab[0]->children;
5284 while (cur != NULL) {
5285 tmp = xmlDocCopyNode(cur, top, 1);
5286 xmlAddChild((xmlNodePtr) top, tmp);
5291 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5293 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5294 /* Deallocate the copied tree value */
5298 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5299 /* Do not deallocate the copied tree value */
5302 case XPATH_LOCATIONSET:
5303 #ifdef LIBXML_XPTR_ENABLED
5305 xmlLocationSetPtr loc = val->user;
5306 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5311 ret->user = val->user;
5313 case XPATH_UNDEFINED:
5314 xmlGenericError(xmlGenericErrorContext,
5315 "xmlXPathObjectCopy: unsupported type %d\n",
5323 * xmlXPathFreeObject:
5324 * @obj: the object to free
5326 * Free up an xmlXPathObjectPtr object.
5329 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5330 if (obj == NULL) return;
5331 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5334 if (obj->user != NULL) {
5335 xmlXPathFreeNodeSet(obj->nodesetval);
5336 xmlFreeNodeList((xmlNodePtr) obj->user);
5339 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5340 if (obj->nodesetval != NULL)
5341 xmlXPathFreeValueTree(obj->nodesetval);
5343 if (obj->nodesetval != NULL)
5344 xmlXPathFreeNodeSet(obj->nodesetval);
5346 #ifdef LIBXML_XPTR_ENABLED
5347 } else if (obj->type == XPATH_LOCATIONSET) {
5348 if (obj->user != NULL)
5349 xmlXPtrFreeLocationSet(obj->user);
5351 } else if (obj->type == XPATH_STRING) {
5352 if (obj->stringval != NULL)
5353 xmlFree(obj->stringval);
5355 #ifdef XP_DEBUG_OBJ_USAGE
5356 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5362 * xmlXPathReleaseObject:
5363 * @obj: the xmlXPathObjectPtr to free or to cache
5365 * Depending on the state of the cache this frees the given
5366 * XPath object or stores it in the cache.
5369 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5371 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5372 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5373 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5375 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5379 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5380 xmlXPathFreeObject(obj);
5382 xmlXPathContextCachePtr cache =
5383 (xmlXPathContextCachePtr) ctxt->cache;
5385 switch (obj->type) {
5387 case XPATH_XSLT_TREE:
5388 if (obj->nodesetval != NULL) {
5391 * It looks like the @boolval is used for
5392 * evaluation if this an XSLT Result Tree Fragment.
5393 * TODO: Check if this assumption is correct.
5395 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5396 xmlXPathFreeValueTree(obj->nodesetval);
5397 obj->nodesetval = NULL;
5398 } else if ((obj->nodesetval->nodeMax <= 40) &&
5399 (XP_CACHE_WANTS(cache->nodesetObjs,
5400 cache->maxNodeset)))
5402 XP_CACHE_ADD(cache->nodesetObjs, obj);
5405 xmlXPathFreeNodeSet(obj->nodesetval);
5406 obj->nodesetval = NULL;
5411 if (obj->stringval != NULL)
5412 xmlFree(obj->stringval);
5414 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5415 XP_CACHE_ADD(cache->stringObjs, obj);
5420 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5421 XP_CACHE_ADD(cache->booleanObjs, obj);
5426 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5427 XP_CACHE_ADD(cache->numberObjs, obj);
5431 #ifdef LIBXML_XPTR_ENABLED
5432 case XPATH_LOCATIONSET:
5433 if (obj->user != NULL) {
5434 xmlXPtrFreeLocationSet(obj->user);
5443 * Fallback to adding to the misc-objects slot.
5445 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5446 XP_CACHE_ADD(cache->miscObjs, obj);
5452 #ifdef XP_DEBUG_OBJ_USAGE
5453 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5456 if (obj->nodesetval != NULL) {
5457 xmlNodeSetPtr tmpset = obj->nodesetval;
5460 * TODO: Due to those nasty ns-nodes, we need to traverse
5461 * the list and free the ns-nodes.
5462 * URGENT TODO: Check if it's actually slowing things down.
5463 * Maybe we shouldn't try to preserve the list.
5465 if (tmpset->nodeNr > 1) {
5469 for (i = 0; i < tmpset->nodeNr; i++) {
5470 node = tmpset->nodeTab[i];
5471 if ((node != NULL) &&
5472 (node->type == XML_NAMESPACE_DECL))
5474 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5477 } else if (tmpset->nodeNr == 1) {
5478 if ((tmpset->nodeTab[0] != NULL) &&
5479 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5480 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5483 memset(obj, 0, sizeof(xmlXPathObject));
5484 obj->nodesetval = tmpset;
5486 memset(obj, 0, sizeof(xmlXPathObject));
5492 * Cache is full; free the object.
5494 if (obj->nodesetval != NULL)
5495 xmlXPathFreeNodeSet(obj->nodesetval);
5496 #ifdef XP_DEBUG_OBJ_USAGE
5497 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5505 /************************************************************************
5507 * Type Casting Routines *
5509 ************************************************************************/
5512 * xmlXPathCastBooleanToString:
5515 * Converts a boolean to its string value.
5517 * Returns a newly allocated string.
5520 xmlXPathCastBooleanToString (int val) {
5523 ret = xmlStrdup((const xmlChar *) "true");
5525 ret = xmlStrdup((const xmlChar *) "false");
5530 * xmlXPathCastNumberToString:
5533 * Converts a number to its string value.
5535 * Returns a newly allocated string.
5538 xmlXPathCastNumberToString (double val) {
5540 switch (xmlXPathIsInf(val)) {
5542 ret = xmlStrdup((const xmlChar *) "Infinity");
5545 ret = xmlStrdup((const xmlChar *) "-Infinity");
5548 if (xmlXPathIsNaN(val)) {
5549 ret = xmlStrdup((const xmlChar *) "NaN");
5550 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5551 ret = xmlStrdup((const xmlChar *) "0");
5553 /* could be improved */
5555 xmlXPathFormatNumber(val, buf, 99);
5557 ret = xmlStrdup((const xmlChar *) buf);
5564 * xmlXPathCastNodeToString:
5567 * Converts a node to its string value.
5569 * Returns a newly allocated string.
5572 xmlXPathCastNodeToString (xmlNodePtr node) {
5573 return(xmlNodeGetContent(node));
5577 * xmlXPathCastNodeSetToString:
5580 * Converts a node-set to its string value.
5582 * Returns a newly allocated string.
5585 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5586 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5587 return(xmlStrdup((const xmlChar *) ""));
5590 xmlXPathNodeSetSort(ns);
5591 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5595 * xmlXPathCastToString:
5596 * @val: an XPath object
5598 * Converts an existing object to its string() equivalent
5600 * Returns the allocated string value of the object, NULL in case of error.
5601 * It's up to the caller to free the string memory with xmlFree().
5604 xmlXPathCastToString(xmlXPathObjectPtr val) {
5605 xmlChar *ret = NULL;
5608 return(xmlStrdup((const xmlChar *) ""));
5609 switch (val->type) {
5610 case XPATH_UNDEFINED:
5612 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5614 ret = xmlStrdup((const xmlChar *) "");
5617 case XPATH_XSLT_TREE:
5618 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5621 return(xmlStrdup(val->stringval));
5623 ret = xmlXPathCastBooleanToString(val->boolval);
5625 case XPATH_NUMBER: {
5626 ret = xmlXPathCastNumberToString(val->floatval);
5632 case XPATH_LOCATIONSET:
5634 ret = xmlStrdup((const xmlChar *) "");
5641 * xmlXPathConvertString:
5642 * @val: an XPath object
5644 * Converts an existing object to its string() equivalent
5646 * Returns the new object, the old one is freed (or the operation
5647 * is done directly on @val)
5650 xmlXPathConvertString(xmlXPathObjectPtr val) {
5651 xmlChar *res = NULL;
5654 return(xmlXPathNewCString(""));
5656 switch (val->type) {
5657 case XPATH_UNDEFINED:
5659 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5663 case XPATH_XSLT_TREE:
5664 res = xmlXPathCastNodeSetToString(val->nodesetval);
5669 res = xmlXPathCastBooleanToString(val->boolval);
5672 res = xmlXPathCastNumberToString(val->floatval);
5677 case XPATH_LOCATIONSET:
5681 xmlXPathFreeObject(val);
5683 return(xmlXPathNewCString(""));
5684 return(xmlXPathWrapString(res));
5688 * xmlXPathCastBooleanToNumber:
5691 * Converts a boolean to its number value
5693 * Returns the number value
5696 xmlXPathCastBooleanToNumber(int val) {
5703 * xmlXPathCastStringToNumber:
5706 * Converts a string to its number value
5708 * Returns the number value
5711 xmlXPathCastStringToNumber(const xmlChar * val) {
5712 return(xmlXPathStringEvalNumber(val));
5716 * xmlXPathCastNodeToNumber:
5719 * Converts a node to its number value
5721 * Returns the number value
5724 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5729 return(xmlXPathNAN);
5730 strval = xmlXPathCastNodeToString(node);
5732 return(xmlXPathNAN);
5733 ret = xmlXPathCastStringToNumber(strval);
5740 * xmlXPathCastNodeSetToNumber:
5743 * Converts a node-set to its number value
5745 * Returns the number value
5748 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5753 return(xmlXPathNAN);
5754 str = xmlXPathCastNodeSetToString(ns);
5755 ret = xmlXPathCastStringToNumber(str);
5761 * xmlXPathCastToNumber:
5762 * @val: an XPath object
5764 * Converts an XPath object to its number value
5766 * Returns the number value
5769 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5773 return(xmlXPathNAN);
5774 switch (val->type) {
5775 case XPATH_UNDEFINED:
5777 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5782 case XPATH_XSLT_TREE:
5783 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5786 ret = xmlXPathCastStringToNumber(val->stringval);
5789 ret = val->floatval;
5792 ret = xmlXPathCastBooleanToNumber(val->boolval);
5797 case XPATH_LOCATIONSET:
5806 * xmlXPathConvertNumber:
5807 * @val: an XPath object
5809 * Converts an existing object to its number() equivalent
5811 * Returns the new object, the old one is freed (or the operation
5812 * is done directly on @val)
5815 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5816 xmlXPathObjectPtr ret;
5819 return(xmlXPathNewFloat(0.0));
5820 if (val->type == XPATH_NUMBER)
5822 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5823 xmlXPathFreeObject(val);
5828 * xmlXPathCastNumberToBoolean:
5831 * Converts a number to its boolean value
5833 * Returns the boolean value
5836 xmlXPathCastNumberToBoolean (double val) {
5837 if (xmlXPathIsNaN(val) || (val == 0.0))
5843 * xmlXPathCastStringToBoolean:
5846 * Converts a string to its boolean value
5848 * Returns the boolean value
5851 xmlXPathCastStringToBoolean (const xmlChar *val) {
5852 if ((val == NULL) || (xmlStrlen(val) == 0))
5858 * xmlXPathCastNodeSetToBoolean:
5861 * Converts a node-set to its boolean value
5863 * Returns the boolean value
5866 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5867 if ((ns == NULL) || (ns->nodeNr == 0))
5873 * xmlXPathCastToBoolean:
5874 * @val: an XPath object
5876 * Converts an XPath object to its boolean value
5878 * Returns the boolean value
5881 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5886 switch (val->type) {
5887 case XPATH_UNDEFINED:
5889 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5894 case XPATH_XSLT_TREE:
5895 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5898 ret = xmlXPathCastStringToBoolean(val->stringval);
5901 ret = xmlXPathCastNumberToBoolean(val->floatval);
5909 case XPATH_LOCATIONSET:
5919 * xmlXPathConvertBoolean:
5920 * @val: an XPath object
5922 * Converts an existing object to its boolean() equivalent
5924 * Returns the new object, the old one is freed (or the operation
5925 * is done directly on @val)
5928 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5929 xmlXPathObjectPtr ret;
5932 return(xmlXPathNewBoolean(0));
5933 if (val->type == XPATH_BOOLEAN)
5935 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5936 xmlXPathFreeObject(val);
5940 /************************************************************************
5942 * Routines to handle XPath contexts *
5944 ************************************************************************/
5947 * xmlXPathNewContext:
5948 * @doc: the XML document
5950 * Create a new xmlXPathContext
5952 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5955 xmlXPathNewContext(xmlDocPtr doc) {
5956 xmlXPathContextPtr ret;
5958 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5960 xmlXPathErrMemory(NULL, "creating context\n");
5963 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
5967 ret->varHash = NULL;
5973 ret->funcHash = xmlHashCreate(0);
5982 ret->contextSize = -1;
5983 ret->proximityPosition = -1;
5985 #ifdef XP_DEFAULT_CACHE_ON
5986 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5987 xmlXPathFreeContext(ret);
5992 xmlXPathRegisterAllFunctions(ret);
5998 * xmlXPathFreeContext:
5999 * @ctxt: the context to free
6001 * Free up an xmlXPathContext
6004 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6005 if (ctxt == NULL) return;
6007 if (ctxt->cache != NULL)
6008 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6009 xmlXPathRegisteredNsCleanup(ctxt);
6010 xmlXPathRegisteredFuncsCleanup(ctxt);
6011 xmlXPathRegisteredVariablesCleanup(ctxt);
6012 xmlResetError(&ctxt->lastError);
6016 /************************************************************************
6018 * Routines to handle XPath parser contexts *
6020 ************************************************************************/
6022 #define CHECK_CTXT(ctxt) \
6023 if (ctxt == NULL) { \
6024 __xmlRaiseError(NULL, NULL, NULL, \
6025 NULL, NULL, XML_FROM_XPATH, \
6026 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6027 __FILE__, __LINE__, \
6028 NULL, NULL, NULL, 0, 0, \
6029 "NULL context pointer\n"); \
6033 #define CHECK_CTXT_NEG(ctxt) \
6034 if (ctxt == NULL) { \
6035 __xmlRaiseError(NULL, NULL, NULL, \
6036 NULL, NULL, XML_FROM_XPATH, \
6037 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6038 __FILE__, __LINE__, \
6039 NULL, NULL, NULL, 0, 0, \
6040 "NULL context pointer\n"); \
6045 #define CHECK_CONTEXT(ctxt) \
6046 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6047 (ctxt->doc->children == NULL)) { \
6048 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6054 * xmlXPathNewParserContext:
6055 * @str: the XPath expression
6056 * @ctxt: the XPath context
6058 * Create a new xmlXPathParserContext
6060 * Returns the xmlXPathParserContext just allocated.
6062 xmlXPathParserContextPtr
6063 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6064 xmlXPathParserContextPtr ret;
6066 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6068 xmlXPathErrMemory(ctxt, "creating parser context\n");
6071 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6072 ret->cur = ret->base = str;
6073 ret->context = ctxt;
6075 ret->comp = xmlXPathNewCompExpr();
6076 if (ret->comp == NULL) {
6077 xmlFree(ret->valueTab);
6081 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6082 ret->comp->dict = ctxt->dict;
6083 xmlDictReference(ret->comp->dict);
6090 * xmlXPathCompParserContext:
6091 * @comp: the XPath compiled expression
6092 * @ctxt: the XPath context
6094 * Create a new xmlXPathParserContext when processing a compiled expression
6096 * Returns the xmlXPathParserContext just allocated.
6098 static xmlXPathParserContextPtr
6099 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6100 xmlXPathParserContextPtr ret;
6102 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6104 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6107 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6109 /* Allocate the value stack */
6110 ret->valueTab = (xmlXPathObjectPtr *)
6111 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6112 if (ret->valueTab == NULL) {
6114 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6121 ret->context = ctxt;
6128 * xmlXPathFreeParserContext:
6129 * @ctxt: the context to free
6131 * Free up an xmlXPathParserContext
6134 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6135 if (ctxt->valueTab != NULL) {
6136 xmlFree(ctxt->valueTab);
6138 if (ctxt->comp != NULL) {
6139 #ifdef XPATH_STREAMING
6140 if (ctxt->comp->stream != NULL) {
6141 xmlFreePatternList(ctxt->comp->stream);
6142 ctxt->comp->stream = NULL;
6145 xmlXPathFreeCompExpr(ctxt->comp);
6150 /************************************************************************
6152 * The implicit core function library *
6154 ************************************************************************/
6157 * xmlXPathNodeValHash:
6158 * @node: a node pointer
6160 * Function computing the beginning of the string value of the node,
6161 * used to speed up comparisons
6163 * Returns an int usable as a hash
6166 xmlXPathNodeValHash(xmlNodePtr node) {
6168 const xmlChar * string = NULL;
6169 xmlNodePtr tmp = NULL;
6170 unsigned int ret = 0;
6175 if (node->type == XML_DOCUMENT_NODE) {
6176 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6178 node = node->children;
6186 switch (node->type) {
6187 case XML_COMMENT_NODE:
6189 case XML_CDATA_SECTION_NODE:
6191 string = node->content;
6196 return(((unsigned int) string[0]) +
6197 (((unsigned int) string[1]) << 8));
6198 case XML_NAMESPACE_DECL:
6199 string = ((xmlNsPtr)node)->href;
6204 return(((unsigned int) string[0]) +
6205 (((unsigned int) string[1]) << 8));
6206 case XML_ATTRIBUTE_NODE:
6207 tmp = ((xmlAttrPtr) node)->children;
6209 case XML_ELEMENT_NODE:
6210 tmp = node->children;
6215 while (tmp != NULL) {
6216 switch (tmp->type) {
6217 case XML_COMMENT_NODE:
6219 case XML_CDATA_SECTION_NODE:
6221 string = tmp->content;
6223 case XML_NAMESPACE_DECL:
6224 string = ((xmlNsPtr)tmp)->href;
6229 if ((string != NULL) && (string[0] != 0)) {
6231 return(ret + (((unsigned int) string[0]) << 8));
6233 if (string[1] == 0) {
6235 ret = (unsigned int) string[0];
6237 return(((unsigned int) string[0]) +
6238 (((unsigned int) string[1]) << 8));
6244 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6245 if (tmp->children->type != XML_ENTITY_DECL) {
6246 tmp = tmp->children;
6253 if (tmp->next != NULL) {
6266 if (tmp->next != NULL) {
6270 } while (tmp != NULL);
6276 * xmlXPathStringHash:
6279 * Function computing the beginning of the string value of the node,
6280 * used to speed up comparisons
6282 * Returns an int usable as a hash
6285 xmlXPathStringHash(const xmlChar * string) {
6287 return((unsigned int) 0);
6290 return(((unsigned int) string[0]) +
6291 (((unsigned int) string[1]) << 8));
6295 * xmlXPathCompareNodeSetFloat:
6296 * @ctxt: the XPath Parser context
6297 * @inf: less than (1) or greater than (0)
6298 * @strict: is the comparison strict
6299 * @arg: the node set
6302 * Implement the compare operation between a nodeset and a number
6303 * @ns < @val (1, 1, ...
6304 * @ns <= @val (1, 0, ...
6305 * @ns > @val (0, 1, ...
6306 * @ns >= @val (0, 0, ...
6308 * If one object to be compared is a node-set and the other is a number,
6309 * then the comparison will be true if and only if there is a node in the
6310 * node-set such that the result of performing the comparison on the number
6311 * to be compared and on the result of converting the string-value of that
6312 * node to a number using the number function is true.
6314 * Returns 0 or 1 depending on the results of the test.
6317 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6318 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6323 if ((f == NULL) || (arg == NULL) ||
6324 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6325 xmlXPathReleaseObject(ctxt->context, arg);
6326 xmlXPathReleaseObject(ctxt->context, f);
6329 ns = arg->nodesetval;
6331 for (i = 0;i < ns->nodeNr;i++) {
6332 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6335 xmlXPathCacheNewString(ctxt->context, str2));
6337 xmlXPathNumberFunction(ctxt, 1);
6338 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6339 ret = xmlXPathCompareValues(ctxt, inf, strict);
6345 xmlXPathReleaseObject(ctxt->context, arg);
6346 xmlXPathReleaseObject(ctxt->context, f);
6351 * xmlXPathCompareNodeSetString:
6352 * @ctxt: the XPath Parser context
6353 * @inf: less than (1) or greater than (0)
6354 * @strict: is the comparison strict
6355 * @arg: the node set
6358 * Implement the compare operation between a nodeset and a string
6359 * @ns < @val (1, 1, ...
6360 * @ns <= @val (1, 0, ...
6361 * @ns > @val (0, 1, ...
6362 * @ns >= @val (0, 0, ...
6364 * If one object to be compared is a node-set and the other is a string,
6365 * then the comparison will be true if and only if there is a node in
6366 * the node-set such that the result of performing the comparison on the
6367 * string-value of the node and the other string is true.
6369 * Returns 0 or 1 depending on the results of the test.
6372 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6373 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6378 if ((s == NULL) || (arg == NULL) ||
6379 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6380 xmlXPathReleaseObject(ctxt->context, arg);
6381 xmlXPathReleaseObject(ctxt->context, s);
6384 ns = arg->nodesetval;
6386 for (i = 0;i < ns->nodeNr;i++) {
6387 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6390 xmlXPathCacheNewString(ctxt->context, str2));
6392 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6393 ret = xmlXPathCompareValues(ctxt, inf, strict);
6399 xmlXPathReleaseObject(ctxt->context, arg);
6400 xmlXPathReleaseObject(ctxt->context, s);
6405 * xmlXPathCompareNodeSets:
6406 * @inf: less than (1) or greater than (0)
6407 * @strict: is the comparison strict
6408 * @arg1: the first node set object
6409 * @arg2: the second node set object
6411 * Implement the compare operation on nodesets:
6413 * If both objects to be compared are node-sets, then the comparison
6414 * will be true if and only if there is a node in the first node-set
6415 * and a node in the second node-set such that the result of performing
6416 * the comparison on the string-values of the two nodes is true.
6418 * When neither object to be compared is a node-set and the operator
6419 * is <=, <, >= or >, then the objects are compared by converting both
6420 * objects to numbers and comparing the numbers according to IEEE 754.
6422 * The number function converts its argument to a number as follows:
6423 * - a string that consists of optional whitespace followed by an
6424 * optional minus sign followed by a Number followed by whitespace
6425 * is converted to the IEEE 754 number that is nearest (according
6426 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6427 * represented by the string; any other string is converted to NaN
6429 * Conclusion all nodes need to be converted first to their string value
6430 * and then the comparison must be done when possible
6433 xmlXPathCompareNodeSets(int inf, int strict,
6434 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6442 if ((arg1 == NULL) ||
6443 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6444 xmlXPathFreeObject(arg2);
6447 if ((arg2 == NULL) ||
6448 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6449 xmlXPathFreeObject(arg1);
6450 xmlXPathFreeObject(arg2);
6454 ns1 = arg1->nodesetval;
6455 ns2 = arg2->nodesetval;
6457 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6458 xmlXPathFreeObject(arg1);
6459 xmlXPathFreeObject(arg2);
6462 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6463 xmlXPathFreeObject(arg1);
6464 xmlXPathFreeObject(arg2);
6468 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6469 if (values2 == NULL) {
6470 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6471 xmlXPathFreeObject(arg1);
6472 xmlXPathFreeObject(arg2);
6475 for (i = 0;i < ns1->nodeNr;i++) {
6476 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6477 if (xmlXPathIsNaN(val1))
6479 for (j = 0;j < ns2->nodeNr;j++) {
6481 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6483 if (xmlXPathIsNaN(values2[j]))
6486 ret = (val1 < values2[j]);
6487 else if (inf && !strict)
6488 ret = (val1 <= values2[j]);
6489 else if (!inf && strict)
6490 ret = (val1 > values2[j]);
6491 else if (!inf && !strict)
6492 ret = (val1 >= values2[j]);
6501 xmlXPathFreeObject(arg1);
6502 xmlXPathFreeObject(arg2);
6507 * xmlXPathCompareNodeSetValue:
6508 * @ctxt: the XPath Parser context
6509 * @inf: less than (1) or greater than (0)
6510 * @strict: is the comparison strict
6511 * @arg: the node set
6514 * Implement the compare operation between a nodeset and a value
6515 * @ns < @val (1, 1, ...
6516 * @ns <= @val (1, 0, ...
6517 * @ns > @val (0, 1, ...
6518 * @ns >= @val (0, 0, ...
6520 * If one object to be compared is a node-set and the other is a boolean,
6521 * then the comparison will be true if and only if the result of performing
6522 * the comparison on the boolean and on the result of converting
6523 * the node-set to a boolean using the boolean function is true.
6525 * Returns 0 or 1 depending on the results of the test.
6528 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6529 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6530 if ((val == NULL) || (arg == NULL) ||
6531 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6536 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6538 case XPATH_XSLT_TREE:
6539 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6541 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6543 valuePush(ctxt, arg);
6544 xmlXPathBooleanFunction(ctxt, 1);
6545 valuePush(ctxt, val);
6546 return(xmlXPathCompareValues(ctxt, inf, strict));
6554 * xmlXPathEqualNodeSetString:
6555 * @arg: the nodeset object argument
6556 * @str: the string to compare to.
6557 * @neq: flag to show whether for '=' (0) or '!=' (1)
6559 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6560 * If one object to be compared is a node-set and the other is a string,
6561 * then the comparison will be true if and only if there is a node in
6562 * the node-set such that the result of performing the comparison on the
6563 * string-value of the node and the other string is true.
6565 * Returns 0 or 1 depending on the results of the test.
6568 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6575 if ((str == NULL) || (arg == NULL) ||
6576 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6578 ns = arg->nodesetval;
6580 * A NULL nodeset compared with a string is always false
6581 * (since there is no node equal, and no node not equal)
6583 if ((ns == NULL) || (ns->nodeNr <= 0) )
6585 hash = xmlXPathStringHash(str);
6586 for (i = 0; i < ns->nodeNr; i++) {
6587 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6588 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6589 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6594 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6612 * xmlXPathEqualNodeSetFloat:
6613 * @arg: the nodeset object argument
6614 * @f: the float to compare to
6615 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6617 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6618 * If one object to be compared is a node-set and the other is a number,
6619 * then the comparison will be true if and only if there is a node in
6620 * the node-set such that the result of performing the comparison on the
6621 * number to be compared and on the result of converting the string-value
6622 * of that node to a number using the number function is true.
6624 * Returns 0 or 1 depending on the results of the test.
6627 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6628 xmlXPathObjectPtr arg, double f, int neq) {
6632 xmlXPathObjectPtr val;
6635 if ((arg == NULL) ||
6636 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6639 ns = arg->nodesetval;
6641 for (i=0;i<ns->nodeNr;i++) {
6642 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6644 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6646 xmlXPathNumberFunction(ctxt, 1);
6647 val = valuePop(ctxt);
6649 xmlXPathReleaseObject(ctxt->context, val);
6650 if (!xmlXPathIsNaN(v)) {
6651 if ((!neq) && (v==f)) {
6654 } else if ((neq) && (v!=f)) {
6658 } else { /* NaN is unequal to any value */
6671 * xmlXPathEqualNodeSets:
6672 * @arg1: first nodeset object argument
6673 * @arg2: second nodeset object argument
6674 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6676 * Implement the equal / not equal operation on XPath nodesets:
6677 * @arg1 == @arg2 or @arg1 != @arg2
6678 * If both objects to be compared are node-sets, then the comparison
6679 * will be true if and only if there is a node in the first node-set and
6680 * a node in the second node-set such that the result of performing the
6681 * comparison on the string-values of the two nodes is true.
6683 * (needless to say, this is a costly operation)
6685 * Returns 0 or 1 depending on the results of the test.
6688 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6690 unsigned int *hashs1;
6691 unsigned int *hashs2;
6698 if ((arg1 == NULL) ||
6699 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6701 if ((arg2 == NULL) ||
6702 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6705 ns1 = arg1->nodesetval;
6706 ns2 = arg2->nodesetval;
6708 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6710 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6714 * for equal, check if there is a node pertaining to both sets
6717 for (i = 0;i < ns1->nodeNr;i++)
6718 for (j = 0;j < ns2->nodeNr;j++)
6719 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6722 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6723 if (values1 == NULL) {
6724 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6727 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6728 if (hashs1 == NULL) {
6729 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6733 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6734 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6735 if (values2 == NULL) {
6736 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6741 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6742 if (hashs2 == NULL) {
6743 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6749 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6750 for (i = 0;i < ns1->nodeNr;i++) {
6751 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6752 for (j = 0;j < ns2->nodeNr;j++) {
6754 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6755 if (hashs1[i] != hashs2[j]) {
6762 if (values1[i] == NULL)
6763 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6764 if (values2[j] == NULL)
6765 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6766 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6774 for (i = 0;i < ns1->nodeNr;i++)
6775 if (values1[i] != NULL)
6776 xmlFree(values1[i]);
6777 for (j = 0;j < ns2->nodeNr;j++)
6778 if (values2[j] != NULL)
6779 xmlFree(values2[j]);
6788 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6789 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6792 *At this point we are assured neither arg1 nor arg2
6793 *is a nodeset, so we can just pick the appropriate routine.
6795 switch (arg1->type) {
6796 case XPATH_UNDEFINED:
6798 xmlGenericError(xmlGenericErrorContext,
6799 "Equal: undefined\n");
6803 switch (arg2->type) {
6804 case XPATH_UNDEFINED:
6806 xmlGenericError(xmlGenericErrorContext,
6807 "Equal: undefined\n");
6812 xmlGenericError(xmlGenericErrorContext,
6813 "Equal: %d boolean %d \n",
6814 arg1->boolval, arg2->boolval);
6816 ret = (arg1->boolval == arg2->boolval);
6819 ret = (arg1->boolval ==
6820 xmlXPathCastNumberToBoolean(arg2->floatval));
6823 if ((arg2->stringval == NULL) ||
6824 (arg2->stringval[0] == 0)) ret = 0;
6827 ret = (arg1->boolval == ret);
6832 case XPATH_LOCATIONSET:
6836 case XPATH_XSLT_TREE:
6841 switch (arg2->type) {
6842 case XPATH_UNDEFINED:
6844 xmlGenericError(xmlGenericErrorContext,
6845 "Equal: undefined\n");
6849 ret = (arg2->boolval==
6850 xmlXPathCastNumberToBoolean(arg1->floatval));
6853 valuePush(ctxt, arg2);
6854 xmlXPathNumberFunction(ctxt, 1);
6855 arg2 = valuePop(ctxt);
6856 /* no break on purpose */
6858 /* Hand check NaN and Infinity equalities */
6859 if (xmlXPathIsNaN(arg1->floatval) ||
6860 xmlXPathIsNaN(arg2->floatval)) {
6862 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6863 if (xmlXPathIsInf(arg2->floatval) == 1)
6867 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6868 if (xmlXPathIsInf(arg2->floatval) == -1)
6872 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6873 if (xmlXPathIsInf(arg1->floatval) == 1)
6877 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6878 if (xmlXPathIsInf(arg1->floatval) == -1)
6883 ret = (arg1->floatval == arg2->floatval);
6889 case XPATH_LOCATIONSET:
6893 case XPATH_XSLT_TREE:
6898 switch (arg2->type) {
6899 case XPATH_UNDEFINED:
6901 xmlGenericError(xmlGenericErrorContext,
6902 "Equal: undefined\n");
6906 if ((arg1->stringval == NULL) ||
6907 (arg1->stringval[0] == 0)) ret = 0;
6910 ret = (arg2->boolval == ret);
6913 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6916 valuePush(ctxt, arg1);
6917 xmlXPathNumberFunction(ctxt, 1);
6918 arg1 = valuePop(ctxt);
6919 /* Hand check NaN and Infinity equalities */
6920 if (xmlXPathIsNaN(arg1->floatval) ||
6921 xmlXPathIsNaN(arg2->floatval)) {
6923 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6924 if (xmlXPathIsInf(arg2->floatval) == 1)
6928 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6929 if (xmlXPathIsInf(arg2->floatval) == -1)
6933 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6934 if (xmlXPathIsInf(arg1->floatval) == 1)
6938 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6939 if (xmlXPathIsInf(arg1->floatval) == -1)
6944 ret = (arg1->floatval == arg2->floatval);
6950 case XPATH_LOCATIONSET:
6954 case XPATH_XSLT_TREE:
6961 case XPATH_LOCATIONSET:
6965 case XPATH_XSLT_TREE:
6968 xmlXPathReleaseObject(ctxt->context, arg1);
6969 xmlXPathReleaseObject(ctxt->context, arg2);
6974 * xmlXPathEqualValues:
6975 * @ctxt: the XPath Parser context
6977 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6979 * Returns 0 or 1 depending on the results of the test.
6982 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6983 xmlXPathObjectPtr arg1, arg2, argtmp;
6986 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6987 arg2 = valuePop(ctxt);
6988 arg1 = valuePop(ctxt);
6989 if ((arg1 == NULL) || (arg2 == NULL)) {
6991 xmlXPathReleaseObject(ctxt->context, arg1);
6993 xmlXPathReleaseObject(ctxt->context, arg2);
6994 XP_ERROR0(XPATH_INVALID_OPERAND);
6999 xmlGenericError(xmlGenericErrorContext,
7000 "Equal: by pointer\n");
7002 xmlXPathFreeObject(arg1);
7007 *If either argument is a nodeset, it's a 'special case'
7009 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7010 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7012 *Hack it to assure arg1 is the nodeset
7014 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7019 switch (arg2->type) {
7020 case XPATH_UNDEFINED:
7022 xmlGenericError(xmlGenericErrorContext,
7023 "Equal: undefined\n");
7027 case XPATH_XSLT_TREE:
7028 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7031 if ((arg1->nodesetval == NULL) ||
7032 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7035 ret = (ret == arg2->boolval);
7038 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7041 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7046 case XPATH_LOCATIONSET:
7050 xmlXPathReleaseObject(ctxt->context, arg1);
7051 xmlXPathReleaseObject(ctxt->context, arg2);
7055 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7059 * xmlXPathNotEqualValues:
7060 * @ctxt: the XPath Parser context
7062 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7064 * Returns 0 or 1 depending on the results of the test.
7067 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7068 xmlXPathObjectPtr arg1, arg2, argtmp;
7071 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7072 arg2 = valuePop(ctxt);
7073 arg1 = valuePop(ctxt);
7074 if ((arg1 == NULL) || (arg2 == NULL)) {
7076 xmlXPathReleaseObject(ctxt->context, arg1);
7078 xmlXPathReleaseObject(ctxt->context, arg2);
7079 XP_ERROR0(XPATH_INVALID_OPERAND);
7084 xmlGenericError(xmlGenericErrorContext,
7085 "NotEqual: by pointer\n");
7087 xmlXPathReleaseObject(ctxt->context, arg1);
7092 *If either argument is a nodeset, it's a 'special case'
7094 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7095 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7097 *Hack it to assure arg1 is the nodeset
7099 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7104 switch (arg2->type) {
7105 case XPATH_UNDEFINED:
7107 xmlGenericError(xmlGenericErrorContext,
7108 "NotEqual: undefined\n");
7112 case XPATH_XSLT_TREE:
7113 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7116 if ((arg1->nodesetval == NULL) ||
7117 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7120 ret = (ret != arg2->boolval);
7123 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7126 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7131 case XPATH_LOCATIONSET:
7135 xmlXPathReleaseObject(ctxt->context, arg1);
7136 xmlXPathReleaseObject(ctxt->context, arg2);
7140 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7144 * xmlXPathCompareValues:
7145 * @ctxt: the XPath Parser context
7146 * @inf: less than (1) or greater than (0)
7147 * @strict: is the comparison strict
7149 * Implement the compare operation on XPath objects:
7150 * @arg1 < @arg2 (1, 1, ...
7151 * @arg1 <= @arg2 (1, 0, ...
7152 * @arg1 > @arg2 (0, 1, ...
7153 * @arg1 >= @arg2 (0, 0, ...
7155 * When neither object to be compared is a node-set and the operator is
7156 * <=, <, >=, >, then the objects are compared by converted both objects
7157 * to numbers and comparing the numbers according to IEEE 754. The <
7158 * comparison will be true if and only if the first number is less than the
7159 * second number. The <= comparison will be true if and only if the first
7160 * number is less than or equal to the second number. The > comparison
7161 * will be true if and only if the first number is greater than the second
7162 * number. The >= comparison will be true if and only if the first number
7163 * is greater than or equal to the second number.
7165 * Returns 1 if the comparison succeeded, 0 if it failed
7168 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7169 int ret = 0, arg1i = 0, arg2i = 0;
7170 xmlXPathObjectPtr arg1, arg2;
7172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7173 arg2 = valuePop(ctxt);
7174 arg1 = valuePop(ctxt);
7175 if ((arg1 == NULL) || (arg2 == NULL)) {
7177 xmlXPathReleaseObject(ctxt->context, arg1);
7179 xmlXPathReleaseObject(ctxt->context, arg2);
7180 XP_ERROR0(XPATH_INVALID_OPERAND);
7183 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7184 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7186 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7187 * are not freed from within this routine; they will be freed from the
7188 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7190 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7191 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7192 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7194 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7195 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7198 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7205 if (arg1->type != XPATH_NUMBER) {
7206 valuePush(ctxt, arg1);
7207 xmlXPathNumberFunction(ctxt, 1);
7208 arg1 = valuePop(ctxt);
7210 if (arg1->type != XPATH_NUMBER) {
7211 xmlXPathFreeObject(arg1);
7212 xmlXPathFreeObject(arg2);
7213 XP_ERROR0(XPATH_INVALID_OPERAND);
7215 if (arg2->type != XPATH_NUMBER) {
7216 valuePush(ctxt, arg2);
7217 xmlXPathNumberFunction(ctxt, 1);
7218 arg2 = valuePop(ctxt);
7220 if (arg2->type != XPATH_NUMBER) {
7221 xmlXPathReleaseObject(ctxt->context, arg1);
7222 xmlXPathReleaseObject(ctxt->context, arg2);
7223 XP_ERROR0(XPATH_INVALID_OPERAND);
7226 * Add tests for infinity and nan
7227 * => feedback on 3.4 for Inf and NaN
7229 /* Hand check NaN and Infinity comparisons */
7230 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7233 arg1i=xmlXPathIsInf(arg1->floatval);
7234 arg2i=xmlXPathIsInf(arg2->floatval);
7235 if (inf && strict) {
7236 if ((arg1i == -1 && arg2i != -1) ||
7237 (arg2i == 1 && arg1i != 1)) {
7239 } else if (arg1i == 0 && arg2i == 0) {
7240 ret = (arg1->floatval < arg2->floatval);
7245 else if (inf && !strict) {
7246 if (arg1i == -1 || arg2i == 1) {
7248 } else if (arg1i == 0 && arg2i == 0) {
7249 ret = (arg1->floatval <= arg2->floatval);
7254 else if (!inf && strict) {
7255 if ((arg1i == 1 && arg2i != 1) ||
7256 (arg2i == -1 && arg1i != -1)) {
7258 } else if (arg1i == 0 && arg2i == 0) {
7259 ret = (arg1->floatval > arg2->floatval);
7264 else if (!inf && !strict) {
7265 if (arg1i == 1 || arg2i == -1) {
7267 } else if (arg1i == 0 && arg2i == 0) {
7268 ret = (arg1->floatval >= arg2->floatval);
7274 xmlXPathReleaseObject(ctxt->context, arg1);
7275 xmlXPathReleaseObject(ctxt->context, arg2);
7280 * xmlXPathValueFlipSign:
7281 * @ctxt: the XPath Parser context
7283 * Implement the unary - operation on an XPath object
7284 * The numeric operators convert their operands to numbers as if
7285 * by calling the number function.
7288 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7289 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7291 CHECK_TYPE(XPATH_NUMBER);
7292 if (xmlXPathIsNaN(ctxt->value->floatval))
7293 ctxt->value->floatval=xmlXPathNAN;
7294 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7295 ctxt->value->floatval=xmlXPathNINF;
7296 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7297 ctxt->value->floatval=xmlXPathPINF;
7298 else if (ctxt->value->floatval == 0) {
7299 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7300 ctxt->value->floatval = xmlXPathNZERO;
7302 ctxt->value->floatval = 0;
7305 ctxt->value->floatval = - ctxt->value->floatval;
7309 * xmlXPathAddValues:
7310 * @ctxt: the XPath Parser context
7312 * Implement the add operation on XPath objects:
7313 * The numeric operators convert their operands to numbers as if
7314 * by calling the number function.
7317 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7318 xmlXPathObjectPtr arg;
7321 arg = valuePop(ctxt);
7323 XP_ERROR(XPATH_INVALID_OPERAND);
7324 val = xmlXPathCastToNumber(arg);
7325 xmlXPathReleaseObject(ctxt->context, arg);
7327 CHECK_TYPE(XPATH_NUMBER);
7328 ctxt->value->floatval += val;
7332 * xmlXPathSubValues:
7333 * @ctxt: the XPath Parser context
7335 * Implement the subtraction operation on XPath objects:
7336 * The numeric operators convert their operands to numbers as if
7337 * by calling the number function.
7340 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7341 xmlXPathObjectPtr arg;
7344 arg = valuePop(ctxt);
7346 XP_ERROR(XPATH_INVALID_OPERAND);
7347 val = xmlXPathCastToNumber(arg);
7348 xmlXPathReleaseObject(ctxt->context, arg);
7350 CHECK_TYPE(XPATH_NUMBER);
7351 ctxt->value->floatval -= val;
7355 * xmlXPathMultValues:
7356 * @ctxt: the XPath Parser context
7358 * Implement the multiply operation on XPath objects:
7359 * The numeric operators convert their operands to numbers as if
7360 * by calling the number function.
7363 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7364 xmlXPathObjectPtr arg;
7367 arg = valuePop(ctxt);
7369 XP_ERROR(XPATH_INVALID_OPERAND);
7370 val = xmlXPathCastToNumber(arg);
7371 xmlXPathReleaseObject(ctxt->context, arg);
7373 CHECK_TYPE(XPATH_NUMBER);
7374 ctxt->value->floatval *= val;
7378 * xmlXPathDivValues:
7379 * @ctxt: the XPath Parser context
7381 * Implement the div operation on XPath objects @arg1 / @arg2:
7382 * The numeric operators convert their operands to numbers as if
7383 * by calling the number function.
7386 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7387 xmlXPathObjectPtr arg;
7390 arg = valuePop(ctxt);
7392 XP_ERROR(XPATH_INVALID_OPERAND);
7393 val = xmlXPathCastToNumber(arg);
7394 xmlXPathReleaseObject(ctxt->context, arg);
7396 CHECK_TYPE(XPATH_NUMBER);
7397 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7398 ctxt->value->floatval = xmlXPathNAN;
7399 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7400 if (ctxt->value->floatval == 0)
7401 ctxt->value->floatval = xmlXPathNAN;
7402 else if (ctxt->value->floatval > 0)
7403 ctxt->value->floatval = xmlXPathNINF;
7404 else if (ctxt->value->floatval < 0)
7405 ctxt->value->floatval = xmlXPathPINF;
7407 else if (val == 0) {
7408 if (ctxt->value->floatval == 0)
7409 ctxt->value->floatval = xmlXPathNAN;
7410 else if (ctxt->value->floatval > 0)
7411 ctxt->value->floatval = xmlXPathPINF;
7412 else if (ctxt->value->floatval < 0)
7413 ctxt->value->floatval = xmlXPathNINF;
7415 ctxt->value->floatval /= val;
7419 * xmlXPathModValues:
7420 * @ctxt: the XPath Parser context
7422 * Implement the mod operation on XPath objects: @arg1 / @arg2
7423 * The numeric operators convert their operands to numbers as if
7424 * by calling the number function.
7427 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7428 xmlXPathObjectPtr arg;
7431 arg = valuePop(ctxt);
7433 XP_ERROR(XPATH_INVALID_OPERAND);
7434 arg2 = xmlXPathCastToNumber(arg);
7435 xmlXPathReleaseObject(ctxt->context, arg);
7437 CHECK_TYPE(XPATH_NUMBER);
7438 arg1 = ctxt->value->floatval;
7440 ctxt->value->floatval = xmlXPathNAN;
7442 ctxt->value->floatval = fmod(arg1, arg2);
7446 /************************************************************************
7448 * The traversal functions *
7450 ************************************************************************/
7453 * A traversal function enumerates nodes along an axis.
7454 * Initially it must be called with NULL, and it indicates
7455 * termination on the axis by returning NULL.
7457 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7458 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7461 * xmlXPathTraversalFunctionExt:
7462 * A traversal function enumerates nodes along an axis.
7463 * Initially it must be called with NULL, and it indicates
7464 * termination on the axis by returning NULL.
7465 * The context node of the traversal is specified via @contextNode.
7467 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7468 (xmlNodePtr cur, xmlNodePtr contextNode);
7471 * xmlXPathNodeSetMergeFunction:
7472 * Used for merging node sets in xmlXPathCollectAndTest().
7474 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7475 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7480 * @ctxt: the XPath Parser context
7481 * @cur: the current node in the traversal
7483 * Traversal function for the "self" direction
7484 * The self axis contains just the context node itself
7486 * Returns the next element following that axis
7489 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7490 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7492 return(ctxt->context->node);
7497 * xmlXPathNextChild:
7498 * @ctxt: the XPath Parser context
7499 * @cur: the current node in the traversal
7501 * Traversal function for the "child" direction
7502 * The child axis contains the children of the context node in document order.
7504 * Returns the next element following that axis
7507 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7508 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7510 if (ctxt->context->node == NULL) return(NULL);
7511 switch (ctxt->context->node->type) {
7512 case XML_ELEMENT_NODE:
7514 case XML_CDATA_SECTION_NODE:
7515 case XML_ENTITY_REF_NODE:
7516 case XML_ENTITY_NODE:
7518 case XML_COMMENT_NODE:
7519 case XML_NOTATION_NODE:
7521 return(ctxt->context->node->children);
7522 case XML_DOCUMENT_NODE:
7523 case XML_DOCUMENT_TYPE_NODE:
7524 case XML_DOCUMENT_FRAG_NODE:
7525 case XML_HTML_DOCUMENT_NODE:
7526 #ifdef LIBXML_DOCB_ENABLED
7527 case XML_DOCB_DOCUMENT_NODE:
7529 return(((xmlDocPtr) ctxt->context->node)->children);
7530 case XML_ELEMENT_DECL:
7531 case XML_ATTRIBUTE_DECL:
7532 case XML_ENTITY_DECL:
7533 case XML_ATTRIBUTE_NODE:
7534 case XML_NAMESPACE_DECL:
7535 case XML_XINCLUDE_START:
7536 case XML_XINCLUDE_END:
7541 if ((cur->type == XML_DOCUMENT_NODE) ||
7542 (cur->type == XML_HTML_DOCUMENT_NODE))
7548 * xmlXPathNextChildElement:
7549 * @ctxt: the XPath Parser context
7550 * @cur: the current node in the traversal
7552 * Traversal function for the "child" direction and nodes of type element.
7553 * The child axis contains the children of the context node in document order.
7555 * Returns the next element following that axis
7558 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7559 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7561 cur = ctxt->context->node;
7562 if (cur == NULL) return(NULL);
7564 * Get the first element child.
7566 switch (cur->type) {
7567 case XML_ELEMENT_NODE:
7568 case XML_DOCUMENT_FRAG_NODE:
7569 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7570 case XML_ENTITY_NODE:
7571 cur = cur->children;
7573 if (cur->type == XML_ELEMENT_NODE)
7577 } while ((cur != NULL) &&
7578 (cur->type != XML_ELEMENT_NODE));
7582 case XML_DOCUMENT_NODE:
7583 case XML_HTML_DOCUMENT_NODE:
7584 #ifdef LIBXML_DOCB_ENABLED
7585 case XML_DOCB_DOCUMENT_NODE:
7587 return(xmlDocGetRootElement((xmlDocPtr) cur));
7594 * Get the next sibling element node.
7596 switch (cur->type) {
7597 case XML_ELEMENT_NODE:
7599 case XML_ENTITY_REF_NODE:
7600 case XML_ENTITY_NODE:
7601 case XML_CDATA_SECTION_NODE:
7603 case XML_COMMENT_NODE:
7604 case XML_XINCLUDE_END:
7606 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7610 if (cur->next != NULL) {
7611 if (cur->next->type == XML_ELEMENT_NODE)
7616 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7623 * xmlXPathNextDescendantOrSelfElemParent:
7624 * @ctxt: the XPath Parser context
7625 * @cur: the current node in the traversal
7627 * Traversal function for the "descendant-or-self" axis.
7628 * Additionally it returns only nodes which can be parents of
7632 * Returns the next element following that axis
7635 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7636 xmlNodePtr contextNode)
7639 if (contextNode == NULL)
7641 switch (contextNode->type) {
7642 case XML_ELEMENT_NODE:
7643 case XML_XINCLUDE_START:
7644 case XML_DOCUMENT_FRAG_NODE:
7645 case XML_DOCUMENT_NODE:
7646 #ifdef LIBXML_DOCB_ENABLED
7647 case XML_DOCB_DOCUMENT_NODE:
7649 case XML_HTML_DOCUMENT_NODE:
7650 return(contextNode);
7656 xmlNodePtr start = cur;
7658 while (cur != NULL) {
7659 switch (cur->type) {
7660 case XML_ELEMENT_NODE:
7661 /* TODO: OK to have XInclude here? */
7662 case XML_XINCLUDE_START:
7663 case XML_DOCUMENT_FRAG_NODE:
7666 if (cur->children != NULL) {
7667 cur = cur->children;
7671 #ifdef LIBXML_DOCB_ENABLED
7672 /* Not sure if we need those here. */
7673 case XML_DOCUMENT_NODE:
7674 case XML_DOCB_DOCUMENT_NODE:
7676 case XML_HTML_DOCUMENT_NODE:
7679 return(xmlDocGetRootElement((xmlDocPtr) cur));
7685 if ((cur == NULL) || (cur == contextNode))
7687 if (cur->next != NULL) {
7699 * xmlXPathNextDescendant:
7700 * @ctxt: the XPath Parser context
7701 * @cur: the current node in the traversal
7703 * Traversal function for the "descendant" direction
7704 * the descendant axis contains the descendants of the context node in document
7705 * order; a descendant is a child or a child of a child and so on.
7707 * Returns the next element following that axis
7710 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7711 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7713 if (ctxt->context->node == NULL)
7715 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7716 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7719 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7720 return(ctxt->context->doc->children);
7721 return(ctxt->context->node->children);
7724 if (cur->children != NULL) {
7726 * Do not descend on entities declarations
7728 if (cur->children->type != XML_ENTITY_DECL) {
7729 cur = cur->children;
7733 if (cur->type != XML_DTD_NODE)
7738 if (cur == ctxt->context->node) return(NULL);
7740 while (cur->next != NULL) {
7742 if ((cur->type != XML_ENTITY_DECL) &&
7743 (cur->type != XML_DTD_NODE))
7749 if (cur == NULL) break;
7750 if (cur == ctxt->context->node) return(NULL);
7751 if (cur->next != NULL) {
7755 } while (cur != NULL);
7760 * xmlXPathNextDescendantOrSelf:
7761 * @ctxt: the XPath Parser context
7762 * @cur: the current node in the traversal
7764 * Traversal function for the "descendant-or-self" direction
7765 * the descendant-or-self axis contains the context node and the descendants
7766 * of the context node in document order; thus the context node is the first
7767 * node on the axis, and the first child of the context node is the second node
7770 * Returns the next element following that axis
7773 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7774 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7776 if (ctxt->context->node == NULL)
7778 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7779 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7781 return(ctxt->context->node);
7784 return(xmlXPathNextDescendant(ctxt, cur));
7788 * xmlXPathNextParent:
7789 * @ctxt: the XPath Parser context
7790 * @cur: the current node in the traversal
7792 * Traversal function for the "parent" direction
7793 * The parent axis contains the parent of the context node, if there is one.
7795 * Returns the next element following that axis
7798 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7799 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7801 * the parent of an attribute or namespace node is the element
7802 * to which the attribute or namespace node is attached
7803 * Namespace handling !!!
7806 if (ctxt->context->node == NULL) return(NULL);
7807 switch (ctxt->context->node->type) {
7808 case XML_ELEMENT_NODE:
7810 case XML_CDATA_SECTION_NODE:
7811 case XML_ENTITY_REF_NODE:
7812 case XML_ENTITY_NODE:
7814 case XML_COMMENT_NODE:
7815 case XML_NOTATION_NODE:
7817 case XML_ELEMENT_DECL:
7818 case XML_ATTRIBUTE_DECL:
7819 case XML_XINCLUDE_START:
7820 case XML_XINCLUDE_END:
7821 case XML_ENTITY_DECL:
7822 if (ctxt->context->node->parent == NULL)
7823 return((xmlNodePtr) ctxt->context->doc);
7824 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7825 ((ctxt->context->node->parent->name[0] == ' ') ||
7826 (xmlStrEqual(ctxt->context->node->parent->name,
7827 BAD_CAST "fake node libxslt"))))
7829 return(ctxt->context->node->parent);
7830 case XML_ATTRIBUTE_NODE: {
7831 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7833 return(att->parent);
7835 case XML_DOCUMENT_NODE:
7836 case XML_DOCUMENT_TYPE_NODE:
7837 case XML_DOCUMENT_FRAG_NODE:
7838 case XML_HTML_DOCUMENT_NODE:
7839 #ifdef LIBXML_DOCB_ENABLED
7840 case XML_DOCB_DOCUMENT_NODE:
7843 case XML_NAMESPACE_DECL: {
7844 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7846 if ((ns->next != NULL) &&
7847 (ns->next->type != XML_NAMESPACE_DECL))
7848 return((xmlNodePtr) ns->next);
7857 * xmlXPathNextAncestor:
7858 * @ctxt: the XPath Parser context
7859 * @cur: the current node in the traversal
7861 * Traversal function for the "ancestor" direction
7862 * the ancestor axis contains the ancestors of the context node; the ancestors
7863 * of the context node consist of the parent of context node and the parent's
7864 * parent and so on; the nodes are ordered in reverse document order; thus the
7865 * parent is the first node on the axis, and the parent's parent is the second
7868 * Returns the next element following that axis
7871 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7872 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7874 * the parent of an attribute or namespace node is the element
7875 * to which the attribute or namespace node is attached
7879 if (ctxt->context->node == NULL) return(NULL);
7880 switch (ctxt->context->node->type) {
7881 case XML_ELEMENT_NODE:
7883 case XML_CDATA_SECTION_NODE:
7884 case XML_ENTITY_REF_NODE:
7885 case XML_ENTITY_NODE:
7887 case XML_COMMENT_NODE:
7889 case XML_ELEMENT_DECL:
7890 case XML_ATTRIBUTE_DECL:
7891 case XML_ENTITY_DECL:
7892 case XML_NOTATION_NODE:
7893 case XML_XINCLUDE_START:
7894 case XML_XINCLUDE_END:
7895 if (ctxt->context->node->parent == NULL)
7896 return((xmlNodePtr) ctxt->context->doc);
7897 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7898 ((ctxt->context->node->parent->name[0] == ' ') ||
7899 (xmlStrEqual(ctxt->context->node->parent->name,
7900 BAD_CAST "fake node libxslt"))))
7902 return(ctxt->context->node->parent);
7903 case XML_ATTRIBUTE_NODE: {
7904 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7906 return(tmp->parent);
7908 case XML_DOCUMENT_NODE:
7909 case XML_DOCUMENT_TYPE_NODE:
7910 case XML_DOCUMENT_FRAG_NODE:
7911 case XML_HTML_DOCUMENT_NODE:
7912 #ifdef LIBXML_DOCB_ENABLED
7913 case XML_DOCB_DOCUMENT_NODE:
7916 case XML_NAMESPACE_DECL: {
7917 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7919 if ((ns->next != NULL) &&
7920 (ns->next->type != XML_NAMESPACE_DECL))
7921 return((xmlNodePtr) ns->next);
7922 /* Bad, how did that namespace end up here ? */
7928 if (cur == ctxt->context->doc->children)
7929 return((xmlNodePtr) ctxt->context->doc);
7930 if (cur == (xmlNodePtr) ctxt->context->doc)
7932 switch (cur->type) {
7933 case XML_ELEMENT_NODE:
7935 case XML_CDATA_SECTION_NODE:
7936 case XML_ENTITY_REF_NODE:
7937 case XML_ENTITY_NODE:
7939 case XML_COMMENT_NODE:
7940 case XML_NOTATION_NODE:
7942 case XML_ELEMENT_DECL:
7943 case XML_ATTRIBUTE_DECL:
7944 case XML_ENTITY_DECL:
7945 case XML_XINCLUDE_START:
7946 case XML_XINCLUDE_END:
7947 if (cur->parent == NULL)
7949 if ((cur->parent->type == XML_ELEMENT_NODE) &&
7950 ((cur->parent->name[0] == ' ') ||
7951 (xmlStrEqual(cur->parent->name,
7952 BAD_CAST "fake node libxslt"))))
7954 return(cur->parent);
7955 case XML_ATTRIBUTE_NODE: {
7956 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7958 return(att->parent);
7960 case XML_NAMESPACE_DECL: {
7961 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7963 if ((ns->next != NULL) &&
7964 (ns->next->type != XML_NAMESPACE_DECL))
7965 return((xmlNodePtr) ns->next);
7966 /* Bad, how did that namespace end up here ? */
7969 case XML_DOCUMENT_NODE:
7970 case XML_DOCUMENT_TYPE_NODE:
7971 case XML_DOCUMENT_FRAG_NODE:
7972 case XML_HTML_DOCUMENT_NODE:
7973 #ifdef LIBXML_DOCB_ENABLED
7974 case XML_DOCB_DOCUMENT_NODE:
7982 * xmlXPathNextAncestorOrSelf:
7983 * @ctxt: the XPath Parser context
7984 * @cur: the current node in the traversal
7986 * Traversal function for the "ancestor-or-self" direction
7987 * he ancestor-or-self axis contains the context node and ancestors of
7988 * the context node in reverse document order; thus the context node is
7989 * the first node on the axis, and the context node's parent the second;
7990 * parent here is defined the same as with the parent axis.
7992 * Returns the next element following that axis
7995 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7996 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7998 return(ctxt->context->node);
7999 return(xmlXPathNextAncestor(ctxt, cur));
8003 * xmlXPathNextFollowingSibling:
8004 * @ctxt: the XPath Parser context
8005 * @cur: the current node in the traversal
8007 * Traversal function for the "following-sibling" direction
8008 * The following-sibling axis contains the following siblings of the context
8009 * node in document order.
8011 * Returns the next element following that axis
8014 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8015 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8016 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8017 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8019 if (cur == (xmlNodePtr) ctxt->context->doc)
8022 return(ctxt->context->node->next);
8027 * xmlXPathNextPrecedingSibling:
8028 * @ctxt: the XPath Parser context
8029 * @cur: the current node in the traversal
8031 * Traversal function for the "preceding-sibling" direction
8032 * The preceding-sibling axis contains the preceding siblings of the context
8033 * node in reverse document order; the first preceding sibling is first on the
8034 * axis; the sibling preceding that node is the second on the axis and so on.
8036 * Returns the next element following that axis
8039 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8040 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8041 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8042 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8044 if (cur == (xmlNodePtr) ctxt->context->doc)
8047 return(ctxt->context->node->prev);
8048 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8051 return(ctxt->context->node->prev);
8057 * xmlXPathNextFollowing:
8058 * @ctxt: the XPath Parser context
8059 * @cur: the current node in the traversal
8061 * Traversal function for the "following" direction
8062 * The following axis contains all nodes in the same document as the context
8063 * node that are after the context node in document order, excluding any
8064 * descendants and excluding attribute nodes and namespace nodes; the nodes
8065 * are ordered in document order
8067 * Returns the next element following that axis
8070 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8071 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8072 if (cur != NULL && cur->children != NULL)
8073 return cur->children ;
8074 if (cur == NULL) cur = ctxt->context->node;
8075 if (cur == NULL) return(NULL) ; /* ERROR */
8076 if (cur->next != NULL) return(cur->next) ;
8079 if (cur == NULL) break;
8080 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8081 if (cur->next != NULL) return(cur->next);
8082 } while (cur != NULL);
8087 * xmlXPathIsAncestor:
8088 * @ancestor: the ancestor node
8089 * @node: the current node
8091 * Check that @ancestor is a @node's ancestor
8093 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8096 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8097 if ((ancestor == NULL) || (node == NULL)) return(0);
8098 /* nodes need to be in the same document */
8099 if (ancestor->doc != node->doc) return(0);
8100 /* avoid searching if ancestor or node is the root node */
8101 if (ancestor == (xmlNodePtr) node->doc) return(1);
8102 if (node == (xmlNodePtr) ancestor->doc) return(0);
8103 while (node->parent != NULL) {
8104 if (node->parent == ancestor)
8106 node = node->parent;
8112 * xmlXPathNextPreceding:
8113 * @ctxt: the XPath Parser context
8114 * @cur: the current node in the traversal
8116 * Traversal function for the "preceding" direction
8117 * the preceding axis contains all nodes in the same document as the context
8118 * node that are before the context node in document order, excluding any
8119 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8120 * ordered in reverse document order
8122 * Returns the next element following that axis
8125 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8127 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8129 cur = ctxt->context->node;
8132 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8135 if (cur->prev != NULL) {
8136 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8143 if (cur == ctxt->context->doc->children)
8145 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8150 * xmlXPathNextPrecedingInternal:
8151 * @ctxt: the XPath Parser context
8152 * @cur: the current node in the traversal
8154 * Traversal function for the "preceding" direction
8155 * the preceding axis contains all nodes in the same document as the context
8156 * node that are before the context node in document order, excluding any
8157 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8158 * ordered in reverse document order
8159 * This is a faster implementation but internal only since it requires a
8160 * state kept in the parser context: ctxt->ancestor.
8162 * Returns the next element following that axis
8165 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8168 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8170 cur = ctxt->context->node;
8173 if (cur->type == XML_NAMESPACE_DECL)
8174 cur = (xmlNodePtr)((xmlNsPtr)cur)->next;
8175 ctxt->ancestor = cur->parent;
8177 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8179 while (cur->prev == NULL) {
8183 if (cur == ctxt->context->doc->children)
8185 if (cur != ctxt->ancestor)
8187 ctxt->ancestor = cur->parent;
8190 while (cur->last != NULL)
8196 * xmlXPathNextNamespace:
8197 * @ctxt: the XPath Parser context
8198 * @cur: the current attribute in the traversal
8200 * Traversal function for the "namespace" direction
8201 * the namespace axis contains the namespace nodes of the context node;
8202 * the order of nodes on this axis is implementation-defined; the axis will
8203 * be empty unless the context node is an element
8205 * We keep the XML namespace node at the end of the list.
8207 * Returns the next element following that axis
8210 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8211 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8212 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8213 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8214 if (ctxt->context->tmpNsList != NULL)
8215 xmlFree(ctxt->context->tmpNsList);
8216 ctxt->context->tmpNsList =
8217 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8218 ctxt->context->tmpNsNr = 0;
8219 if (ctxt->context->tmpNsList != NULL) {
8220 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8221 ctxt->context->tmpNsNr++;
8224 return((xmlNodePtr) xmlXPathXMLNamespace);
8226 if (ctxt->context->tmpNsNr > 0) {
8227 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8229 if (ctxt->context->tmpNsList != NULL)
8230 xmlFree(ctxt->context->tmpNsList);
8231 ctxt->context->tmpNsList = NULL;
8237 * xmlXPathNextAttribute:
8238 * @ctxt: the XPath Parser context
8239 * @cur: the current attribute in the traversal
8241 * Traversal function for the "attribute" direction
8242 * TODO: support DTD inherited default attributes
8244 * Returns the next element following that axis
8247 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8248 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8249 if (ctxt->context->node == NULL)
8251 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8254 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8256 return((xmlNodePtr)ctxt->context->node->properties);
8258 return((xmlNodePtr)cur->next);
8261 /************************************************************************
8263 * NodeTest Functions *
8265 ************************************************************************/
8267 #define IS_FUNCTION 200
8270 /************************************************************************
8272 * Implicit tree core function library *
8274 ************************************************************************/
8278 * @ctxt: the XPath Parser context
8280 * Initialize the context to the root of the document
8283 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8284 if ((ctxt == NULL) || (ctxt->context == NULL))
8286 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8287 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8288 ctxt->context->node));
8291 /************************************************************************
8293 * The explicit core function library *
8294 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8296 ************************************************************************/
8300 * xmlXPathLastFunction:
8301 * @ctxt: the XPath Parser context
8302 * @nargs: the number of arguments
8304 * Implement the last() XPath function
8306 * The last function returns the number of nodes in the context node list.
8309 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8311 if (ctxt->context->contextSize >= 0) {
8313 xmlXPathCacheNewFloat(ctxt->context,
8314 (double) ctxt->context->contextSize));
8316 xmlGenericError(xmlGenericErrorContext,
8317 "last() : %d\n", ctxt->context->contextSize);
8320 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8325 * xmlXPathPositionFunction:
8326 * @ctxt: the XPath Parser context
8327 * @nargs: the number of arguments
8329 * Implement the position() XPath function
8331 * The position function returns the position of the context node in the
8332 * context node list. The first position is 1, and so the last position
8333 * will be equal to last().
8336 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8338 if (ctxt->context->proximityPosition >= 0) {
8340 xmlXPathCacheNewFloat(ctxt->context,
8341 (double) ctxt->context->proximityPosition));
8343 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8344 ctxt->context->proximityPosition);
8347 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8352 * xmlXPathCountFunction:
8353 * @ctxt: the XPath Parser context
8354 * @nargs: the number of arguments
8356 * Implement the count() XPath function
8357 * number count(node-set)
8360 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8361 xmlXPathObjectPtr cur;
8364 if ((ctxt->value == NULL) ||
8365 ((ctxt->value->type != XPATH_NODESET) &&
8366 (ctxt->value->type != XPATH_XSLT_TREE)))
8367 XP_ERROR(XPATH_INVALID_TYPE);
8368 cur = valuePop(ctxt);
8370 if ((cur == NULL) || (cur->nodesetval == NULL))
8371 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8372 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8373 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8374 (double) cur->nodesetval->nodeNr));
8376 if ((cur->nodesetval->nodeNr != 1) ||
8377 (cur->nodesetval->nodeTab == NULL)) {
8378 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8383 tmp = cur->nodesetval->nodeTab[0];
8385 tmp = tmp->children;
8386 while (tmp != NULL) {
8391 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8394 xmlXPathReleaseObject(ctxt->context, cur);
8398 * xmlXPathGetElementsByIds:
8399 * @doc: the document
8400 * @ids: a whitespace separated list of IDs
8402 * Selects elements by their unique ID.
8404 * Returns a node-set of selected elements.
8406 static xmlNodeSetPtr
8407 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8409 const xmlChar *cur = ids;
8412 xmlNodePtr elem = NULL;
8414 if (ids == NULL) return(NULL);
8416 ret = xmlXPathNodeSetCreate(NULL);
8418 while (IS_BLANK_CH(*cur)) cur++;
8420 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8423 ID = xmlStrndup(ids, cur - ids);
8426 * We used to check the fact that the value passed
8427 * was an NCName, but this generated much troubles for
8428 * me and Aleksey Sanin, people blatantly violated that
8429 * constaint, like Visa3D spec.
8430 * if (xmlValidateNCName(ID, 1) == 0)
8432 attr = xmlGetID(doc, ID);
8434 if (attr->type == XML_ATTRIBUTE_NODE)
8435 elem = attr->parent;
8436 else if (attr->type == XML_ELEMENT_NODE)
8437 elem = (xmlNodePtr) attr;
8441 xmlXPathNodeSetAdd(ret, elem);
8446 while (IS_BLANK_CH(*cur)) cur++;
8453 * xmlXPathIdFunction:
8454 * @ctxt: the XPath Parser context
8455 * @nargs: the number of arguments
8457 * Implement the id() XPath function
8458 * node-set id(object)
8459 * The id function selects elements by their unique ID
8460 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8461 * then the result is the union of the result of applying id to the
8462 * string value of each of the nodes in the argument node-set. When the
8463 * argument to id is of any other type, the argument is converted to a
8464 * string as if by a call to the string function; the string is split
8465 * into a whitespace-separated list of tokens (whitespace is any sequence
8466 * of characters matching the production S); the result is a node-set
8467 * containing the elements in the same document as the context node that
8468 * have a unique ID equal to any of the tokens in the list.
8471 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8474 xmlXPathObjectPtr obj;
8477 obj = valuePop(ctxt);
8478 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8479 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8483 ret = xmlXPathNodeSetCreate(NULL);
8485 if (obj->nodesetval != NULL) {
8486 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8488 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8489 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8490 ret = xmlXPathNodeSetMerge(ret, ns);
8491 xmlXPathFreeNodeSet(ns);
8496 xmlXPathReleaseObject(ctxt->context, obj);
8497 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8500 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8501 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8502 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8503 xmlXPathReleaseObject(ctxt->context, obj);
8508 * xmlXPathLocalNameFunction:
8509 * @ctxt: the XPath Parser context
8510 * @nargs: the number of arguments
8512 * Implement the local-name() XPath function
8513 * string local-name(node-set?)
8514 * The local-name function returns a string containing the local part
8515 * of the name of the node in the argument node-set that is first in
8516 * document order. If the node-set is empty or the first node has no
8517 * name, an empty string is returned. If the argument is omitted it
8518 * defaults to the context node.
8521 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8522 xmlXPathObjectPtr cur;
8524 if (ctxt == NULL) return;
8527 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8528 ctxt->context->node));
8533 if ((ctxt->value == NULL) ||
8534 ((ctxt->value->type != XPATH_NODESET) &&
8535 (ctxt->value->type != XPATH_XSLT_TREE)))
8536 XP_ERROR(XPATH_INVALID_TYPE);
8537 cur = valuePop(ctxt);
8539 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8540 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8542 int i = 0; /* Should be first in document order !!!!! */
8543 switch (cur->nodesetval->nodeTab[i]->type) {
8544 case XML_ELEMENT_NODE:
8545 case XML_ATTRIBUTE_NODE:
8547 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8548 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8551 xmlXPathCacheNewString(ctxt->context,
8552 cur->nodesetval->nodeTab[i]->name));
8554 case XML_NAMESPACE_DECL:
8555 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8556 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8559 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8562 xmlXPathReleaseObject(ctxt->context, cur);
8566 * xmlXPathNamespaceURIFunction:
8567 * @ctxt: the XPath Parser context
8568 * @nargs: the number of arguments
8570 * Implement the namespace-uri() XPath function
8571 * string namespace-uri(node-set?)
8572 * The namespace-uri function returns a string containing the
8573 * namespace URI of the expanded name of the node in the argument
8574 * node-set that is first in document order. If the node-set is empty,
8575 * the first node has no name, or the expanded name has no namespace
8576 * URI, an empty string is returned. If the argument is omitted it
8577 * defaults to the context node.
8580 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8581 xmlXPathObjectPtr cur;
8583 if (ctxt == NULL) return;
8586 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8587 ctxt->context->node));
8591 if ((ctxt->value == NULL) ||
8592 ((ctxt->value->type != XPATH_NODESET) &&
8593 (ctxt->value->type != XPATH_XSLT_TREE)))
8594 XP_ERROR(XPATH_INVALID_TYPE);
8595 cur = valuePop(ctxt);
8597 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8598 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8600 int i = 0; /* Should be first in document order !!!!! */
8601 switch (cur->nodesetval->nodeTab[i]->type) {
8602 case XML_ELEMENT_NODE:
8603 case XML_ATTRIBUTE_NODE:
8604 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8605 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8607 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8608 cur->nodesetval->nodeTab[i]->ns->href));
8611 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8614 xmlXPathReleaseObject(ctxt->context, cur);
8618 * xmlXPathNameFunction:
8619 * @ctxt: the XPath Parser context
8620 * @nargs: the number of arguments
8622 * Implement the name() XPath function
8623 * string name(node-set?)
8624 * The name function returns a string containing a QName representing
8625 * the name of the node in the argument node-set that is first in document
8626 * order. The QName must represent the name with respect to the namespace
8627 * declarations in effect on the node whose name is being represented.
8628 * Typically, this will be the form in which the name occurred in the XML
8629 * source. This need not be the case if there are namespace declarations
8630 * in effect on the node that associate multiple prefixes with the same
8631 * namespace. However, an implementation may include information about
8632 * the original prefix in its representation of nodes; in this case, an
8633 * implementation can ensure that the returned string is always the same
8634 * as the QName used in the XML source. If the argument it omitted it
8635 * defaults to the context node.
8636 * Libxml keep the original prefix so the "real qualified name" used is
8640 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8642 xmlXPathObjectPtr cur;
8645 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8646 ctxt->context->node));
8651 if ((ctxt->value == NULL) ||
8652 ((ctxt->value->type != XPATH_NODESET) &&
8653 (ctxt->value->type != XPATH_XSLT_TREE)))
8654 XP_ERROR(XPATH_INVALID_TYPE);
8655 cur = valuePop(ctxt);
8657 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8658 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8660 int i = 0; /* Should be first in document order !!!!! */
8662 switch (cur->nodesetval->nodeTab[i]->type) {
8663 case XML_ELEMENT_NODE:
8664 case XML_ATTRIBUTE_NODE:
8665 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8667 xmlXPathCacheNewCString(ctxt->context, ""));
8668 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8669 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8671 xmlXPathCacheNewString(ctxt->context,
8672 cur->nodesetval->nodeTab[i]->name));
8676 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8677 cur->nodesetval->nodeTab[i]->ns->prefix,
8679 if (fullname == cur->nodesetval->nodeTab[i]->name)
8680 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8681 if (fullname == NULL) {
8682 XP_ERROR(XPATH_MEMORY_ERROR);
8684 valuePush(ctxt, xmlXPathCacheWrapString(
8685 ctxt->context, fullname));
8689 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8690 cur->nodesetval->nodeTab[i]));
8691 xmlXPathLocalNameFunction(ctxt, 1);
8694 xmlXPathReleaseObject(ctxt->context, cur);
8699 * xmlXPathStringFunction:
8700 * @ctxt: the XPath Parser context
8701 * @nargs: the number of arguments
8703 * Implement the string() XPath function
8704 * string string(object?)
8705 * The string function converts an object to a string as follows:
8706 * - A node-set is converted to a string by returning the value of
8707 * the node in the node-set that is first in document order.
8708 * If the node-set is empty, an empty string is returned.
8709 * - A number is converted to a string as follows
8710 * + NaN is converted to the string NaN
8711 * + positive zero is converted to the string 0
8712 * + negative zero is converted to the string 0
8713 * + positive infinity is converted to the string Infinity
8714 * + negative infinity is converted to the string -Infinity
8715 * + if the number is an integer, the number is represented in
8716 * decimal form as a Number with no decimal point and no leading
8717 * zeros, preceded by a minus sign (-) if the number is negative
8718 * + otherwise, the number is represented in decimal form as a
8719 * Number including a decimal point with at least one digit
8720 * before the decimal point and at least one digit after the
8721 * decimal point, preceded by a minus sign (-) if the number
8722 * is negative; there must be no leading zeros before the decimal
8723 * point apart possibly from the one required digit immediately
8724 * before the decimal point; beyond the one required digit
8725 * after the decimal point there must be as many, but only as
8726 * many, more digits as are needed to uniquely distinguish the
8727 * number from all other IEEE 754 numeric values.
8728 * - The boolean false value is converted to the string false.
8729 * The boolean true value is converted to the string true.
8731 * If the argument is omitted, it defaults to a node-set with the
8732 * context node as its only member.
8735 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8736 xmlXPathObjectPtr cur;
8738 if (ctxt == NULL) return;
8741 xmlXPathCacheWrapString(ctxt->context,
8742 xmlXPathCastNodeToString(ctxt->context->node)));
8747 cur = valuePop(ctxt);
8748 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8749 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8753 * xmlXPathStringLengthFunction:
8754 * @ctxt: the XPath Parser context
8755 * @nargs: the number of arguments
8757 * Implement the string-length() XPath function
8758 * number string-length(string?)
8759 * The string-length returns the number of characters in the string
8760 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8761 * the context node converted to a string, in other words the value
8762 * of the context node.
8765 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8766 xmlXPathObjectPtr cur;
8769 if ((ctxt == NULL) || (ctxt->context == NULL))
8771 if (ctxt->context->node == NULL) {
8772 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8776 content = xmlXPathCastNodeToString(ctxt->context->node);
8777 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8778 xmlUTF8Strlen(content)));
8785 CHECK_TYPE(XPATH_STRING);
8786 cur = valuePop(ctxt);
8787 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8788 xmlUTF8Strlen(cur->stringval)));
8789 xmlXPathReleaseObject(ctxt->context, cur);
8793 * xmlXPathConcatFunction:
8794 * @ctxt: the XPath Parser context
8795 * @nargs: the number of arguments
8797 * Implement the concat() XPath function
8798 * string concat(string, string, string*)
8799 * The concat function returns the concatenation of its arguments.
8802 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8803 xmlXPathObjectPtr cur, newobj;
8806 if (ctxt == NULL) return;
8812 cur = valuePop(ctxt);
8813 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8814 xmlXPathReleaseObject(ctxt->context, cur);
8821 newobj = valuePop(ctxt);
8822 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8823 xmlXPathReleaseObject(ctxt->context, newobj);
8824 xmlXPathReleaseObject(ctxt->context, cur);
8825 XP_ERROR(XPATH_INVALID_TYPE);
8827 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8828 newobj->stringval = cur->stringval;
8829 cur->stringval = tmp;
8830 xmlXPathReleaseObject(ctxt->context, newobj);
8833 valuePush(ctxt, cur);
8837 * xmlXPathContainsFunction:
8838 * @ctxt: the XPath Parser context
8839 * @nargs: the number of arguments
8841 * Implement the contains() XPath function
8842 * boolean contains(string, string)
8843 * The contains function returns true if the first argument string
8844 * contains the second argument string, and otherwise returns false.
8847 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8848 xmlXPathObjectPtr hay, needle;
8852 CHECK_TYPE(XPATH_STRING);
8853 needle = valuePop(ctxt);
8855 hay = valuePop(ctxt);
8857 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8858 xmlXPathReleaseObject(ctxt->context, hay);
8859 xmlXPathReleaseObject(ctxt->context, needle);
8860 XP_ERROR(XPATH_INVALID_TYPE);
8862 if (xmlStrstr(hay->stringval, needle->stringval))
8863 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8865 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8866 xmlXPathReleaseObject(ctxt->context, hay);
8867 xmlXPathReleaseObject(ctxt->context, needle);
8871 * xmlXPathStartsWithFunction:
8872 * @ctxt: the XPath Parser context
8873 * @nargs: the number of arguments
8875 * Implement the starts-with() XPath function
8876 * boolean starts-with(string, string)
8877 * The starts-with function returns true if the first argument string
8878 * starts with the second argument string, and otherwise returns false.
8881 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8882 xmlXPathObjectPtr hay, needle;
8887 CHECK_TYPE(XPATH_STRING);
8888 needle = valuePop(ctxt);
8890 hay = valuePop(ctxt);
8892 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8893 xmlXPathReleaseObject(ctxt->context, hay);
8894 xmlXPathReleaseObject(ctxt->context, needle);
8895 XP_ERROR(XPATH_INVALID_TYPE);
8897 n = xmlStrlen(needle->stringval);
8898 if (xmlStrncmp(hay->stringval, needle->stringval, n))
8899 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8901 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8902 xmlXPathReleaseObject(ctxt->context, hay);
8903 xmlXPathReleaseObject(ctxt->context, needle);
8907 * xmlXPathSubstringFunction:
8908 * @ctxt: the XPath Parser context
8909 * @nargs: the number of arguments
8911 * Implement the substring() XPath function
8912 * string substring(string, number, number?)
8913 * The substring function returns the substring of the first argument
8914 * starting at the position specified in the second argument with
8915 * length specified in the third argument. For example,
8916 * substring("12345",2,3) returns "234". If the third argument is not
8917 * specified, it returns the substring starting at the position specified
8918 * in the second argument and continuing to the end of the string. For
8919 * example, substring("12345",2) returns "2345". More precisely, each
8920 * character in the string (see [3.6 Strings]) is considered to have a
8921 * numeric position: the position of the first character is 1, the position
8922 * of the second character is 2 and so on. The returned substring contains
8923 * those characters for which the position of the character is greater than
8924 * or equal to the second argument and, if the third argument is specified,
8925 * less than the sum of the second and third arguments; the comparisons
8926 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8927 * - substring("12345", 1.5, 2.6) returns "234"
8928 * - substring("12345", 0, 3) returns "12"
8929 * - substring("12345", 0 div 0, 3) returns ""
8930 * - substring("12345", 1, 0 div 0) returns ""
8931 * - substring("12345", -42, 1 div 0) returns "12345"
8932 * - substring("12345", -1 div 0, 1 div 0) returns ""
8935 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8936 xmlXPathObjectPtr str, start, len;
8948 * take care of possible last (position) argument
8952 CHECK_TYPE(XPATH_NUMBER);
8953 len = valuePop(ctxt);
8955 xmlXPathReleaseObject(ctxt->context, len);
8959 CHECK_TYPE(XPATH_NUMBER);
8960 start = valuePop(ctxt);
8961 in = start->floatval;
8962 xmlXPathReleaseObject(ctxt->context, start);
8964 CHECK_TYPE(XPATH_STRING);
8965 str = valuePop(ctxt);
8966 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
8969 * If last pos not present, calculate last position
8977 /* Need to check for the special cases where either
8978 * the index is NaN, the length is NaN, or both
8979 * arguments are infinity (relying on Inf + -Inf = NaN)
8981 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
8983 * To meet the requirements of the spec, the arguments
8984 * must be converted to integer format before
8985 * initial index calculations are done
8987 * First we go to integer form, rounding up
8988 * and checking for special cases
8991 if (((double)i)+0.5 <= in) i++;
8993 if (xmlXPathIsInf(le) == 1) {
8998 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9002 if (((double)l)+0.5 <= le) l++;
9005 /* Now we normalize inidices */
9013 /* number of chars to copy */
9016 ret = xmlUTF8Strsub(str->stringval, i, l);
9022 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9024 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9027 xmlXPathReleaseObject(ctxt->context, str);
9031 * xmlXPathSubstringBeforeFunction:
9032 * @ctxt: the XPath Parser context
9033 * @nargs: the number of arguments
9035 * Implement the substring-before() XPath function
9036 * string substring-before(string, string)
9037 * The substring-before function returns the substring of the first
9038 * argument string that precedes the first occurrence of the second
9039 * argument string in the first argument string, or the empty string
9040 * if the first argument string does not contain the second argument
9041 * string. For example, substring-before("1999/04/01","/") returns 1999.
9044 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9045 xmlXPathObjectPtr str;
9046 xmlXPathObjectPtr find;
9047 xmlBufferPtr target;
9048 const xmlChar *point;
9053 find = valuePop(ctxt);
9055 str = valuePop(ctxt);
9057 target = xmlBufferCreate();
9059 point = xmlStrstr(str->stringval, find->stringval);
9061 offset = (int)(point - str->stringval);
9062 xmlBufferAdd(target, str->stringval, offset);
9064 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9065 xmlBufferContent(target)));
9066 xmlBufferFree(target);
9068 xmlXPathReleaseObject(ctxt->context, str);
9069 xmlXPathReleaseObject(ctxt->context, find);
9073 * xmlXPathSubstringAfterFunction:
9074 * @ctxt: the XPath Parser context
9075 * @nargs: the number of arguments
9077 * Implement the substring-after() XPath function
9078 * string substring-after(string, string)
9079 * The substring-after function returns the substring of the first
9080 * argument string that follows the first occurrence of the second
9081 * argument string in the first argument string, or the empty stringi
9082 * if the first argument string does not contain the second argument
9083 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9084 * and substring-after("1999/04/01","19") returns 99/04/01.
9087 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9088 xmlXPathObjectPtr str;
9089 xmlXPathObjectPtr find;
9090 xmlBufferPtr target;
9091 const xmlChar *point;
9096 find = valuePop(ctxt);
9098 str = valuePop(ctxt);
9100 target = xmlBufferCreate();
9102 point = xmlStrstr(str->stringval, find->stringval);
9104 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9105 xmlBufferAdd(target, &str->stringval[offset],
9106 xmlStrlen(str->stringval) - offset);
9108 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9109 xmlBufferContent(target)));
9110 xmlBufferFree(target);
9112 xmlXPathReleaseObject(ctxt->context, str);
9113 xmlXPathReleaseObject(ctxt->context, find);
9117 * xmlXPathNormalizeFunction:
9118 * @ctxt: the XPath Parser context
9119 * @nargs: the number of arguments
9121 * Implement the normalize-space() XPath function
9122 * string normalize-space(string?)
9123 * The normalize-space function returns the argument string with white
9124 * space normalized by stripping leading and trailing whitespace
9125 * and replacing sequences of whitespace characters by a single
9126 * space. Whitespace characters are the same allowed by the S production
9127 * in XML. If the argument is omitted, it defaults to the context
9128 * node converted to a string, in other words the value of the context node.
9131 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9132 xmlXPathObjectPtr obj = NULL;
9133 xmlChar *source = NULL;
9134 xmlBufferPtr target;
9137 if (ctxt == NULL) return;
9139 /* Use current context node */
9141 xmlXPathCacheWrapString(ctxt->context,
9142 xmlXPathCastNodeToString(ctxt->context->node)));
9148 CHECK_TYPE(XPATH_STRING);
9149 obj = valuePop(ctxt);
9150 source = obj->stringval;
9152 target = xmlBufferCreate();
9153 if (target && source) {
9155 /* Skip leading whitespaces */
9156 while (IS_BLANK_CH(*source))
9159 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9162 if (IS_BLANK_CH(*source)) {
9166 xmlBufferAdd(target, &blank, 1);
9169 xmlBufferAdd(target, source, 1);
9173 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9174 xmlBufferContent(target)));
9175 xmlBufferFree(target);
9177 xmlXPathReleaseObject(ctxt->context, obj);
9181 * xmlXPathTranslateFunction:
9182 * @ctxt: the XPath Parser context
9183 * @nargs: the number of arguments
9185 * Implement the translate() XPath function
9186 * string translate(string, string, string)
9187 * The translate function returns the first argument string with
9188 * occurrences of characters in the second argument string replaced
9189 * by the character at the corresponding position in the third argument
9190 * string. For example, translate("bar","abc","ABC") returns the string
9191 * BAr. If there is a character in the second argument string with no
9192 * character at a corresponding position in the third argument string
9193 * (because the second argument string is longer than the third argument
9194 * string), then occurrences of that character in the first argument
9195 * string are removed. For example, translate("--aaa--","abc-","ABC")
9196 * returns "AAA". If a character occurs more than once in second
9197 * argument string, then the first occurrence determines the replacement
9198 * character. If the third argument string is longer than the second
9199 * argument string, then excess characters are ignored.
9202 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9203 xmlXPathObjectPtr str;
9204 xmlXPathObjectPtr from;
9205 xmlXPathObjectPtr to;
9206 xmlBufferPtr target;
9209 const xmlChar *point;
9215 to = valuePop(ctxt);
9217 from = valuePop(ctxt);
9219 str = valuePop(ctxt);
9221 target = xmlBufferCreate();
9223 max = xmlUTF8Strlen(to->stringval);
9224 for (cptr = str->stringval; (ch=*cptr); ) {
9225 offset = xmlUTF8Strloc(from->stringval, cptr);
9228 point = xmlUTF8Strpos(to->stringval, offset);
9230 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9233 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9235 /* Step to next character in input */
9238 /* if not simple ascii, verify proper format */
9239 if ( (ch & 0xc0) != 0xc0 ) {
9240 xmlGenericError(xmlGenericErrorContext,
9241 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9244 /* then skip over remaining bytes for this char */
9245 while ( (ch <<= 1) & 0x80 )
9246 if ( (*cptr++ & 0xc0) != 0x80 ) {
9247 xmlGenericError(xmlGenericErrorContext,
9248 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9251 if (ch & 0x80) /* must have had error encountered */
9256 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9257 xmlBufferContent(target)));
9258 xmlBufferFree(target);
9259 xmlXPathReleaseObject(ctxt->context, str);
9260 xmlXPathReleaseObject(ctxt->context, from);
9261 xmlXPathReleaseObject(ctxt->context, to);
9265 * xmlXPathBooleanFunction:
9266 * @ctxt: the XPath Parser context
9267 * @nargs: the number of arguments
9269 * Implement the boolean() XPath function
9270 * boolean boolean(object)
9271 * The boolean function converts its argument to a boolean as follows:
9272 * - a number is true if and only if it is neither positive or
9273 * negative zero nor NaN
9274 * - a node-set is true if and only if it is non-empty
9275 * - a string is true if and only if its length is non-zero
9278 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9279 xmlXPathObjectPtr cur;
9282 cur = valuePop(ctxt);
9283 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9284 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9285 valuePush(ctxt, cur);
9289 * xmlXPathNotFunction:
9290 * @ctxt: the XPath Parser context
9291 * @nargs: the number of arguments
9293 * Implement the not() XPath function
9294 * boolean not(boolean)
9295 * The not function returns true if its argument is false,
9296 * and false otherwise.
9299 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9302 CHECK_TYPE(XPATH_BOOLEAN);
9303 ctxt->value->boolval = ! ctxt->value->boolval;
9307 * xmlXPathTrueFunction:
9308 * @ctxt: the XPath Parser context
9309 * @nargs: the number of arguments
9311 * Implement the true() XPath function
9315 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9317 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9321 * xmlXPathFalseFunction:
9322 * @ctxt: the XPath Parser context
9323 * @nargs: the number of arguments
9325 * Implement the false() XPath function
9329 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9331 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9335 * xmlXPathLangFunction:
9336 * @ctxt: the XPath Parser context
9337 * @nargs: the number of arguments
9339 * Implement the lang() XPath function
9340 * boolean lang(string)
9341 * The lang function returns true or false depending on whether the
9342 * language of the context node as specified by xml:lang attributes
9343 * is the same as or is a sublanguage of the language specified by
9344 * the argument string. The language of the context node is determined
9345 * by the value of the xml:lang attribute on the context node, or, if
9346 * the context node has no xml:lang attribute, by the value of the
9347 * xml:lang attribute on the nearest ancestor of the context node that
9348 * has an xml:lang attribute. If there is no such attribute, then lang
9349 * returns false. If there is such an attribute, then lang returns
9350 * true if the attribute value is equal to the argument ignoring case,
9351 * or if there is some suffix starting with - such that the attribute
9352 * value is equal to the argument ignoring that suffix of the attribute
9353 * value and ignoring case.
9356 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9357 xmlXPathObjectPtr val = NULL;
9358 const xmlChar *theLang = NULL;
9359 const xmlChar *lang;
9365 CHECK_TYPE(XPATH_STRING);
9366 val = valuePop(ctxt);
9367 lang = val->stringval;
9368 theLang = xmlNodeGetLang(ctxt->context->node);
9369 if ((theLang != NULL) && (lang != NULL)) {
9370 for (i = 0;lang[i] != 0;i++)
9371 if (toupper(lang[i]) != toupper(theLang[i]))
9373 if ((theLang[i] == 0) || (theLang[i] == '-'))
9377 if (theLang != NULL)
9378 xmlFree((void *)theLang);
9380 xmlXPathReleaseObject(ctxt->context, val);
9381 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9385 * xmlXPathNumberFunction:
9386 * @ctxt: the XPath Parser context
9387 * @nargs: the number of arguments
9389 * Implement the number() XPath function
9390 * number number(object?)
9393 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9394 xmlXPathObjectPtr cur;
9397 if (ctxt == NULL) return;
9399 if (ctxt->context->node == NULL) {
9400 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9402 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9404 res = xmlXPathStringEvalNumber(content);
9405 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9412 cur = valuePop(ctxt);
9413 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9417 * xmlXPathSumFunction:
9418 * @ctxt: the XPath Parser context
9419 * @nargs: the number of arguments
9421 * Implement the sum() XPath function
9422 * number sum(node-set)
9423 * The sum function returns the sum of the values of the nodes in
9424 * the argument node-set.
9427 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9428 xmlXPathObjectPtr cur;
9433 if ((ctxt->value == NULL) ||
9434 ((ctxt->value->type != XPATH_NODESET) &&
9435 (ctxt->value->type != XPATH_XSLT_TREE)))
9436 XP_ERROR(XPATH_INVALID_TYPE);
9437 cur = valuePop(ctxt);
9439 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9440 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9441 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9444 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9445 xmlXPathReleaseObject(ctxt->context, cur);
9449 * To assure working code on multiple platforms, we want to only depend
9450 * upon the characteristic truncation of converting a floating point value
9451 * to an integer. Unfortunately, because of the different storage sizes
9452 * of our internal floating point value (double) and integer (int), we
9453 * can't directly convert (see bug 301162). This macro is a messy
9456 #define XTRUNC(f, v) \
9457 f = fmod((v), INT_MAX); \
9458 f = (v) - (f) + (double)((int)(f));
9461 * xmlXPathFloorFunction:
9462 * @ctxt: the XPath Parser context
9463 * @nargs: the number of arguments
9465 * Implement the floor() XPath function
9466 * number floor(number)
9467 * The floor function returns the largest (closest to positive infinity)
9468 * number that is not greater than the argument and that is an integer.
9471 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9476 CHECK_TYPE(XPATH_NUMBER);
9478 XTRUNC(f, ctxt->value->floatval);
9479 if (f != ctxt->value->floatval) {
9480 if (ctxt->value->floatval > 0)
9481 ctxt->value->floatval = f;
9483 ctxt->value->floatval = f - 1;
9488 * xmlXPathCeilingFunction:
9489 * @ctxt: the XPath Parser context
9490 * @nargs: the number of arguments
9492 * Implement the ceiling() XPath function
9493 * number ceiling(number)
9494 * The ceiling function returns the smallest (closest to negative infinity)
9495 * number that is not less than the argument and that is an integer.
9498 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9503 CHECK_TYPE(XPATH_NUMBER);
9506 ctxt->value->floatval = ceil(ctxt->value->floatval);
9508 XTRUNC(f, ctxt->value->floatval);
9509 if (f != ctxt->value->floatval) {
9510 if (ctxt->value->floatval > 0)
9511 ctxt->value->floatval = f + 1;
9513 if (ctxt->value->floatval < 0 && f == 0)
9514 ctxt->value->floatval = xmlXPathNZERO;
9516 ctxt->value->floatval = f;
9524 * xmlXPathRoundFunction:
9525 * @ctxt: the XPath Parser context
9526 * @nargs: the number of arguments
9528 * Implement the round() XPath function
9529 * number round(number)
9530 * The round function returns the number that is closest to the
9531 * argument and that is an integer. If there are two such numbers,
9532 * then the one that is even is returned.
9535 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9540 CHECK_TYPE(XPATH_NUMBER);
9542 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9543 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9544 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9545 (ctxt->value->floatval == 0.0))
9548 XTRUNC(f, ctxt->value->floatval);
9549 if (ctxt->value->floatval < 0) {
9550 if (ctxt->value->floatval < f - 0.5)
9551 ctxt->value->floatval = f - 1;
9553 ctxt->value->floatval = f;
9554 if (ctxt->value->floatval == 0)
9555 ctxt->value->floatval = xmlXPathNZERO;
9557 if (ctxt->value->floatval < f + 0.5)
9558 ctxt->value->floatval = f;
9560 ctxt->value->floatval = f + 1;
9564 /************************************************************************
9568 ************************************************************************/
9571 * a few forward declarations since we use a recursive call based
9574 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9575 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9576 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9577 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9578 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9582 * xmlXPathCurrentChar:
9583 * @ctxt: the XPath parser context
9584 * @cur: pointer to the beginning of the char
9585 * @len: pointer to the length of the char read
9587 * The current char value, if using UTF-8 this may actually span multiple
9588 * bytes in the input buffer.
9590 * Returns the current char value and its length
9594 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9604 * We are supposed to handle UTF8, check it's valid
9605 * From rfc2044: encoding of the Unicode values on UTF-8:
9607 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9608 * 0000 0000-0000 007F 0xxxxxxx
9609 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9610 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9612 * Check for the 0x110000 limit too
9616 if ((cur[1] & 0xc0) != 0x80)
9617 goto encoding_error;
9618 if ((c & 0xe0) == 0xe0) {
9620 if ((cur[2] & 0xc0) != 0x80)
9621 goto encoding_error;
9622 if ((c & 0xf0) == 0xf0) {
9623 if (((c & 0xf8) != 0xf0) ||
9624 ((cur[3] & 0xc0) != 0x80))
9625 goto encoding_error;
9628 val = (cur[0] & 0x7) << 18;
9629 val |= (cur[1] & 0x3f) << 12;
9630 val |= (cur[2] & 0x3f) << 6;
9631 val |= cur[3] & 0x3f;
9635 val = (cur[0] & 0xf) << 12;
9636 val |= (cur[1] & 0x3f) << 6;
9637 val |= cur[2] & 0x3f;
9642 val = (cur[0] & 0x1f) << 6;
9643 val |= cur[1] & 0x3f;
9645 if (!IS_CHAR(val)) {
9646 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9656 * If we detect an UTF8 error that probably means that the
9657 * input encoding didn't get properly advertised in the
9658 * declaration header. Report the error and switch the encoding
9659 * to ISO-Latin-1 (if you don't like this policy, just declare the
9663 XP_ERROR0(XPATH_ENCODING_ERROR);
9667 * xmlXPathParseNCName:
9668 * @ctxt: the XPath Parser context
9670 * parse an XML namespace non qualified name.
9672 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9674 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9675 * CombiningChar | Extender
9677 * Returns the namespace name or NULL
9681 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9686 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9688 * Accelerator for simple ASCII names
9691 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9692 ((*in >= 0x41) && (*in <= 0x5A)) ||
9695 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9696 ((*in >= 0x41) && (*in <= 0x5A)) ||
9697 ((*in >= 0x30) && (*in <= 0x39)) ||
9698 (*in == '_') || (*in == '.') ||
9701 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9702 (*in == '[') || (*in == ']') || (*in == ':') ||
9703 (*in == '@') || (*in == '*')) {
9704 count = in - ctxt->cur;
9707 ret = xmlStrndup(ctxt->cur, count);
9712 return(xmlXPathParseNameComplex(ctxt, 0));
9717 * xmlXPathParseQName:
9718 * @ctxt: the XPath Parser context
9719 * @prefix: a xmlChar **
9721 * parse an XML qualified name
9723 * [NS 5] QName ::= (Prefix ':')? LocalPart
9725 * [NS 6] Prefix ::= NCName
9727 * [NS 7] LocalPart ::= NCName
9729 * Returns the function returns the local part, and prefix is updated
9730 * to get the Prefix if any.
9734 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9735 xmlChar *ret = NULL;
9738 ret = xmlXPathParseNCName(ctxt);
9742 ret = xmlXPathParseNCName(ctxt);
9748 * xmlXPathParseName:
9749 * @ctxt: the XPath Parser context
9753 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9754 * CombiningChar | Extender
9756 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9758 * Returns the namespace name or NULL
9762 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9767 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9769 * Accelerator for simple ASCII names
9772 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9773 ((*in >= 0x41) && (*in <= 0x5A)) ||
9774 (*in == '_') || (*in == ':')) {
9776 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9777 ((*in >= 0x41) && (*in <= 0x5A)) ||
9778 ((*in >= 0x30) && (*in <= 0x39)) ||
9779 (*in == '_') || (*in == '-') ||
9780 (*in == ':') || (*in == '.'))
9782 if ((*in > 0) && (*in < 0x80)) {
9783 count = in - ctxt->cur;
9784 ret = xmlStrndup(ctxt->cur, count);
9789 return(xmlXPathParseNameComplex(ctxt, 1));
9793 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9794 xmlChar buf[XML_MAX_NAMELEN + 5];
9799 * Handler for more complex cases
9802 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9803 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9804 (c == '*') || /* accelerators */
9805 (!IS_LETTER(c) && (c != '_') &&
9806 ((qualified) && (c != ':')))) {
9810 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9811 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9812 (c == '.') || (c == '-') ||
9813 (c == '_') || ((qualified) && (c == ':')) ||
9814 (IS_COMBINING(c)) ||
9815 (IS_EXTENDER(c)))) {
9816 COPY_BUF(l,buf,len,c);
9819 if (len >= XML_MAX_NAMELEN) {
9821 * Okay someone managed to make a huge name, so he's ready to pay
9822 * for the processing speed.
9827 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9828 if (buffer == NULL) {
9829 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9831 memcpy(buffer, buf, len);
9832 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9833 (c == '.') || (c == '-') ||
9834 (c == '_') || ((qualified) && (c == ':')) ||
9835 (IS_COMBINING(c)) ||
9837 if (len + 10 > max) {
9839 buffer = (xmlChar *) xmlRealloc(buffer,
9840 max * sizeof(xmlChar));
9841 if (buffer == NULL) {
9842 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9845 COPY_BUF(l,buffer,len,c);
9855 return(xmlStrndup(buf, len));
9861 * These are used as divisors for the fractional part of a number.
9862 * Since the table includes 1.0 (representing '0' fractional digits),
9863 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9865 static double my_pow10[MAX_FRAC+1] = {
9866 1.0, 10.0, 100.0, 1000.0, 10000.0,
9867 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9868 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9870 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9871 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9875 * xmlXPathStringEvalNumber:
9876 * @str: A string to scan
9878 * [30a] Float ::= Number ('e' Digits?)?
9880 * [30] Number ::= Digits ('.' Digits?)?
9882 * [31] Digits ::= [0-9]+
9884 * Compile a Number in the string
9885 * In complement of the Number expression, this function also handles
9886 * negative values : '-' Number.
9888 * Returns the double value.
9891 xmlXPathStringEvalNumber(const xmlChar *str) {
9892 const xmlChar *cur = str;
9897 int is_exponent_negative = 0;
9899 unsigned long tmp = 0;
9902 if (cur == NULL) return(0);
9903 while (IS_BLANK_CH(*cur)) cur++;
9904 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9905 return(xmlXPathNAN);
9914 * tmp/temp is a workaround against a gcc compiler bug
9915 * http://veillard.com/gcc.bug
9918 while ((*cur >= '0') && (*cur <= '9')) {
9923 temp = (double) tmp;
9928 while ((*cur >= '0') && (*cur <= '9')) {
9929 ret = ret * 10 + (*cur - '0');
9937 double fraction = 0;
9940 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9941 return(xmlXPathNAN);
9943 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
9945 fraction = fraction * 10 + v;
9949 fraction /= my_pow10[frac];
9950 ret = ret + fraction;
9951 while ((*cur >= '0') && (*cur <= '9'))
9954 if ((*cur == 'e') || (*cur == 'E')) {
9957 is_exponent_negative = 1;
9959 } else if (*cur == '+') {
9962 while ((*cur >= '0') && (*cur <= '9')) {
9963 exponent = exponent * 10 + (*cur - '0');
9967 while (IS_BLANK_CH(*cur)) cur++;
9968 if (*cur != 0) return(xmlXPathNAN);
9969 if (isneg) ret = -ret;
9970 if (is_exponent_negative) exponent = -exponent;
9971 ret *= pow(10.0, (double)exponent);
9976 * xmlXPathCompNumber:
9977 * @ctxt: the XPath Parser context
9979 * [30] Number ::= Digits ('.' Digits?)?
9981 * [31] Digits ::= [0-9]+
9983 * Compile a Number, then push it on the stack
9987 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9993 int is_exponent_negative = 0;
9995 unsigned long tmp = 0;
10000 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10001 XP_ERROR(XPATH_NUMBER_ERROR);
10005 * tmp/temp is a workaround against a gcc compiler bug
10006 * http://veillard.com/gcc.bug
10009 while ((CUR >= '0') && (CUR <= '9')) {
10014 temp = (double) tmp;
10019 while ((CUR >= '0') && (CUR <= '9')) {
10020 ret = ret * 10 + (CUR - '0');
10027 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10028 XP_ERROR(XPATH_NUMBER_ERROR);
10030 while ((CUR >= '0') && (CUR <= '9')) {
10032 ret = ret + (CUR - '0') * mult;
10036 if ((CUR == 'e') || (CUR == 'E')) {
10039 is_exponent_negative = 1;
10041 } else if (CUR == '+') {
10044 while ((CUR >= '0') && (CUR <= '9')) {
10045 exponent = exponent * 10 + (CUR - '0');
10048 if (is_exponent_negative)
10049 exponent = -exponent;
10050 ret *= pow(10.0, (double) exponent);
10052 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10053 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10057 * xmlXPathParseLiteral:
10058 * @ctxt: the XPath Parser context
10062 * [29] Literal ::= '"' [^"]* '"'
10065 * Returns the value found or NULL in case of error
10068 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10070 xmlChar *ret = NULL;
10075 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10077 if (!IS_CHAR_CH(CUR)) {
10078 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10080 ret = xmlStrndup(q, CUR_PTR - q);
10083 } else if (CUR == '\'') {
10086 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10088 if (!IS_CHAR_CH(CUR)) {
10089 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10091 ret = xmlStrndup(q, CUR_PTR - q);
10095 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10101 * xmlXPathCompLiteral:
10102 * @ctxt: the XPath Parser context
10104 * Parse a Literal and push it on the stack.
10106 * [29] Literal ::= '"' [^"]* '"'
10109 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10112 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10114 xmlChar *ret = NULL;
10119 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10121 if (!IS_CHAR_CH(CUR)) {
10122 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10124 ret = xmlStrndup(q, CUR_PTR - q);
10127 } else if (CUR == '\'') {
10130 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10132 if (!IS_CHAR_CH(CUR)) {
10133 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10135 ret = xmlStrndup(q, CUR_PTR - q);
10139 XP_ERROR(XPATH_START_LITERAL_ERROR);
10141 if (ret == NULL) return;
10142 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10143 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10148 * xmlXPathCompVariableReference:
10149 * @ctxt: the XPath Parser context
10151 * Parse a VariableReference, evaluate it and push it on the stack.
10153 * The variable bindings consist of a mapping from variable names
10154 * to variable values. The value of a variable is an object, which can be
10155 * of any of the types that are possible for the value of an expression,
10156 * and may also be of additional types not specified here.
10158 * Early evaluation is possible since:
10159 * The variable bindings [...] used to evaluate a subexpression are
10160 * always the same as those used to evaluate the containing expression.
10162 * [36] VariableReference ::= '$' QName
10165 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10171 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10174 name = xmlXPathParseQName(ctxt, &prefix);
10175 if (name == NULL) {
10176 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10178 ctxt->comp->last = -1;
10179 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10182 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10183 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10188 * xmlXPathIsNodeType:
10189 * @name: a name string
10191 * Is the name given a NodeType one.
10193 * [38] NodeType ::= 'comment'
10195 * | 'processing-instruction'
10198 * Returns 1 if true 0 otherwise
10201 xmlXPathIsNodeType(const xmlChar *name) {
10205 if (xmlStrEqual(name, BAD_CAST "node"))
10207 if (xmlStrEqual(name, BAD_CAST "text"))
10209 if (xmlStrEqual(name, BAD_CAST "comment"))
10211 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10217 * xmlXPathCompFunctionCall:
10218 * @ctxt: the XPath Parser context
10220 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10221 * [17] Argument ::= Expr
10223 * Compile a function call, the evaluation of all arguments are
10224 * pushed on the stack
10227 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10233 name = xmlXPathParseQName(ctxt, &prefix);
10234 if (name == NULL) {
10235 XP_ERROR(XPATH_EXPR_ERROR);
10239 if (prefix == NULL)
10240 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10243 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10248 XP_ERROR(XPATH_EXPR_ERROR);
10254 * Optimization for count(): we don't need the node-set to be sorted.
10256 if ((prefix == NULL) && (name[0] == 'c') &&
10257 xmlStrEqual(name, BAD_CAST "count"))
10261 ctxt->comp->last = -1;
10264 int op1 = ctxt->comp->last;
10265 ctxt->comp->last = -1;
10266 xmlXPathCompileExpr(ctxt, sort);
10268 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10270 if (CUR == ')') break;
10272 XP_ERROR(XPATH_EXPR_ERROR);
10278 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10285 * xmlXPathCompPrimaryExpr:
10286 * @ctxt: the XPath Parser context
10288 * [15] PrimaryExpr ::= VariableReference
10294 * Compile a primary expression.
10297 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10299 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10300 else if (CUR == '(') {
10303 xmlXPathCompileExpr(ctxt, 1);
10306 XP_ERROR(XPATH_EXPR_ERROR);
10310 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10311 xmlXPathCompNumber(ctxt);
10312 } else if ((CUR == '\'') || (CUR == '"')) {
10313 xmlXPathCompLiteral(ctxt);
10315 xmlXPathCompFunctionCall(ctxt);
10321 * xmlXPathCompFilterExpr:
10322 * @ctxt: the XPath Parser context
10324 * [20] FilterExpr ::= PrimaryExpr
10325 * | FilterExpr Predicate
10327 * Compile a filter expression.
10328 * Square brackets are used to filter expressions in the same way that
10329 * they are used in location paths. It is an error if the expression to
10330 * be filtered does not evaluate to a node-set. The context node list
10331 * used for evaluating the expression in square brackets is the node-set
10332 * to be filtered listed in document order.
10336 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10337 xmlXPathCompPrimaryExpr(ctxt);
10341 while (CUR == '[') {
10342 xmlXPathCompPredicate(ctxt, 1);
10350 * xmlXPathScanName:
10351 * @ctxt: the XPath Parser context
10353 * Trickery: parse an XML name but without consuming the input flow
10354 * Needed to avoid insanity in the parser state.
10356 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10357 * CombiningChar | Extender
10359 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10361 * [6] Names ::= Name (S Name)*
10363 * Returns the Name parsed or NULL
10367 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10370 const xmlChar *cur;
10376 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10377 (!IS_LETTER(c) && (c != '_') &&
10382 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10383 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10384 (c == '.') || (c == '-') ||
10385 (c == '_') || (c == ':') ||
10386 (IS_COMBINING(c)) ||
10387 (IS_EXTENDER(c)))) {
10392 ret = xmlStrndup(cur, ctxt->cur - cur);
10398 * xmlXPathCompPathExpr:
10399 * @ctxt: the XPath Parser context
10401 * [19] PathExpr ::= LocationPath
10403 * | FilterExpr '/' RelativeLocationPath
10404 * | FilterExpr '//' RelativeLocationPath
10406 * Compile a path expression.
10407 * The / operator and // operators combine an arbitrary expression
10408 * and a relative location path. It is an error if the expression
10409 * does not evaluate to a node-set.
10410 * The / operator does composition in the same way as when / is
10411 * used in a location path. As in location paths, // is short for
10412 * /descendant-or-self::node()/.
10416 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10417 int lc = 1; /* Should we branch to LocationPath ? */
10418 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10421 if ((CUR == '$') || (CUR == '(') ||
10422 (IS_ASCII_DIGIT(CUR)) ||
10423 (CUR == '\'') || (CUR == '"') ||
10424 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10426 } else if (CUR == '*') {
10427 /* relative or absolute location path */
10429 } else if (CUR == '/') {
10430 /* relative or absolute location path */
10432 } else if (CUR == '@') {
10433 /* relative abbreviated attribute location path */
10435 } else if (CUR == '.') {
10436 /* relative abbreviated attribute location path */
10440 * Problem is finding if we have a name here whether it's:
10442 * - a function call in which case it's followed by '('
10443 * - an axis in which case it's followed by ':'
10445 * We do an a priori analysis here rather than having to
10446 * maintain parsed token content through the recursive function
10447 * calls. This looks uglier but makes the code easier to
10448 * read/write/debug.
10451 name = xmlXPathScanName(ctxt);
10452 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10454 xmlGenericError(xmlGenericErrorContext,
10455 "PathExpr: Axis\n");
10459 } else if (name != NULL) {
10460 int len =xmlStrlen(name);
10463 while (NXT(len) != 0) {
10464 if (NXT(len) == '/') {
10467 xmlGenericError(xmlGenericErrorContext,
10468 "PathExpr: AbbrRelLocation\n");
10472 } else if (IS_BLANK_CH(NXT(len))) {
10473 /* ignore blanks */
10475 } else if (NXT(len) == ':') {
10477 xmlGenericError(xmlGenericErrorContext,
10478 "PathExpr: AbbrRelLocation\n");
10482 } else if ((NXT(len) == '(')) {
10483 /* Note Type or Function */
10484 if (xmlXPathIsNodeType(name)) {
10486 xmlGenericError(xmlGenericErrorContext,
10487 "PathExpr: Type search\n");
10492 xmlGenericError(xmlGenericErrorContext,
10493 "PathExpr: function call\n");
10498 } else if ((NXT(len) == '[')) {
10501 xmlGenericError(xmlGenericErrorContext,
10502 "PathExpr: AbbrRelLocation\n");
10506 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10507 (NXT(len) == '=')) {
10516 if (NXT(len) == 0) {
10518 xmlGenericError(xmlGenericErrorContext,
10519 "PathExpr: AbbrRelLocation\n");
10526 /* make sure all cases are covered explicitly */
10527 XP_ERROR(XPATH_EXPR_ERROR);
10533 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10535 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10537 xmlXPathCompLocationPath(ctxt);
10539 xmlXPathCompFilterExpr(ctxt);
10541 if ((CUR == '/') && (NXT(1) == '/')) {
10545 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10546 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10547 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10549 xmlXPathCompRelativeLocationPath(ctxt);
10550 } else if (CUR == '/') {
10551 xmlXPathCompRelativeLocationPath(ctxt);
10558 * xmlXPathCompUnionExpr:
10559 * @ctxt: the XPath Parser context
10561 * [18] UnionExpr ::= PathExpr
10562 * | UnionExpr '|' PathExpr
10564 * Compile an union expression.
10568 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10569 xmlXPathCompPathExpr(ctxt);
10572 while (CUR == '|') {
10573 int op1 = ctxt->comp->last;
10574 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10578 xmlXPathCompPathExpr(ctxt);
10580 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10587 * xmlXPathCompUnaryExpr:
10588 * @ctxt: the XPath Parser context
10590 * [27] UnaryExpr ::= UnionExpr
10593 * Compile an unary expression.
10597 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10602 while (CUR == '-') {
10609 xmlXPathCompUnionExpr(ctxt);
10613 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10615 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10620 * xmlXPathCompMultiplicativeExpr:
10621 * @ctxt: the XPath Parser context
10623 * [26] MultiplicativeExpr ::= UnaryExpr
10624 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10625 * | MultiplicativeExpr 'div' UnaryExpr
10626 * | MultiplicativeExpr 'mod' UnaryExpr
10627 * [34] MultiplyOperator ::= '*'
10629 * Compile an Additive expression.
10633 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10634 xmlXPathCompUnaryExpr(ctxt);
10637 while ((CUR == '*') ||
10638 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10639 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10641 int op1 = ctxt->comp->last;
10646 } else if (CUR == 'd') {
10649 } else if (CUR == 'm') {
10654 xmlXPathCompUnaryExpr(ctxt);
10656 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10662 * xmlXPathCompAdditiveExpr:
10663 * @ctxt: the XPath Parser context
10665 * [25] AdditiveExpr ::= MultiplicativeExpr
10666 * | AdditiveExpr '+' MultiplicativeExpr
10667 * | AdditiveExpr '-' MultiplicativeExpr
10669 * Compile an Additive expression.
10673 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10675 xmlXPathCompMultiplicativeExpr(ctxt);
10678 while ((CUR == '+') || (CUR == '-')) {
10680 int op1 = ctxt->comp->last;
10682 if (CUR == '+') plus = 1;
10686 xmlXPathCompMultiplicativeExpr(ctxt);
10688 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10694 * xmlXPathCompRelationalExpr:
10695 * @ctxt: the XPath Parser context
10697 * [24] RelationalExpr ::= AdditiveExpr
10698 * | RelationalExpr '<' AdditiveExpr
10699 * | RelationalExpr '>' AdditiveExpr
10700 * | RelationalExpr '<=' AdditiveExpr
10701 * | RelationalExpr '>=' AdditiveExpr
10703 * A <= B > C is allowed ? Answer from James, yes with
10704 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10705 * which is basically what got implemented.
10707 * Compile a Relational expression, then push the result
10712 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10713 xmlXPathCompAdditiveExpr(ctxt);
10716 while ((CUR == '<') ||
10718 ((CUR == '<') && (NXT(1) == '=')) ||
10719 ((CUR == '>') && (NXT(1) == '='))) {
10721 int op1 = ctxt->comp->last;
10723 if (CUR == '<') inf = 1;
10725 if (NXT(1) == '=') strict = 0;
10730 xmlXPathCompAdditiveExpr(ctxt);
10732 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10738 * xmlXPathCompEqualityExpr:
10739 * @ctxt: the XPath Parser context
10741 * [23] EqualityExpr ::= RelationalExpr
10742 * | EqualityExpr '=' RelationalExpr
10743 * | EqualityExpr '!=' RelationalExpr
10745 * A != B != C is allowed ? Answer from James, yes with
10746 * (RelationalExpr = RelationalExpr) = RelationalExpr
10747 * (RelationalExpr != RelationalExpr) != RelationalExpr
10748 * which is basically what got implemented.
10750 * Compile an Equality expression.
10754 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10755 xmlXPathCompRelationalExpr(ctxt);
10758 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10760 int op1 = ctxt->comp->last;
10762 if (CUR == '=') eq = 1;
10767 xmlXPathCompRelationalExpr(ctxt);
10769 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10775 * xmlXPathCompAndExpr:
10776 * @ctxt: the XPath Parser context
10778 * [22] AndExpr ::= EqualityExpr
10779 * | AndExpr 'and' EqualityExpr
10781 * Compile an AND expression.
10785 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10786 xmlXPathCompEqualityExpr(ctxt);
10789 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10790 int op1 = ctxt->comp->last;
10793 xmlXPathCompEqualityExpr(ctxt);
10795 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10801 * xmlXPathCompileExpr:
10802 * @ctxt: the XPath Parser context
10804 * [14] Expr ::= OrExpr
10805 * [21] OrExpr ::= AndExpr
10806 * | OrExpr 'or' AndExpr
10808 * Parse and compile an expression
10811 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10812 xmlXPathCompAndExpr(ctxt);
10815 while ((CUR == 'o') && (NXT(1) == 'r')) {
10816 int op1 = ctxt->comp->last;
10819 xmlXPathCompAndExpr(ctxt);
10821 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10822 op1 = ctxt->comp->nbStep;
10825 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10826 /* more ops could be optimized too */
10828 * This is the main place to eliminate sorting for
10829 * operations which don't require a sorted node-set.
10832 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10837 * xmlXPathCompPredicate:
10838 * @ctxt: the XPath Parser context
10839 * @filter: act as a filter
10841 * [8] Predicate ::= '[' PredicateExpr ']'
10842 * [9] PredicateExpr ::= Expr
10844 * Compile a predicate expression
10847 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10848 int op1 = ctxt->comp->last;
10852 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10857 ctxt->comp->last = -1;
10859 * This call to xmlXPathCompileExpr() will deactivate sorting
10860 * of the predicate result.
10861 * TODO: Sorting is still activated for filters, since I'm not
10862 * sure if needed. Normally sorting should not be needed, since
10863 * a filter can only diminish the number of items in a sequence,
10864 * but won't change its order; so if the initial sequence is sorted,
10865 * subsequent sorting is not needed.
10868 xmlXPathCompileExpr(ctxt, 0);
10870 xmlXPathCompileExpr(ctxt, 1);
10874 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10878 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10880 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10887 * xmlXPathCompNodeTest:
10888 * @ctxt: the XPath Parser context
10889 * @test: pointer to a xmlXPathTestVal
10890 * @type: pointer to a xmlXPathTypeVal
10891 * @prefix: placeholder for a possible name prefix
10893 * [7] NodeTest ::= NameTest
10894 * | NodeType '(' ')'
10895 * | 'processing-instruction' '(' Literal ')'
10897 * [37] NameTest ::= '*'
10900 * [38] NodeType ::= 'comment'
10902 * | 'processing-instruction'
10905 * Returns the name found and updates @test, @type and @prefix appropriately
10908 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10909 xmlXPathTypeVal *type, const xmlChar **prefix,
10913 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10917 *type = (xmlXPathTypeVal) 0;
10918 *test = (xmlXPathTestVal) 0;
10922 if ((name == NULL) && (CUR == '*')) {
10927 *test = NODE_TEST_ALL;
10932 name = xmlXPathParseNCName(ctxt);
10933 if (name == NULL) {
10934 XP_ERRORNULL(XPATH_EXPR_ERROR);
10937 blanks = IS_BLANK_CH(CUR);
10942 * NodeType or PI search
10944 if (xmlStrEqual(name, BAD_CAST "comment"))
10945 *type = NODE_TYPE_COMMENT;
10946 else if (xmlStrEqual(name, BAD_CAST "node"))
10947 *type = NODE_TYPE_NODE;
10948 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10949 *type = NODE_TYPE_PI;
10950 else if (xmlStrEqual(name, BAD_CAST "text"))
10951 *type = NODE_TYPE_TEXT;
10955 XP_ERRORNULL(XPATH_EXPR_ERROR);
10958 *test = NODE_TEST_TYPE;
10961 if (*type == NODE_TYPE_PI) {
10963 * Specific case: search a PI by name.
10969 name = xmlXPathParseLiteral(ctxt);
10971 *test = NODE_TEST_PI;
10978 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10983 *test = NODE_TEST_NAME;
10984 if ((!blanks) && (CUR == ':')) {
10988 * Since currently the parser context don't have a
10989 * namespace list associated:
10990 * The namespace name for this prefix can be computed
10991 * only at evaluation time. The compilation is done
10992 * outside of any context.
10995 *prefix = xmlXPathNsLookup(ctxt->context, name);
10998 if (*prefix == NULL) {
10999 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11010 *test = NODE_TEST_ALL;
11014 name = xmlXPathParseNCName(ctxt);
11015 if (name == NULL) {
11016 XP_ERRORNULL(XPATH_EXPR_ERROR);
11023 * xmlXPathIsAxisName:
11024 * @name: a preparsed name token
11026 * [6] AxisName ::= 'ancestor'
11027 * | 'ancestor-or-self'
11031 * | 'descendant-or-self'
11033 * | 'following-sibling'
11037 * | 'preceding-sibling'
11040 * Returns the axis or 0
11042 static xmlXPathAxisVal
11043 xmlXPathIsAxisName(const xmlChar *name) {
11044 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11047 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11048 ret = AXIS_ANCESTOR;
11049 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11050 ret = AXIS_ANCESTOR_OR_SELF;
11051 if (xmlStrEqual(name, BAD_CAST "attribute"))
11052 ret = AXIS_ATTRIBUTE;
11055 if (xmlStrEqual(name, BAD_CAST "child"))
11059 if (xmlStrEqual(name, BAD_CAST "descendant"))
11060 ret = AXIS_DESCENDANT;
11061 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11062 ret = AXIS_DESCENDANT_OR_SELF;
11065 if (xmlStrEqual(name, BAD_CAST "following"))
11066 ret = AXIS_FOLLOWING;
11067 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11068 ret = AXIS_FOLLOWING_SIBLING;
11071 if (xmlStrEqual(name, BAD_CAST "namespace"))
11072 ret = AXIS_NAMESPACE;
11075 if (xmlStrEqual(name, BAD_CAST "parent"))
11077 if (xmlStrEqual(name, BAD_CAST "preceding"))
11078 ret = AXIS_PRECEDING;
11079 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11080 ret = AXIS_PRECEDING_SIBLING;
11083 if (xmlStrEqual(name, BAD_CAST "self"))
11091 * xmlXPathCompStep:
11092 * @ctxt: the XPath Parser context
11094 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11095 * | AbbreviatedStep
11097 * [12] AbbreviatedStep ::= '.' | '..'
11099 * [5] AxisSpecifier ::= AxisName '::'
11100 * | AbbreviatedAxisSpecifier
11102 * [13] AbbreviatedAxisSpecifier ::= '@'?
11104 * Modified for XPtr range support as:
11106 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11107 * | AbbreviatedStep
11108 * | 'range-to' '(' Expr ')' Predicate*
11110 * Compile one step in a Location Path
11111 * A location step of . is short for self::node(). This is
11112 * particularly useful in conjunction with //. For example, the
11113 * location path .//para is short for
11114 * self::node()/descendant-or-self::node()/child::para
11115 * and so will select all para descendant elements of the context
11117 * Similarly, a location step of .. is short for parent::node().
11118 * For example, ../title is short for parent::node()/child::title
11119 * and so will select the title children of the parent of the context
11123 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11124 #ifdef LIBXML_XPTR_ENABLED
11130 if ((CUR == '.') && (NXT(1) == '.')) {
11133 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11134 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11135 } else if (CUR == '.') {
11139 xmlChar *name = NULL;
11140 const xmlChar *prefix = NULL;
11141 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11142 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11143 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11147 * The modification needed for XPointer change to the production
11149 #ifdef LIBXML_XPTR_ENABLED
11151 name = xmlXPathParseNCName(ctxt);
11152 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11153 op2 = ctxt->comp->last;
11157 XP_ERROR(XPATH_EXPR_ERROR);
11162 xmlXPathCompileExpr(ctxt, 1);
11163 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11168 XP_ERROR(XPATH_EXPR_ERROR);
11172 goto eval_predicates;
11180 name = xmlXPathParseNCName(ctxt);
11181 if (name != NULL) {
11182 axis = xmlXPathIsAxisName(name);
11185 if ((CUR == ':') && (NXT(1) == ':')) {
11190 /* an element name can conflict with an axis one :-\ */
11196 } else if (CUR == '@') {
11198 axis = AXIS_ATTRIBUTE;
11206 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11210 if ((prefix != NULL) && (ctxt->context != NULL) &&
11211 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11212 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11213 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11217 xmlGenericError(xmlGenericErrorContext,
11218 "Basis : computing new set\n");
11222 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11223 if (ctxt->value == NULL)
11224 xmlGenericError(xmlGenericErrorContext, "no value\n");
11225 else if (ctxt->value->nodesetval == NULL)
11226 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11228 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11231 #ifdef LIBXML_XPTR_ENABLED
11234 op1 = ctxt->comp->last;
11235 ctxt->comp->last = -1;
11238 while (CUR == '[') {
11239 xmlXPathCompPredicate(ctxt, 0);
11242 #ifdef LIBXML_XPTR_ENABLED
11244 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11247 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11248 test, type, (void *)prefix, (void *)name);
11252 xmlGenericError(xmlGenericErrorContext, "Step : ");
11253 if (ctxt->value == NULL)
11254 xmlGenericError(xmlGenericErrorContext, "no value\n");
11255 else if (ctxt->value->nodesetval == NULL)
11256 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11258 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11259 ctxt->value->nodesetval);
11264 * xmlXPathCompRelativeLocationPath:
11265 * @ctxt: the XPath Parser context
11267 * [3] RelativeLocationPath ::= Step
11268 * | RelativeLocationPath '/' Step
11269 * | AbbreviatedRelativeLocationPath
11270 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11272 * Compile a relative location path.
11275 xmlXPathCompRelativeLocationPath
11276 (xmlXPathParserContextPtr ctxt) {
11278 if ((CUR == '/') && (NXT(1) == '/')) {
11281 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11282 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11283 } else if (CUR == '/') {
11287 xmlXPathCompStep(ctxt);
11289 while (CUR == '/') {
11290 if ((CUR == '/') && (NXT(1) == '/')) {
11293 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11294 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11295 xmlXPathCompStep(ctxt);
11296 } else if (CUR == '/') {
11299 xmlXPathCompStep(ctxt);
11306 * xmlXPathCompLocationPath:
11307 * @ctxt: the XPath Parser context
11309 * [1] LocationPath ::= RelativeLocationPath
11310 * | AbsoluteLocationPath
11311 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11312 * | AbbreviatedAbsoluteLocationPath
11313 * [10] AbbreviatedAbsoluteLocationPath ::=
11314 * '//' RelativeLocationPath
11316 * Compile a location path
11318 * // is short for /descendant-or-self::node()/. For example,
11319 * //para is short for /descendant-or-self::node()/child::para and
11320 * so will select any para element in the document (even a para element
11321 * that is a document element will be selected by //para since the
11322 * document element node is a child of the root node); div//para is
11323 * short for div/descendant-or-self::node()/child::para and so will
11324 * select all para descendants of div children.
11327 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11330 xmlXPathCompRelativeLocationPath(ctxt);
11332 while (CUR == '/') {
11333 if ((CUR == '/') && (NXT(1) == '/')) {
11336 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11337 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11338 xmlXPathCompRelativeLocationPath(ctxt);
11339 } else if (CUR == '/') {
11343 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11344 (CUR == '@') || (CUR == '*')))
11345 xmlXPathCompRelativeLocationPath(ctxt);
11351 /************************************************************************
11353 * XPath precompiled expression evaluation *
11355 ************************************************************************/
11358 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11362 xmlXPathDebugDumpStepAxis(xmlXPathAxisVal axis,
11363 xmlXPathTestVal test,
11366 xmlGenericError(xmlGenericErrorContext, "new step : ");
11368 case AXIS_ANCESTOR:
11369 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11371 case AXIS_ANCESTOR_OR_SELF:
11372 xmlGenericError(xmlGenericErrorContext,
11373 "axis 'ancestors-or-self' ");
11375 case AXIS_ATTRIBUTE:
11376 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11379 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11381 case AXIS_DESCENDANT:
11382 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11384 case AXIS_DESCENDANT_OR_SELF:
11385 xmlGenericError(xmlGenericErrorContext,
11386 "axis 'descendant-or-self' ");
11388 case AXIS_FOLLOWING:
11389 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11391 case AXIS_FOLLOWING_SIBLING:
11392 xmlGenericError(xmlGenericErrorContext,
11393 "axis 'following-siblings' ");
11395 case AXIS_NAMESPACE:
11396 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11399 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11401 case AXIS_PRECEDING:
11402 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11404 case AXIS_PRECEDING_SIBLING:
11405 xmlGenericError(xmlGenericErrorContext,
11406 "axis 'preceding-sibling' ");
11409 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11412 xmlGenericError(xmlGenericErrorContext,
11413 " context contains %d nodes\n", nbNodes);
11415 case NODE_TEST_NONE:
11416 xmlGenericError(xmlGenericErrorContext,
11417 " searching for none !!!\n");
11419 case NODE_TEST_TYPE:
11420 xmlGenericError(xmlGenericErrorContext,
11421 " searching for type %d\n", type);
11424 xmlGenericError(xmlGenericErrorContext,
11425 " searching for PI !!!\n");
11427 case NODE_TEST_ALL:
11428 xmlGenericError(xmlGenericErrorContext,
11429 " searching for *\n");
11432 xmlGenericError(xmlGenericErrorContext,
11433 " searching for namespace %s\n",
11436 case NODE_TEST_NAME:
11437 xmlGenericError(xmlGenericErrorContext,
11438 " searching for name %s\n", name);
11439 if (prefix != NULL)
11440 xmlGenericError(xmlGenericErrorContext,
11441 " with namespace %s\n", prefix);
11444 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11446 #endif /* DEBUG_STEP */
11449 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11450 xmlXPathStepOpPtr op,
11455 if (op->ch1 != -1) {
11456 xmlXPathCompExprPtr comp = ctxt->comp;
11458 * Process inner predicates first.
11460 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11462 * TODO: raise an internal error.
11465 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11466 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11468 if (contextSize <= 0)
11471 if (op->ch2 != -1) {
11472 xmlXPathContextPtr xpctxt = ctxt->context;
11473 xmlNodePtr contextNode, oldContextNode;
11474 xmlDocPtr oldContextDoc;
11475 int i, res, contextPos = 0, newContextSize;
11476 xmlXPathStepOpPtr exprOp;
11477 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11479 #ifdef LIBXML_XPTR_ENABLED
11481 * URGENT TODO: Check the following:
11482 * We don't expect location sets if evaluating prediates, right?
11483 * Only filters should expect location sets, right?
11488 * "For each node in the node-set to be filtered, the
11489 * PredicateExpr is evaluated with that node as the
11490 * context node, with the number of nodes in the
11491 * node-set as the context size, and with the proximity
11492 * position of the node in the node-set with respect to
11493 * the axis as the context position;"
11494 * @oldset is the node-set" to be filtered.
11497 * "only predicates change the context position and
11498 * context size (see [2.4 Predicates])."
11500 * node-set context pos
11504 * After applying predicate [position() > 1] :
11505 * node-set context pos
11509 oldContextNode = xpctxt->node;
11510 oldContextDoc = xpctxt->doc;
11512 * Get the expression of this predicate.
11514 exprOp = &ctxt->comp->steps[op->ch2];
11515 newContextSize = 0;
11516 for (i = 0; i < set->nodeNr; i++) {
11517 if (set->nodeTab[i] == NULL)
11520 contextNode = set->nodeTab[i];
11521 xpctxt->node = contextNode;
11522 xpctxt->contextSize = contextSize;
11523 xpctxt->proximityPosition = ++contextPos;
11526 * Also set the xpath document in case things like
11527 * key() are evaluated in the predicate.
11529 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11530 (contextNode->doc != NULL))
11531 xpctxt->doc = contextNode->doc;
11533 * Evaluate the predicate expression with 1 context node
11534 * at a time; this node is packaged into a node set; this
11535 * node set is handed over to the evaluation mechanism.
11537 if (contextObj == NULL)
11538 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11540 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11543 valuePush(ctxt, contextObj);
11545 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11547 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
11548 goto evaluation_error;
11554 * Remove the entry from the initial node set.
11556 set->nodeTab[i] = NULL;
11557 if (contextNode->type == XML_NAMESPACE_DECL)
11558 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11560 if (ctxt->value == contextObj) {
11562 * Don't free the temporary XPath object holding the
11563 * context node, in order to avoid massive recreation
11564 * inside this loop.
11567 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11570 * TODO: The object was lost in the evaluation machinery.
11571 * Can this happen? Maybe in internal-error cases.
11576 goto evaluation_exit;
11579 xmlXPathNodeSetClear(set, hasNsNodes);
11580 newContextSize = 0;
11583 if (contextObj != NULL) {
11584 if (ctxt->value == contextObj)
11586 xmlXPathReleaseObject(xpctxt, contextObj);
11588 if (exprRes != NULL)
11589 xmlXPathReleaseObject(ctxt->context, exprRes);
11591 * Reset/invalidate the context.
11593 xpctxt->node = oldContextNode;
11594 xpctxt->doc = oldContextDoc;
11595 xpctxt->contextSize = -1;
11596 xpctxt->proximityPosition = -1;
11597 return(newContextSize);
11599 return(contextSize);
11603 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11604 xmlXPathStepOpPtr op,
11611 if (op->ch1 != -1) {
11612 xmlXPathCompExprPtr comp = ctxt->comp;
11613 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11615 * TODO: raise an internal error.
11618 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11619 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11621 if (contextSize <= 0)
11625 * Check if the node set contains a sufficient number of nodes for
11626 * the requested range.
11628 if (contextSize < minPos) {
11629 xmlXPathNodeSetClear(set, hasNsNodes);
11632 if (op->ch2 == -1) {
11634 * TODO: Can this ever happen?
11636 return (contextSize);
11638 xmlDocPtr oldContextDoc;
11639 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11640 xmlXPathStepOpPtr exprOp;
11641 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11642 xmlNodePtr oldContextNode, contextNode = NULL;
11643 xmlXPathContextPtr xpctxt = ctxt->context;
11645 #ifdef LIBXML_XPTR_ENABLED
11647 * URGENT TODO: Check the following:
11648 * We don't expect location sets if evaluating prediates, right?
11649 * Only filters should expect location sets, right?
11651 #endif /* LIBXML_XPTR_ENABLED */
11654 * Save old context.
11656 oldContextNode = xpctxt->node;
11657 oldContextDoc = xpctxt->doc;
11659 * Get the expression of this predicate.
11661 exprOp = &ctxt->comp->steps[op->ch2];
11662 for (i = 0; i < set->nodeNr; i++) {
11663 if (set->nodeTab[i] == NULL)
11666 contextNode = set->nodeTab[i];
11667 xpctxt->node = contextNode;
11668 xpctxt->contextSize = contextSize;
11669 xpctxt->proximityPosition = ++contextPos;
11672 * Initialize the new set.
11673 * Also set the xpath document in case things like
11674 * key() evaluation are attempted on the predicate
11676 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11677 (contextNode->doc != NULL))
11678 xpctxt->doc = contextNode->doc;
11680 * Evaluate the predicate expression with 1 context node
11681 * at a time; this node is packaged into a node set; this
11682 * node set is handed over to the evaluation mechanism.
11684 if (contextObj == NULL)
11685 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11687 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11690 valuePush(ctxt, contextObj);
11691 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11693 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1))
11694 goto evaluation_error;
11699 if (res && (pos >= minPos) && (pos <= maxPos)) {
11701 * Fits in the requested range.
11704 if (minPos == maxPos) {
11706 * Only 1 node was requested.
11708 if (contextNode->type == XML_NAMESPACE_DECL) {
11710 * As always: take care of those nasty
11713 set->nodeTab[i] = NULL;
11715 xmlXPathNodeSetClear(set, hasNsNodes);
11717 set->nodeTab[0] = contextNode;
11718 goto evaluation_exit;
11720 if (pos == maxPos) {
11724 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11725 goto evaluation_exit;
11729 * Remove the entry from the initial node set.
11731 set->nodeTab[i] = NULL;
11732 if (contextNode->type == XML_NAMESPACE_DECL)
11733 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11735 if (exprRes != NULL) {
11736 xmlXPathReleaseObject(ctxt->context, exprRes);
11739 if (ctxt->value == contextObj) {
11741 * Don't free the temporary XPath object holding the
11742 * context node, in order to avoid massive recreation
11743 * inside this loop.
11746 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11749 * The object was lost in the evaluation machinery.
11750 * Can this happen? Maybe in case of internal-errors.
11755 goto evaluation_exit;
11758 xmlXPathNodeSetClear(set, hasNsNodes);
11759 newContextSize = 0;
11762 if (contextObj != NULL) {
11763 if (ctxt->value == contextObj)
11765 xmlXPathReleaseObject(xpctxt, contextObj);
11767 if (exprRes != NULL)
11768 xmlXPathReleaseObject(ctxt->context, exprRes);
11770 * Reset/invalidate the context.
11772 xpctxt->node = oldContextNode;
11773 xpctxt->doc = oldContextDoc;
11774 xpctxt->contextSize = -1;
11775 xpctxt->proximityPosition = -1;
11776 return(newContextSize);
11778 return(contextSize);
11782 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11783 xmlXPathStepOpPtr op,
11787 xmlXPathStepOpPtr exprOp;
11790 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11794 * If not -1, then ch1 will point to:
11795 * 1) For predicates (XPATH_OP_PREDICATE):
11796 * - an inner predicate operator
11797 * 2) For filters (XPATH_OP_FILTER):
11798 * - an inner filter operater OR
11799 * - an expression selecting the node set.
11800 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11802 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11805 if (op->ch2 != -1) {
11806 exprOp = &ctxt->comp->steps[op->ch2];
11810 if ((exprOp != NULL) &&
11811 (exprOp->op == XPATH_OP_VALUE) &&
11812 (exprOp->value4 != NULL) &&
11813 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11816 * We have a "[n]" predicate here.
11817 * TODO: Unfortunately this simplistic test here is not
11818 * able to detect a position() predicate in compound
11819 * expressions like "[@attr = 'a" and position() = 1],
11820 * and even not the usage of position() in
11821 * "[position() = 1]"; thus - obviously - a position-range,
11822 * like it "[position() < 5]", is also not detected.
11823 * Maybe we could rewrite the AST to ease the optimization.
11825 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11827 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11837 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11838 xmlXPathStepOpPtr op,
11839 xmlNodePtr * first, xmlNodePtr * last,
11843 #define XP_TEST_HIT \
11844 if (hasAxisRange != 0) { \
11845 if (++pos == maxPos) { \
11846 addNode(seq, cur); \
11847 goto axis_range_end; } \
11849 addNode(seq, cur); \
11850 if (breakOnFirstHit) goto first_hit; }
11852 #define XP_TEST_HIT_NS \
11853 if (hasAxisRange != 0) { \
11854 if (++pos == maxPos) { \
11856 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11857 goto axis_range_end; } \
11860 xmlXPathNodeSetAddNs(seq, \
11861 xpctxt->node, (xmlNsPtr) cur); \
11862 if (breakOnFirstHit) goto first_hit; }
11864 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11865 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11866 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11867 const xmlChar *prefix = op->value4;
11868 const xmlChar *name = op->value5;
11869 const xmlChar *URI = NULL;
11872 int nbMatches = 0, prevMatches = 0;
11874 int total = 0, hasNsNodes = 0;
11875 /* The popped object holding the context nodes */
11876 xmlXPathObjectPtr obj;
11877 /* The set of context nodes for the node tests */
11878 xmlNodeSetPtr contextSeq;
11880 xmlNodePtr contextNode;
11881 /* The context node for a compound traversal */
11882 xmlNodePtr outerContextNode;
11883 /* The final resulting node set wrt to all context nodes */
11884 xmlNodeSetPtr outSeq;
11886 * The temporary resulting node set wrt 1 context node.
11887 * Used to feed predicate evaluation.
11891 /* First predicate operator */
11892 xmlXPathStepOpPtr predOp;
11893 int maxPos; /* The requested position() (when a "[n]" predicate) */
11894 int hasPredicateRange, hasAxisRange, pos, size, newSize;
11895 int breakOnFirstHit;
11897 xmlXPathTraversalFunction next = NULL;
11898 /* compound axis traversal */
11899 xmlXPathTraversalFunctionExt outerNext = NULL;
11900 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11901 xmlXPathNodeSetMergeFunction mergeAndClear;
11902 xmlNodePtr oldContextNode;
11903 xmlXPathContextPtr xpctxt = ctxt->context;
11906 CHECK_TYPE0(XPATH_NODESET);
11907 obj = valuePop(ctxt);
11909 * Setup namespaces.
11911 if (prefix != NULL) {
11912 URI = xmlXPathNsLookup(xpctxt, prefix);
11914 xmlXPathReleaseObject(xpctxt, obj);
11915 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11921 * MAYBE FUTURE TODO: merging optimizations:
11922 * - If the nodes to be traversed wrt to the initial nodes and
11923 * the current axis cannot overlap, then we could avoid searching
11924 * for duplicates during the merge.
11925 * But the question is how/when to evaluate if they cannot overlap.
11926 * Example: if we know that for two initial nodes, the one is
11927 * not in the ancestor-or-self axis of the other, then we could safely
11928 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11929 * the descendant-or-self axis.
11931 addNode = xmlXPathNodeSetAdd;
11932 mergeAndClear = xmlXPathNodeSetMergeAndClear;
11934 case AXIS_ANCESTOR:
11936 next = xmlXPathNextAncestor;
11938 case AXIS_ANCESTOR_OR_SELF:
11940 next = xmlXPathNextAncestorOrSelf;
11942 case AXIS_ATTRIBUTE:
11945 next = xmlXPathNextAttribute;
11946 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11950 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
11952 * This iterator will give us only nodes which can
11953 * hold element nodes.
11955 outerNext = xmlXPathNextDescendantOrSelfElemParent;
11957 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11958 (type == NODE_TYPE_NODE))
11961 * Optimization if an element node type is 'element'.
11963 next = xmlXPathNextChildElement;
11965 next = xmlXPathNextChild;
11966 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11968 case AXIS_DESCENDANT:
11970 next = xmlXPathNextDescendant;
11972 case AXIS_DESCENDANT_OR_SELF:
11974 next = xmlXPathNextDescendantOrSelf;
11976 case AXIS_FOLLOWING:
11978 next = xmlXPathNextFollowing;
11980 case AXIS_FOLLOWING_SIBLING:
11982 next = xmlXPathNextFollowingSibling;
11984 case AXIS_NAMESPACE:
11987 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11988 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11992 next = xmlXPathNextParent;
11994 case AXIS_PRECEDING:
11996 next = xmlXPathNextPrecedingInternal;
11998 case AXIS_PRECEDING_SIBLING:
12000 next = xmlXPathNextPrecedingSibling;
12005 next = xmlXPathNextSelf;
12006 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12011 xmlXPathDebugDumpStepAxis(axis, test,
12012 (obj->nodesetval != NULL) ? obj->nodsetval->nodeNr : 0);
12015 if (next == NULL) {
12016 xmlXPathReleaseObject(xpctxt, obj);
12019 contextSeq = obj->nodesetval;
12020 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12021 xmlXPathReleaseObject(xpctxt, obj);
12022 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12026 * Predicate optimization ---------------------------------------------
12027 * If this step has a last predicate, which contains a position(),
12028 * then we'll optimize (although not exactly "position()", but only
12029 * the short-hand form, i.e., "[n]".
12031 * Example - expression "/foo[parent::bar][1]":
12033 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12035 * PREDICATE -- op->ch2 (predOp)
12036 * PREDICATE -- predOp->ch1 = [parent::bar]
12038 * COLLECT 'parent' 'name' 'node' bar
12040 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12045 hasPredicateRange = 0;
12047 if (op->ch2 != -1) {
12049 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12051 predOp = &ctxt->comp->steps[op->ch2];
12052 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12053 if (predOp->ch1 != -1) {
12055 * Use the next inner predicate operator.
12057 predOp = &ctxt->comp->steps[predOp->ch1];
12058 hasPredicateRange = 1;
12061 * There's no other predicate than the [n] predicate.
12068 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12070 * Axis traversal -----------------------------------------------------
12074 * - For the attribute axis, the principal node type is attribute.
12075 * - For the namespace axis, the principal node type is namespace.
12076 * - For other axes, the principal node type is element.
12078 * A node test * is true for any node of the
12079 * principal node type. For example, child::* will
12080 * select all element children of the context node
12082 oldContextNode = xpctxt->node;
12083 addNode = xmlXPathNodeSetAddUnique;
12086 outerContextNode = NULL;
12087 contextNode = NULL;
12091 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12092 if (outerNext != NULL) {
12094 * This is a compound traversal.
12096 if (contextNode == NULL) {
12098 * Set the context for the outer traversal.
12100 outerContextNode = contextSeq->nodeTab[contextIdx++];
12101 contextNode = outerNext(NULL, outerContextNode);
12103 contextNode = outerNext(contextNode, outerContextNode);
12104 if (contextNode == NULL)
12107 * Set the context for the main traversal.
12109 xpctxt->node = contextNode;
12111 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12114 seq = xmlXPathNodeSetCreate(NULL);
12121 * Traverse the axis and test the nodes.
12127 cur = next(ctxt, cur);
12132 * QUESTION TODO: What does the "first" and "last" stuff do?
12134 if ((first != NULL) && (*first != NULL)) {
12137 if (((total % 256) == 0) &&
12138 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12139 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12141 (xmlXPathCmpNodes(*first, cur) >= 0))
12147 if ((last != NULL) && (*last != NULL)) {
12150 if (((total % 256) == 0) &&
12151 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12152 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12154 (xmlXPathCmpNodes(cur, *last) >= 0))
12164 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12167 case NODE_TEST_NONE:
12171 case NODE_TEST_TYPE:
12173 * TODO: Don't we need to use
12174 * xmlXPathNodeSetAddNs() for namespace nodes here?
12175 * Surprisingly, some c14n tests fail, if we do this.
12177 if (type == NODE_TYPE_NODE) {
12178 switch (cur->type) {
12179 case XML_DOCUMENT_NODE:
12180 case XML_HTML_DOCUMENT_NODE:
12181 #ifdef LIBXML_DOCB_ENABLED
12182 case XML_DOCB_DOCUMENT_NODE:
12184 case XML_ELEMENT_NODE:
12185 case XML_ATTRIBUTE_NODE:
12187 case XML_COMMENT_NODE:
12188 case XML_CDATA_SECTION_NODE:
12189 case XML_TEXT_NODE:
12190 case XML_NAMESPACE_DECL:
12196 } else if (cur->type == type) {
12197 if (type == XML_NAMESPACE_DECL)
12201 } else if ((type == NODE_TYPE_TEXT) &&
12202 (cur->type == XML_CDATA_SECTION_NODE))
12208 if ((cur->type == XML_PI_NODE) &&
12209 ((name == NULL) || xmlStrEqual(name, cur->name)))
12214 case NODE_TEST_ALL:
12215 if (axis == AXIS_ATTRIBUTE) {
12216 if (cur->type == XML_ATTRIBUTE_NODE)
12220 } else if (axis == AXIS_NAMESPACE) {
12221 if (cur->type == XML_NAMESPACE_DECL)
12226 if (cur->type == XML_ELEMENT_NODE) {
12227 if (prefix == NULL)
12231 } else if ((cur->ns != NULL) &&
12232 (xmlStrEqual(URI, cur->ns->href)))
12239 case NODE_TEST_NS:{
12243 case NODE_TEST_NAME:
12244 switch (cur->type) {
12245 case XML_ELEMENT_NODE:
12246 if (xmlStrEqual(name, cur->name)) {
12247 if (prefix == NULL) {
12248 if (cur->ns == NULL)
12253 if ((cur->ns != NULL) &&
12254 (xmlStrEqual(URI, cur->ns->href)))
12261 case XML_ATTRIBUTE_NODE:{
12262 xmlAttrPtr attr = (xmlAttrPtr) cur;
12264 if (xmlStrEqual(name, attr->name)) {
12265 if (prefix == NULL) {
12266 if ((attr->ns == NULL) ||
12267 (attr->ns->prefix == NULL))
12272 if ((attr->ns != NULL) &&
12282 case XML_NAMESPACE_DECL:
12283 if (cur->type == XML_NAMESPACE_DECL) {
12284 xmlNsPtr ns = (xmlNsPtr) cur;
12286 if ((ns->prefix != NULL) && (name != NULL)
12287 && (xmlStrEqual(ns->prefix, name)))
12297 } /* switch(test) */
12298 } while (cur != NULL);
12300 goto apply_predicates;
12302 axis_range_end: /* ----------------------------------------------------- */
12304 * We have a "/foo[n]", and position() = n was reached.
12305 * Note that we can have as well "/foo/::parent::foo[1]", so
12306 * a duplicate-aware merge is still needed.
12307 * Merge with the result.
12309 if (outSeq == NULL) {
12313 outSeq = mergeAndClear(outSeq, seq, 0);
12315 * Break if only a true/false result was requested.
12321 first_hit: /* ---------------------------------------------------------- */
12323 * Break if only a true/false result was requested and
12324 * no predicates existed and a node test succeeded.
12326 if (outSeq == NULL) {
12330 outSeq = mergeAndClear(outSeq, seq, 0);
12335 nbMatches += seq->nodeNr;
12338 apply_predicates: /* --------------------------------------------------- */
12340 * Apply predicates.
12342 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12344 * E.g. when we have a "/foo[some expression][n]".
12347 * QUESTION TODO: The old predicate evaluation took into
12348 * account location-sets.
12349 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12350 * Do we expect such a set here?
12351 * All what I learned now from the evaluation semantics
12352 * does not indicate that a location-set will be processed
12353 * here, so this looks OK.
12356 * Iterate over all predicates, starting with the outermost
12358 * TODO: Problem: we cannot execute the inner predicates first
12359 * since we cannot go back *up* the operator tree!
12361 * 1) Use of recursive functions (like is it currently done
12362 * via xmlXPathCompOpEval())
12363 * 2) Add a predicate evaluation information stack to the
12365 * 3) Change the way the operators are linked; we need a
12366 * "parent" field on xmlXPathStepOp
12368 * For the moment, I'll try to solve this with a recursive
12369 * function: xmlXPathCompOpEvalPredicate().
12371 size = seq->nodeNr;
12372 if (hasPredicateRange != 0)
12373 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12374 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12376 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12377 predOp, seq, size, hasNsNodes);
12379 if (ctxt->error != XPATH_EXPRESSION_OK) {
12384 * Add the filtered set of nodes to the result node set.
12386 if (newSize == 0) {
12388 * The predicates filtered all nodes out.
12390 xmlXPathNodeSetClear(seq, hasNsNodes);
12391 } else if (seq->nodeNr > 0) {
12393 * Add to result set.
12395 if (outSeq == NULL) {
12396 if (size != newSize) {
12398 * We need to merge and clear here, since
12399 * the sequence will contained NULLed entries.
12401 outSeq = mergeAndClear(NULL, seq, 1);
12407 outSeq = mergeAndClear(outSeq, seq,
12408 (size != newSize) ? 1: 0);
12410 * Break if only a true/false result was requested.
12415 } else if (seq->nodeNr > 0) {
12417 * Add to result set.
12419 if (outSeq == NULL) {
12423 outSeq = mergeAndClear(outSeq, seq, 0);
12429 if ((obj->boolval) && (obj->user != NULL)) {
12431 * QUESTION TODO: What does this do and why?
12432 * TODO: Do we have to do this also for the "error"
12433 * cleanup further down?
12435 ctxt->value->boolval = 1;
12436 ctxt->value->user = obj->user;
12440 xmlXPathReleaseObject(xpctxt, obj);
12443 * Ensure we return at least an emtpy set.
12445 if (outSeq == NULL) {
12446 if ((seq != NULL) && (seq->nodeNr == 0))
12449 outSeq = xmlXPathNodeSetCreate(NULL);
12451 if ((seq != NULL) && (seq != outSeq)) {
12452 xmlXPathFreeNodeSet(seq);
12455 * Hand over the result. Better to push the set also in
12458 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12460 * Reset the context node.
12462 xpctxt->node = oldContextNode;
12465 xmlGenericError(xmlGenericErrorContext,
12466 "\nExamined %d nodes, found %d nodes at that step\n",
12474 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12475 xmlXPathStepOpPtr op, xmlNodePtr * first);
12478 * xmlXPathCompOpEvalFirst:
12479 * @ctxt: the XPath parser context with the compiled expression
12480 * @op: an XPath compiled operation
12481 * @first: the first elem found so far
12483 * Evaluate the Precompiled XPath operation searching only the first
12484 * element in document order
12486 * Returns the number of examined objects.
12489 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12490 xmlXPathStepOpPtr op, xmlNodePtr * first)
12492 int total = 0, cur;
12493 xmlXPathCompExprPtr comp;
12494 xmlXPathObjectPtr arg1, arg2;
12501 case XPATH_OP_UNION:
12503 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12506 if ((ctxt->value != NULL)
12507 && (ctxt->value->type == XPATH_NODESET)
12508 && (ctxt->value->nodesetval != NULL)
12509 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12511 * limit tree traversing to first node in the result
12514 * OPTIMIZE TODO: This implicitely sorts
12515 * the result, even if not needed. E.g. if the argument
12516 * of the count() function, no sorting is needed.
12517 * OPTIMIZE TODO: How do we know if the node-list wasn't
12520 if (ctxt->value->nodesetval->nodeNr > 1)
12521 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12522 *first = ctxt->value->nodesetval->nodeTab[0];
12525 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12528 CHECK_TYPE0(XPATH_NODESET);
12529 arg2 = valuePop(ctxt);
12531 CHECK_TYPE0(XPATH_NODESET);
12532 arg1 = valuePop(ctxt);
12534 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12536 valuePush(ctxt, arg1);
12537 xmlXPathReleaseObject(ctxt->context, arg2);
12540 xmlXPathCompSwap(op);
12541 return (total + cur);
12542 case XPATH_OP_ROOT:
12543 xmlXPathRoot(ctxt);
12545 case XPATH_OP_NODE:
12547 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12550 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12552 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12553 ctxt->context->node));
12555 case XPATH_OP_RESET:
12557 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12560 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12562 ctxt->context->node = NULL;
12564 case XPATH_OP_COLLECT:{
12568 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12571 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12574 case XPATH_OP_VALUE:
12576 xmlXPathCacheObjectCopy(ctxt->context,
12577 (xmlXPathObjectPtr) op->value4));
12579 case XPATH_OP_SORT:
12582 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12585 if ((ctxt->value != NULL)
12586 && (ctxt->value->type == XPATH_NODESET)
12587 && (ctxt->value->nodesetval != NULL)
12588 && (ctxt->value->nodesetval->nodeNr > 1))
12589 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12591 #ifdef XP_OPTIMIZED_FILTER_FIRST
12592 case XPATH_OP_FILTER:
12593 total =+ xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12597 return (xmlXPathCompOpEval(ctxt, op));
12602 * xmlXPathCompOpEvalLast:
12603 * @ctxt: the XPath parser context with the compiled expression
12604 * @op: an XPath compiled operation
12605 * @last: the last elem found so far
12607 * Evaluate the Precompiled XPath operation searching only the last
12608 * element in document order
12610 * Returns the number of nodes traversed
12613 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12616 int total = 0, cur;
12617 xmlXPathCompExprPtr comp;
12618 xmlXPathObjectPtr arg1, arg2;
12629 case XPATH_OP_UNION:
12630 bakd = ctxt->context->doc;
12631 bak = ctxt->context->node;
12632 pp = ctxt->context->proximityPosition;
12633 cs = ctxt->context->contextSize;
12635 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12637 if ((ctxt->value != NULL)
12638 && (ctxt->value->type == XPATH_NODESET)
12639 && (ctxt->value->nodesetval != NULL)
12640 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12642 * limit tree traversing to first node in the result
12644 if (ctxt->value->nodesetval->nodeNr > 1)
12645 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12647 ctxt->value->nodesetval->nodeTab[ctxt->value->
12648 nodesetval->nodeNr -
12651 ctxt->context->doc = bakd;
12652 ctxt->context->node = bak;
12653 ctxt->context->proximityPosition = pp;
12654 ctxt->context->contextSize = cs;
12656 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12658 if ((ctxt->value != NULL)
12659 && (ctxt->value->type == XPATH_NODESET)
12660 && (ctxt->value->nodesetval != NULL)
12661 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12663 CHECK_TYPE0(XPATH_NODESET);
12664 arg2 = valuePop(ctxt);
12666 CHECK_TYPE0(XPATH_NODESET);
12667 arg1 = valuePop(ctxt);
12669 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12671 valuePush(ctxt, arg1);
12672 xmlXPathReleaseObject(ctxt->context, arg2);
12675 xmlXPathCompSwap(op);
12676 return (total + cur);
12677 case XPATH_OP_ROOT:
12678 xmlXPathRoot(ctxt);
12680 case XPATH_OP_NODE:
12682 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12685 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12687 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12688 ctxt->context->node));
12690 case XPATH_OP_RESET:
12692 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12697 ctxt->context->node = NULL;
12699 case XPATH_OP_COLLECT:{
12703 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12706 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12709 case XPATH_OP_VALUE:
12711 xmlXPathCacheObjectCopy(ctxt->context,
12712 (xmlXPathObjectPtr) op->value4));
12714 case XPATH_OP_SORT:
12717 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12720 if ((ctxt->value != NULL)
12721 && (ctxt->value->type == XPATH_NODESET)
12722 && (ctxt->value->nodesetval != NULL)
12723 && (ctxt->value->nodesetval->nodeNr > 1))
12724 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12727 return (xmlXPathCompOpEval(ctxt, op));
12731 #ifdef XP_OPTIMIZED_FILTER_FIRST
12733 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12734 xmlXPathStepOpPtr op, xmlNodePtr * first)
12737 xmlXPathCompExprPtr comp;
12738 xmlXPathObjectPtr res;
12739 xmlXPathObjectPtr obj;
12740 xmlNodeSetPtr oldset;
12741 xmlNodePtr oldnode;
12748 * Optimization for ()[last()] selection i.e. the last elem
12750 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12751 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12752 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12753 int f = comp->steps[op->ch2].ch1;
12756 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12757 (comp->steps[f].value5 == NULL) &&
12758 (comp->steps[f].value == 0) &&
12759 (comp->steps[f].value4 != NULL) &&
12761 (comp->steps[f].value4, BAD_CAST "last"))) {
12762 xmlNodePtr last = NULL;
12765 xmlXPathCompOpEvalLast(ctxt,
12766 &comp->steps[op->ch1],
12770 * The nodeset should be in document order,
12771 * Keep only the last value
12773 if ((ctxt->value != NULL) &&
12774 (ctxt->value->type == XPATH_NODESET) &&
12775 (ctxt->value->nodesetval != NULL) &&
12776 (ctxt->value->nodesetval->nodeTab != NULL) &&
12777 (ctxt->value->nodesetval->nodeNr > 1)) {
12778 ctxt->value->nodesetval->nodeTab[0] =
12779 ctxt->value->nodesetval->nodeTab[ctxt->
12784 ctxt->value->nodesetval->nodeNr = 1;
12785 *first = *(ctxt->value->nodesetval->nodeTab);
12792 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12796 if (ctxt->value == NULL)
12799 #ifdef LIBXML_XPTR_ENABLED
12800 oldnode = ctxt->context->node;
12802 * Hum are we filtering the result of an XPointer expression
12804 if (ctxt->value->type == XPATH_LOCATIONSET) {
12805 xmlXPathObjectPtr tmp = NULL;
12806 xmlLocationSetPtr newlocset = NULL;
12807 xmlLocationSetPtr oldlocset;
12810 * Extract the old locset, and then evaluate the result of the
12811 * expression for all the element in the locset. use it to grow
12814 CHECK_TYPE0(XPATH_LOCATIONSET);
12815 obj = valuePop(ctxt);
12816 oldlocset = obj->user;
12817 ctxt->context->node = NULL;
12819 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12820 ctxt->context->contextSize = 0;
12821 ctxt->context->proximityPosition = 0;
12823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12824 res = valuePop(ctxt);
12826 xmlXPathReleaseObject(ctxt->context, res);
12828 valuePush(ctxt, obj);
12832 newlocset = xmlXPtrLocationSetCreate(NULL);
12834 for (i = 0; i < oldlocset->locNr; i++) {
12836 * Run the evaluation with a node list made of a
12837 * single item in the nodelocset.
12839 ctxt->context->node = oldlocset->locTab[i]->user;
12840 ctxt->context->contextSize = oldlocset->locNr;
12841 ctxt->context->proximityPosition = i + 1;
12843 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12844 ctxt->context->node);
12846 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12847 ctxt->context->node);
12849 valuePush(ctxt, tmp);
12851 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12852 if (ctxt->error != XPATH_EXPRESSION_OK) {
12853 xmlXPathFreeObject(obj);
12857 * The result of the evaluation need to be tested to
12858 * decided whether the filter succeeded or not
12860 res = valuePop(ctxt);
12861 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12862 xmlXPtrLocationSetAdd(newlocset,
12863 xmlXPathCacheObjectCopy(ctxt->context,
12864 oldlocset->locTab[i]));
12870 xmlXPathReleaseObject(ctxt->context, res);
12872 if (ctxt->value == tmp) {
12874 xmlXPathNodeSetClear(tmp->nodesetval, 1);
12876 * REVISIT TODO: Don't create a temporary nodeset
12877 * for everly iteration.
12879 /* OLD: xmlXPathFreeObject(res); */
12882 ctxt->context->node = NULL;
12884 * Only put the first node in the result, then leave.
12886 if (newlocset->locNr > 0) {
12887 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12892 xmlXPathReleaseObject(ctxt->context, tmp);
12895 * The result is used as the new evaluation locset.
12897 xmlXPathReleaseObject(ctxt->context, obj);
12898 ctxt->context->node = NULL;
12899 ctxt->context->contextSize = -1;
12900 ctxt->context->proximityPosition = -1;
12901 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12902 ctxt->context->node = oldnode;
12905 #endif /* LIBXML_XPTR_ENABLED */
12908 * Extract the old set, and then evaluate the result of the
12909 * expression for all the element in the set. use it to grow
12912 CHECK_TYPE0(XPATH_NODESET);
12913 obj = valuePop(ctxt);
12914 oldset = obj->nodesetval;
12916 oldnode = ctxt->context->node;
12917 oldDoc = ctxt->context->doc;
12918 ctxt->context->node = NULL;
12920 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
12921 ctxt->context->contextSize = 0;
12922 ctxt->context->proximityPosition = 0;
12923 /* QUESTION TODO: Why was this code commented out?
12926 xmlXPathCompOpEval(ctxt,
12927 &comp->steps[op->ch2]);
12929 res = valuePop(ctxt);
12931 xmlXPathFreeObject(res);
12933 valuePush(ctxt, obj);
12934 ctxt->context->node = oldnode;
12937 xmlNodeSetPtr newset;
12938 xmlXPathObjectPtr tmp = NULL;
12940 * Initialize the new set.
12941 * Also set the xpath document in case things like
12942 * key() evaluation are attempted on the predicate
12944 newset = xmlXPathNodeSetCreate(NULL);
12946 for (i = 0; i < oldset->nodeNr; i++) {
12948 * Run the evaluation with a node list made of
12949 * a single item in the nodeset.
12951 ctxt->context->node = oldset->nodeTab[i];
12952 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
12953 (oldset->nodeTab[i]->doc != NULL))
12954 ctxt->context->doc = oldset->nodeTab[i]->doc;
12956 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12957 ctxt->context->node);
12959 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12960 ctxt->context->node);
12962 valuePush(ctxt, tmp);
12963 ctxt->context->contextSize = oldset->nodeNr;
12964 ctxt->context->proximityPosition = i + 1;
12966 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12967 if (ctxt->error != XPATH_EXPRESSION_OK) {
12968 xmlXPathFreeNodeSet(newset);
12969 xmlXPathFreeObject(obj);
12973 * The result of the evaluation needs to be tested to
12974 * decide whether the filter succeeded or not
12976 res = valuePop(ctxt);
12977 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12978 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
12984 xmlXPathReleaseObject(ctxt->context, res);
12986 if (ctxt->value == tmp) {
12989 * Don't free the temporary nodeset
12990 * in order to avoid massive recreation inside this
12993 xmlXPathNodeSetClear(tmp->nodesetval, 1);
12996 ctxt->context->node = NULL;
12998 * Only put the first node in the result, then leave.
13000 if (newset->nodeNr > 0) {
13001 *first = *(newset->nodeTab);
13006 xmlXPathReleaseObject(ctxt->context, tmp);
13009 * The result is used as the new evaluation set.
13011 xmlXPathReleaseObject(ctxt->context, obj);
13012 ctxt->context->node = NULL;
13013 ctxt->context->contextSize = -1;
13014 ctxt->context->proximityPosition = -1;
13015 /* may want to move this past the '}' later */
13016 ctxt->context->doc = oldDoc;
13017 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13019 ctxt->context->node = oldnode;
13022 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13025 * xmlXPathCompOpEval:
13026 * @ctxt: the XPath parser context with the compiled expression
13027 * @op: an XPath compiled operation
13029 * Evaluate the Precompiled XPath operation
13030 * Returns the number of nodes traversed
13033 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13037 xmlXPathCompExprPtr comp;
13038 xmlXPathObjectPtr arg1, arg2;
13050 bakd = ctxt->context->doc;
13051 bak = ctxt->context->node;
13052 pp = ctxt->context->proximityPosition;
13053 cs = ctxt->context->contextSize;
13054 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13056 xmlXPathBooleanFunction(ctxt, 1);
13057 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13059 arg2 = valuePop(ctxt);
13060 ctxt->context->doc = bakd;
13061 ctxt->context->node = bak;
13062 ctxt->context->proximityPosition = pp;
13063 ctxt->context->contextSize = cs;
13064 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13066 xmlXPathFreeObject(arg2);
13069 xmlXPathBooleanFunction(ctxt, 1);
13070 arg1 = valuePop(ctxt);
13071 arg1->boolval &= arg2->boolval;
13072 valuePush(ctxt, arg1);
13073 xmlXPathReleaseObject(ctxt->context, arg2);
13076 bakd = ctxt->context->doc;
13077 bak = ctxt->context->node;
13078 pp = ctxt->context->proximityPosition;
13079 cs = ctxt->context->contextSize;
13080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13082 xmlXPathBooleanFunction(ctxt, 1);
13083 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13085 arg2 = valuePop(ctxt);
13086 ctxt->context->doc = bakd;
13087 ctxt->context->node = bak;
13088 ctxt->context->proximityPosition = pp;
13089 ctxt->context->contextSize = cs;
13090 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13092 xmlXPathFreeObject(arg2);
13095 xmlXPathBooleanFunction(ctxt, 1);
13096 arg1 = valuePop(ctxt);
13097 arg1->boolval |= arg2->boolval;
13098 valuePush(ctxt, arg1);
13099 xmlXPathReleaseObject(ctxt->context, arg2);
13101 case XPATH_OP_EQUAL:
13102 bakd = ctxt->context->doc;
13103 bak = ctxt->context->node;
13104 pp = ctxt->context->proximityPosition;
13105 cs = ctxt->context->contextSize;
13106 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13108 ctxt->context->doc = bakd;
13109 ctxt->context->node = bak;
13110 ctxt->context->proximityPosition = pp;
13111 ctxt->context->contextSize = cs;
13112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13115 equal = xmlXPathEqualValues(ctxt);
13117 equal = xmlXPathNotEqualValues(ctxt);
13118 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13121 bakd = ctxt->context->doc;
13122 bak = ctxt->context->node;
13123 pp = ctxt->context->proximityPosition;
13124 cs = ctxt->context->contextSize;
13125 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13127 ctxt->context->doc = bakd;
13128 ctxt->context->node = bak;
13129 ctxt->context->proximityPosition = pp;
13130 ctxt->context->contextSize = cs;
13131 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13133 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13134 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13136 case XPATH_OP_PLUS:
13137 bakd = ctxt->context->doc;
13138 bak = ctxt->context->node;
13139 pp = ctxt->context->proximityPosition;
13140 cs = ctxt->context->contextSize;
13141 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13143 if (op->ch2 != -1) {
13144 ctxt->context->doc = bakd;
13145 ctxt->context->node = bak;
13146 ctxt->context->proximityPosition = pp;
13147 ctxt->context->contextSize = cs;
13148 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13151 if (op->value == 0)
13152 xmlXPathSubValues(ctxt);
13153 else if (op->value == 1)
13154 xmlXPathAddValues(ctxt);
13155 else if (op->value == 2)
13156 xmlXPathValueFlipSign(ctxt);
13157 else if (op->value == 3) {
13159 CHECK_TYPE0(XPATH_NUMBER);
13162 case XPATH_OP_MULT:
13163 bakd = ctxt->context->doc;
13164 bak = ctxt->context->node;
13165 pp = ctxt->context->proximityPosition;
13166 cs = ctxt->context->contextSize;
13167 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13169 ctxt->context->doc = bakd;
13170 ctxt->context->node = bak;
13171 ctxt->context->proximityPosition = pp;
13172 ctxt->context->contextSize = cs;
13173 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13175 if (op->value == 0)
13176 xmlXPathMultValues(ctxt);
13177 else if (op->value == 1)
13178 xmlXPathDivValues(ctxt);
13179 else if (op->value == 2)
13180 xmlXPathModValues(ctxt);
13182 case XPATH_OP_UNION:
13183 bakd = ctxt->context->doc;
13184 bak = ctxt->context->node;
13185 pp = ctxt->context->proximityPosition;
13186 cs = ctxt->context->contextSize;
13187 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13189 ctxt->context->doc = bakd;
13190 ctxt->context->node = bak;
13191 ctxt->context->proximityPosition = pp;
13192 ctxt->context->contextSize = cs;
13193 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13195 CHECK_TYPE0(XPATH_NODESET);
13196 arg2 = valuePop(ctxt);
13198 CHECK_TYPE0(XPATH_NODESET);
13199 arg1 = valuePop(ctxt);
13201 if ((arg1->nodesetval == NULL) ||
13202 ((arg2->nodesetval != NULL) &&
13203 (arg2->nodesetval->nodeNr != 0)))
13205 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13209 valuePush(ctxt, arg1);
13210 xmlXPathReleaseObject(ctxt->context, arg2);
13212 case XPATH_OP_ROOT:
13213 xmlXPathRoot(ctxt);
13215 case XPATH_OP_NODE:
13217 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13220 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13222 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13223 ctxt->context->node));
13225 case XPATH_OP_RESET:
13227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13230 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13232 ctxt->context->node = NULL;
13234 case XPATH_OP_COLLECT:{
13238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13241 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13244 case XPATH_OP_VALUE:
13246 xmlXPathCacheObjectCopy(ctxt->context,
13247 (xmlXPathObjectPtr) op->value4));
13249 case XPATH_OP_VARIABLE:{
13250 xmlXPathObjectPtr val;
13254 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13255 if (op->value5 == NULL) {
13256 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13258 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13261 valuePush(ctxt, val);
13263 const xmlChar *URI;
13265 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13267 xmlGenericError(xmlGenericErrorContext,
13268 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13269 op->value4, op->value5);
13272 val = xmlXPathVariableLookupNS(ctxt->context,
13275 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13278 valuePush(ctxt, val);
13282 case XPATH_OP_FUNCTION:{
13283 xmlXPathFunction func;
13284 const xmlChar *oldFunc, *oldFuncURI;
13289 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13290 if (ctxt->valueNr < op->value) {
13291 xmlGenericError(xmlGenericErrorContext,
13292 "xmlXPathCompOpEval: parameter error\n");
13293 ctxt->error = XPATH_INVALID_OPERAND;
13296 for (i = 0; i < op->value; i++)
13297 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13298 xmlGenericError(xmlGenericErrorContext,
13299 "xmlXPathCompOpEval: parameter error\n");
13300 ctxt->error = XPATH_INVALID_OPERAND;
13303 if (op->cache != NULL)
13304 XML_CAST_FPTR(func) = op->cache;
13306 const xmlChar *URI = NULL;
13308 if (op->value5 == NULL)
13310 xmlXPathFunctionLookup(ctxt->context,
13313 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13315 xmlGenericError(xmlGenericErrorContext,
13316 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13317 op->value4, op->value5);
13320 func = xmlXPathFunctionLookupNS(ctxt->context,
13323 if (func == NULL) {
13324 xmlGenericError(xmlGenericErrorContext,
13325 "xmlXPathCompOpEval: function %s not found\n",
13327 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13329 op->cache = XML_CAST_FPTR(func);
13330 op->cacheURI = (void *) URI;
13332 oldFunc = ctxt->context->function;
13333 oldFuncURI = ctxt->context->functionURI;
13334 ctxt->context->function = op->value4;
13335 ctxt->context->functionURI = op->cacheURI;
13336 func(ctxt, op->value);
13337 ctxt->context->function = oldFunc;
13338 ctxt->context->functionURI = oldFuncURI;
13342 bakd = ctxt->context->doc;
13343 bak = ctxt->context->node;
13344 pp = ctxt->context->proximityPosition;
13345 cs = ctxt->context->contextSize;
13347 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13348 ctxt->context->contextSize = cs;
13349 ctxt->context->proximityPosition = pp;
13350 ctxt->context->node = bak;
13351 ctxt->context->doc = bakd;
13353 if (op->ch2 != -1) {
13354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13355 ctxt->context->doc = bakd;
13356 ctxt->context->node = bak;
13360 case XPATH_OP_PREDICATE:
13361 case XPATH_OP_FILTER:{
13362 xmlXPathObjectPtr res;
13363 xmlXPathObjectPtr obj, tmp;
13364 xmlNodeSetPtr newset = NULL;
13365 xmlNodeSetPtr oldset;
13366 xmlNodePtr oldnode;
13371 * Optimization for ()[1] selection i.e. the first elem
13373 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13374 #ifdef XP_OPTIMIZED_FILTER_FIRST
13376 * FILTER TODO: Can we assume that the inner processing
13377 * will result in an ordered list if we have an
13379 * What about an additional field or flag on
13380 * xmlXPathObject like @sorted ? This way we wouln'd need
13381 * to assume anything, so it would be more robust and
13382 * easier to optimize.
13384 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13385 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13387 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13389 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13390 xmlXPathObjectPtr val;
13392 val = comp->steps[op->ch2].value4;
13393 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13394 (val->floatval == 1.0)) {
13395 xmlNodePtr first = NULL;
13398 xmlXPathCompOpEvalFirst(ctxt,
13399 &comp->steps[op->ch1],
13403 * The nodeset should be in document order,
13404 * Keep only the first value
13406 if ((ctxt->value != NULL) &&
13407 (ctxt->value->type == XPATH_NODESET) &&
13408 (ctxt->value->nodesetval != NULL) &&
13409 (ctxt->value->nodesetval->nodeNr > 1))
13410 ctxt->value->nodesetval->nodeNr = 1;
13415 * Optimization for ()[last()] selection i.e. the last elem
13417 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13418 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13419 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13420 int f = comp->steps[op->ch2].ch1;
13423 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13424 (comp->steps[f].value5 == NULL) &&
13425 (comp->steps[f].value == 0) &&
13426 (comp->steps[f].value4 != NULL) &&
13428 (comp->steps[f].value4, BAD_CAST "last"))) {
13429 xmlNodePtr last = NULL;
13432 xmlXPathCompOpEvalLast(ctxt,
13433 &comp->steps[op->ch1],
13437 * The nodeset should be in document order,
13438 * Keep only the last value
13440 if ((ctxt->value != NULL) &&
13441 (ctxt->value->type == XPATH_NODESET) &&
13442 (ctxt->value->nodesetval != NULL) &&
13443 (ctxt->value->nodesetval->nodeTab != NULL) &&
13444 (ctxt->value->nodesetval->nodeNr > 1)) {
13445 ctxt->value->nodesetval->nodeTab[0] =
13446 ctxt->value->nodesetval->nodeTab[ctxt->
13451 ctxt->value->nodesetval->nodeNr = 1;
13457 * Process inner predicates first.
13458 * Example "index[parent::book][1]":
13460 * PREDICATE <-- we are here "[1]"
13461 * PREDICATE <-- process "[parent::book]" first
13463 * COLLECT 'parent' 'name' 'node' book
13465 * ELEM Object is a number : 1
13469 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13473 if (ctxt->value == NULL)
13476 oldnode = ctxt->context->node;
13478 #ifdef LIBXML_XPTR_ENABLED
13480 * Hum are we filtering the result of an XPointer expression
13482 if (ctxt->value->type == XPATH_LOCATIONSET) {
13483 xmlLocationSetPtr newlocset = NULL;
13484 xmlLocationSetPtr oldlocset;
13487 * Extract the old locset, and then evaluate the result of the
13488 * expression for all the element in the locset. use it to grow
13491 CHECK_TYPE0(XPATH_LOCATIONSET);
13492 obj = valuePop(ctxt);
13493 oldlocset = obj->user;
13494 ctxt->context->node = NULL;
13496 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13497 ctxt->context->contextSize = 0;
13498 ctxt->context->proximityPosition = 0;
13501 xmlXPathCompOpEval(ctxt,
13502 &comp->steps[op->ch2]);
13503 res = valuePop(ctxt);
13505 xmlXPathReleaseObject(ctxt->context, res);
13507 valuePush(ctxt, obj);
13511 newlocset = xmlXPtrLocationSetCreate(NULL);
13513 for (i = 0; i < oldlocset->locNr; i++) {
13515 * Run the evaluation with a node list made of a
13516 * single item in the nodelocset.
13518 ctxt->context->node = oldlocset->locTab[i]->user;
13519 ctxt->context->contextSize = oldlocset->locNr;
13520 ctxt->context->proximityPosition = i + 1;
13521 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13522 ctxt->context->node);
13523 valuePush(ctxt, tmp);
13527 xmlXPathCompOpEval(ctxt,
13528 &comp->steps[op->ch2]);
13529 if (ctxt->error != XPATH_EXPRESSION_OK) {
13530 xmlXPathFreeObject(obj);
13535 * The result of the evaluation need to be tested to
13536 * decided whether the filter succeeded or not
13538 res = valuePop(ctxt);
13539 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13540 xmlXPtrLocationSetAdd(newlocset,
13542 (oldlocset->locTab[i]));
13549 xmlXPathReleaseObject(ctxt->context, res);
13551 if (ctxt->value == tmp) {
13552 res = valuePop(ctxt);
13553 xmlXPathReleaseObject(ctxt->context, res);
13556 ctxt->context->node = NULL;
13560 * The result is used as the new evaluation locset.
13562 xmlXPathReleaseObject(ctxt->context, obj);
13563 ctxt->context->node = NULL;
13564 ctxt->context->contextSize = -1;
13565 ctxt->context->proximityPosition = -1;
13566 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13567 ctxt->context->node = oldnode;
13570 #endif /* LIBXML_XPTR_ENABLED */
13573 * Extract the old set, and then evaluate the result of the
13574 * expression for all the element in the set. use it to grow
13577 CHECK_TYPE0(XPATH_NODESET);
13578 obj = valuePop(ctxt);
13579 oldset = obj->nodesetval;
13581 oldnode = ctxt->context->node;
13582 oldDoc = ctxt->context->doc;
13583 ctxt->context->node = NULL;
13585 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13586 ctxt->context->contextSize = 0;
13587 ctxt->context->proximityPosition = 0;
13591 xmlXPathCompOpEval(ctxt,
13592 &comp->steps[op->ch2]);
13594 res = valuePop(ctxt);
13596 xmlXPathFreeObject(res);
13598 valuePush(ctxt, obj);
13599 ctxt->context->node = oldnode;
13604 * Initialize the new set.
13605 * Also set the xpath document in case things like
13606 * key() evaluation are attempted on the predicate
13608 newset = xmlXPathNodeSetCreate(NULL);
13611 * "For each node in the node-set to be filtered, the
13612 * PredicateExpr is evaluated with that node as the
13613 * context node, with the number of nodes in the
13614 * node-set as the context size, and with the proximity
13615 * position of the node in the node-set with respect to
13616 * the axis as the context position;"
13617 * @oldset is the node-set" to be filtered.
13620 * "only predicates change the context position and
13621 * context size (see [2.4 Predicates])."
13623 * node-set context pos
13627 * After applying predicate [position() > 1] :
13628 * node-set context pos
13632 * removed the first node in the node-set, then
13633 * the context position of the
13635 for (i = 0; i < oldset->nodeNr; i++) {
13637 * Run the evaluation with a node list made of
13638 * a single item in the nodeset.
13640 ctxt->context->node = oldset->nodeTab[i];
13641 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13642 (oldset->nodeTab[i]->doc != NULL))
13643 ctxt->context->doc = oldset->nodeTab[i]->doc;
13645 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13646 ctxt->context->node);
13648 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13649 ctxt->context->node);
13651 valuePush(ctxt, tmp);
13652 ctxt->context->contextSize = oldset->nodeNr;
13653 ctxt->context->proximityPosition = i + 1;
13655 * Evaluate the predicate against the context node.
13656 * Can/should we optimize position() predicates
13657 * here (e.g. "[1]")?
13661 xmlXPathCompOpEval(ctxt,
13662 &comp->steps[op->ch2]);
13663 if (ctxt->error != XPATH_EXPRESSION_OK) {
13664 xmlXPathFreeNodeSet(newset);
13665 xmlXPathFreeObject(obj);
13670 * The result of the evaluation needs to be tested to
13671 * decide whether the filter succeeded or not
13674 * OPTIMIZE TODO: Can we use
13675 * xmlXPathNodeSetAdd*Unique()* instead?
13677 res = valuePop(ctxt);
13678 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13679 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13686 xmlXPathReleaseObject(ctxt->context, res);
13688 if (ctxt->value == tmp) {
13690 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13692 * Don't free the temporary nodeset
13693 * in order to avoid massive recreation inside this
13698 ctxt->context->node = NULL;
13701 xmlXPathReleaseObject(ctxt->context, tmp);
13703 * The result is used as the new evaluation set.
13705 xmlXPathReleaseObject(ctxt->context, obj);
13706 ctxt->context->node = NULL;
13707 ctxt->context->contextSize = -1;
13708 ctxt->context->proximityPosition = -1;
13709 /* may want to move this past the '}' later */
13710 ctxt->context->doc = oldDoc;
13712 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13714 ctxt->context->node = oldnode;
13717 case XPATH_OP_SORT:
13719 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13721 if ((ctxt->value != NULL) &&
13722 (ctxt->value->type == XPATH_NODESET) &&
13723 (ctxt->value->nodesetval != NULL) &&
13724 (ctxt->value->nodesetval->nodeNr > 1))
13726 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13729 #ifdef LIBXML_XPTR_ENABLED
13730 case XPATH_OP_RANGETO:{
13731 xmlXPathObjectPtr range;
13732 xmlXPathObjectPtr res, obj;
13733 xmlXPathObjectPtr tmp;
13734 xmlLocationSetPtr newlocset = NULL;
13735 xmlLocationSetPtr oldlocset;
13736 xmlNodeSetPtr oldset;
13741 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13745 if (ctxt->value->type == XPATH_LOCATIONSET) {
13747 * Extract the old locset, and then evaluate the result of the
13748 * expression for all the element in the locset. use it to grow
13751 CHECK_TYPE0(XPATH_LOCATIONSET);
13752 obj = valuePop(ctxt);
13753 oldlocset = obj->user;
13755 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13756 ctxt->context->node = NULL;
13757 ctxt->context->contextSize = 0;
13758 ctxt->context->proximityPosition = 0;
13759 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13760 res = valuePop(ctxt);
13762 xmlXPathReleaseObject(ctxt->context, res);
13764 valuePush(ctxt, obj);
13768 newlocset = xmlXPtrLocationSetCreate(NULL);
13770 for (i = 0; i < oldlocset->locNr; i++) {
13772 * Run the evaluation with a node list made of a
13773 * single item in the nodelocset.
13775 ctxt->context->node = oldlocset->locTab[i]->user;
13776 ctxt->context->contextSize = oldlocset->locNr;
13777 ctxt->context->proximityPosition = i + 1;
13778 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13779 ctxt->context->node);
13780 valuePush(ctxt, tmp);
13784 xmlXPathCompOpEval(ctxt,
13785 &comp->steps[op->ch2]);
13786 if (ctxt->error != XPATH_EXPRESSION_OK) {
13787 xmlXPathFreeObject(obj);
13791 res = valuePop(ctxt);
13792 if (res->type == XPATH_LOCATIONSET) {
13793 xmlLocationSetPtr rloc =
13794 (xmlLocationSetPtr)res->user;
13795 for (j=0; j<rloc->locNr; j++) {
13796 range = xmlXPtrNewRange(
13797 oldlocset->locTab[i]->user,
13798 oldlocset->locTab[i]->index,
13799 rloc->locTab[j]->user2,
13800 rloc->locTab[j]->index2);
13801 if (range != NULL) {
13802 xmlXPtrLocationSetAdd(newlocset, range);
13806 range = xmlXPtrNewRangeNodeObject(
13807 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13808 if (range != NULL) {
13809 xmlXPtrLocationSetAdd(newlocset,range);
13817 xmlXPathReleaseObject(ctxt->context, res);
13819 if (ctxt->value == tmp) {
13820 res = valuePop(ctxt);
13821 xmlXPathReleaseObject(ctxt->context, res);
13824 ctxt->context->node = NULL;
13826 } else { /* Not a location set */
13827 CHECK_TYPE0(XPATH_NODESET);
13828 obj = valuePop(ctxt);
13829 oldset = obj->nodesetval;
13830 ctxt->context->node = NULL;
13832 newlocset = xmlXPtrLocationSetCreate(NULL);
13834 if (oldset != NULL) {
13835 for (i = 0; i < oldset->nodeNr; i++) {
13837 * Run the evaluation with a node list made of a single item
13840 ctxt->context->node = oldset->nodeTab[i];
13842 * OPTIMIZE TODO: Avoid recreation for every iteration.
13844 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13845 ctxt->context->node);
13846 valuePush(ctxt, tmp);
13850 xmlXPathCompOpEval(ctxt,
13851 &comp->steps[op->ch2]);
13852 if (ctxt->error != XPATH_EXPRESSION_OK) {
13853 xmlXPathFreeObject(obj);
13857 res = valuePop(ctxt);
13859 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13861 if (range != NULL) {
13862 xmlXPtrLocationSetAdd(newlocset, range);
13869 xmlXPathReleaseObject(ctxt->context, res);
13871 if (ctxt->value == tmp) {
13872 res = valuePop(ctxt);
13873 xmlXPathReleaseObject(ctxt->context, res);
13876 ctxt->context->node = NULL;
13882 * The result is used as the new evaluation set.
13884 xmlXPathReleaseObject(ctxt->context, obj);
13885 ctxt->context->node = NULL;
13886 ctxt->context->contextSize = -1;
13887 ctxt->context->proximityPosition = -1;
13888 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13891 #endif /* LIBXML_XPTR_ENABLED */
13893 xmlGenericError(xmlGenericErrorContext,
13894 "XPath: unknown precompiled operation %d\n", op->op);
13899 * xmlXPathCompOpEvalToBoolean:
13900 * @ctxt: the XPath parser context
13902 * Evaluates if the expression evaluates to true.
13904 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13907 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13908 xmlXPathStepOpPtr op,
13911 xmlXPathObjectPtr resObj = NULL;
13914 /* comp = ctxt->comp; */
13918 case XPATH_OP_VALUE:
13919 resObj = (xmlXPathObjectPtr) op->value4;
13921 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
13922 return(xmlXPathCastToBoolean(resObj));
13923 case XPATH_OP_SORT:
13925 * We don't need sorting for boolean results. Skip this one.
13927 if (op->ch1 != -1) {
13928 op = &ctxt->comp->steps[op->ch1];
13932 case XPATH_OP_COLLECT:
13936 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
13937 if (ctxt->error != XPATH_EXPRESSION_OK)
13940 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
13941 if (ctxt->error != XPATH_EXPRESSION_OK)
13944 resObj = valuePop(ctxt);
13945 if (resObj == NULL)
13950 * Fallback to call xmlXPathCompOpEval().
13952 xmlXPathCompOpEval(ctxt, op);
13953 if (ctxt->error != XPATH_EXPRESSION_OK)
13956 resObj = valuePop(ctxt);
13957 if (resObj == NULL)
13965 if (resObj->type == XPATH_BOOLEAN) {
13966 res = resObj->boolval;
13967 } else if (isPredicate) {
13969 * For predicates a result of type "number" is handled
13972 * "If the result is a number, the result will be converted
13973 * to true if the number is equal to the context position
13974 * and will be converted to false otherwise;"
13976 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
13978 res = xmlXPathCastToBoolean(resObj);
13980 xmlXPathReleaseObject(ctxt->context, resObj);
13987 #ifdef XPATH_STREAMING
13989 * xmlXPathRunStreamEval:
13990 * @ctxt: the XPath parser context with the compiled expression
13992 * Evaluate the Precompiled Streamable XPath expression in the given context.
13995 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
13996 xmlXPathObjectPtr *resultSeq, int toBool)
13998 int max_depth, min_depth;
14001 int eval_all_nodes;
14002 xmlNodePtr cur = NULL, limit = NULL;
14003 xmlStreamCtxtPtr patstream = NULL;
14007 if ((ctxt == NULL) || (comp == NULL))
14009 max_depth = xmlPatternMaxDepth(comp);
14010 if (max_depth == -1)
14012 if (max_depth == -2)
14014 min_depth = xmlPatternMinDepth(comp);
14015 if (min_depth == -1)
14017 from_root = xmlPatternFromRoot(comp);
14021 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14025 if (resultSeq == NULL)
14027 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14028 if (*resultSeq == NULL)
14033 * handle the special cases of "/" amd "." being matched
14035 if (min_depth == 0) {
14040 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14041 (xmlNodePtr) ctxt->doc);
14043 /* Select "self::node()" */
14046 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14049 if (max_depth == 0) {
14054 cur = (xmlNodePtr)ctxt->doc;
14055 } else if (ctxt->node != NULL) {
14056 switch (ctxt->node->type) {
14057 case XML_ELEMENT_NODE:
14058 case XML_DOCUMENT_NODE:
14059 case XML_DOCUMENT_FRAG_NODE:
14060 case XML_HTML_DOCUMENT_NODE:
14061 #ifdef LIBXML_DOCB_ENABLED
14062 case XML_DOCB_DOCUMENT_NODE:
14066 case XML_ATTRIBUTE_NODE:
14067 case XML_TEXT_NODE:
14068 case XML_CDATA_SECTION_NODE:
14069 case XML_ENTITY_REF_NODE:
14070 case XML_ENTITY_NODE:
14072 case XML_COMMENT_NODE:
14073 case XML_NOTATION_NODE:
14075 case XML_DOCUMENT_TYPE_NODE:
14076 case XML_ELEMENT_DECL:
14077 case XML_ATTRIBUTE_DECL:
14078 case XML_ENTITY_DECL:
14079 case XML_NAMESPACE_DECL:
14080 case XML_XINCLUDE_START:
14081 case XML_XINCLUDE_END:
14090 patstream = xmlPatternGetStreamCtxt(comp);
14091 if (patstream == NULL) {
14093 * QUESTION TODO: Is this an error?
14098 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14101 ret = xmlStreamPush(patstream, NULL, NULL);
14103 } else if (ret == 1) {
14106 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14110 goto scan_children;
14115 switch (cur->type) {
14116 case XML_ELEMENT_NODE:
14117 case XML_TEXT_NODE:
14118 case XML_CDATA_SECTION_NODE:
14119 case XML_COMMENT_NODE:
14121 if (cur->type == XML_ELEMENT_NODE) {
14122 ret = xmlStreamPush(patstream, cur->name,
14123 (cur->ns ? cur->ns->href : NULL));
14124 } else if (eval_all_nodes)
14125 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14131 } else if (ret == 1) {
14134 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14136 if ((cur->children == NULL) || (depth >= max_depth)) {
14137 ret = xmlStreamPop(patstream);
14138 while (cur->next != NULL) {
14140 if ((cur->type != XML_ENTITY_DECL) &&
14141 (cur->type != XML_DTD_NODE))
14150 if ((cur->children != NULL) && (depth < max_depth)) {
14152 * Do not descend on entities declarations
14154 if (cur->children->type != XML_ENTITY_DECL) {
14155 cur = cur->children;
14160 if (cur->type != XML_DTD_NODE)
14168 while (cur->next != NULL) {
14170 if ((cur->type != XML_ENTITY_DECL) &&
14171 (cur->type != XML_DTD_NODE))
14178 if ((cur == NULL) || (cur == limit))
14180 if (cur->type == XML_ELEMENT_NODE) {
14181 ret = xmlStreamPop(patstream);
14182 } else if ((eval_all_nodes) &&
14183 ((cur->type == XML_TEXT_NODE) ||
14184 (cur->type == XML_CDATA_SECTION_NODE) ||
14185 (cur->type == XML_COMMENT_NODE) ||
14186 (cur->type == XML_PI_NODE)))
14188 ret = xmlStreamPop(patstream);
14190 if (cur->next != NULL) {
14194 } while (cur != NULL);
14196 } while ((cur != NULL) && (depth >= 0));
14201 printf("stream eval: checked %d nodes selected %d\n",
14202 nb_nodes, retObj->nodesetval->nodeNr);
14206 xmlFreeStreamCtxt(patstream);
14211 xmlFreeStreamCtxt(patstream);
14214 #endif /* XPATH_STREAMING */
14218 * @ctxt: the XPath parser context with the compiled expression
14219 * @toBool: evaluate to a boolean result
14221 * Evaluate the Precompiled XPath expression in the given context.
14224 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14226 xmlXPathCompExprPtr comp;
14228 if ((ctxt == NULL) || (ctxt->comp == NULL))
14231 if (ctxt->valueTab == NULL) {
14232 /* Allocate the value stack */
14233 ctxt->valueTab = (xmlXPathObjectPtr *)
14234 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14235 if (ctxt->valueTab == NULL) {
14236 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14240 ctxt->valueMax = 10;
14241 ctxt->value = NULL;
14243 #ifdef XPATH_STREAMING
14244 if (ctxt->comp->stream) {
14249 * Evaluation to boolean result.
14251 res = xmlXPathRunStreamEval(ctxt->context,
14252 ctxt->comp->stream, NULL, 1);
14256 xmlXPathObjectPtr resObj = NULL;
14259 * Evaluation to a sequence.
14261 res = xmlXPathRunStreamEval(ctxt->context,
14262 ctxt->comp->stream, &resObj, 0);
14264 if ((res != -1) && (resObj != NULL)) {
14265 valuePush(ctxt, resObj);
14268 if (resObj != NULL)
14269 xmlXPathReleaseObject(ctxt->context, resObj);
14272 * QUESTION TODO: This falls back to normal XPath evaluation
14273 * if res == -1. Is this intended?
14278 if (comp->last < 0) {
14279 xmlGenericError(xmlGenericErrorContext,
14280 "xmlXPathRunEval: last is less than zero\n");
14284 return(xmlXPathCompOpEvalToBoolean(ctxt,
14285 &comp->steps[comp->last], 0));
14287 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14292 /************************************************************************
14294 * Public interfaces *
14296 ************************************************************************/
14299 * xmlXPathEvalPredicate:
14300 * @ctxt: the XPath context
14301 * @res: the Predicate Expression evaluation result
14303 * Evaluate a predicate result for the current node.
14304 * A PredicateExpr is evaluated by evaluating the Expr and converting
14305 * the result to a boolean. If the result is a number, the result will
14306 * be converted to true if the number is equal to the position of the
14307 * context node in the context node list (as returned by the position
14308 * function) and will be converted to false otherwise; if the result
14309 * is not a number, then the result will be converted as if by a call
14310 * to the boolean function.
14312 * Returns 1 if predicate is true, 0 otherwise
14315 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14316 if ((ctxt == NULL) || (res == NULL)) return(0);
14317 switch (res->type) {
14318 case XPATH_BOOLEAN:
14319 return(res->boolval);
14321 return(res->floatval == ctxt->proximityPosition);
14322 case XPATH_NODESET:
14323 case XPATH_XSLT_TREE:
14324 if (res->nodesetval == NULL)
14326 return(res->nodesetval->nodeNr != 0);
14328 return((res->stringval != NULL) &&
14329 (xmlStrlen(res->stringval) != 0));
14337 * xmlXPathEvaluatePredicateResult:
14338 * @ctxt: the XPath Parser context
14339 * @res: the Predicate Expression evaluation result
14341 * Evaluate a predicate result for the current node.
14342 * A PredicateExpr is evaluated by evaluating the Expr and converting
14343 * the result to a boolean. If the result is a number, the result will
14344 * be converted to true if the number is equal to the position of the
14345 * context node in the context node list (as returned by the position
14346 * function) and will be converted to false otherwise; if the result
14347 * is not a number, then the result will be converted as if by a call
14348 * to the boolean function.
14350 * Returns 1 if predicate is true, 0 otherwise
14353 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14354 xmlXPathObjectPtr res) {
14355 if ((ctxt == NULL) || (res == NULL)) return(0);
14356 switch (res->type) {
14357 case XPATH_BOOLEAN:
14358 return(res->boolval);
14360 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14361 return((res->floatval == ctxt->context->proximityPosition) &&
14362 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14364 return(res->floatval == ctxt->context->proximityPosition);
14366 case XPATH_NODESET:
14367 case XPATH_XSLT_TREE:
14368 if (res->nodesetval == NULL)
14370 return(res->nodesetval->nodeNr != 0);
14372 return((res->stringval != NULL) && (res->stringval[0] != 0));
14373 #ifdef LIBXML_XPTR_ENABLED
14374 case XPATH_LOCATIONSET:{
14375 xmlLocationSetPtr ptr = res->user;
14378 return (ptr->locNr != 0);
14387 #ifdef XPATH_STREAMING
14389 * xmlXPathTryStreamCompile:
14390 * @ctxt: an XPath context
14391 * @str: the XPath expression
14393 * Try to compile the XPath expression as a streamable subset.
14395 * Returns the compiled expression or NULL if failed to compile.
14397 static xmlXPathCompExprPtr
14398 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14400 * Optimization: use streaming patterns when the XPath expression can
14401 * be compiled to a stream lookup
14403 xmlPatternPtr stream;
14404 xmlXPathCompExprPtr comp;
14405 xmlDictPtr dict = NULL;
14406 const xmlChar **namespaces = NULL;
14410 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14411 (!xmlStrchr(str, '@'))) {
14412 const xmlChar *tmp;
14415 * We don't try to handle expressions using the verbose axis
14416 * specifiers ("::"), just the simplied form at this point.
14417 * Additionally, if there is no list of namespaces available and
14418 * there's a ":" in the expression, indicating a prefixed QName,
14419 * then we won't try to compile either. xmlPatterncompile() needs
14420 * to have a list of namespaces at compilation time in order to
14421 * compile prefixed name tests.
14423 tmp = xmlStrchr(str, ':');
14424 if ((tmp != NULL) &&
14425 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14428 if (ctxt != NULL) {
14430 if (ctxt->nsNr > 0) {
14431 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14432 if (namespaces == NULL) {
14433 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14436 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14437 ns = ctxt->namespaces[j];
14438 namespaces[i++] = ns->href;
14439 namespaces[i++] = ns->prefix;
14441 namespaces[i++] = NULL;
14442 namespaces[i++] = NULL;
14446 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14448 if (namespaces != NULL) {
14449 xmlFree((xmlChar **)namespaces);
14451 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14452 comp = xmlXPathNewCompExpr();
14453 if (comp == NULL) {
14454 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14457 comp->stream = stream;
14460 xmlDictReference(comp->dict);
14463 xmlFreePattern(stream);
14467 #endif /* XPATH_STREAMING */
14470 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14475 if ((*expr == '/') && (*(++expr) == '/'))
14481 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14484 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14485 * internal representation.
14487 if (op->ch1 != -1) {
14488 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14489 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14490 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14491 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14494 * This is a "child::foo"
14496 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14498 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14499 (prevop->ch1 != -1) &&
14500 ((xmlXPathAxisVal) prevop->value ==
14501 AXIS_DESCENDANT_OR_SELF) &&
14502 (prevop->ch2 == -1) &&
14503 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14504 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14505 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14508 * This is a "/descendant-or-self::node()" without predicates.
14511 op->ch1 = prevop->ch1;
14512 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14516 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14519 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14523 * xmlXPathCtxtCompile:
14524 * @ctxt: an XPath context
14525 * @str: the XPath expression
14527 * Compile an XPath expression
14529 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14530 * the caller has to free the object.
14532 xmlXPathCompExprPtr
14533 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14534 xmlXPathParserContextPtr pctxt;
14535 xmlXPathCompExprPtr comp;
14537 #ifdef XPATH_STREAMING
14538 comp = xmlXPathTryStreamCompile(ctxt, str);
14545 pctxt = xmlXPathNewParserContext(str, ctxt);
14546 xmlXPathCompileExpr(pctxt, 1);
14548 if( pctxt->error != XPATH_EXPRESSION_OK )
14550 xmlXPathFreeParserContext(pctxt);
14554 if (*pctxt->cur != 0) {
14556 * aleksey: in some cases this line prints *second* error message
14557 * (see bug #78858) and probably this should be fixed.
14558 * However, we are not sure that all error messages are printed
14559 * out in other places. It's not critical so we leave it as-is for now
14561 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14564 comp = pctxt->comp;
14565 pctxt->comp = NULL;
14567 xmlXPathFreeParserContext(pctxt);
14569 if (comp != NULL) {
14570 comp->expr = xmlStrdup(str);
14571 #ifdef DEBUG_EVAL_COUNTS
14572 comp->string = xmlStrdup(str);
14575 if ((comp->expr != NULL) &&
14576 (comp->nbStep > 2) &&
14577 (comp->last >= 0) &&
14578 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14580 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14588 * @str: the XPath expression
14590 * Compile an XPath expression
14592 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14593 * the caller has to free the object.
14595 xmlXPathCompExprPtr
14596 xmlXPathCompile(const xmlChar *str) {
14597 return(xmlXPathCtxtCompile(NULL, str));
14601 * xmlXPathCompiledEvalInternal:
14602 * @comp: the compiled XPath expression
14603 * @ctxt: the XPath context
14604 * @resObj: the resulting XPath object or NULL
14605 * @toBool: 1 if only a boolean result is requested
14607 * Evaluate the Precompiled XPath expression in the given context.
14608 * The caller has to free @resObj.
14610 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14611 * the caller has to free the object.
14614 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14615 xmlXPathContextPtr ctxt,
14616 xmlXPathObjectPtr *resObj,
14619 xmlXPathParserContextPtr pctxt;
14620 #ifndef LIBXML_THREAD_ENABLED
14621 static int reentance = 0;
14625 CHECK_CTXT_NEG(ctxt)
14631 #ifndef LIBXML_THREAD_ENABLED
14634 xmlXPathDisableOptimizer = 1;
14637 #ifdef DEBUG_EVAL_COUNTS
14639 if ((comp->string != NULL) && (comp->nb > 100)) {
14640 fprintf(stderr, "100 x %s\n", comp->string);
14644 pctxt = xmlXPathCompParserContext(comp, ctxt);
14645 res = xmlXPathRunEval(pctxt, toBool);
14648 if (pctxt->value == NULL) {
14649 xmlGenericError(xmlGenericErrorContext,
14650 "xmlXPathCompiledEval: evaluation failed\n");
14653 *resObj = valuePop(pctxt);
14658 * Pop all remaining objects from the stack.
14660 if (pctxt->valueNr > 0) {
14661 xmlXPathObjectPtr tmp;
14665 tmp = valuePop(pctxt);
14669 xmlXPathReleaseObject(ctxt, tmp);
14671 } while (tmp != NULL);
14672 if ((stack != 0) &&
14673 ((toBool) || ((resObj) && (*resObj))))
14675 xmlGenericError(xmlGenericErrorContext,
14676 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14681 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14682 xmlXPathFreeObject(*resObj);
14685 pctxt->comp = NULL;
14686 xmlXPathFreeParserContext(pctxt);
14687 #ifndef LIBXML_THREAD_ENABLED
14695 * xmlXPathCompiledEval:
14696 * @comp: the compiled XPath expression
14697 * @ctx: the XPath context
14699 * Evaluate the Precompiled XPath expression in the given context.
14701 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14702 * the caller has to free the object.
14705 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14707 xmlXPathObjectPtr res = NULL;
14709 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14714 * xmlXPathCompiledEvalToBoolean:
14715 * @comp: the compiled XPath expression
14716 * @ctxt: the XPath context
14718 * Applies the XPath boolean() function on the result of the given
14719 * compiled expression.
14721 * Returns 1 if the expression evaluated to true, 0 if to false and
14722 * -1 in API and internal errors.
14725 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14726 xmlXPathContextPtr ctxt)
14728 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14732 * xmlXPathEvalExpr:
14733 * @ctxt: the XPath Parser context
14735 * Parse and evaluate an XPath expression in the given context,
14736 * then push the result on the context stack
14739 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14740 #ifdef XPATH_STREAMING
14741 xmlXPathCompExprPtr comp;
14744 if (ctxt == NULL) return;
14746 #ifdef XPATH_STREAMING
14747 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14748 if (comp != NULL) {
14749 if (ctxt->comp != NULL)
14750 xmlXPathFreeCompExpr(ctxt->comp);
14752 if (ctxt->cur != NULL)
14753 while (*ctxt->cur != 0) ctxt->cur++;
14757 xmlXPathCompileExpr(ctxt, 1);
14759 * In this scenario the expression string will sit in ctxt->base.
14761 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14762 (ctxt->comp != NULL) &&
14763 (ctxt->base != NULL) &&
14764 (ctxt->comp->nbStep > 2) &&
14765 (ctxt->comp->last >= 0) &&
14766 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14768 xmlXPathRewriteDOSExpression(ctxt->comp,
14769 &ctxt->comp->steps[ctxt->comp->last]);
14773 xmlXPathRunEval(ctxt, 0);
14778 * @str: the XPath expression
14779 * @ctx: the XPath context
14781 * Evaluate the XPath Location Path in the given context.
14783 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14784 * the caller has to free the object.
14787 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14788 xmlXPathParserContextPtr ctxt;
14789 xmlXPathObjectPtr res, tmp, init = NULL;
14796 ctxt = xmlXPathNewParserContext(str, ctx);
14797 xmlXPathEvalExpr(ctxt);
14799 if (ctxt->value == NULL) {
14800 xmlGenericError(xmlGenericErrorContext,
14801 "xmlXPathEval: evaluation failed\n");
14803 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14804 #ifdef XPATH_STREAMING
14805 && (ctxt->comp->stream == NULL)
14808 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14811 res = valuePop(ctxt);
14815 tmp = valuePop(ctxt);
14819 xmlXPathReleaseObject(ctx, tmp);
14821 } while (tmp != NULL);
14822 if ((stack != 0) && (res != NULL)) {
14823 xmlGenericError(xmlGenericErrorContext,
14824 "xmlXPathEval: %d object left on the stack\n",
14827 if (ctxt->error != XPATH_EXPRESSION_OK) {
14828 xmlXPathFreeObject(res);
14832 xmlXPathFreeParserContext(ctxt);
14837 * xmlXPathEvalExpression:
14838 * @str: the XPath expression
14839 * @ctxt: the XPath context
14841 * Evaluate the XPath expression in the given context.
14843 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14844 * the caller has to free the object.
14847 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14848 xmlXPathParserContextPtr pctxt;
14849 xmlXPathObjectPtr res, tmp;
14856 pctxt = xmlXPathNewParserContext(str, ctxt);
14857 xmlXPathEvalExpr(pctxt);
14859 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14860 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14863 res = valuePop(pctxt);
14866 tmp = valuePop(pctxt);
14868 xmlXPathReleaseObject(ctxt, tmp);
14871 } while (tmp != NULL);
14872 if ((stack != 0) && (res != NULL)) {
14873 xmlGenericError(xmlGenericErrorContext,
14874 "xmlXPathEvalExpression: %d object left on the stack\n",
14877 xmlXPathFreeParserContext(pctxt);
14881 /************************************************************************
14883 * Extra functions not pertaining to the XPath spec *
14885 ************************************************************************/
14887 * xmlXPathEscapeUriFunction:
14888 * @ctxt: the XPath Parser context
14889 * @nargs: the number of arguments
14891 * Implement the escape-uri() XPath function
14892 * string escape-uri(string $str, bool $escape-reserved)
14894 * This function applies the URI escaping rules defined in section 2 of [RFC
14895 * 2396] to the string supplied as $uri-part, which typically represents all
14896 * or part of a URI. The effect of the function is to replace any special
14897 * character in the string by an escape sequence of the form %xx%yy...,
14898 * where xxyy... is the hexadecimal representation of the octets used to
14899 * represent the character in UTF-8.
14901 * The set of characters that are escaped depends on the setting of the
14902 * boolean argument $escape-reserved.
14904 * If $escape-reserved is true, all characters are escaped other than lower
14905 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14906 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14907 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14908 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14911 * If $escape-reserved is false, the behavior differs in that characters
14912 * referred to in [RFC 2396] as reserved characters are not escaped. These
14913 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14915 * [RFC 2396] does not define whether escaped URIs should use lower case or
14916 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14917 * compared using string comparison functions, this function must always use
14918 * the upper-case letters A-F.
14920 * Generally, $escape-reserved should be set to true when escaping a string
14921 * that is to form a single part of a URI, and to false when escaping an
14922 * entire URI or URI reference.
14924 * In the case of non-ascii characters, the string is encoded according to
14925 * utf-8 and then converted according to RFC 2396.
14928 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14929 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14930 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14931 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14935 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
14936 xmlXPathObjectPtr str;
14937 int escape_reserved;
14938 xmlBufferPtr target;
14944 escape_reserved = xmlXPathPopBoolean(ctxt);
14947 str = valuePop(ctxt);
14949 target = xmlBufferCreate();
14955 for (cptr = str->stringval; *cptr; cptr++) {
14956 if ((*cptr >= 'A' && *cptr <= 'Z') ||
14957 (*cptr >= 'a' && *cptr <= 'z') ||
14958 (*cptr >= '0' && *cptr <= '9') ||
14959 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
14960 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
14961 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
14963 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
14964 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
14965 (cptr[1] >= '0' && cptr[1] <= '9')) &&
14966 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
14967 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
14968 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
14969 (!escape_reserved &&
14970 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
14971 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
14972 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
14974 xmlBufferAdd(target, cptr, 1);
14976 if ((*cptr >> 4) < 10)
14977 escape[1] = '0' + (*cptr >> 4);
14979 escape[1] = 'A' - 10 + (*cptr >> 4);
14980 if ((*cptr & 0xF) < 10)
14981 escape[2] = '0' + (*cptr & 0xF);
14983 escape[2] = 'A' - 10 + (*cptr & 0xF);
14985 xmlBufferAdd(target, &escape[0], 3);
14989 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
14990 xmlBufferContent(target)));
14991 xmlBufferFree(target);
14992 xmlXPathReleaseObject(ctxt->context, str);
14996 * xmlXPathRegisterAllFunctions:
14997 * @ctxt: the XPath context
14999 * Registers all default XPath functions in this context
15002 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15004 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15005 xmlXPathBooleanFunction);
15006 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15007 xmlXPathCeilingFunction);
15008 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15009 xmlXPathCountFunction);
15010 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15011 xmlXPathConcatFunction);
15012 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15013 xmlXPathContainsFunction);
15014 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15015 xmlXPathIdFunction);
15016 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15017 xmlXPathFalseFunction);
15018 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15019 xmlXPathFloorFunction);
15020 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15021 xmlXPathLastFunction);
15022 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15023 xmlXPathLangFunction);
15024 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15025 xmlXPathLocalNameFunction);
15026 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15027 xmlXPathNotFunction);
15028 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15029 xmlXPathNameFunction);
15030 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15031 xmlXPathNamespaceURIFunction);
15032 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15033 xmlXPathNormalizeFunction);
15034 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15035 xmlXPathNumberFunction);
15036 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15037 xmlXPathPositionFunction);
15038 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15039 xmlXPathRoundFunction);
15040 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15041 xmlXPathStringFunction);
15042 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15043 xmlXPathStringLengthFunction);
15044 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15045 xmlXPathStartsWithFunction);
15046 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15047 xmlXPathSubstringFunction);
15048 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15049 xmlXPathSubstringBeforeFunction);
15050 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15051 xmlXPathSubstringAfterFunction);
15052 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15053 xmlXPathSumFunction);
15054 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15055 xmlXPathTrueFunction);
15056 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15057 xmlXPathTranslateFunction);
15059 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15060 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15061 xmlXPathEscapeUriFunction);
15064 #endif /* LIBXML_XPATH_ENABLED */
15065 #define bottom_xpath
15066 #include "elfgcchack.h"