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] = ' '
190 #ifdef DEBUG_XPATH_EXPRESSION
193 #define DEBUG_EVAL_COUNTS
196 static xmlNs xmlXPathXMLNamespaceStruct = {
204 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
205 #ifndef LIBXML_THREAD_ENABLED
207 * Optimizer is disabled only when threaded apps are detected while
208 * the library ain't compiled for thread safety.
210 static int xmlXPathDisableOptimizer = 0;
213 /************************************************************************
215 * Error handling routines *
217 ************************************************************************/
223 * Macro to raise an XPath error and return NULL.
225 #define XP_ERRORNULL(X) \
226 { xmlXPathErr(ctxt, X); return(NULL); }
229 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
231 static const char *xmlXPathErrorMessages[] = {
234 "Unfinished literal\n",
235 "Start of literal\n",
236 "Expected $ for variable reference\n",
237 "Undefined variable\n",
238 "Invalid predicate\n",
239 "Invalid expression\n",
240 "Missing closing curly brace\n",
241 "Unregistered function\n",
244 "Invalid number of arguments\n",
245 "Invalid context size\n",
246 "Invalid context position\n",
247 "Memory allocation error\n",
250 "Sub resource error\n",
251 "Undefined namespace prefix\n",
253 "Char out of XML range\n",
254 "Invalid or incomplete context\n",
255 "?? Unknown error ??\n" /* Must be last in the list! */
257 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
258 sizeof(xmlXPathErrorMessages[0])) - 1)
261 * @ctxt: an XPath context
262 * @extra: extra informations
264 * Handle a redefinition of attribute error
267 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
273 xmlStrPrintf(buf, 200,
274 BAD_CAST "Memory allocation failed : %s\n",
276 ctxt->lastError.message = (char *) xmlStrdup(buf);
278 ctxt->lastError.message = (char *)
279 xmlStrdup(BAD_CAST "Memory allocation failed\n");
281 ctxt->lastError.domain = XML_FROM_XPATH;
282 ctxt->lastError.code = XML_ERR_NO_MEMORY;
283 if (ctxt->error != NULL)
284 ctxt->error(ctxt->userData, &ctxt->lastError);
287 __xmlRaiseError(NULL, NULL, NULL,
288 NULL, NULL, XML_FROM_XPATH,
289 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
290 extra, NULL, NULL, 0, 0,
291 "Memory allocation failed : %s\n", extra);
293 __xmlRaiseError(NULL, NULL, NULL,
294 NULL, NULL, XML_FROM_XPATH,
295 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
296 NULL, NULL, NULL, 0, 0,
297 "Memory allocation failed\n");
302 * xmlXPathPErrMemory:
303 * @ctxt: an XPath parser context
304 * @extra: extra informations
306 * Handle a redefinition of attribute error
309 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
312 xmlXPathErrMemory(NULL, extra);
314 ctxt->error = XPATH_MEMORY_ERROR;
315 xmlXPathErrMemory(ctxt->context, extra);
321 * @ctxt: a XPath parser context
322 * @error: the error code
324 * Handle an XPath error
327 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
329 if ((error < 0) || (error > MAXERRNO))
332 __xmlRaiseError(NULL, NULL, NULL,
333 NULL, NULL, XML_FROM_XPATH,
334 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
335 XML_ERR_ERROR, NULL, 0,
336 NULL, NULL, NULL, 0, 0,
337 "%s", xmlXPathErrorMessages[error]);
341 if (ctxt->context == NULL) {
342 __xmlRaiseError(NULL, NULL, NULL,
343 NULL, NULL, XML_FROM_XPATH,
344 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
345 XML_ERR_ERROR, NULL, 0,
346 (const char *) ctxt->base, NULL, NULL,
347 ctxt->cur - ctxt->base, 0,
348 "%s", xmlXPathErrorMessages[error]);
352 /* cleanup current last error */
353 xmlResetError(&ctxt->context->lastError);
355 ctxt->context->lastError.domain = XML_FROM_XPATH;
356 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
358 ctxt->context->lastError.level = XML_ERR_ERROR;
359 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
360 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
361 ctxt->context->lastError.node = ctxt->context->debugNode;
362 if (ctxt->context->error != NULL) {
363 ctxt->context->error(ctxt->context->userData,
364 &ctxt->context->lastError);
366 __xmlRaiseError(NULL, NULL, NULL,
367 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
368 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
369 XML_ERR_ERROR, NULL, 0,
370 (const char *) ctxt->base, NULL, NULL,
371 ctxt->cur - ctxt->base, 0,
372 "%s", xmlXPathErrorMessages[error]);
379 * @ctxt: the XPath Parser context
380 * @file: the file name
381 * @line: the line number
382 * @no: the error number
384 * Formats an error message.
387 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
388 int line ATTRIBUTE_UNUSED, int no) {
389 xmlXPathErr(ctxt, no);
392 /************************************************************************
396 ************************************************************************/
401 * Pointer-list for various purposes.
403 typedef struct _xmlPointerList xmlPointerList;
404 typedef xmlPointerList *xmlPointerListPtr;
405 struct _xmlPointerList {
411 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
412 * and here, we should make the functions public.
415 xmlPointerListAddSize(xmlPointerListPtr list,
419 if (list->items == NULL) {
420 if (initialSize <= 0)
422 list->items = (void **) xmlMalloc(
423 initialSize * sizeof(void *));
424 if (list->items == NULL) {
425 xmlXPathErrMemory(NULL,
426 "xmlPointerListCreate: allocating item\n");
430 list->size = initialSize;
431 } else if (list->size <= list->number) {
433 list->items = (void **) xmlRealloc(list->items,
434 list->size * sizeof(void *));
435 if (list->items == NULL) {
436 xmlXPathErrMemory(NULL,
437 "xmlPointerListCreate: re-allocating item\n");
442 list->items[list->number++] = item;
447 * xsltPointerListCreate:
449 * Creates an xsltPointerList structure.
451 * Returns a xsltPointerList structure or NULL in case of an error.
453 static xmlPointerListPtr
454 xmlPointerListCreate(int initialSize)
456 xmlPointerListPtr ret;
458 ret = xmlMalloc(sizeof(xmlPointerList));
460 xmlXPathErrMemory(NULL,
461 "xmlPointerListCreate: allocating item\n");
464 memset(ret, 0, sizeof(xmlPointerList));
465 if (initialSize > 0) {
466 xmlPointerListAddSize(ret, NULL, initialSize);
473 * xsltPointerListFree:
475 * Frees the xsltPointerList structure. This does not free
476 * the content of the list.
479 xmlPointerListFree(xmlPointerListPtr list)
483 if (list->items != NULL)
484 xmlFree(list->items);
488 /************************************************************************
492 ************************************************************************/
509 XPATH_OP_RESET, /* 10 */
511 XPATH_OP_VALUE, /* 12 */
516 XPATH_OP_FILTER, /* 17 */
517 XPATH_OP_SORT /* 18 */
518 #ifdef LIBXML_XPTR_ENABLED
525 AXIS_ANCESTOR_OR_SELF,
529 AXIS_DESCENDANT_OR_SELF,
531 AXIS_FOLLOWING_SIBLING,
535 AXIS_PRECEDING_SIBLING,
550 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
551 NODE_TYPE_TEXT = XML_TEXT_NODE,
552 NODE_TYPE_PI = XML_PI_NODE
555 #define XP_REWRITE_DOS_CHILD_ELEM 1
557 typedef struct _xmlXPathStepOp xmlXPathStepOp;
558 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
559 struct _xmlXPathStepOp {
560 xmlXPathOp op; /* The identifier of the operation */
561 int ch1; /* First child */
562 int ch2; /* Second child */
573 struct _xmlXPathCompExpr {
574 int nbStep; /* Number of steps in this expression */
575 int maxStep; /* Maximum number of steps allocated */
576 xmlXPathStepOp *steps; /* ops for computation of this expression */
577 int last; /* index of last step in expression */
578 xmlChar *expr; /* the expression being computed */
579 xmlDictPtr dict; /* the dictionnary to use if any */
580 #ifdef DEBUG_EVAL_COUNTS
584 #ifdef XPATH_STREAMING
585 xmlPatternPtr stream;
589 /************************************************************************
591 * Forward declarations *
593 ************************************************************************/
595 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
597 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
599 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
600 xmlXPathStepOpPtr op, xmlNodePtr *first);
602 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
603 xmlXPathStepOpPtr op,
606 /************************************************************************
608 * Parser Type functions *
610 ************************************************************************/
613 * xmlXPathNewCompExpr:
615 * Create a new Xpath component
617 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
619 static xmlXPathCompExprPtr
620 xmlXPathNewCompExpr(void) {
621 xmlXPathCompExprPtr cur;
623 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
625 xmlXPathErrMemory(NULL, "allocating component\n");
628 memset(cur, 0, sizeof(xmlXPathCompExpr));
631 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
632 sizeof(xmlXPathStepOp));
633 if (cur->steps == NULL) {
634 xmlXPathErrMemory(NULL, "allocating steps\n");
638 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
640 #ifdef DEBUG_EVAL_COUNTS
647 * xmlXPathFreeCompExpr:
648 * @comp: an XPATH comp
650 * Free up the memory allocated by @comp
653 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
655 xmlXPathStepOpPtr op;
660 if (comp->dict == NULL) {
661 for (i = 0; i < comp->nbStep; i++) {
662 op = &comp->steps[i];
663 if (op->value4 != NULL) {
664 if (op->op == XPATH_OP_VALUE)
665 xmlXPathFreeObject(op->value4);
669 if (op->value5 != NULL)
673 for (i = 0; i < comp->nbStep; i++) {
674 op = &comp->steps[i];
675 if (op->value4 != NULL) {
676 if (op->op == XPATH_OP_VALUE)
677 xmlXPathFreeObject(op->value4);
680 xmlDictFree(comp->dict);
682 if (comp->steps != NULL) {
683 xmlFree(comp->steps);
685 #ifdef DEBUG_EVAL_COUNTS
686 if (comp->string != NULL) {
687 xmlFree(comp->string);
690 #ifdef XPATH_STREAMING
691 if (comp->stream != NULL) {
692 xmlFreePatternList(comp->stream);
695 if (comp->expr != NULL) {
703 * xmlXPathCompExprAdd:
704 * @comp: the compiled expression
705 * @ch1: first child index
706 * @ch2: second child index
708 * @value: the first int value
709 * @value2: the second int value
710 * @value3: the third int value
711 * @value4: the first string value
712 * @value5: the second string value
714 * Add a step to an XPath Compiled Expression
716 * Returns -1 in case of failure, the index otherwise
719 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
720 xmlXPathOp op, int value,
721 int value2, int value3, void *value4, void *value5) {
722 if (comp->nbStep >= comp->maxStep) {
723 xmlXPathStepOp *real;
726 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
727 comp->maxStep * sizeof(xmlXPathStepOp));
730 xmlXPathErrMemory(NULL, "adding step\n");
735 comp->last = comp->nbStep;
736 comp->steps[comp->nbStep].rewriteType = 0;
737 comp->steps[comp->nbStep].ch1 = ch1;
738 comp->steps[comp->nbStep].ch2 = ch2;
739 comp->steps[comp->nbStep].op = op;
740 comp->steps[comp->nbStep].value = value;
741 comp->steps[comp->nbStep].value2 = value2;
742 comp->steps[comp->nbStep].value3 = value3;
743 if ((comp->dict != NULL) &&
744 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
745 (op == XPATH_OP_COLLECT))) {
746 if (value4 != NULL) {
747 comp->steps[comp->nbStep].value4 = (xmlChar *)
748 (void *)xmlDictLookup(comp->dict, value4, -1);
751 comp->steps[comp->nbStep].value4 = NULL;
752 if (value5 != NULL) {
753 comp->steps[comp->nbStep].value5 = (xmlChar *)
754 (void *)xmlDictLookup(comp->dict, value5, -1);
757 comp->steps[comp->nbStep].value5 = NULL;
759 comp->steps[comp->nbStep].value4 = value4;
760 comp->steps[comp->nbStep].value5 = value5;
762 comp->steps[comp->nbStep].cache = NULL;
763 return(comp->nbStep++);
768 * @comp: the compiled expression
769 * @op: operation index
771 * Swaps 2 operations in the compiled expression
774 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
777 #ifndef LIBXML_THREAD_ENABLED
779 * Since this manipulates possibly shared variables, this is
780 * disabled if one detects that the library is used in a multithreaded
783 if (xmlXPathDisableOptimizer)
792 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
793 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
794 (op), (val), (val2), (val3), (val4), (val5))
795 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
796 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
797 (op), (val), (val2), (val3), (val4), (val5))
799 #define PUSH_LEAVE_EXPR(op, val, val2) \
800 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
802 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
803 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
805 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
806 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
807 (val), (val2), 0 ,NULL ,NULL)
809 /************************************************************************
811 * XPath object cache structures *
813 ************************************************************************/
815 /* #define XP_DEFAULT_CACHE_ON */
817 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
819 typedef struct _xmlXPathContextCache xmlXPathContextCache;
820 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
821 struct _xmlXPathContextCache {
822 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
823 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
832 #ifdef XP_DEBUG_OBJ_USAGE
834 int dbgCachedNodeset;
842 int dbgCachedXSLTTree;
843 int dbgCachedUndefined;
847 int dbgReusedNodeset;
855 int dbgReusedXSLTTree;
856 int dbgReusedUndefined;
861 /************************************************************************
863 * Debugging related functions *
865 ************************************************************************/
868 xmlGenericError(xmlGenericErrorContext, \
869 "Internal error at %s:%d\n", \
872 #ifdef LIBXML_DEBUG_ENABLED
874 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
878 for (i = 0;((i < depth) && (i < 25));i++)
879 shift[2 * i] = shift[2 * i + 1] = ' ';
880 shift[2 * i] = shift[2 * i + 1] = 0;
882 fprintf(output, "%s", shift);
883 fprintf(output, "Node is NULL !\n");
888 if ((cur->type == XML_DOCUMENT_NODE) ||
889 (cur->type == XML_HTML_DOCUMENT_NODE)) {
890 fprintf(output, "%s", shift);
891 fprintf(output, " /\n");
892 } else if (cur->type == XML_ATTRIBUTE_NODE)
893 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
895 xmlDebugDumpOneNode(output, cur, depth);
898 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
903 for (i = 0;((i < depth) && (i < 25));i++)
904 shift[2 * i] = shift[2 * i + 1] = ' ';
905 shift[2 * i] = shift[2 * i + 1] = 0;
907 fprintf(output, "%s", shift);
908 fprintf(output, "Node is NULL !\n");
913 while (cur != NULL) {
916 xmlDebugDumpOneNode(output, tmp, depth);
921 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
925 for (i = 0;((i < depth) && (i < 25));i++)
926 shift[2 * i] = shift[2 * i + 1] = ' ';
927 shift[2 * i] = shift[2 * i + 1] = 0;
930 fprintf(output, "%s", shift);
931 fprintf(output, "NodeSet is NULL !\n");
937 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
938 for (i = 0;i < cur->nodeNr;i++) {
939 fprintf(output, "%s", shift);
940 fprintf(output, "%d", i + 1);
941 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
947 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
951 for (i = 0;((i < depth) && (i < 25));i++)
952 shift[2 * i] = shift[2 * i + 1] = ' ';
953 shift[2 * i] = shift[2 * i + 1] = 0;
955 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
956 fprintf(output, "%s", shift);
957 fprintf(output, "Value Tree is NULL !\n");
962 fprintf(output, "%s", shift);
963 fprintf(output, "%d", i + 1);
964 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
966 #if defined(LIBXML_XPTR_ENABLED)
968 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
972 for (i = 0;((i < depth) && (i < 25));i++)
973 shift[2 * i] = shift[2 * i + 1] = ' ';
974 shift[2 * i] = shift[2 * i + 1] = 0;
977 fprintf(output, "%s", shift);
978 fprintf(output, "LocationSet is NULL !\n");
983 for (i = 0;i < cur->locNr;i++) {
984 fprintf(output, "%s", shift);
985 fprintf(output, "%d : ", i + 1);
986 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
989 #endif /* LIBXML_XPTR_ENABLED */
992 * xmlXPathDebugDumpObject:
993 * @output: the FILE * to dump the output
994 * @cur: the object to inspect
995 * @depth: indentation level
997 * Dump the content of the object for debugging purposes
1000 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1004 if (output == NULL) return;
1006 for (i = 0;((i < depth) && (i < 25));i++)
1007 shift[2 * i] = shift[2 * i + 1] = ' ';
1008 shift[2 * i] = shift[2 * i + 1] = 0;
1011 fprintf(output, "%s", shift);
1014 fprintf(output, "Object is empty (NULL)\n");
1018 case XPATH_UNDEFINED:
1019 fprintf(output, "Object is uninitialized\n");
1022 fprintf(output, "Object is a Node Set :\n");
1023 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1025 case XPATH_XSLT_TREE:
1026 fprintf(output, "Object is an XSLT value tree :\n");
1027 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1030 fprintf(output, "Object is a Boolean : ");
1031 if (cur->boolval) fprintf(output, "true\n");
1032 else fprintf(output, "false\n");
1035 switch (xmlXPathIsInf(cur->floatval)) {
1037 fprintf(output, "Object is a number : Infinity\n");
1040 fprintf(output, "Object is a number : -Infinity\n");
1043 if (xmlXPathIsNaN(cur->floatval)) {
1044 fprintf(output, "Object is a number : NaN\n");
1045 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1046 fprintf(output, "Object is a number : 0\n");
1048 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1053 fprintf(output, "Object is a string : ");
1054 xmlDebugDumpString(output, cur->stringval);
1055 fprintf(output, "\n");
1058 fprintf(output, "Object is a point : index %d in node", cur->index);
1059 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1060 fprintf(output, "\n");
1063 if ((cur->user2 == NULL) ||
1064 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1065 fprintf(output, "Object is a collapsed range :\n");
1066 fprintf(output, "%s", shift);
1067 if (cur->index >= 0)
1068 fprintf(output, "index %d in ", cur->index);
1069 fprintf(output, "node\n");
1070 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1073 fprintf(output, "Object is a range :\n");
1074 fprintf(output, "%s", shift);
1075 fprintf(output, "From ");
1076 if (cur->index >= 0)
1077 fprintf(output, "index %d in ", cur->index);
1078 fprintf(output, "node\n");
1079 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1081 fprintf(output, "%s", shift);
1082 fprintf(output, "To ");
1083 if (cur->index2 >= 0)
1084 fprintf(output, "index %d in ", cur->index2);
1085 fprintf(output, "node\n");
1086 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1088 fprintf(output, "\n");
1091 case XPATH_LOCATIONSET:
1092 #if defined(LIBXML_XPTR_ENABLED)
1093 fprintf(output, "Object is a Location Set:\n");
1094 xmlXPathDebugDumpLocationSet(output,
1095 (xmlLocationSetPtr) cur->user, depth);
1099 fprintf(output, "Object is user defined\n");
1105 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1106 xmlXPathStepOpPtr op, int depth) {
1110 for (i = 0;((i < depth) && (i < 25));i++)
1111 shift[2 * i] = shift[2 * i + 1] = ' ';
1112 shift[2 * i] = shift[2 * i + 1] = 0;
1114 fprintf(output, "%s", shift);
1116 fprintf(output, "Step is NULL\n");
1121 fprintf(output, "END"); break;
1123 fprintf(output, "AND"); break;
1125 fprintf(output, "OR"); break;
1126 case XPATH_OP_EQUAL:
1128 fprintf(output, "EQUAL =");
1130 fprintf(output, "EQUAL !=");
1134 fprintf(output, "CMP <");
1136 fprintf(output, "CMP >");
1138 fprintf(output, "=");
1142 fprintf(output, "PLUS -");
1143 else if (op->value == 1)
1144 fprintf(output, "PLUS +");
1145 else if (op->value == 2)
1146 fprintf(output, "PLUS unary -");
1147 else if (op->value == 3)
1148 fprintf(output, "PLUS unary - -");
1152 fprintf(output, "MULT *");
1153 else if (op->value == 1)
1154 fprintf(output, "MULT div");
1156 fprintf(output, "MULT mod");
1158 case XPATH_OP_UNION:
1159 fprintf(output, "UNION"); break;
1161 fprintf(output, "ROOT"); break;
1163 fprintf(output, "NODE"); break;
1164 case XPATH_OP_RESET:
1165 fprintf(output, "RESET"); break;
1167 fprintf(output, "SORT"); break;
1168 case XPATH_OP_COLLECT: {
1169 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1170 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1171 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1172 const xmlChar *prefix = op->value4;
1173 const xmlChar *name = op->value5;
1175 fprintf(output, "COLLECT ");
1178 fprintf(output, " 'ancestors' "); break;
1179 case AXIS_ANCESTOR_OR_SELF:
1180 fprintf(output, " 'ancestors-or-self' "); break;
1181 case AXIS_ATTRIBUTE:
1182 fprintf(output, " 'attributes' "); break;
1184 fprintf(output, " 'child' "); break;
1185 case AXIS_DESCENDANT:
1186 fprintf(output, " 'descendant' "); break;
1187 case AXIS_DESCENDANT_OR_SELF:
1188 fprintf(output, " 'descendant-or-self' "); break;
1189 case AXIS_FOLLOWING:
1190 fprintf(output, " 'following' "); break;
1191 case AXIS_FOLLOWING_SIBLING:
1192 fprintf(output, " 'following-siblings' "); break;
1193 case AXIS_NAMESPACE:
1194 fprintf(output, " 'namespace' "); break;
1196 fprintf(output, " 'parent' "); break;
1197 case AXIS_PRECEDING:
1198 fprintf(output, " 'preceding' "); break;
1199 case AXIS_PRECEDING_SIBLING:
1200 fprintf(output, " 'preceding-sibling' "); break;
1202 fprintf(output, " 'self' "); break;
1205 case NODE_TEST_NONE:
1206 fprintf(output, "'none' "); break;
1207 case NODE_TEST_TYPE:
1208 fprintf(output, "'type' "); break;
1210 fprintf(output, "'PI' "); break;
1212 fprintf(output, "'all' "); break;
1214 fprintf(output, "'namespace' "); break;
1215 case NODE_TEST_NAME:
1216 fprintf(output, "'name' "); break;
1219 case NODE_TYPE_NODE:
1220 fprintf(output, "'node' "); break;
1221 case NODE_TYPE_COMMENT:
1222 fprintf(output, "'comment' "); break;
1223 case NODE_TYPE_TEXT:
1224 fprintf(output, "'text' "); break;
1226 fprintf(output, "'PI' "); break;
1229 fprintf(output, "%s:", prefix);
1231 fprintf(output, "%s", (const char *) name);
1235 case XPATH_OP_VALUE: {
1236 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1238 fprintf(output, "ELEM ");
1239 xmlXPathDebugDumpObject(output, object, 0);
1242 case XPATH_OP_VARIABLE: {
1243 const xmlChar *prefix = op->value5;
1244 const xmlChar *name = op->value4;
1247 fprintf(output, "VARIABLE %s:%s", prefix, name);
1249 fprintf(output, "VARIABLE %s", name);
1252 case XPATH_OP_FUNCTION: {
1253 int nbargs = op->value;
1254 const xmlChar *prefix = op->value5;
1255 const xmlChar *name = op->value4;
1258 fprintf(output, "FUNCTION %s:%s(%d args)",
1259 prefix, name, nbargs);
1261 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1264 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1265 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1266 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1267 #ifdef LIBXML_XPTR_ENABLED
1268 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1271 fprintf(output, "UNKNOWN %d\n", op->op); return;
1273 fprintf(output, "\n");
1276 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1278 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1282 * xmlXPathDebugDumpCompExpr:
1283 * @output: the FILE * for the output
1284 * @comp: the precompiled XPath expression
1285 * @depth: the indentation level.
1287 * Dumps the tree of the compiled XPath expression.
1290 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1295 if ((output == NULL) || (comp == NULL)) return;
1297 for (i = 0;((i < depth) && (i < 25));i++)
1298 shift[2 * i] = shift[2 * i + 1] = ' ';
1299 shift[2 * i] = shift[2 * i + 1] = 0;
1301 fprintf(output, "%s", shift);
1303 fprintf(output, "Compiled Expression : %d elements\n",
1306 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1309 #ifdef XP_DEBUG_OBJ_USAGE
1312 * XPath object usage related debugging variables.
1314 static int xmlXPathDebugObjCounterUndefined = 0;
1315 static int xmlXPathDebugObjCounterNodeset = 0;
1316 static int xmlXPathDebugObjCounterBool = 0;
1317 static int xmlXPathDebugObjCounterNumber = 0;
1318 static int xmlXPathDebugObjCounterString = 0;
1319 static int xmlXPathDebugObjCounterPoint = 0;
1320 static int xmlXPathDebugObjCounterRange = 0;
1321 static int xmlXPathDebugObjCounterLocset = 0;
1322 static int xmlXPathDebugObjCounterUsers = 0;
1323 static int xmlXPathDebugObjCounterXSLTTree = 0;
1324 static int xmlXPathDebugObjCounterAll = 0;
1326 static int xmlXPathDebugObjTotalUndefined = 0;
1327 static int xmlXPathDebugObjTotalNodeset = 0;
1328 static int xmlXPathDebugObjTotalBool = 0;
1329 static int xmlXPathDebugObjTotalNumber = 0;
1330 static int xmlXPathDebugObjTotalString = 0;
1331 static int xmlXPathDebugObjTotalPoint = 0;
1332 static int xmlXPathDebugObjTotalRange = 0;
1333 static int xmlXPathDebugObjTotalLocset = 0;
1334 static int xmlXPathDebugObjTotalUsers = 0;
1335 static int xmlXPathDebugObjTotalXSLTTree = 0;
1336 static int xmlXPathDebugObjTotalAll = 0;
1338 static int xmlXPathDebugObjMaxUndefined = 0;
1339 static int xmlXPathDebugObjMaxNodeset = 0;
1340 static int xmlXPathDebugObjMaxBool = 0;
1341 static int xmlXPathDebugObjMaxNumber = 0;
1342 static int xmlXPathDebugObjMaxString = 0;
1343 static int xmlXPathDebugObjMaxPoint = 0;
1344 static int xmlXPathDebugObjMaxRange = 0;
1345 static int xmlXPathDebugObjMaxLocset = 0;
1346 static int xmlXPathDebugObjMaxUsers = 0;
1347 static int xmlXPathDebugObjMaxXSLTTree = 0;
1348 static int xmlXPathDebugObjMaxAll = 0;
1350 /* REVISIT TODO: Make this static when committing */
1352 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1355 if (ctxt->cache != NULL) {
1356 xmlXPathContextCachePtr cache =
1357 (xmlXPathContextCachePtr) ctxt->cache;
1359 cache->dbgCachedAll = 0;
1360 cache->dbgCachedNodeset = 0;
1361 cache->dbgCachedString = 0;
1362 cache->dbgCachedBool = 0;
1363 cache->dbgCachedNumber = 0;
1364 cache->dbgCachedPoint = 0;
1365 cache->dbgCachedRange = 0;
1366 cache->dbgCachedLocset = 0;
1367 cache->dbgCachedUsers = 0;
1368 cache->dbgCachedXSLTTree = 0;
1369 cache->dbgCachedUndefined = 0;
1371 cache->dbgReusedAll = 0;
1372 cache->dbgReusedNodeset = 0;
1373 cache->dbgReusedString = 0;
1374 cache->dbgReusedBool = 0;
1375 cache->dbgReusedNumber = 0;
1376 cache->dbgReusedPoint = 0;
1377 cache->dbgReusedRange = 0;
1378 cache->dbgReusedLocset = 0;
1379 cache->dbgReusedUsers = 0;
1380 cache->dbgReusedXSLTTree = 0;
1381 cache->dbgReusedUndefined = 0;
1385 xmlXPathDebugObjCounterUndefined = 0;
1386 xmlXPathDebugObjCounterNodeset = 0;
1387 xmlXPathDebugObjCounterBool = 0;
1388 xmlXPathDebugObjCounterNumber = 0;
1389 xmlXPathDebugObjCounterString = 0;
1390 xmlXPathDebugObjCounterPoint = 0;
1391 xmlXPathDebugObjCounterRange = 0;
1392 xmlXPathDebugObjCounterLocset = 0;
1393 xmlXPathDebugObjCounterUsers = 0;
1394 xmlXPathDebugObjCounterXSLTTree = 0;
1395 xmlXPathDebugObjCounterAll = 0;
1397 xmlXPathDebugObjTotalUndefined = 0;
1398 xmlXPathDebugObjTotalNodeset = 0;
1399 xmlXPathDebugObjTotalBool = 0;
1400 xmlXPathDebugObjTotalNumber = 0;
1401 xmlXPathDebugObjTotalString = 0;
1402 xmlXPathDebugObjTotalPoint = 0;
1403 xmlXPathDebugObjTotalRange = 0;
1404 xmlXPathDebugObjTotalLocset = 0;
1405 xmlXPathDebugObjTotalUsers = 0;
1406 xmlXPathDebugObjTotalXSLTTree = 0;
1407 xmlXPathDebugObjTotalAll = 0;
1409 xmlXPathDebugObjMaxUndefined = 0;
1410 xmlXPathDebugObjMaxNodeset = 0;
1411 xmlXPathDebugObjMaxBool = 0;
1412 xmlXPathDebugObjMaxNumber = 0;
1413 xmlXPathDebugObjMaxString = 0;
1414 xmlXPathDebugObjMaxPoint = 0;
1415 xmlXPathDebugObjMaxRange = 0;
1416 xmlXPathDebugObjMaxLocset = 0;
1417 xmlXPathDebugObjMaxUsers = 0;
1418 xmlXPathDebugObjMaxXSLTTree = 0;
1419 xmlXPathDebugObjMaxAll = 0;
1424 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1425 xmlXPathObjectType objType)
1430 if (ctxt->cache != NULL) {
1431 xmlXPathContextCachePtr cache =
1432 (xmlXPathContextCachePtr) ctxt->cache;
1436 cache->dbgReusedAll++;
1438 case XPATH_UNDEFINED:
1439 cache->dbgReusedUndefined++;
1442 cache->dbgReusedNodeset++;
1445 cache->dbgReusedBool++;
1448 cache->dbgReusedNumber++;
1451 cache->dbgReusedString++;
1454 cache->dbgReusedPoint++;
1457 cache->dbgReusedRange++;
1459 case XPATH_LOCATIONSET:
1460 cache->dbgReusedLocset++;
1463 cache->dbgReusedUsers++;
1465 case XPATH_XSLT_TREE:
1466 cache->dbgReusedXSLTTree++;
1475 case XPATH_UNDEFINED:
1477 xmlXPathDebugObjTotalUndefined++;
1478 xmlXPathDebugObjCounterUndefined++;
1479 if (xmlXPathDebugObjCounterUndefined >
1480 xmlXPathDebugObjMaxUndefined)
1481 xmlXPathDebugObjMaxUndefined =
1482 xmlXPathDebugObjCounterUndefined;
1486 xmlXPathDebugObjTotalNodeset++;
1487 xmlXPathDebugObjCounterNodeset++;
1488 if (xmlXPathDebugObjCounterNodeset >
1489 xmlXPathDebugObjMaxNodeset)
1490 xmlXPathDebugObjMaxNodeset =
1491 xmlXPathDebugObjCounterNodeset;
1495 xmlXPathDebugObjTotalBool++;
1496 xmlXPathDebugObjCounterBool++;
1497 if (xmlXPathDebugObjCounterBool >
1498 xmlXPathDebugObjMaxBool)
1499 xmlXPathDebugObjMaxBool =
1500 xmlXPathDebugObjCounterBool;
1504 xmlXPathDebugObjTotalNumber++;
1505 xmlXPathDebugObjCounterNumber++;
1506 if (xmlXPathDebugObjCounterNumber >
1507 xmlXPathDebugObjMaxNumber)
1508 xmlXPathDebugObjMaxNumber =
1509 xmlXPathDebugObjCounterNumber;
1513 xmlXPathDebugObjTotalString++;
1514 xmlXPathDebugObjCounterString++;
1515 if (xmlXPathDebugObjCounterString >
1516 xmlXPathDebugObjMaxString)
1517 xmlXPathDebugObjMaxString =
1518 xmlXPathDebugObjCounterString;
1522 xmlXPathDebugObjTotalPoint++;
1523 xmlXPathDebugObjCounterPoint++;
1524 if (xmlXPathDebugObjCounterPoint >
1525 xmlXPathDebugObjMaxPoint)
1526 xmlXPathDebugObjMaxPoint =
1527 xmlXPathDebugObjCounterPoint;
1531 xmlXPathDebugObjTotalRange++;
1532 xmlXPathDebugObjCounterRange++;
1533 if (xmlXPathDebugObjCounterRange >
1534 xmlXPathDebugObjMaxRange)
1535 xmlXPathDebugObjMaxRange =
1536 xmlXPathDebugObjCounterRange;
1538 case XPATH_LOCATIONSET:
1540 xmlXPathDebugObjTotalLocset++;
1541 xmlXPathDebugObjCounterLocset++;
1542 if (xmlXPathDebugObjCounterLocset >
1543 xmlXPathDebugObjMaxLocset)
1544 xmlXPathDebugObjMaxLocset =
1545 xmlXPathDebugObjCounterLocset;
1549 xmlXPathDebugObjTotalUsers++;
1550 xmlXPathDebugObjCounterUsers++;
1551 if (xmlXPathDebugObjCounterUsers >
1552 xmlXPathDebugObjMaxUsers)
1553 xmlXPathDebugObjMaxUsers =
1554 xmlXPathDebugObjCounterUsers;
1556 case XPATH_XSLT_TREE:
1558 xmlXPathDebugObjTotalXSLTTree++;
1559 xmlXPathDebugObjCounterXSLTTree++;
1560 if (xmlXPathDebugObjCounterXSLTTree >
1561 xmlXPathDebugObjMaxXSLTTree)
1562 xmlXPathDebugObjMaxXSLTTree =
1563 xmlXPathDebugObjCounterXSLTTree;
1569 xmlXPathDebugObjTotalAll++;
1570 xmlXPathDebugObjCounterAll++;
1571 if (xmlXPathDebugObjCounterAll >
1572 xmlXPathDebugObjMaxAll)
1573 xmlXPathDebugObjMaxAll =
1574 xmlXPathDebugObjCounterAll;
1578 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1579 xmlXPathObjectType objType)
1584 if (ctxt->cache != NULL) {
1585 xmlXPathContextCachePtr cache =
1586 (xmlXPathContextCachePtr) ctxt->cache;
1590 cache->dbgCachedAll++;
1592 case XPATH_UNDEFINED:
1593 cache->dbgCachedUndefined++;
1596 cache->dbgCachedNodeset++;
1599 cache->dbgCachedBool++;
1602 cache->dbgCachedNumber++;
1605 cache->dbgCachedString++;
1608 cache->dbgCachedPoint++;
1611 cache->dbgCachedRange++;
1613 case XPATH_LOCATIONSET:
1614 cache->dbgCachedLocset++;
1617 cache->dbgCachedUsers++;
1619 case XPATH_XSLT_TREE:
1620 cache->dbgCachedXSLTTree++;
1629 case XPATH_UNDEFINED:
1630 xmlXPathDebugObjCounterUndefined--;
1633 xmlXPathDebugObjCounterNodeset--;
1636 xmlXPathDebugObjCounterBool--;
1639 xmlXPathDebugObjCounterNumber--;
1642 xmlXPathDebugObjCounterString--;
1645 xmlXPathDebugObjCounterPoint--;
1648 xmlXPathDebugObjCounterRange--;
1650 case XPATH_LOCATIONSET:
1651 xmlXPathDebugObjCounterLocset--;
1654 xmlXPathDebugObjCounterUsers--;
1656 case XPATH_XSLT_TREE:
1657 xmlXPathDebugObjCounterXSLTTree--;
1662 xmlXPathDebugObjCounterAll--;
1665 /* REVISIT TODO: Make this static when committing */
1667 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1669 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1670 reqXSLTTree, reqUndefined;
1671 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1672 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1673 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1674 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1675 int leftObjs = xmlXPathDebugObjCounterAll;
1677 reqAll = xmlXPathDebugObjTotalAll;
1678 reqNodeset = xmlXPathDebugObjTotalNodeset;
1679 reqString = xmlXPathDebugObjTotalString;
1680 reqBool = xmlXPathDebugObjTotalBool;
1681 reqNumber = xmlXPathDebugObjTotalNumber;
1682 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1683 reqUndefined = xmlXPathDebugObjTotalUndefined;
1685 printf("# XPath object usage:\n");
1688 if (ctxt->cache != NULL) {
1689 xmlXPathContextCachePtr cache =
1690 (xmlXPathContextCachePtr) ctxt->cache;
1692 reAll = cache->dbgReusedAll;
1694 reNodeset = cache->dbgReusedNodeset;
1695 reqNodeset += reNodeset;
1696 reString = cache->dbgReusedString;
1697 reqString += reString;
1698 reBool = cache->dbgReusedBool;
1700 reNumber = cache->dbgReusedNumber;
1701 reqNumber += reNumber;
1702 reXSLTTree = cache->dbgReusedXSLTTree;
1703 reqXSLTTree += reXSLTTree;
1704 reUndefined = cache->dbgReusedUndefined;
1705 reqUndefined += reUndefined;
1707 caAll = cache->dbgCachedAll;
1708 caBool = cache->dbgCachedBool;
1709 caNodeset = cache->dbgCachedNodeset;
1710 caString = cache->dbgCachedString;
1711 caNumber = cache->dbgCachedNumber;
1712 caXSLTTree = cache->dbgCachedXSLTTree;
1713 caUndefined = cache->dbgCachedUndefined;
1715 if (cache->nodesetObjs)
1716 leftObjs -= cache->nodesetObjs->number;
1717 if (cache->stringObjs)
1718 leftObjs -= cache->stringObjs->number;
1719 if (cache->booleanObjs)
1720 leftObjs -= cache->booleanObjs->number;
1721 if (cache->numberObjs)
1722 leftObjs -= cache->numberObjs->number;
1723 if (cache->miscObjs)
1724 leftObjs -= cache->miscObjs->number;
1729 printf("# total : %d\n", reqAll);
1730 printf("# left : %d\n", leftObjs);
1731 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1732 printf("# reused : %d\n", reAll);
1733 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1735 printf("# node-sets\n");
1736 printf("# total : %d\n", reqNodeset);
1737 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1738 printf("# reused : %d\n", reNodeset);
1739 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1741 printf("# strings\n");
1742 printf("# total : %d\n", reqString);
1743 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1744 printf("# reused : %d\n", reString);
1745 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1747 printf("# booleans\n");
1748 printf("# total : %d\n", reqBool);
1749 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1750 printf("# reused : %d\n", reBool);
1751 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1753 printf("# numbers\n");
1754 printf("# total : %d\n", reqNumber);
1755 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1756 printf("# reused : %d\n", reNumber);
1757 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1759 printf("# XSLT result tree fragments\n");
1760 printf("# total : %d\n", reqXSLTTree);
1761 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1762 printf("# reused : %d\n", reXSLTTree);
1763 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1765 printf("# undefined\n");
1766 printf("# total : %d\n", reqUndefined);
1767 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1768 printf("# reused : %d\n", reUndefined);
1769 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1773 #endif /* XP_DEBUG_OBJ_USAGE */
1775 #endif /* LIBXML_DEBUG_ENABLED */
1777 /************************************************************************
1779 * XPath object caching *
1781 ************************************************************************/
1786 * Create a new object cache
1788 * Returns the xmlXPathCache just allocated.
1790 static xmlXPathContextCachePtr
1791 xmlXPathNewCache(void)
1793 xmlXPathContextCachePtr ret;
1795 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1797 xmlXPathErrMemory(NULL, "creating object cache\n");
1800 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1801 ret->maxNodeset = 100;
1802 ret->maxString = 100;
1803 ret->maxBoolean = 100;
1804 ret->maxNumber = 100;
1810 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1813 xmlXPathObjectPtr obj;
1818 for (i = 0; i < list->number; i++) {
1819 obj = list->items[i];
1821 * Note that it is already assured that we don't need to
1822 * look out for namespace nodes in the node-set.
1824 if (obj->nodesetval != NULL) {
1825 if (obj->nodesetval->nodeTab != NULL)
1826 xmlFree(obj->nodesetval->nodeTab);
1827 xmlFree(obj->nodesetval);
1830 #ifdef XP_DEBUG_OBJ_USAGE
1831 xmlXPathDebugObjCounterAll--;
1834 xmlPointerListFree(list);
1838 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1842 if (cache->nodesetObjs)
1843 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1844 if (cache->stringObjs)
1845 xmlXPathCacheFreeObjectList(cache->stringObjs);
1846 if (cache->booleanObjs)
1847 xmlXPathCacheFreeObjectList(cache->booleanObjs);
1848 if (cache->numberObjs)
1849 xmlXPathCacheFreeObjectList(cache->numberObjs);
1850 if (cache->miscObjs)
1851 xmlXPathCacheFreeObjectList(cache->miscObjs);
1856 * xmlXPathContextSetCache:
1858 * @ctxt: the XPath context
1859 * @active: enables/disables (creates/frees) the cache
1860 * @value: a value with semantics dependant on @options
1861 * @options: options (currently only the value 0 is used)
1863 * Creates/frees an object cache on the XPath context.
1864 * If activates XPath objects (xmlXPathObject) will be cached internally
1867 * 0: This will set the XPath object caching:
1869 * This will set the maximum number of XPath objects
1870 * to be cached per slot
1871 * There are 5 slots for: node-set, string, number, boolean, and
1872 * misc objects. Use <0 for the default number (100).
1873 * Other values for @options have currently no effect.
1875 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1878 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1886 xmlXPathContextCachePtr cache;
1888 if (ctxt->cache == NULL) {
1889 ctxt->cache = xmlXPathNewCache();
1890 if (ctxt->cache == NULL)
1893 cache = (xmlXPathContextCachePtr) ctxt->cache;
1897 cache->maxNodeset = value;
1898 cache->maxString = value;
1899 cache->maxNumber = value;
1900 cache->maxBoolean = value;
1901 cache->maxMisc = value;
1903 } else if (ctxt->cache != NULL) {
1904 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1911 * xmlXPathCacheWrapNodeSet:
1912 * @ctxt: the XPath context
1913 * @val: the NodePtr value
1915 * This is the cached version of xmlXPathWrapNodeSet().
1916 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1918 * Returns the created or reused object.
1920 static xmlXPathObjectPtr
1921 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1923 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1924 xmlXPathContextCachePtr cache =
1925 (xmlXPathContextCachePtr) ctxt->cache;
1927 if ((cache->miscObjs != NULL) &&
1928 (cache->miscObjs->number != 0))
1930 xmlXPathObjectPtr ret;
1932 ret = (xmlXPathObjectPtr)
1933 cache->miscObjs->items[--cache->miscObjs->number];
1934 ret->type = XPATH_NODESET;
1935 ret->nodesetval = val;
1936 #ifdef XP_DEBUG_OBJ_USAGE
1937 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1943 return(xmlXPathWrapNodeSet(val));
1948 * xmlXPathCacheWrapString:
1949 * @ctxt: the XPath context
1950 * @val: the xmlChar * value
1952 * This is the cached version of xmlXPathWrapString().
1953 * Wraps the @val string into an XPath object.
1955 * Returns the created or reused object.
1957 static xmlXPathObjectPtr
1958 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1960 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1961 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1963 if ((cache->stringObjs != NULL) &&
1964 (cache->stringObjs->number != 0))
1967 xmlXPathObjectPtr ret;
1969 ret = (xmlXPathObjectPtr)
1970 cache->stringObjs->items[--cache->stringObjs->number];
1971 ret->type = XPATH_STRING;
1972 ret->stringval = val;
1973 #ifdef XP_DEBUG_OBJ_USAGE
1974 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1977 } else if ((cache->miscObjs != NULL) &&
1978 (cache->miscObjs->number != 0))
1980 xmlXPathObjectPtr ret;
1982 * Fallback to misc-cache.
1984 ret = (xmlXPathObjectPtr)
1985 cache->miscObjs->items[--cache->miscObjs->number];
1987 ret->type = XPATH_STRING;
1988 ret->stringval = val;
1989 #ifdef XP_DEBUG_OBJ_USAGE
1990 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1995 return(xmlXPathWrapString(val));
1999 * xmlXPathCacheNewNodeSet:
2000 * @ctxt: the XPath context
2001 * @val: the NodePtr value
2003 * This is the cached version of xmlXPathNewNodeSet().
2004 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2005 * it with the single Node @val
2007 * Returns the created or reused object.
2009 static xmlXPathObjectPtr
2010 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2012 if ((ctxt != NULL) && (ctxt->cache)) {
2013 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2015 if ((cache->nodesetObjs != NULL) &&
2016 (cache->nodesetObjs->number != 0))
2018 xmlXPathObjectPtr ret;
2020 * Use the nodset-cache.
2022 ret = (xmlXPathObjectPtr)
2023 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2024 ret->type = XPATH_NODESET;
2027 if ((ret->nodesetval->nodeMax == 0) ||
2028 (val->type == XML_NAMESPACE_DECL))
2030 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2032 ret->nodesetval->nodeTab[0] = val;
2033 ret->nodesetval->nodeNr = 1;
2036 #ifdef XP_DEBUG_OBJ_USAGE
2037 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2040 } else if ((cache->miscObjs != NULL) &&
2041 (cache->miscObjs->number != 0))
2043 xmlXPathObjectPtr ret;
2045 * Fallback to misc-cache.
2048 ret = (xmlXPathObjectPtr)
2049 cache->miscObjs->items[--cache->miscObjs->number];
2051 ret->type = XPATH_NODESET;
2053 ret->nodesetval = xmlXPathNodeSetCreate(val);
2054 #ifdef XP_DEBUG_OBJ_USAGE
2055 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2060 return(xmlXPathNewNodeSet(val));
2064 * xmlXPathCacheNewCString:
2065 * @ctxt: the XPath context
2066 * @val: the char * value
2068 * This is the cached version of xmlXPathNewCString().
2069 * Acquire an xmlXPathObjectPtr of type string and of value @val
2071 * Returns the created or reused object.
2073 static xmlXPathObjectPtr
2074 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2076 if ((ctxt != NULL) && (ctxt->cache)) {
2077 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2079 if ((cache->stringObjs != NULL) &&
2080 (cache->stringObjs->number != 0))
2082 xmlXPathObjectPtr ret;
2084 ret = (xmlXPathObjectPtr)
2085 cache->stringObjs->items[--cache->stringObjs->number];
2087 ret->type = XPATH_STRING;
2088 ret->stringval = xmlStrdup(BAD_CAST val);
2089 #ifdef XP_DEBUG_OBJ_USAGE
2090 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2093 } else if ((cache->miscObjs != NULL) &&
2094 (cache->miscObjs->number != 0))
2096 xmlXPathObjectPtr ret;
2098 ret = (xmlXPathObjectPtr)
2099 cache->miscObjs->items[--cache->miscObjs->number];
2101 ret->type = XPATH_STRING;
2102 ret->stringval = xmlStrdup(BAD_CAST val);
2103 #ifdef XP_DEBUG_OBJ_USAGE
2104 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2109 return(xmlXPathNewCString(val));
2113 * xmlXPathCacheNewString:
2114 * @ctxt: the XPath context
2115 * @val: the xmlChar * value
2117 * This is the cached version of xmlXPathNewString().
2118 * Acquire an xmlXPathObjectPtr of type string and of value @val
2120 * Returns the created or reused object.
2122 static xmlXPathObjectPtr
2123 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2125 if ((ctxt != NULL) && (ctxt->cache)) {
2126 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2128 if ((cache->stringObjs != NULL) &&
2129 (cache->stringObjs->number != 0))
2131 xmlXPathObjectPtr ret;
2133 ret = (xmlXPathObjectPtr)
2134 cache->stringObjs->items[--cache->stringObjs->number];
2135 ret->type = XPATH_STRING;
2137 ret->stringval = xmlStrdup(val);
2139 ret->stringval = xmlStrdup((const xmlChar *)"");
2140 #ifdef XP_DEBUG_OBJ_USAGE
2141 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2144 } else if ((cache->miscObjs != NULL) &&
2145 (cache->miscObjs->number != 0))
2147 xmlXPathObjectPtr ret;
2149 ret = (xmlXPathObjectPtr)
2150 cache->miscObjs->items[--cache->miscObjs->number];
2152 ret->type = XPATH_STRING;
2154 ret->stringval = xmlStrdup(val);
2156 ret->stringval = xmlStrdup((const xmlChar *)"");
2157 #ifdef XP_DEBUG_OBJ_USAGE
2158 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2163 return(xmlXPathNewString(val));
2167 * xmlXPathCacheNewBoolean:
2168 * @ctxt: the XPath context
2169 * @val: the boolean value
2171 * This is the cached version of xmlXPathNewBoolean().
2172 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2174 * Returns the created or reused object.
2176 static xmlXPathObjectPtr
2177 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2179 if ((ctxt != NULL) && (ctxt->cache)) {
2180 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2182 if ((cache->booleanObjs != NULL) &&
2183 (cache->booleanObjs->number != 0))
2185 xmlXPathObjectPtr ret;
2187 ret = (xmlXPathObjectPtr)
2188 cache->booleanObjs->items[--cache->booleanObjs->number];
2189 ret->type = XPATH_BOOLEAN;
2190 ret->boolval = (val != 0);
2191 #ifdef XP_DEBUG_OBJ_USAGE
2192 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2195 } else if ((cache->miscObjs != NULL) &&
2196 (cache->miscObjs->number != 0))
2198 xmlXPathObjectPtr ret;
2200 ret = (xmlXPathObjectPtr)
2201 cache->miscObjs->items[--cache->miscObjs->number];
2203 ret->type = XPATH_BOOLEAN;
2204 ret->boolval = (val != 0);
2205 #ifdef XP_DEBUG_OBJ_USAGE
2206 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2211 return(xmlXPathNewBoolean(val));
2215 * xmlXPathCacheNewFloat:
2216 * @ctxt: the XPath context
2217 * @val: the double value
2219 * This is the cached version of xmlXPathNewFloat().
2220 * Acquires an xmlXPathObjectPtr of type double and of value @val
2222 * Returns the created or reused object.
2224 static xmlXPathObjectPtr
2225 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2227 if ((ctxt != NULL) && (ctxt->cache)) {
2228 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2230 if ((cache->numberObjs != NULL) &&
2231 (cache->numberObjs->number != 0))
2233 xmlXPathObjectPtr ret;
2235 ret = (xmlXPathObjectPtr)
2236 cache->numberObjs->items[--cache->numberObjs->number];
2237 ret->type = XPATH_NUMBER;
2238 ret->floatval = val;
2239 #ifdef XP_DEBUG_OBJ_USAGE
2240 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2243 } else if ((cache->miscObjs != NULL) &&
2244 (cache->miscObjs->number != 0))
2246 xmlXPathObjectPtr ret;
2248 ret = (xmlXPathObjectPtr)
2249 cache->miscObjs->items[--cache->miscObjs->number];
2251 ret->type = XPATH_NUMBER;
2252 ret->floatval = val;
2253 #ifdef XP_DEBUG_OBJ_USAGE
2254 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2259 return(xmlXPathNewFloat(val));
2263 * xmlXPathCacheConvertString:
2264 * @ctxt: the XPath context
2265 * @val: an XPath object
2267 * This is the cached version of xmlXPathConvertString().
2268 * Converts an existing object to its string() equivalent
2270 * Returns a created or reused object, the old one is freed (cached)
2271 * (or the operation is done directly on @val)
2274 static xmlXPathObjectPtr
2275 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2276 xmlChar *res = NULL;
2279 return(xmlXPathCacheNewCString(ctxt, ""));
2281 switch (val->type) {
2282 case XPATH_UNDEFINED:
2284 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2288 case XPATH_XSLT_TREE:
2289 res = xmlXPathCastNodeSetToString(val->nodesetval);
2294 res = xmlXPathCastBooleanToString(val->boolval);
2297 res = xmlXPathCastNumberToString(val->floatval);
2302 case XPATH_LOCATIONSET:
2306 xmlXPathReleaseObject(ctxt, val);
2308 return(xmlXPathCacheNewCString(ctxt, ""));
2309 return(xmlXPathCacheWrapString(ctxt, res));
2313 * xmlXPathCacheObjectCopy:
2314 * @ctxt: the XPath context
2315 * @val: the original object
2317 * This is the cached version of xmlXPathObjectCopy().
2318 * Acquire a copy of a given object
2320 * Returns a created or reused created object.
2322 static xmlXPathObjectPtr
2323 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2328 if (XP_HAS_CACHE(ctxt)) {
2329 switch (val->type) {
2331 return(xmlXPathCacheWrapNodeSet(ctxt,
2332 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2334 return(xmlXPathCacheNewString(ctxt, val->stringval));
2336 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2338 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2343 return(xmlXPathObjectCopy(val));
2347 * xmlXPathCacheConvertBoolean:
2348 * @ctxt: the XPath context
2349 * @val: an XPath object
2351 * This is the cached version of xmlXPathConvertBoolean().
2352 * Converts an existing object to its boolean() equivalent
2354 * Returns a created or reused object, the old one is freed (or the operation
2355 * is done directly on @val)
2357 static xmlXPathObjectPtr
2358 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2359 xmlXPathObjectPtr ret;
2362 return(xmlXPathCacheNewBoolean(ctxt, 0));
2363 if (val->type == XPATH_BOOLEAN)
2365 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2366 xmlXPathReleaseObject(ctxt, val);
2371 * xmlXPathCacheConvertNumber:
2372 * @ctxt: the XPath context
2373 * @val: an XPath object
2375 * This is the cached version of xmlXPathConvertNumber().
2376 * Converts an existing object to its number() equivalent
2378 * Returns a created or reused object, the old one is freed (or the operation
2379 * is done directly on @val)
2381 static xmlXPathObjectPtr
2382 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2383 xmlXPathObjectPtr ret;
2386 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2387 if (val->type == XPATH_NUMBER)
2389 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2390 xmlXPathReleaseObject(ctxt, val);
2394 /************************************************************************
2396 * Parser stacks related functions and macros *
2398 ************************************************************************/
2402 * @ctxt: an XPath evaluation context
2404 * Pops the top XPath object from the value stack
2406 * Returns the XPath object just removed
2409 valuePop(xmlXPathParserContextPtr ctxt)
2411 xmlXPathObjectPtr ret;
2413 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2416 if (ctxt->valueNr > 0)
2417 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2420 ret = ctxt->valueTab[ctxt->valueNr];
2421 ctxt->valueTab[ctxt->valueNr] = NULL;
2426 * @ctxt: an XPath evaluation context
2427 * @value: the XPath object
2429 * Pushes a new XPath object on top of the value stack
2431 * returns the number of items on the value stack
2434 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2436 if ((ctxt == NULL) || (value == NULL)) return(-1);
2437 if (ctxt->valueNr >= ctxt->valueMax) {
2438 xmlXPathObjectPtr *tmp;
2440 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2441 2 * ctxt->valueMax *
2442 sizeof(ctxt->valueTab[0]));
2444 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2447 ctxt->valueMax *= 2;
2448 ctxt->valueTab = tmp;
2450 ctxt->valueTab[ctxt->valueNr] = value;
2451 ctxt->value = value;
2452 return (ctxt->valueNr++);
2456 * xmlXPathPopBoolean:
2457 * @ctxt: an XPath parser context
2459 * Pops a boolean from the stack, handling conversion if needed.
2460 * Check error with #xmlXPathCheckError.
2462 * Returns the boolean
2465 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2466 xmlXPathObjectPtr obj;
2469 obj = valuePop(ctxt);
2471 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2474 if (obj->type != XPATH_BOOLEAN)
2475 ret = xmlXPathCastToBoolean(obj);
2478 xmlXPathReleaseObject(ctxt->context, obj);
2483 * xmlXPathPopNumber:
2484 * @ctxt: an XPath parser context
2486 * Pops a number from the stack, handling conversion if needed.
2487 * Check error with #xmlXPathCheckError.
2489 * Returns the number
2492 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2493 xmlXPathObjectPtr obj;
2496 obj = valuePop(ctxt);
2498 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2501 if (obj->type != XPATH_NUMBER)
2502 ret = xmlXPathCastToNumber(obj);
2504 ret = obj->floatval;
2505 xmlXPathReleaseObject(ctxt->context, obj);
2510 * xmlXPathPopString:
2511 * @ctxt: an XPath parser context
2513 * Pops a string from the stack, handling conversion if needed.
2514 * Check error with #xmlXPathCheckError.
2516 * Returns the string
2519 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2520 xmlXPathObjectPtr obj;
2523 obj = valuePop(ctxt);
2525 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2528 ret = xmlXPathCastToString(obj); /* this does required strdup */
2529 /* TODO: needs refactoring somewhere else */
2530 if (obj->stringval == ret)
2531 obj->stringval = NULL;
2532 xmlXPathReleaseObject(ctxt->context, obj);
2537 * xmlXPathPopNodeSet:
2538 * @ctxt: an XPath parser context
2540 * Pops a node-set from the stack, handling conversion if needed.
2541 * Check error with #xmlXPathCheckError.
2543 * Returns the node-set
2546 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2547 xmlXPathObjectPtr obj;
2550 if (ctxt == NULL) return(NULL);
2551 if (ctxt->value == NULL) {
2552 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2555 if (!xmlXPathStackIsNodeSet(ctxt)) {
2556 xmlXPathSetTypeError(ctxt);
2559 obj = valuePop(ctxt);
2560 ret = obj->nodesetval;
2562 /* to fix memory leak of not clearing obj->user */
2563 if (obj->boolval && obj->user != NULL)
2564 xmlFreeNodeList((xmlNodePtr) obj->user);
2566 obj->nodesetval = NULL;
2567 xmlXPathReleaseObject(ctxt->context, obj);
2572 * xmlXPathPopExternal:
2573 * @ctxt: an XPath parser context
2575 * Pops an external object from the stack, handling conversion if needed.
2576 * Check error with #xmlXPathCheckError.
2578 * Returns the object
2581 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2582 xmlXPathObjectPtr obj;
2585 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2586 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2589 if (ctxt->value->type != XPATH_USERS) {
2590 xmlXPathSetTypeError(ctxt);
2593 obj = valuePop(ctxt);
2596 xmlXPathReleaseObject(ctxt->context, obj);
2601 * Macros for accessing the content. Those should be used only by the parser,
2604 * Dirty macros, i.e. one need to make assumption on the context to use them
2606 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2607 * CUR returns the current xmlChar value, i.e. a 8 bit value
2608 * in ISO-Latin or UTF-8.
2609 * This should be used internally by the parser
2610 * only to compare to ASCII values otherwise it would break when
2611 * running with UTF-8 encoding.
2612 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2613 * to compare on ASCII based substring.
2614 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2615 * strings within the parser.
2616 * CURRENT Returns the current char value, with the full decoding of
2617 * UTF-8 if we are using this mode. It returns an int.
2618 * NEXT Skip to the next character, this does the proper decoding
2619 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2620 * It returns the pointer to the current xmlChar.
2623 #define CUR (*ctxt->cur)
2624 #define SKIP(val) ctxt->cur += (val)
2625 #define NXT(val) ctxt->cur[(val)]
2626 #define CUR_PTR ctxt->cur
2627 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2629 #define COPY_BUF(l,b,i,v) \
2630 if (l == 1) b[i++] = (xmlChar) v; \
2631 else i += xmlCopyChar(l,&b[i],v)
2633 #define NEXTL(l) ctxt->cur += l
2635 #define SKIP_BLANKS \
2636 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2638 #define CURRENT (*ctxt->cur)
2639 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2646 #define DBL_EPSILON 1E-9
2649 #define UPPER_DOUBLE 1E9
2650 #define LOWER_DOUBLE 1E-5
2651 #define LOWER_DOUBLE_EXP 5
2653 #define INTEGER_DIGITS DBL_DIG
2654 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2655 #define EXPONENT_DIGITS (3 + 2)
2658 * xmlXPathFormatNumber:
2659 * @number: number to format
2660 * @buffer: output buffer
2661 * @buffersize: size of output buffer
2663 * Convert the number into a string representation.
2666 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2668 switch (xmlXPathIsInf(number)) {
2670 if (buffersize > (int)sizeof("Infinity"))
2671 snprintf(buffer, buffersize, "Infinity");
2674 if (buffersize > (int)sizeof("-Infinity"))
2675 snprintf(buffer, buffersize, "-Infinity");
2678 if (xmlXPathIsNaN(number)) {
2679 if (buffersize > (int)sizeof("NaN"))
2680 snprintf(buffer, buffersize, "NaN");
2681 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2682 snprintf(buffer, buffersize, "0");
2683 } else if (number == ((int) number)) {
2686 int value = (int) number;
2692 snprintf(work, 29, "%d", value);
2694 while ((*cur) && (ptr - buffer < buffersize)) {
2698 if (ptr - buffer < buffersize) {
2700 } else if (buffersize > 0) {
2706 For the dimension of work,
2707 DBL_DIG is number of significant digits
2708 EXPONENT is only needed for "scientific notation"
2709 3 is sign, decimal point, and terminating zero
2710 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2711 Note that this dimension is slightly (a few characters)
2712 larger than actually necessary.
2714 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2715 int integer_place, fraction_place;
2717 char *after_fraction;
2718 double absolute_value;
2721 absolute_value = fabs(number);
2724 * First choose format - scientific or regular floating point.
2725 * In either case, result is in work, and after_fraction points
2726 * just past the fractional part.
2728 if ( ((absolute_value > UPPER_DOUBLE) ||
2729 (absolute_value < LOWER_DOUBLE)) &&
2730 (absolute_value != 0.0) ) {
2731 /* Use scientific notation */
2732 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2733 fraction_place = DBL_DIG - 1;
2734 size = snprintf(work, sizeof(work),"%*.*e",
2735 integer_place, fraction_place, number);
2736 while ((size > 0) && (work[size] != 'e')) size--;
2740 /* Use regular notation */
2741 if (absolute_value > 0.0) {
2742 integer_place = (int)log10(absolute_value);
2743 if (integer_place > 0)
2744 fraction_place = DBL_DIG - integer_place - 1;
2746 fraction_place = DBL_DIG - integer_place;
2750 size = snprintf(work, sizeof(work), "%0.*f",
2751 fraction_place, number);
2754 /* Remove fractional trailing zeroes */
2755 after_fraction = work + size;
2756 ptr = after_fraction;
2757 while (*(--ptr) == '0')
2761 while ((*ptr++ = *after_fraction++) != 0);
2763 /* Finally copy result back to caller */
2764 size = strlen(work) + 1;
2765 if (size > buffersize) {
2766 work[buffersize - 1] = 0;
2769 memmove(buffer, work, size);
2776 /************************************************************************
2778 * Routines to handle NodeSets *
2780 ************************************************************************/
2783 * xmlXPathOrderDocElems:
2784 * @doc: an input document
2786 * Call this routine to speed up XPath computation on static documents.
2787 * This stamps all the element nodes with the document order
2788 * Like for line information, the order is kept in the element->content
2789 * field, the value stored is actually - the node number (starting at -1)
2790 * to be able to differentiate from line numbers.
2792 * Returns the number of elements found in the document or -1 in case
2796 xmlXPathOrderDocElems(xmlDocPtr doc) {
2802 cur = doc->children;
2803 while (cur != NULL) {
2804 if (cur->type == XML_ELEMENT_NODE) {
2805 cur->content = (void *) (-(++count));
2806 if (cur->children != NULL) {
2807 cur = cur->children;
2811 if (cur->next != NULL) {
2819 if (cur == (xmlNodePtr) doc) {
2823 if (cur->next != NULL) {
2827 } while (cur != NULL);
2834 * @node1: the first node
2835 * @node2: the second node
2837 * Compare two nodes w.r.t document order
2839 * Returns -2 in case of error 1 if first point < second point, 0 if
2840 * it's the same node, -1 otherwise
2843 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2845 int attr1 = 0, attr2 = 0;
2846 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2847 xmlNodePtr cur, root;
2849 if ((node1 == NULL) || (node2 == NULL))
2852 * a couple of optimizations which will avoid computations in most cases
2854 if (node1 == node2) /* trivial case */
2856 if (node1->type == XML_ATTRIBUTE_NODE) {
2859 node1 = node1->parent;
2861 if (node2->type == XML_ATTRIBUTE_NODE) {
2864 node2 = node2->parent;
2866 if (node1 == node2) {
2867 if (attr1 == attr2) {
2868 /* not required, but we keep attributes in order */
2870 cur = attrNode2->prev;
2871 while (cur != NULL) {
2872 if (cur == attrNode1)
2884 if ((node1->type == XML_NAMESPACE_DECL) ||
2885 (node2->type == XML_NAMESPACE_DECL))
2887 if (node1 == node2->prev)
2889 if (node1 == node2->next)
2893 * Speedup using document order if availble.
2895 if ((node1->type == XML_ELEMENT_NODE) &&
2896 (node2->type == XML_ELEMENT_NODE) &&
2897 (0 > (long) node1->content) &&
2898 (0 > (long) node2->content) &&
2899 (node1->doc == node2->doc)) {
2902 l1 = -((long) node1->content);
2903 l2 = -((long) node2->content);
2911 * compute depth to root
2913 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2919 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2925 * Distinct document (or distinct entities :-( ) case.
2931 * get the nearest common ancestor.
2933 while (depth1 > depth2) {
2935 node1 = node1->parent;
2937 while (depth2 > depth1) {
2939 node2 = node2->parent;
2941 while (node1->parent != node2->parent) {
2942 node1 = node1->parent;
2943 node2 = node2->parent;
2944 /* should not happen but just in case ... */
2945 if ((node1 == NULL) || (node2 == NULL))
2951 if (node1 == node2->prev)
2953 if (node1 == node2->next)
2956 * Speedup using document order if availble.
2958 if ((node1->type == XML_ELEMENT_NODE) &&
2959 (node2->type == XML_ELEMENT_NODE) &&
2960 (0 > (long) node1->content) &&
2961 (0 > (long) node2->content) &&
2962 (node1->doc == node2->doc)) {
2965 l1 = -((long) node1->content);
2966 l2 = -((long) node2->content);
2973 for (cur = node1->next;cur != NULL;cur = cur->next)
2976 return(-1); /* assume there is no sibling list corruption */
2979 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2981 * xmlXPathCmpNodesExt:
2982 * @node1: the first node
2983 * @node2: the second node
2985 * Compare two nodes w.r.t document order.
2986 * This one is optimized for handling of non-element nodes.
2988 * Returns -2 in case of error 1 if first point < second point, 0 if
2989 * it's the same node, -1 otherwise
2992 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
2994 int misc = 0, precedence1 = 0, precedence2 = 0;
2995 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
2996 xmlNodePtr cur, root;
2999 if ((node1 == NULL) || (node2 == NULL))
3006 * a couple of optimizations which will avoid computations in most cases
3008 switch (node1->type) {
3009 case XML_ELEMENT_NODE:
3010 if (node2->type == XML_ELEMENT_NODE) {
3011 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3012 (0 > (long) node2->content) &&
3013 (node1->doc == node2->doc))
3015 l1 = -((long) node1->content);
3016 l2 = -((long) node2->content);
3022 goto turtle_comparison;
3025 case XML_ATTRIBUTE_NODE:
3026 precedence1 = 1; /* element is owner */
3028 node1 = node1->parent;
3032 case XML_CDATA_SECTION_NODE:
3033 case XML_COMMENT_NODE:
3037 * Find nearest element node.
3039 if (node1->prev != NULL) {
3041 node1 = node1->prev;
3042 if (node1->type == XML_ELEMENT_NODE) {
3043 precedence1 = 3; /* element in prev-sibl axis */
3046 if (node1->prev == NULL) {
3047 precedence1 = 2; /* element is parent */
3049 * URGENT TODO: Are there any cases, where the
3050 * parent of such a node is not an element node?
3052 node1 = node1->parent;
3057 precedence1 = 2; /* element is parent */
3058 node1 = node1->parent;
3060 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3061 (0 <= (long) node1->content)) {
3063 * Fallback for whatever case.
3071 case XML_NAMESPACE_DECL:
3073 * TODO: why do we return 1 for namespace nodes?
3079 switch (node2->type) {
3080 case XML_ELEMENT_NODE:
3082 case XML_ATTRIBUTE_NODE:
3083 precedence2 = 1; /* element is owner */
3085 node2 = node2->parent;
3089 case XML_CDATA_SECTION_NODE:
3090 case XML_COMMENT_NODE:
3093 if (node2->prev != NULL) {
3095 node2 = node2->prev;
3096 if (node2->type == XML_ELEMENT_NODE) {
3097 precedence2 = 3; /* element in prev-sibl axis */
3100 if (node2->prev == NULL) {
3101 precedence2 = 2; /* element is parent */
3102 node2 = node2->parent;
3107 precedence2 = 2; /* element is parent */
3108 node2 = node2->parent;
3110 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3111 (0 <= (long) node1->content))
3119 case XML_NAMESPACE_DECL:
3125 if (node1 == node2) {
3126 if (precedence1 == precedence2) {
3128 * The ugly case; but normally there aren't many
3129 * adjacent non-element nodes around.
3131 cur = miscNode2->prev;
3132 while (cur != NULL) {
3133 if (cur == miscNode1)
3135 if (cur->type == XML_ELEMENT_NODE)
3142 * Evaluate based on higher precedence wrt to the element.
3143 * TODO: This assumes attributes are sorted before content.
3144 * Is this 100% correct?
3146 if (precedence1 < precedence2)
3153 * Special case: One of the helper-elements is contained by the other.
3156 * <node1>Text-1(precedence1 == 2)</node1>
3158 * Text-6(precedence2 == 3)
3161 if ((precedence2 == 3) && (precedence1 > 1)) {
3162 cur = node1->parent;
3169 if ((precedence1 == 3) && (precedence2 > 1)) {
3170 cur = node2->parent;
3180 * Speedup using document order if availble.
3182 if ((node1->type == XML_ELEMENT_NODE) &&
3183 (node2->type == XML_ELEMENT_NODE) &&
3184 (0 > (long) node1->content) &&
3185 (0 > (long) node2->content) &&
3186 (node1->doc == node2->doc)) {
3188 l1 = -((long) node1->content);
3189 l2 = -((long) node2->content);
3198 if (node1 == node2->prev)
3200 if (node1 == node2->next)
3203 * compute depth to root
3205 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3211 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3217 * Distinct document (or distinct entities :-( ) case.
3223 * get the nearest common ancestor.
3225 while (depth1 > depth2) {
3227 node1 = node1->parent;
3229 while (depth2 > depth1) {
3231 node2 = node2->parent;
3233 while (node1->parent != node2->parent) {
3234 node1 = node1->parent;
3235 node2 = node2->parent;
3236 /* should not happen but just in case ... */
3237 if ((node1 == NULL) || (node2 == NULL))
3243 if (node1 == node2->prev)
3245 if (node1 == node2->next)
3248 * Speedup using document order if availble.
3250 if ((node1->type == XML_ELEMENT_NODE) &&
3251 (node2->type == XML_ELEMENT_NODE) &&
3252 (0 > (long) node1->content) &&
3253 (0 > (long) node2->content) &&
3254 (node1->doc == node2->doc)) {
3256 l1 = -((long) node1->content);
3257 l2 = -((long) node2->content);
3264 for (cur = node1->next;cur != NULL;cur = cur->next)
3267 return(-1); /* assume there is no sibling list corruption */
3269 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3272 * xmlXPathNodeSetSort:
3273 * @set: the node set
3275 * Sort the node set in document order
3278 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3279 int i, j, incr, len;
3285 /* Use Shell's sort to sort the node-set */
3287 for (incr = len / 2; incr > 0; incr /= 2) {
3288 for (i = incr; i < len; i++) {
3291 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3292 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3293 set->nodeTab[j + incr]) == -1)
3295 if (xmlXPathCmpNodes(set->nodeTab[j],
3296 set->nodeTab[j + incr]) == -1)
3299 tmp = set->nodeTab[j];
3300 set->nodeTab[j] = set->nodeTab[j + incr];
3301 set->nodeTab[j + incr] = tmp;
3310 #define XML_NODESET_DEFAULT 10
3312 * xmlXPathNodeSetDupNs:
3313 * @node: the parent node of the namespace XPath node
3314 * @ns: the libxml namespace declaration node.
3316 * Namespace node in libxml don't match the XPath semantic. In a node set
3317 * the namespace nodes are duplicated and the next pointer is set to the
3318 * parent node in the XPath semantic.
3320 * Returns the newly created object.
3323 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3326 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3328 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3329 return((xmlNodePtr) ns);
3332 * Allocate a new Namespace and fill the fields.
3334 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3336 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3339 memset(cur, 0, sizeof(xmlNs));
3340 cur->type = XML_NAMESPACE_DECL;
3341 if (ns->href != NULL)
3342 cur->href = xmlStrdup(ns->href);
3343 if (ns->prefix != NULL)
3344 cur->prefix = xmlStrdup(ns->prefix);
3345 cur->next = (xmlNsPtr) node;
3346 return((xmlNodePtr) cur);
3350 * xmlXPathNodeSetFreeNs:
3351 * @ns: the XPath namespace node found in a nodeset.
3353 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3354 * the namespace nodes are duplicated and the next pointer is set to the
3355 * parent node in the XPath semantic. Check if such a node needs to be freed
3358 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3359 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3362 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3363 if (ns->href != NULL)
3364 xmlFree((xmlChar *)ns->href);
3365 if (ns->prefix != NULL)
3366 xmlFree((xmlChar *)ns->prefix);
3372 * xmlXPathNodeSetCreate:
3373 * @val: an initial xmlNodePtr, or NULL
3375 * Create a new xmlNodeSetPtr of type double and of value @val
3377 * Returns the newly created object.
3380 xmlXPathNodeSetCreate(xmlNodePtr val) {
3383 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3385 xmlXPathErrMemory(NULL, "creating nodeset\n");
3388 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3390 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3391 sizeof(xmlNodePtr));
3392 if (ret->nodeTab == NULL) {
3393 xmlXPathErrMemory(NULL, "creating nodeset\n");
3397 memset(ret->nodeTab, 0 ,
3398 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3399 ret->nodeMax = XML_NODESET_DEFAULT;
3400 if (val->type == XML_NAMESPACE_DECL) {
3401 xmlNsPtr ns = (xmlNsPtr) val;
3403 ret->nodeTab[ret->nodeNr++] =
3404 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3406 ret->nodeTab[ret->nodeNr++] = val;
3412 * xmlXPathNodeSetCreateSize:
3413 * @size: the initial size of the set
3415 * Create a new xmlNodeSetPtr of type double and of value @val
3417 * Returns the newly created object.
3419 static xmlNodeSetPtr
3420 xmlXPathNodeSetCreateSize(int size) {
3423 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3425 xmlXPathErrMemory(NULL, "creating nodeset\n");
3428 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3429 if (size < XML_NODESET_DEFAULT)
3430 size = XML_NODESET_DEFAULT;
3431 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3432 if (ret->nodeTab == NULL) {
3433 xmlXPathErrMemory(NULL, "creating nodeset\n");
3437 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3438 ret->nodeMax = size;
3443 * xmlXPathNodeSetContains:
3444 * @cur: the node-set
3447 * checks whether @cur contains @val
3449 * Returns true (1) if @cur contains @val, false (0) otherwise
3452 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3455 if ((cur == NULL) || (val == NULL)) return(0);
3456 if (val->type == XML_NAMESPACE_DECL) {
3457 for (i = 0; i < cur->nodeNr; i++) {
3458 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3461 ns1 = (xmlNsPtr) val;
3462 ns2 = (xmlNsPtr) cur->nodeTab[i];
3465 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3466 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3471 for (i = 0; i < cur->nodeNr; i++) {
3472 if (cur->nodeTab[i] == val)
3480 * xmlXPathNodeSetAddNs:
3481 * @cur: the initial node set
3482 * @node: the hosting node
3483 * @ns: a the namespace node
3485 * add a new namespace node to an existing NodeSet
3488 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3492 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3493 (ns->type != XML_NAMESPACE_DECL) ||
3494 (node->type != XML_ELEMENT_NODE))
3497 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3499 * prevent duplicates
3501 for (i = 0;i < cur->nodeNr;i++) {
3502 if ((cur->nodeTab[i] != NULL) &&
3503 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3504 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3505 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3510 * grow the nodeTab if needed
3512 if (cur->nodeMax == 0) {
3513 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3514 sizeof(xmlNodePtr));
3515 if (cur->nodeTab == NULL) {
3516 xmlXPathErrMemory(NULL, "growing nodeset\n");
3519 memset(cur->nodeTab, 0 ,
3520 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3521 cur->nodeMax = XML_NODESET_DEFAULT;
3522 } else if (cur->nodeNr == cur->nodeMax) {
3526 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3527 sizeof(xmlNodePtr));
3529 xmlXPathErrMemory(NULL, "growing nodeset\n");
3532 cur->nodeTab = temp;
3534 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3538 * xmlXPathNodeSetAdd:
3539 * @cur: the initial node set
3540 * @val: a new xmlNodePtr
3542 * add a new xmlNodePtr to an existing NodeSet
3545 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3548 if ((cur == NULL) || (val == NULL)) return;
3551 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3552 return; /* an XSLT fake node */
3555 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3559 for (i = 0;i < cur->nodeNr;i++)
3560 if (cur->nodeTab[i] == val) return;
3563 * grow the nodeTab if needed
3565 if (cur->nodeMax == 0) {
3566 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3567 sizeof(xmlNodePtr));
3568 if (cur->nodeTab == NULL) {
3569 xmlXPathErrMemory(NULL, "growing nodeset\n");
3572 memset(cur->nodeTab, 0 ,
3573 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3574 cur->nodeMax = XML_NODESET_DEFAULT;
3575 } else if (cur->nodeNr == cur->nodeMax) {
3579 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3580 sizeof(xmlNodePtr));
3582 xmlXPathErrMemory(NULL, "growing nodeset\n");
3585 cur->nodeTab = temp;
3587 if (val->type == XML_NAMESPACE_DECL) {
3588 xmlNsPtr ns = (xmlNsPtr) val;
3590 cur->nodeTab[cur->nodeNr++] =
3591 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3593 cur->nodeTab[cur->nodeNr++] = val;
3597 * xmlXPathNodeSetAddUnique:
3598 * @cur: the initial node set
3599 * @val: a new xmlNodePtr
3601 * add a new xmlNodePtr to an existing NodeSet, optimized version
3602 * when we are sure the node is not already in the set.
3605 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3606 if ((cur == NULL) || (val == NULL)) return;
3609 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3610 return; /* an XSLT fake node */
3613 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3615 * grow the nodeTab if needed
3617 if (cur->nodeMax == 0) {
3618 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3619 sizeof(xmlNodePtr));
3620 if (cur->nodeTab == NULL) {
3621 xmlXPathErrMemory(NULL, "growing nodeset\n");
3624 memset(cur->nodeTab, 0 ,
3625 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3626 cur->nodeMax = XML_NODESET_DEFAULT;
3627 } else if (cur->nodeNr == cur->nodeMax) {
3631 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
3632 sizeof(xmlNodePtr));
3634 xmlXPathErrMemory(NULL, "growing nodeset\n");
3637 cur->nodeTab = temp;
3639 if (val->type == XML_NAMESPACE_DECL) {
3640 xmlNsPtr ns = (xmlNsPtr) val;
3642 cur->nodeTab[cur->nodeNr++] =
3643 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3645 cur->nodeTab[cur->nodeNr++] = val;
3649 * xmlXPathNodeSetMerge:
3650 * @val1: the first NodeSet or NULL
3651 * @val2: the second NodeSet
3653 * Merges two nodesets, all nodes from @val2 are added to @val1
3654 * if @val1 is NULL, a new set is created and copied from @val2
3656 * Returns @val1 once extended or NULL in case of error.
3659 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3660 int i, j, initNr, skip;
3663 if (val2 == NULL) return(val1);
3665 val1 = xmlXPathNodeSetCreate(NULL);
3670 * TODO: The optimization won't work in every case, since
3671 * those nasty namespace nodes need to be added with
3672 * xmlXPathNodeSetDupNs() to the set; thus a pure
3673 * memcpy is not possible.
3674 * If there was a flag on the nodesetval, indicating that
3675 * some temporary nodes are in, that would be helpfull.
3678 * Optimization: Create an equally sized node-set
3679 * and memcpy the content.
3681 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3684 if (val2->nodeNr != 0) {
3685 if (val2->nodeNr == 1)
3686 *(val1->nodeTab) = *(val2->nodeTab);
3688 memcpy(val1->nodeTab, val2->nodeTab,
3689 val2->nodeNr * sizeof(xmlNodePtr));
3691 val1->nodeNr = val2->nodeNr;
3697 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3698 initNr = val1->nodeNr;
3700 for (i = 0;i < val2->nodeNr;i++) {
3701 n2 = val2->nodeTab[i];
3703 * check against duplicates
3706 for (j = 0; j < initNr; j++) {
3707 n1 = val1->nodeTab[j];
3711 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3712 (n2->type == XML_NAMESPACE_DECL)) {
3713 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3714 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3715 ((xmlNsPtr) n2)->prefix)))
3726 * grow the nodeTab if needed
3728 if (val1->nodeMax == 0) {
3729 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3730 sizeof(xmlNodePtr));
3731 if (val1->nodeTab == NULL) {
3732 xmlXPathErrMemory(NULL, "merging nodeset\n");
3735 memset(val1->nodeTab, 0 ,
3736 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3737 val1->nodeMax = XML_NODESET_DEFAULT;
3738 } else if (val1->nodeNr == val1->nodeMax) {
3742 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3743 sizeof(xmlNodePtr));
3745 xmlXPathErrMemory(NULL, "merging nodeset\n");
3748 val1->nodeTab = temp;
3750 if (n2->type == XML_NAMESPACE_DECL) {
3751 xmlNsPtr ns = (xmlNsPtr) n2;
3753 val1->nodeTab[val1->nodeNr++] =
3754 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3756 val1->nodeTab[val1->nodeNr++] = n2;
3762 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3764 * xmlXPathNodeSetMergeUnique:
3765 * @val1: the first NodeSet or NULL
3766 * @val2: the second NodeSet
3768 * Merges two nodesets, all nodes from @val2 are added to @val1
3769 * if @val1 is NULL, a new set is created and copied from @val2
3771 * Returns @val1 once extended or NULL in case of error.
3773 static xmlNodeSetPtr
3774 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3777 if (val2 == NULL) return(val1);
3779 val1 = xmlXPathNodeSetCreate(NULL);
3784 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3786 for (i = 0;i < val2->nodeNr;i++) {
3788 * grow the nodeTab if needed
3790 if (val1->nodeMax == 0) {
3791 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3792 sizeof(xmlNodePtr));
3793 if (val1->nodeTab == NULL) {
3794 xmlXPathErrMemory(NULL, "merging nodeset\n");
3797 memset(val1->nodeTab, 0 ,
3798 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3799 val1->nodeMax = XML_NODESET_DEFAULT;
3800 } else if (val1->nodeNr == val1->nodeMax) {
3804 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3805 sizeof(xmlNodePtr));
3807 xmlXPathErrMemory(NULL, "merging nodeset\n");
3810 val1->nodeTab = temp;
3812 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3813 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3815 val1->nodeTab[val1->nodeNr++] =
3816 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3818 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3823 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3826 * xmlXPathNodeSetMergeAndClear:
3827 * @set1: the first NodeSet or NULL
3828 * @set2: the second NodeSet
3829 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3831 * Merges two nodesets, all nodes from @set2 are added to @set1
3832 * if @set1 is NULL, a new set is created and copied from @set2.
3833 * Checks for duplicate nodes. Clears set2.
3835 * Returns @set1 once extended or NULL in case of error.
3837 static xmlNodeSetPtr
3838 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3841 if ((set1 == NULL) && (hasNullEntries == 0)) {
3843 * Note that doing a memcpy of the list, namespace nodes are
3844 * just assigned to set1, since set2 is cleared anyway.
3846 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3849 if (set2->nodeNr != 0) {
3850 memcpy(set1->nodeTab, set2->nodeTab,
3851 set2->nodeNr * sizeof(xmlNodePtr));
3852 set1->nodeNr = set2->nodeNr;
3855 int i, j, initNbSet1;
3859 set1 = xmlXPathNodeSetCreate(NULL);
3863 initNbSet1 = set1->nodeNr;
3864 for (i = 0;i < set2->nodeNr;i++) {
3865 n2 = set2->nodeTab[i];
3867 * Skip NULLed entries.
3874 for (j = 0; j < initNbSet1; j++) {
3875 n1 = set1->nodeTab[j];
3878 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3879 (n2->type == XML_NAMESPACE_DECL))
3881 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3882 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3883 ((xmlNsPtr) n2)->prefix)))
3886 * Free the namespace node.
3888 set2->nodeTab[i] = NULL;
3889 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3895 * grow the nodeTab if needed
3897 if (set1->nodeMax == 0) {
3898 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3899 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3900 if (set1->nodeTab == NULL) {
3901 xmlXPathErrMemory(NULL, "merging nodeset\n");
3904 memset(set1->nodeTab, 0,
3905 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3906 set1->nodeMax = XML_NODESET_DEFAULT;
3907 } else if (set1->nodeNr >= set1->nodeMax) {
3911 temp = (xmlNodePtr *) xmlRealloc(
3912 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3914 xmlXPathErrMemory(NULL, "merging nodeset\n");
3917 set1->nodeTab = temp;
3919 if (n2->type == XML_NAMESPACE_DECL) {
3920 xmlNsPtr ns = (xmlNsPtr) n2;
3922 set1->nodeTab[set1->nodeNr++] =
3923 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3925 set1->nodeTab[set1->nodeNr++] = n2;
3935 * xmlXPathNodeSetMergeAndClearNoDupls:
3936 * @set1: the first NodeSet or NULL
3937 * @set2: the second NodeSet
3938 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3940 * Merges two nodesets, all nodes from @set2 are added to @set1
3941 * if @set1 is NULL, a new set is created and copied from @set2.
3942 * Doesn't chack for duplicate nodes. Clears set2.
3944 * Returns @set1 once extended or NULL in case of error.
3946 static xmlNodeSetPtr
3947 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3952 if ((set1 == NULL) && (hasNullEntries == 0)) {
3954 * Note that doing a memcpy of the list, namespace nodes are
3955 * just assigned to set1, since set2 is cleared anyway.
3957 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3960 if (set2->nodeNr != 0) {
3961 memcpy(set1->nodeTab, set2->nodeTab,
3962 set2->nodeNr * sizeof(xmlNodePtr));
3963 set1->nodeNr = set2->nodeNr;
3970 set1 = xmlXPathNodeSetCreate(NULL);
3974 for (i = 0;i < set2->nodeNr;i++) {
3975 n2 = set2->nodeTab[i];
3977 * Skip NULLed entries.
3981 if (set1->nodeMax == 0) {
3982 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3983 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3984 if (set1->nodeTab == NULL) {
3985 xmlXPathErrMemory(NULL, "merging nodeset\n");
3988 memset(set1->nodeTab, 0,
3989 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3990 set1->nodeMax = XML_NODESET_DEFAULT;
3991 } else if (set1->nodeNr >= set1->nodeMax) {
3995 temp = (xmlNodePtr *) xmlRealloc(
3996 set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
3998 xmlXPathErrMemory(NULL, "merging nodeset\n");
4001 set1->nodeTab = temp;
4003 set1->nodeTab[set1->nodeNr++] = n2;
4011 * xmlXPathNodeSetDel:
4012 * @cur: the initial node set
4013 * @val: an xmlNodePtr
4015 * Removes an xmlNodePtr from an existing NodeSet
4018 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4021 if (cur == NULL) return;
4022 if (val == NULL) return;
4025 * find node in nodeTab
4027 for (i = 0;i < cur->nodeNr;i++)
4028 if (cur->nodeTab[i] == val) break;
4030 if (i >= cur->nodeNr) { /* not found */
4032 xmlGenericError(xmlGenericErrorContext,
4033 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4038 if ((cur->nodeTab[i] != NULL) &&
4039 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4040 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4042 for (;i < cur->nodeNr;i++)
4043 cur->nodeTab[i] = cur->nodeTab[i + 1];
4044 cur->nodeTab[cur->nodeNr] = NULL;
4048 * xmlXPathNodeSetRemove:
4049 * @cur: the initial node set
4050 * @val: the index to remove
4052 * Removes an entry from an existing NodeSet list.
4055 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4056 if (cur == NULL) return;
4057 if (val >= cur->nodeNr) return;
4058 if ((cur->nodeTab[val] != NULL) &&
4059 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4060 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4062 for (;val < cur->nodeNr;val++)
4063 cur->nodeTab[val] = cur->nodeTab[val + 1];
4064 cur->nodeTab[cur->nodeNr] = NULL;
4068 * xmlXPathFreeNodeSet:
4069 * @obj: the xmlNodeSetPtr to free
4071 * Free the NodeSet compound (not the actual nodes !).
4074 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4075 if (obj == NULL) return;
4076 if (obj->nodeTab != NULL) {
4079 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4080 for (i = 0;i < obj->nodeNr;i++)
4081 if ((obj->nodeTab[i] != NULL) &&
4082 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4083 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4084 xmlFree(obj->nodeTab);
4090 * xmlXPathNodeSetClear:
4091 * @set: the node set to clear
4093 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4094 * are feed), but does *not* free the list itself. Sets the length of the
4098 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4100 if ((set == NULL) || (set->nodeNr <= 0))
4102 else if (hasNsNodes) {
4106 for (i = 0; i < set->nodeNr; i++) {
4107 node = set->nodeTab[i];
4108 if ((node != NULL) &&
4109 (node->type == XML_NAMESPACE_DECL))
4110 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4117 * xmlXPathNodeSetClearFromPos:
4118 * @set: the node set to be cleared
4119 * @pos: the start position to clear from
4121 * Clears the list from temporary XPath objects (e.g. namespace nodes
4122 * are feed) starting with the entry at @pos, but does *not* free the list
4123 * itself. Sets the length of the list to @pos.
4126 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4128 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4130 else if ((hasNsNodes)) {
4134 for (i = pos; i < set->nodeNr; i++) {
4135 node = set->nodeTab[i];
4136 if ((node != NULL) &&
4137 (node->type == XML_NAMESPACE_DECL))
4138 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4145 * xmlXPathFreeValueTree:
4146 * @obj: the xmlNodeSetPtr to free
4148 * Free the NodeSet compound and the actual tree, this is different
4149 * from xmlXPathFreeNodeSet()
4152 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4155 if (obj == NULL) return;
4157 if (obj->nodeTab != NULL) {
4158 for (i = 0;i < obj->nodeNr;i++) {
4159 if (obj->nodeTab[i] != NULL) {
4160 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4161 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4163 xmlFreeNodeList(obj->nodeTab[i]);
4167 xmlFree(obj->nodeTab);
4172 #if defined(DEBUG) || defined(DEBUG_STEP)
4174 * xmlGenericErrorContextNodeSet:
4175 * @output: a FILE * for the output
4176 * @obj: the xmlNodeSetPtr to display
4178 * Quick display of a NodeSet
4181 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4184 if (output == NULL) output = xmlGenericErrorContext;
4186 fprintf(output, "NodeSet == NULL !\n");
4189 if (obj->nodeNr == 0) {
4190 fprintf(output, "NodeSet is empty\n");
4193 if (obj->nodeTab == NULL) {
4194 fprintf(output, " nodeTab == NULL !\n");
4197 for (i = 0; i < obj->nodeNr; i++) {
4198 if (obj->nodeTab[i] == NULL) {
4199 fprintf(output, " NULL !\n");
4202 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4203 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4204 fprintf(output, " /");
4205 else if (obj->nodeTab[i]->name == NULL)
4206 fprintf(output, " noname!");
4207 else fprintf(output, " %s", obj->nodeTab[i]->name);
4209 fprintf(output, "\n");
4214 * xmlXPathNewNodeSet:
4215 * @val: the NodePtr value
4217 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4218 * it with the single Node @val
4220 * Returns the newly created object.
4223 xmlXPathNewNodeSet(xmlNodePtr val) {
4224 xmlXPathObjectPtr ret;
4226 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4228 xmlXPathErrMemory(NULL, "creating nodeset\n");
4231 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4232 ret->type = XPATH_NODESET;
4234 ret->nodesetval = xmlXPathNodeSetCreate(val);
4235 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4236 #ifdef XP_DEBUG_OBJ_USAGE
4237 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4243 * xmlXPathNewValueTree:
4244 * @val: the NodePtr value
4246 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4247 * it with the tree root @val
4249 * Returns the newly created object.
4252 xmlXPathNewValueTree(xmlNodePtr val) {
4253 xmlXPathObjectPtr ret;
4255 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4257 xmlXPathErrMemory(NULL, "creating result value tree\n");
4260 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4261 ret->type = XPATH_XSLT_TREE;
4263 ret->user = (void *) val;
4264 ret->nodesetval = xmlXPathNodeSetCreate(val);
4265 #ifdef XP_DEBUG_OBJ_USAGE
4266 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4272 * xmlXPathNewNodeSetList:
4273 * @val: an existing NodeSet
4275 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4276 * it with the Nodeset @val
4278 * Returns the newly created object.
4281 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4283 xmlXPathObjectPtr ret;
4288 else if (val->nodeTab == NULL)
4289 ret = xmlXPathNewNodeSet(NULL);
4291 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4293 for (i = 1; i < val->nodeNr; ++i)
4294 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4301 * xmlXPathWrapNodeSet:
4302 * @val: the NodePtr value
4304 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4306 * Returns the newly created object.
4309 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4310 xmlXPathObjectPtr ret;
4312 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4314 xmlXPathErrMemory(NULL, "creating node set object\n");
4317 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4318 ret->type = XPATH_NODESET;
4319 ret->nodesetval = val;
4320 #ifdef XP_DEBUG_OBJ_USAGE
4321 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4327 * xmlXPathFreeNodeSetList:
4328 * @obj: an existing NodeSetList object
4330 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4331 * the list contrary to xmlXPathFreeObject().
4334 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4335 if (obj == NULL) return;
4336 #ifdef XP_DEBUG_OBJ_USAGE
4337 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4343 * xmlXPathDifference:
4344 * @nodes1: a node-set
4345 * @nodes2: a node-set
4347 * Implements the EXSLT - Sets difference() function:
4348 * node-set set:difference (node-set, node-set)
4350 * Returns the difference between the two node sets, or nodes1 if
4354 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4359 if (xmlXPathNodeSetIsEmpty(nodes2))
4362 ret = xmlXPathNodeSetCreate(NULL);
4363 if (xmlXPathNodeSetIsEmpty(nodes1))
4366 l1 = xmlXPathNodeSetGetLength(nodes1);
4368 for (i = 0; i < l1; i++) {
4369 cur = xmlXPathNodeSetItem(nodes1, i);
4370 if (!xmlXPathNodeSetContains(nodes2, cur))
4371 xmlXPathNodeSetAddUnique(ret, cur);
4377 * xmlXPathIntersection:
4378 * @nodes1: a node-set
4379 * @nodes2: a node-set
4381 * Implements the EXSLT - Sets intersection() function:
4382 * node-set set:intersection (node-set, node-set)
4384 * Returns a node set comprising the nodes that are within both the
4385 * node sets passed as arguments
4388 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4389 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4395 if (xmlXPathNodeSetIsEmpty(nodes1))
4397 if (xmlXPathNodeSetIsEmpty(nodes2))
4400 l1 = xmlXPathNodeSetGetLength(nodes1);
4402 for (i = 0; i < l1; i++) {
4403 cur = xmlXPathNodeSetItem(nodes1, i);
4404 if (xmlXPathNodeSetContains(nodes2, cur))
4405 xmlXPathNodeSetAddUnique(ret, cur);
4411 * xmlXPathDistinctSorted:
4412 * @nodes: a node-set, sorted by document order
4414 * Implements the EXSLT - Sets distinct() function:
4415 * node-set set:distinct (node-set)
4417 * Returns a subset of the nodes contained in @nodes, or @nodes if
4421 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4423 xmlHashTablePtr hash;
4428 if (xmlXPathNodeSetIsEmpty(nodes))
4431 ret = xmlXPathNodeSetCreate(NULL);
4434 l = xmlXPathNodeSetGetLength(nodes);
4435 hash = xmlHashCreate (l);
4436 for (i = 0; i < l; i++) {
4437 cur = xmlXPathNodeSetItem(nodes, i);
4438 strval = xmlXPathCastNodeToString(cur);
4439 if (xmlHashLookup(hash, strval) == NULL) {
4440 xmlHashAddEntry(hash, strval, strval);
4441 xmlXPathNodeSetAddUnique(ret, cur);
4446 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4452 * @nodes: a node-set
4454 * Implements the EXSLT - Sets distinct() function:
4455 * node-set set:distinct (node-set)
4456 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4457 * is called with the sorted node-set
4459 * Returns a subset of the nodes contained in @nodes, or @nodes if
4463 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4464 if (xmlXPathNodeSetIsEmpty(nodes))
4467 xmlXPathNodeSetSort(nodes);
4468 return(xmlXPathDistinctSorted(nodes));
4472 * xmlXPathHasSameNodes:
4473 * @nodes1: a node-set
4474 * @nodes2: a node-set
4476 * Implements the EXSLT - Sets has-same-nodes function:
4477 * boolean set:has-same-node(node-set, node-set)
4479 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4483 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4487 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4488 xmlXPathNodeSetIsEmpty(nodes2))
4491 l = xmlXPathNodeSetGetLength(nodes1);
4492 for (i = 0; i < l; i++) {
4493 cur = xmlXPathNodeSetItem(nodes1, i);
4494 if (xmlXPathNodeSetContains(nodes2, cur))
4501 * xmlXPathNodeLeadingSorted:
4502 * @nodes: a node-set, sorted by document order
4505 * Implements the EXSLT - Sets leading() function:
4506 * node-set set:leading (node-set, node-set)
4508 * Returns the nodes in @nodes that precede @node in document order,
4509 * @nodes if @node is NULL or an empty node-set if @nodes
4510 * doesn't contain @node
4513 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4521 ret = xmlXPathNodeSetCreate(NULL);
4524 if (xmlXPathNodeSetIsEmpty(nodes) ||
4525 (!xmlXPathNodeSetContains(nodes, node)))
4528 l = xmlXPathNodeSetGetLength(nodes);
4529 for (i = 0; i < l; i++) {
4530 cur = xmlXPathNodeSetItem(nodes, i);
4533 xmlXPathNodeSetAddUnique(ret, cur);
4539 * xmlXPathNodeLeading:
4540 * @nodes: a node-set
4543 * Implements the EXSLT - Sets leading() function:
4544 * node-set set:leading (node-set, node-set)
4545 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4548 * Returns the nodes in @nodes that precede @node in document order,
4549 * @nodes if @node is NULL or an empty node-set if @nodes
4550 * doesn't contain @node
4553 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4554 xmlXPathNodeSetSort(nodes);
4555 return(xmlXPathNodeLeadingSorted(nodes, node));
4559 * xmlXPathLeadingSorted:
4560 * @nodes1: a node-set, sorted by document order
4561 * @nodes2: a node-set, sorted by document order
4563 * Implements the EXSLT - Sets leading() function:
4564 * node-set set:leading (node-set, node-set)
4566 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4567 * in document order, @nodes1 if @nodes2 is NULL or empty or
4568 * an empty node-set if @nodes1 doesn't contain @nodes2
4571 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4572 if (xmlXPathNodeSetIsEmpty(nodes2))
4574 return(xmlXPathNodeLeadingSorted(nodes1,
4575 xmlXPathNodeSetItem(nodes2, 1)));
4580 * @nodes1: a node-set
4581 * @nodes2: a node-set
4583 * Implements the EXSLT - Sets leading() function:
4584 * node-set set:leading (node-set, node-set)
4585 * @nodes1 and @nodes2 are sorted by document order, then
4586 * #exslSetsLeadingSorted is called.
4588 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4589 * in document order, @nodes1 if @nodes2 is NULL or empty or
4590 * an empty node-set if @nodes1 doesn't contain @nodes2
4593 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4594 if (xmlXPathNodeSetIsEmpty(nodes2))
4596 if (xmlXPathNodeSetIsEmpty(nodes1))
4597 return(xmlXPathNodeSetCreate(NULL));
4598 xmlXPathNodeSetSort(nodes1);
4599 xmlXPathNodeSetSort(nodes2);
4600 return(xmlXPathNodeLeadingSorted(nodes1,
4601 xmlXPathNodeSetItem(nodes2, 1)));
4605 * xmlXPathNodeTrailingSorted:
4606 * @nodes: a node-set, sorted by document order
4609 * Implements the EXSLT - Sets trailing() function:
4610 * node-set set:trailing (node-set, node-set)
4612 * Returns the nodes in @nodes that follow @node in document order,
4613 * @nodes if @node is NULL or an empty node-set if @nodes
4614 * doesn't contain @node
4617 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4625 ret = xmlXPathNodeSetCreate(NULL);
4628 if (xmlXPathNodeSetIsEmpty(nodes) ||
4629 (!xmlXPathNodeSetContains(nodes, node)))
4632 l = xmlXPathNodeSetGetLength(nodes);
4633 for (i = l - 1; i >= 0; i--) {
4634 cur = xmlXPathNodeSetItem(nodes, i);
4637 xmlXPathNodeSetAddUnique(ret, cur);
4639 xmlXPathNodeSetSort(ret); /* bug 413451 */
4644 * xmlXPathNodeTrailing:
4645 * @nodes: a node-set
4648 * Implements the EXSLT - Sets trailing() function:
4649 * node-set set:trailing (node-set, node-set)
4650 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4653 * Returns the nodes in @nodes that follow @node in document order,
4654 * @nodes if @node is NULL or an empty node-set if @nodes
4655 * doesn't contain @node
4658 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4659 xmlXPathNodeSetSort(nodes);
4660 return(xmlXPathNodeTrailingSorted(nodes, node));
4664 * xmlXPathTrailingSorted:
4665 * @nodes1: a node-set, sorted by document order
4666 * @nodes2: a node-set, sorted by document order
4668 * Implements the EXSLT - Sets trailing() function:
4669 * node-set set:trailing (node-set, node-set)
4671 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4672 * in document order, @nodes1 if @nodes2 is NULL or empty or
4673 * an empty node-set if @nodes1 doesn't contain @nodes2
4676 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4677 if (xmlXPathNodeSetIsEmpty(nodes2))
4679 return(xmlXPathNodeTrailingSorted(nodes1,
4680 xmlXPathNodeSetItem(nodes2, 0)));
4685 * @nodes1: a node-set
4686 * @nodes2: a node-set
4688 * Implements the EXSLT - Sets trailing() function:
4689 * node-set set:trailing (node-set, node-set)
4690 * @nodes1 and @nodes2 are sorted by document order, then
4691 * #xmlXPathTrailingSorted is called.
4693 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4694 * in document order, @nodes1 if @nodes2 is NULL or empty or
4695 * an empty node-set if @nodes1 doesn't contain @nodes2
4698 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4699 if (xmlXPathNodeSetIsEmpty(nodes2))
4701 if (xmlXPathNodeSetIsEmpty(nodes1))
4702 return(xmlXPathNodeSetCreate(NULL));
4703 xmlXPathNodeSetSort(nodes1);
4704 xmlXPathNodeSetSort(nodes2);
4705 return(xmlXPathNodeTrailingSorted(nodes1,
4706 xmlXPathNodeSetItem(nodes2, 0)));
4709 /************************************************************************
4711 * Routines to handle extra functions *
4713 ************************************************************************/
4716 * xmlXPathRegisterFunc:
4717 * @ctxt: the XPath context
4718 * @name: the function name
4719 * @f: the function implementation or NULL
4721 * Register a new function. If @f is NULL it unregisters the function
4723 * Returns 0 in case of success, -1 in case of error
4726 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4727 xmlXPathFunction f) {
4728 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4732 * xmlXPathRegisterFuncNS:
4733 * @ctxt: the XPath context
4734 * @name: the function name
4735 * @ns_uri: the function namespace URI
4736 * @f: the function implementation or NULL
4738 * Register a new function. If @f is NULL it unregisters the function
4740 * Returns 0 in case of success, -1 in case of error
4743 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4744 const xmlChar *ns_uri, xmlXPathFunction f) {
4750 if (ctxt->funcHash == NULL)
4751 ctxt->funcHash = xmlHashCreate(0);
4752 if (ctxt->funcHash == NULL)
4755 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4756 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4760 * xmlXPathRegisterFuncLookup:
4761 * @ctxt: the XPath context
4762 * @f: the lookup function
4763 * @funcCtxt: the lookup data
4765 * Registers an external mechanism to do function lookup.
4768 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4769 xmlXPathFuncLookupFunc f,
4773 ctxt->funcLookupFunc = f;
4774 ctxt->funcLookupData = funcCtxt;
4778 * xmlXPathFunctionLookup:
4779 * @ctxt: the XPath context
4780 * @name: the function name
4782 * Search in the Function array of the context for the given
4785 * Returns the xmlXPathFunction or NULL if not found
4788 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4792 if (ctxt->funcLookupFunc != NULL) {
4793 xmlXPathFunction ret;
4794 xmlXPathFuncLookupFunc f;
4796 f = ctxt->funcLookupFunc;
4797 ret = f(ctxt->funcLookupData, name, NULL);
4801 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4805 * xmlXPathFunctionLookupNS:
4806 * @ctxt: the XPath context
4807 * @name: the function name
4808 * @ns_uri: the function namespace URI
4810 * Search in the Function array of the context for the given
4813 * Returns the xmlXPathFunction or NULL if not found
4816 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4817 const xmlChar *ns_uri) {
4818 xmlXPathFunction ret;
4825 if (ctxt->funcLookupFunc != NULL) {
4826 xmlXPathFuncLookupFunc f;
4828 f = ctxt->funcLookupFunc;
4829 ret = f(ctxt->funcLookupData, name, ns_uri);
4834 if (ctxt->funcHash == NULL)
4837 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4842 * xmlXPathRegisteredFuncsCleanup:
4843 * @ctxt: the XPath context
4845 * Cleanup the XPath context data associated to registered functions
4848 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4852 xmlHashFree(ctxt->funcHash, NULL);
4853 ctxt->funcHash = NULL;
4856 /************************************************************************
4858 * Routines to handle Variables *
4860 ************************************************************************/
4863 * xmlXPathRegisterVariable:
4864 * @ctxt: the XPath context
4865 * @name: the variable name
4866 * @value: the variable value or NULL
4868 * Register a new variable value. If @value is NULL it unregisters
4871 * Returns 0 in case of success, -1 in case of error
4874 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4875 xmlXPathObjectPtr value) {
4876 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4880 * xmlXPathRegisterVariableNS:
4881 * @ctxt: the XPath context
4882 * @name: the variable name
4883 * @ns_uri: the variable namespace URI
4884 * @value: the variable value or NULL
4886 * Register a new variable value. If @value is NULL it unregisters
4889 * Returns 0 in case of success, -1 in case of error
4892 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4893 const xmlChar *ns_uri,
4894 xmlXPathObjectPtr value) {
4900 if (ctxt->varHash == NULL)
4901 ctxt->varHash = xmlHashCreate(0);
4902 if (ctxt->varHash == NULL)
4905 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4906 (xmlHashDeallocator)xmlXPathFreeObject));
4907 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4909 (xmlHashDeallocator)xmlXPathFreeObject));
4913 * xmlXPathRegisterVariableLookup:
4914 * @ctxt: the XPath context
4915 * @f: the lookup function
4916 * @data: the lookup data
4918 * register an external mechanism to do variable lookup
4921 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4922 xmlXPathVariableLookupFunc f, void *data) {
4925 ctxt->varLookupFunc = f;
4926 ctxt->varLookupData = data;
4930 * xmlXPathVariableLookup:
4931 * @ctxt: the XPath context
4932 * @name: the variable name
4934 * Search in the Variable array of the context for the given
4937 * Returns a copy of the value or NULL if not found
4940 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4944 if (ctxt->varLookupFunc != NULL) {
4945 xmlXPathObjectPtr ret;
4947 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4948 (ctxt->varLookupData, name, NULL);
4951 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4955 * xmlXPathVariableLookupNS:
4956 * @ctxt: the XPath context
4957 * @name: the variable name
4958 * @ns_uri: the variable namespace URI
4960 * Search in the Variable array of the context for the given
4963 * Returns the a copy of the value or NULL if not found
4966 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4967 const xmlChar *ns_uri) {
4971 if (ctxt->varLookupFunc != NULL) {
4972 xmlXPathObjectPtr ret;
4974 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4975 (ctxt->varLookupData, name, ns_uri);
4976 if (ret != NULL) return(ret);
4979 if (ctxt->varHash == NULL)
4984 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4985 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4989 * xmlXPathRegisteredVariablesCleanup:
4990 * @ctxt: the XPath context
4992 * Cleanup the XPath context data associated to registered variables
4995 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4999 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5000 ctxt->varHash = NULL;
5004 * xmlXPathRegisterNs:
5005 * @ctxt: the XPath context
5006 * @prefix: the namespace prefix cannot be NULL or empty string
5007 * @ns_uri: the namespace name
5009 * Register a new namespace. If @ns_uri is NULL it unregisters
5012 * Returns 0 in case of success, -1 in case of error
5015 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5016 const xmlChar *ns_uri) {
5024 if (ctxt->nsHash == NULL)
5025 ctxt->nsHash = xmlHashCreate(10);
5026 if (ctxt->nsHash == NULL)
5029 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5030 (xmlHashDeallocator)xmlFree));
5031 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5032 (xmlHashDeallocator)xmlFree));
5037 * @ctxt: the XPath context
5038 * @prefix: the namespace prefix value
5040 * Search in the namespace declaration array of the context for the given
5041 * namespace name associated to the given prefix
5043 * Returns the value or NULL if not found
5046 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5052 #ifdef XML_XML_NAMESPACE
5053 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5054 return(XML_XML_NAMESPACE);
5057 if (ctxt->namespaces != NULL) {
5060 for (i = 0;i < ctxt->nsNr;i++) {
5061 if ((ctxt->namespaces[i] != NULL) &&
5062 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5063 return(ctxt->namespaces[i]->href);
5067 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5071 * xmlXPathRegisteredNsCleanup:
5072 * @ctxt: the XPath context
5074 * Cleanup the XPath context data associated to registered variables
5077 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5081 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5082 ctxt->nsHash = NULL;
5085 /************************************************************************
5087 * Routines to handle Values *
5089 ************************************************************************/
5091 /* Allocations are terrible, one needs to optimize all this !!! */
5095 * @val: the double value
5097 * Create a new xmlXPathObjectPtr of type double and of value @val
5099 * Returns the newly created object.
5102 xmlXPathNewFloat(double val) {
5103 xmlXPathObjectPtr ret;
5105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5107 xmlXPathErrMemory(NULL, "creating float object\n");
5110 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5111 ret->type = XPATH_NUMBER;
5112 ret->floatval = val;
5113 #ifdef XP_DEBUG_OBJ_USAGE
5114 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5120 * xmlXPathNewBoolean:
5121 * @val: the boolean value
5123 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5125 * Returns the newly created object.
5128 xmlXPathNewBoolean(int val) {
5129 xmlXPathObjectPtr ret;
5131 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5133 xmlXPathErrMemory(NULL, "creating boolean object\n");
5136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5137 ret->type = XPATH_BOOLEAN;
5138 ret->boolval = (val != 0);
5139 #ifdef XP_DEBUG_OBJ_USAGE
5140 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5146 * xmlXPathNewString:
5147 * @val: the xmlChar * value
5149 * Create a new xmlXPathObjectPtr of type string and of value @val
5151 * Returns the newly created object.
5154 xmlXPathNewString(const xmlChar *val) {
5155 xmlXPathObjectPtr ret;
5157 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5159 xmlXPathErrMemory(NULL, "creating string object\n");
5162 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5163 ret->type = XPATH_STRING;
5165 ret->stringval = xmlStrdup(val);
5167 ret->stringval = xmlStrdup((const xmlChar *)"");
5168 #ifdef XP_DEBUG_OBJ_USAGE
5169 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5175 * xmlXPathWrapString:
5176 * @val: the xmlChar * value
5178 * Wraps the @val string into an XPath object.
5180 * Returns the newly created object.
5183 xmlXPathWrapString (xmlChar *val) {
5184 xmlXPathObjectPtr ret;
5186 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5188 xmlXPathErrMemory(NULL, "creating string object\n");
5191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5192 ret->type = XPATH_STRING;
5193 ret->stringval = val;
5194 #ifdef XP_DEBUG_OBJ_USAGE
5195 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5201 * xmlXPathNewCString:
5202 * @val: the char * value
5204 * Create a new xmlXPathObjectPtr of type string and of value @val
5206 * Returns the newly created object.
5209 xmlXPathNewCString(const char *val) {
5210 xmlXPathObjectPtr ret;
5212 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5214 xmlXPathErrMemory(NULL, "creating string object\n");
5217 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5218 ret->type = XPATH_STRING;
5219 ret->stringval = xmlStrdup(BAD_CAST val);
5220 #ifdef XP_DEBUG_OBJ_USAGE
5221 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5227 * xmlXPathWrapCString:
5228 * @val: the char * value
5230 * Wraps a string into an XPath object.
5232 * Returns the newly created object.
5235 xmlXPathWrapCString (char * val) {
5236 return(xmlXPathWrapString((xmlChar *)(val)));
5240 * xmlXPathWrapExternal:
5241 * @val: the user data
5243 * Wraps the @val data into an XPath object.
5245 * Returns the newly created object.
5248 xmlXPathWrapExternal (void *val) {
5249 xmlXPathObjectPtr ret;
5251 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5253 xmlXPathErrMemory(NULL, "creating user object\n");
5256 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5257 ret->type = XPATH_USERS;
5259 #ifdef XP_DEBUG_OBJ_USAGE
5260 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5266 * xmlXPathObjectCopy:
5267 * @val: the original object
5269 * allocate a new copy of a given object
5271 * Returns the newly created object.
5274 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5275 xmlXPathObjectPtr ret;
5280 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5282 xmlXPathErrMemory(NULL, "copying object\n");
5285 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5286 #ifdef XP_DEBUG_OBJ_USAGE
5287 xmlXPathDebugObjUsageRequested(NULL, val->type);
5289 switch (val->type) {
5296 ret->stringval = xmlStrdup(val->stringval);
5298 case XPATH_XSLT_TREE:
5301 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5302 this previous handling is no longer correct, and can cause some serious
5303 problems (ref. bug 145547)
5305 if ((val->nodesetval != NULL) &&
5306 (val->nodesetval->nodeTab != NULL)) {
5307 xmlNodePtr cur, tmp;
5311 top = xmlNewDoc(NULL);
5312 top->name = (char *)
5313 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5317 cur = val->nodesetval->nodeTab[0]->children;
5318 while (cur != NULL) {
5319 tmp = xmlDocCopyNode(cur, top, 1);
5320 xmlAddChild((xmlNodePtr) top, tmp);
5325 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5327 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5328 /* Deallocate the copied tree value */
5332 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5333 /* Do not deallocate the copied tree value */
5336 case XPATH_LOCATIONSET:
5337 #ifdef LIBXML_XPTR_ENABLED
5339 xmlLocationSetPtr loc = val->user;
5340 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5345 ret->user = val->user;
5347 case XPATH_UNDEFINED:
5348 xmlGenericError(xmlGenericErrorContext,
5349 "xmlXPathObjectCopy: unsupported type %d\n",
5357 * xmlXPathFreeObject:
5358 * @obj: the object to free
5360 * Free up an xmlXPathObjectPtr object.
5363 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5364 if (obj == NULL) return;
5365 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5368 if (obj->user != NULL) {
5369 xmlXPathFreeNodeSet(obj->nodesetval);
5370 xmlFreeNodeList((xmlNodePtr) obj->user);
5373 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5374 if (obj->nodesetval != NULL)
5375 xmlXPathFreeValueTree(obj->nodesetval);
5377 if (obj->nodesetval != NULL)
5378 xmlXPathFreeNodeSet(obj->nodesetval);
5380 #ifdef LIBXML_XPTR_ENABLED
5381 } else if (obj->type == XPATH_LOCATIONSET) {
5382 if (obj->user != NULL)
5383 xmlXPtrFreeLocationSet(obj->user);
5385 } else if (obj->type == XPATH_STRING) {
5386 if (obj->stringval != NULL)
5387 xmlFree(obj->stringval);
5389 #ifdef XP_DEBUG_OBJ_USAGE
5390 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5396 * xmlXPathReleaseObject:
5397 * @obj: the xmlXPathObjectPtr to free or to cache
5399 * Depending on the state of the cache this frees the given
5400 * XPath object or stores it in the cache.
5403 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5405 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5406 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5407 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5409 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5413 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5414 xmlXPathFreeObject(obj);
5416 xmlXPathContextCachePtr cache =
5417 (xmlXPathContextCachePtr) ctxt->cache;
5419 switch (obj->type) {
5421 case XPATH_XSLT_TREE:
5422 if (obj->nodesetval != NULL) {
5425 * It looks like the @boolval is used for
5426 * evaluation if this an XSLT Result Tree Fragment.
5427 * TODO: Check if this assumption is correct.
5429 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5430 xmlXPathFreeValueTree(obj->nodesetval);
5431 obj->nodesetval = NULL;
5432 } else if ((obj->nodesetval->nodeMax <= 40) &&
5433 (XP_CACHE_WANTS(cache->nodesetObjs,
5434 cache->maxNodeset)))
5436 XP_CACHE_ADD(cache->nodesetObjs, obj);
5439 xmlXPathFreeNodeSet(obj->nodesetval);
5440 obj->nodesetval = NULL;
5445 if (obj->stringval != NULL)
5446 xmlFree(obj->stringval);
5448 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5449 XP_CACHE_ADD(cache->stringObjs, obj);
5454 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5455 XP_CACHE_ADD(cache->booleanObjs, obj);
5460 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5461 XP_CACHE_ADD(cache->numberObjs, obj);
5465 #ifdef LIBXML_XPTR_ENABLED
5466 case XPATH_LOCATIONSET:
5467 if (obj->user != NULL) {
5468 xmlXPtrFreeLocationSet(obj->user);
5477 * Fallback to adding to the misc-objects slot.
5479 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5480 XP_CACHE_ADD(cache->miscObjs, obj);
5486 #ifdef XP_DEBUG_OBJ_USAGE
5487 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5490 if (obj->nodesetval != NULL) {
5491 xmlNodeSetPtr tmpset = obj->nodesetval;
5494 * TODO: Due to those nasty ns-nodes, we need to traverse
5495 * the list and free the ns-nodes.
5496 * URGENT TODO: Check if it's actually slowing things down.
5497 * Maybe we shouldn't try to preserve the list.
5499 if (tmpset->nodeNr > 1) {
5503 for (i = 0; i < tmpset->nodeNr; i++) {
5504 node = tmpset->nodeTab[i];
5505 if ((node != NULL) &&
5506 (node->type == XML_NAMESPACE_DECL))
5508 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5511 } else if (tmpset->nodeNr == 1) {
5512 if ((tmpset->nodeTab[0] != NULL) &&
5513 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5514 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5517 memset(obj, 0, sizeof(xmlXPathObject));
5518 obj->nodesetval = tmpset;
5520 memset(obj, 0, sizeof(xmlXPathObject));
5526 * Cache is full; free the object.
5528 if (obj->nodesetval != NULL)
5529 xmlXPathFreeNodeSet(obj->nodesetval);
5530 #ifdef XP_DEBUG_OBJ_USAGE
5531 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5539 /************************************************************************
5541 * Type Casting Routines *
5543 ************************************************************************/
5546 * xmlXPathCastBooleanToString:
5549 * Converts a boolean to its string value.
5551 * Returns a newly allocated string.
5554 xmlXPathCastBooleanToString (int val) {
5557 ret = xmlStrdup((const xmlChar *) "true");
5559 ret = xmlStrdup((const xmlChar *) "false");
5564 * xmlXPathCastNumberToString:
5567 * Converts a number to its string value.
5569 * Returns a newly allocated string.
5572 xmlXPathCastNumberToString (double val) {
5574 switch (xmlXPathIsInf(val)) {
5576 ret = xmlStrdup((const xmlChar *) "Infinity");
5579 ret = xmlStrdup((const xmlChar *) "-Infinity");
5582 if (xmlXPathIsNaN(val)) {
5583 ret = xmlStrdup((const xmlChar *) "NaN");
5584 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5585 ret = xmlStrdup((const xmlChar *) "0");
5587 /* could be improved */
5589 xmlXPathFormatNumber(val, buf, 99);
5591 ret = xmlStrdup((const xmlChar *) buf);
5598 * xmlXPathCastNodeToString:
5601 * Converts a node to its string value.
5603 * Returns a newly allocated string.
5606 xmlXPathCastNodeToString (xmlNodePtr node) {
5608 if ((ret = xmlNodeGetContent(node)) == NULL)
5609 ret = xmlStrdup((const xmlChar *) "");
5614 * xmlXPathCastNodeSetToString:
5617 * Converts a node-set to its string value.
5619 * Returns a newly allocated string.
5622 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5623 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5624 return(xmlStrdup((const xmlChar *) ""));
5627 xmlXPathNodeSetSort(ns);
5628 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5632 * xmlXPathCastToString:
5633 * @val: an XPath object
5635 * Converts an existing object to its string() equivalent
5637 * Returns the allocated string value of the object, NULL in case of error.
5638 * It's up to the caller to free the string memory with xmlFree().
5641 xmlXPathCastToString(xmlXPathObjectPtr val) {
5642 xmlChar *ret = NULL;
5645 return(xmlStrdup((const xmlChar *) ""));
5646 switch (val->type) {
5647 case XPATH_UNDEFINED:
5649 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5651 ret = xmlStrdup((const xmlChar *) "");
5654 case XPATH_XSLT_TREE:
5655 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5658 return(xmlStrdup(val->stringval));
5660 ret = xmlXPathCastBooleanToString(val->boolval);
5662 case XPATH_NUMBER: {
5663 ret = xmlXPathCastNumberToString(val->floatval);
5669 case XPATH_LOCATIONSET:
5671 ret = xmlStrdup((const xmlChar *) "");
5678 * xmlXPathConvertString:
5679 * @val: an XPath object
5681 * Converts an existing object to its string() equivalent
5683 * Returns the new object, the old one is freed (or the operation
5684 * is done directly on @val)
5687 xmlXPathConvertString(xmlXPathObjectPtr val) {
5688 xmlChar *res = NULL;
5691 return(xmlXPathNewCString(""));
5693 switch (val->type) {
5694 case XPATH_UNDEFINED:
5696 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5700 case XPATH_XSLT_TREE:
5701 res = xmlXPathCastNodeSetToString(val->nodesetval);
5706 res = xmlXPathCastBooleanToString(val->boolval);
5709 res = xmlXPathCastNumberToString(val->floatval);
5714 case XPATH_LOCATIONSET:
5718 xmlXPathFreeObject(val);
5720 return(xmlXPathNewCString(""));
5721 return(xmlXPathWrapString(res));
5725 * xmlXPathCastBooleanToNumber:
5728 * Converts a boolean to its number value
5730 * Returns the number value
5733 xmlXPathCastBooleanToNumber(int val) {
5740 * xmlXPathCastStringToNumber:
5743 * Converts a string to its number value
5745 * Returns the number value
5748 xmlXPathCastStringToNumber(const xmlChar * val) {
5749 return(xmlXPathStringEvalNumber(val));
5753 * xmlXPathCastNodeToNumber:
5756 * Converts a node to its number value
5758 * Returns the number value
5761 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5766 return(xmlXPathNAN);
5767 strval = xmlXPathCastNodeToString(node);
5769 return(xmlXPathNAN);
5770 ret = xmlXPathCastStringToNumber(strval);
5777 * xmlXPathCastNodeSetToNumber:
5780 * Converts a node-set to its number value
5782 * Returns the number value
5785 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5790 return(xmlXPathNAN);
5791 str = xmlXPathCastNodeSetToString(ns);
5792 ret = xmlXPathCastStringToNumber(str);
5798 * xmlXPathCastToNumber:
5799 * @val: an XPath object
5801 * Converts an XPath object to its number value
5803 * Returns the number value
5806 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5810 return(xmlXPathNAN);
5811 switch (val->type) {
5812 case XPATH_UNDEFINED:
5814 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5819 case XPATH_XSLT_TREE:
5820 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5823 ret = xmlXPathCastStringToNumber(val->stringval);
5826 ret = val->floatval;
5829 ret = xmlXPathCastBooleanToNumber(val->boolval);
5834 case XPATH_LOCATIONSET:
5843 * xmlXPathConvertNumber:
5844 * @val: an XPath object
5846 * Converts an existing object to its number() equivalent
5848 * Returns the new object, the old one is freed (or the operation
5849 * is done directly on @val)
5852 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5853 xmlXPathObjectPtr ret;
5856 return(xmlXPathNewFloat(0.0));
5857 if (val->type == XPATH_NUMBER)
5859 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5860 xmlXPathFreeObject(val);
5865 * xmlXPathCastNumberToBoolean:
5868 * Converts a number to its boolean value
5870 * Returns the boolean value
5873 xmlXPathCastNumberToBoolean (double val) {
5874 if (xmlXPathIsNaN(val) || (val == 0.0))
5880 * xmlXPathCastStringToBoolean:
5883 * Converts a string to its boolean value
5885 * Returns the boolean value
5888 xmlXPathCastStringToBoolean (const xmlChar *val) {
5889 if ((val == NULL) || (xmlStrlen(val) == 0))
5895 * xmlXPathCastNodeSetToBoolean:
5898 * Converts a node-set to its boolean value
5900 * Returns the boolean value
5903 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5904 if ((ns == NULL) || (ns->nodeNr == 0))
5910 * xmlXPathCastToBoolean:
5911 * @val: an XPath object
5913 * Converts an XPath object to its boolean value
5915 * Returns the boolean value
5918 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5923 switch (val->type) {
5924 case XPATH_UNDEFINED:
5926 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5931 case XPATH_XSLT_TREE:
5932 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5935 ret = xmlXPathCastStringToBoolean(val->stringval);
5938 ret = xmlXPathCastNumberToBoolean(val->floatval);
5946 case XPATH_LOCATIONSET:
5956 * xmlXPathConvertBoolean:
5957 * @val: an XPath object
5959 * Converts an existing object to its boolean() equivalent
5961 * Returns the new object, the old one is freed (or the operation
5962 * is done directly on @val)
5965 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5966 xmlXPathObjectPtr ret;
5969 return(xmlXPathNewBoolean(0));
5970 if (val->type == XPATH_BOOLEAN)
5972 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5973 xmlXPathFreeObject(val);
5977 /************************************************************************
5979 * Routines to handle XPath contexts *
5981 ************************************************************************/
5984 * xmlXPathNewContext:
5985 * @doc: the XML document
5987 * Create a new xmlXPathContext
5989 * Returns the xmlXPathContext just allocated. The caller will need to free it.
5992 xmlXPathNewContext(xmlDocPtr doc) {
5993 xmlXPathContextPtr ret;
5995 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5997 xmlXPathErrMemory(NULL, "creating context\n");
6000 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6004 ret->varHash = NULL;
6010 ret->funcHash = xmlHashCreate(0);
6019 ret->contextSize = -1;
6020 ret->proximityPosition = -1;
6022 #ifdef XP_DEFAULT_CACHE_ON
6023 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6024 xmlXPathFreeContext(ret);
6029 xmlXPathRegisterAllFunctions(ret);
6035 * xmlXPathFreeContext:
6036 * @ctxt: the context to free
6038 * Free up an xmlXPathContext
6041 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6042 if (ctxt == NULL) return;
6044 if (ctxt->cache != NULL)
6045 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6046 xmlXPathRegisteredNsCleanup(ctxt);
6047 xmlXPathRegisteredFuncsCleanup(ctxt);
6048 xmlXPathRegisteredVariablesCleanup(ctxt);
6049 xmlResetError(&ctxt->lastError);
6053 /************************************************************************
6055 * Routines to handle XPath parser contexts *
6057 ************************************************************************/
6059 #define CHECK_CTXT(ctxt) \
6060 if (ctxt == NULL) { \
6061 __xmlRaiseError(NULL, NULL, NULL, \
6062 NULL, NULL, XML_FROM_XPATH, \
6063 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6064 __FILE__, __LINE__, \
6065 NULL, NULL, NULL, 0, 0, \
6066 "NULL context pointer\n"); \
6070 #define CHECK_CTXT_NEG(ctxt) \
6071 if (ctxt == NULL) { \
6072 __xmlRaiseError(NULL, NULL, NULL, \
6073 NULL, NULL, XML_FROM_XPATH, \
6074 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6075 __FILE__, __LINE__, \
6076 NULL, NULL, NULL, 0, 0, \
6077 "NULL context pointer\n"); \
6082 #define CHECK_CONTEXT(ctxt) \
6083 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6084 (ctxt->doc->children == NULL)) { \
6085 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6091 * xmlXPathNewParserContext:
6092 * @str: the XPath expression
6093 * @ctxt: the XPath context
6095 * Create a new xmlXPathParserContext
6097 * Returns the xmlXPathParserContext just allocated.
6099 xmlXPathParserContextPtr
6100 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6101 xmlXPathParserContextPtr ret;
6103 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6105 xmlXPathErrMemory(ctxt, "creating parser context\n");
6108 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6109 ret->cur = ret->base = str;
6110 ret->context = ctxt;
6112 ret->comp = xmlXPathNewCompExpr();
6113 if (ret->comp == NULL) {
6114 xmlFree(ret->valueTab);
6118 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6119 ret->comp->dict = ctxt->dict;
6120 xmlDictReference(ret->comp->dict);
6127 * xmlXPathCompParserContext:
6128 * @comp: the XPath compiled expression
6129 * @ctxt: the XPath context
6131 * Create a new xmlXPathParserContext when processing a compiled expression
6133 * Returns the xmlXPathParserContext just allocated.
6135 static xmlXPathParserContextPtr
6136 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6137 xmlXPathParserContextPtr ret;
6139 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6141 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6144 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6146 /* Allocate the value stack */
6147 ret->valueTab = (xmlXPathObjectPtr *)
6148 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6149 if (ret->valueTab == NULL) {
6151 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6158 ret->context = ctxt;
6165 * xmlXPathFreeParserContext:
6166 * @ctxt: the context to free
6168 * Free up an xmlXPathParserContext
6171 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6172 if (ctxt->valueTab != NULL) {
6173 xmlFree(ctxt->valueTab);
6175 if (ctxt->comp != NULL) {
6176 #ifdef XPATH_STREAMING
6177 if (ctxt->comp->stream != NULL) {
6178 xmlFreePatternList(ctxt->comp->stream);
6179 ctxt->comp->stream = NULL;
6182 xmlXPathFreeCompExpr(ctxt->comp);
6187 /************************************************************************
6189 * The implicit core function library *
6191 ************************************************************************/
6194 * xmlXPathNodeValHash:
6195 * @node: a node pointer
6197 * Function computing the beginning of the string value of the node,
6198 * used to speed up comparisons
6200 * Returns an int usable as a hash
6203 xmlXPathNodeValHash(xmlNodePtr node) {
6205 const xmlChar * string = NULL;
6206 xmlNodePtr tmp = NULL;
6207 unsigned int ret = 0;
6212 if (node->type == XML_DOCUMENT_NODE) {
6213 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6215 node = node->children;
6223 switch (node->type) {
6224 case XML_COMMENT_NODE:
6226 case XML_CDATA_SECTION_NODE:
6228 string = node->content;
6233 return(((unsigned int) string[0]) +
6234 (((unsigned int) string[1]) << 8));
6235 case XML_NAMESPACE_DECL:
6236 string = ((xmlNsPtr)node)->href;
6241 return(((unsigned int) string[0]) +
6242 (((unsigned int) string[1]) << 8));
6243 case XML_ATTRIBUTE_NODE:
6244 tmp = ((xmlAttrPtr) node)->children;
6246 case XML_ELEMENT_NODE:
6247 tmp = node->children;
6252 while (tmp != NULL) {
6253 switch (tmp->type) {
6254 case XML_COMMENT_NODE:
6256 case XML_CDATA_SECTION_NODE:
6258 string = tmp->content;
6260 case XML_NAMESPACE_DECL:
6261 string = ((xmlNsPtr)tmp)->href;
6266 if ((string != NULL) && (string[0] != 0)) {
6268 return(ret + (((unsigned int) string[0]) << 8));
6270 if (string[1] == 0) {
6272 ret = (unsigned int) string[0];
6274 return(((unsigned int) string[0]) +
6275 (((unsigned int) string[1]) << 8));
6281 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6282 if (tmp->children->type != XML_ENTITY_DECL) {
6283 tmp = tmp->children;
6290 if (tmp->next != NULL) {
6303 if (tmp->next != NULL) {
6307 } while (tmp != NULL);
6313 * xmlXPathStringHash:
6316 * Function computing the beginning of the string value of the node,
6317 * used to speed up comparisons
6319 * Returns an int usable as a hash
6322 xmlXPathStringHash(const xmlChar * string) {
6324 return((unsigned int) 0);
6327 return(((unsigned int) string[0]) +
6328 (((unsigned int) string[1]) << 8));
6332 * xmlXPathCompareNodeSetFloat:
6333 * @ctxt: the XPath Parser context
6334 * @inf: less than (1) or greater than (0)
6335 * @strict: is the comparison strict
6336 * @arg: the node set
6339 * Implement the compare operation between a nodeset and a number
6340 * @ns < @val (1, 1, ...
6341 * @ns <= @val (1, 0, ...
6342 * @ns > @val (0, 1, ...
6343 * @ns >= @val (0, 0, ...
6345 * If one object to be compared is a node-set and the other is a number,
6346 * then the comparison will be true if and only if there is a node in the
6347 * node-set such that the result of performing the comparison on the number
6348 * to be compared and on the result of converting the string-value of that
6349 * node to a number using the number function is true.
6351 * Returns 0 or 1 depending on the results of the test.
6354 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6355 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6360 if ((f == NULL) || (arg == NULL) ||
6361 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6362 xmlXPathReleaseObject(ctxt->context, arg);
6363 xmlXPathReleaseObject(ctxt->context, f);
6366 ns = arg->nodesetval;
6368 for (i = 0;i < ns->nodeNr;i++) {
6369 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6372 xmlXPathCacheNewString(ctxt->context, str2));
6374 xmlXPathNumberFunction(ctxt, 1);
6375 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6376 ret = xmlXPathCompareValues(ctxt, inf, strict);
6382 xmlXPathReleaseObject(ctxt->context, arg);
6383 xmlXPathReleaseObject(ctxt->context, f);
6388 * xmlXPathCompareNodeSetString:
6389 * @ctxt: the XPath Parser context
6390 * @inf: less than (1) or greater than (0)
6391 * @strict: is the comparison strict
6392 * @arg: the node set
6395 * Implement the compare operation between a nodeset and a string
6396 * @ns < @val (1, 1, ...
6397 * @ns <= @val (1, 0, ...
6398 * @ns > @val (0, 1, ...
6399 * @ns >= @val (0, 0, ...
6401 * If one object to be compared is a node-set and the other is a string,
6402 * then the comparison will be true if and only if there is a node in
6403 * the node-set such that the result of performing the comparison on the
6404 * string-value of the node and the other string is true.
6406 * Returns 0 or 1 depending on the results of the test.
6409 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6410 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6415 if ((s == NULL) || (arg == NULL) ||
6416 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6417 xmlXPathReleaseObject(ctxt->context, arg);
6418 xmlXPathReleaseObject(ctxt->context, s);
6421 ns = arg->nodesetval;
6423 for (i = 0;i < ns->nodeNr;i++) {
6424 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6427 xmlXPathCacheNewString(ctxt->context, str2));
6429 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6430 ret = xmlXPathCompareValues(ctxt, inf, strict);
6436 xmlXPathReleaseObject(ctxt->context, arg);
6437 xmlXPathReleaseObject(ctxt->context, s);
6442 * xmlXPathCompareNodeSets:
6443 * @inf: less than (1) or greater than (0)
6444 * @strict: is the comparison strict
6445 * @arg1: the first node set object
6446 * @arg2: the second node set object
6448 * Implement the compare operation on nodesets:
6450 * If both objects to be compared are node-sets, then the comparison
6451 * will be true if and only if there is a node in the first node-set
6452 * and a node in the second node-set such that the result of performing
6453 * the comparison on the string-values of the two nodes is true.
6455 * When neither object to be compared is a node-set and the operator
6456 * is <=, <, >= or >, then the objects are compared by converting both
6457 * objects to numbers and comparing the numbers according to IEEE 754.
6459 * The number function converts its argument to a number as follows:
6460 * - a string that consists of optional whitespace followed by an
6461 * optional minus sign followed by a Number followed by whitespace
6462 * is converted to the IEEE 754 number that is nearest (according
6463 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6464 * represented by the string; any other string is converted to NaN
6466 * Conclusion all nodes need to be converted first to their string value
6467 * and then the comparison must be done when possible
6470 xmlXPathCompareNodeSets(int inf, int strict,
6471 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6479 if ((arg1 == NULL) ||
6480 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6481 xmlXPathFreeObject(arg2);
6484 if ((arg2 == NULL) ||
6485 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6486 xmlXPathFreeObject(arg1);
6487 xmlXPathFreeObject(arg2);
6491 ns1 = arg1->nodesetval;
6492 ns2 = arg2->nodesetval;
6494 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6495 xmlXPathFreeObject(arg1);
6496 xmlXPathFreeObject(arg2);
6499 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6500 xmlXPathFreeObject(arg1);
6501 xmlXPathFreeObject(arg2);
6505 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6506 if (values2 == NULL) {
6507 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6508 xmlXPathFreeObject(arg1);
6509 xmlXPathFreeObject(arg2);
6512 for (i = 0;i < ns1->nodeNr;i++) {
6513 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6514 if (xmlXPathIsNaN(val1))
6516 for (j = 0;j < ns2->nodeNr;j++) {
6518 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6520 if (xmlXPathIsNaN(values2[j]))
6523 ret = (val1 < values2[j]);
6524 else if (inf && !strict)
6525 ret = (val1 <= values2[j]);
6526 else if (!inf && strict)
6527 ret = (val1 > values2[j]);
6528 else if (!inf && !strict)
6529 ret = (val1 >= values2[j]);
6538 xmlXPathFreeObject(arg1);
6539 xmlXPathFreeObject(arg2);
6544 * xmlXPathCompareNodeSetValue:
6545 * @ctxt: the XPath Parser context
6546 * @inf: less than (1) or greater than (0)
6547 * @strict: is the comparison strict
6548 * @arg: the node set
6551 * Implement the compare operation between a nodeset and a value
6552 * @ns < @val (1, 1, ...
6553 * @ns <= @val (1, 0, ...
6554 * @ns > @val (0, 1, ...
6555 * @ns >= @val (0, 0, ...
6557 * If one object to be compared is a node-set and the other is a boolean,
6558 * then the comparison will be true if and only if the result of performing
6559 * the comparison on the boolean and on the result of converting
6560 * the node-set to a boolean using the boolean function is true.
6562 * Returns 0 or 1 depending on the results of the test.
6565 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6566 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6567 if ((val == NULL) || (arg == NULL) ||
6568 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6573 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6575 case XPATH_XSLT_TREE:
6576 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6578 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6580 valuePush(ctxt, arg);
6581 xmlXPathBooleanFunction(ctxt, 1);
6582 valuePush(ctxt, val);
6583 return(xmlXPathCompareValues(ctxt, inf, strict));
6591 * xmlXPathEqualNodeSetString:
6592 * @arg: the nodeset object argument
6593 * @str: the string to compare to.
6594 * @neq: flag to show whether for '=' (0) or '!=' (1)
6596 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6597 * If one object to be compared is a node-set and the other is a string,
6598 * then the comparison will be true if and only if there is a node in
6599 * the node-set such that the result of performing the comparison on the
6600 * string-value of the node and the other string is true.
6602 * Returns 0 or 1 depending on the results of the test.
6605 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6612 if ((str == NULL) || (arg == NULL) ||
6613 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6615 ns = arg->nodesetval;
6617 * A NULL nodeset compared with a string is always false
6618 * (since there is no node equal, and no node not equal)
6620 if ((ns == NULL) || (ns->nodeNr <= 0) )
6622 hash = xmlXPathStringHash(str);
6623 for (i = 0; i < ns->nodeNr; i++) {
6624 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6625 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6626 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6631 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6649 * xmlXPathEqualNodeSetFloat:
6650 * @arg: the nodeset object argument
6651 * @f: the float to compare to
6652 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6654 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6655 * If one object to be compared is a node-set and the other is a number,
6656 * then the comparison will be true if and only if there is a node in
6657 * the node-set such that the result of performing the comparison on the
6658 * number to be compared and on the result of converting the string-value
6659 * of that node to a number using the number function is true.
6661 * Returns 0 or 1 depending on the results of the test.
6664 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6665 xmlXPathObjectPtr arg, double f, int neq) {
6669 xmlXPathObjectPtr val;
6672 if ((arg == NULL) ||
6673 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6676 ns = arg->nodesetval;
6678 for (i=0;i<ns->nodeNr;i++) {
6679 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6681 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6683 xmlXPathNumberFunction(ctxt, 1);
6684 val = valuePop(ctxt);
6686 xmlXPathReleaseObject(ctxt->context, val);
6687 if (!xmlXPathIsNaN(v)) {
6688 if ((!neq) && (v==f)) {
6691 } else if ((neq) && (v!=f)) {
6695 } else { /* NaN is unequal to any value */
6708 * xmlXPathEqualNodeSets:
6709 * @arg1: first nodeset object argument
6710 * @arg2: second nodeset object argument
6711 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6713 * Implement the equal / not equal operation on XPath nodesets:
6714 * @arg1 == @arg2 or @arg1 != @arg2
6715 * If both objects to be compared are node-sets, then the comparison
6716 * will be true if and only if there is a node in the first node-set and
6717 * a node in the second node-set such that the result of performing the
6718 * comparison on the string-values of the two nodes is true.
6720 * (needless to say, this is a costly operation)
6722 * Returns 0 or 1 depending on the results of the test.
6725 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6727 unsigned int *hashs1;
6728 unsigned int *hashs2;
6735 if ((arg1 == NULL) ||
6736 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6738 if ((arg2 == NULL) ||
6739 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6742 ns1 = arg1->nodesetval;
6743 ns2 = arg2->nodesetval;
6745 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6747 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6751 * for equal, check if there is a node pertaining to both sets
6754 for (i = 0;i < ns1->nodeNr;i++)
6755 for (j = 0;j < ns2->nodeNr;j++)
6756 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6759 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6760 if (values1 == NULL) {
6761 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6764 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6765 if (hashs1 == NULL) {
6766 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6770 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6771 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6772 if (values2 == NULL) {
6773 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6778 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6779 if (hashs2 == NULL) {
6780 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6786 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6787 for (i = 0;i < ns1->nodeNr;i++) {
6788 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6789 for (j = 0;j < ns2->nodeNr;j++) {
6791 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6792 if (hashs1[i] != hashs2[j]) {
6799 if (values1[i] == NULL)
6800 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6801 if (values2[j] == NULL)
6802 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6803 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6811 for (i = 0;i < ns1->nodeNr;i++)
6812 if (values1[i] != NULL)
6813 xmlFree(values1[i]);
6814 for (j = 0;j < ns2->nodeNr;j++)
6815 if (values2[j] != NULL)
6816 xmlFree(values2[j]);
6825 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6826 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6829 *At this point we are assured neither arg1 nor arg2
6830 *is a nodeset, so we can just pick the appropriate routine.
6832 switch (arg1->type) {
6833 case XPATH_UNDEFINED:
6835 xmlGenericError(xmlGenericErrorContext,
6836 "Equal: undefined\n");
6840 switch (arg2->type) {
6841 case XPATH_UNDEFINED:
6843 xmlGenericError(xmlGenericErrorContext,
6844 "Equal: undefined\n");
6849 xmlGenericError(xmlGenericErrorContext,
6850 "Equal: %d boolean %d \n",
6851 arg1->boolval, arg2->boolval);
6853 ret = (arg1->boolval == arg2->boolval);
6856 ret = (arg1->boolval ==
6857 xmlXPathCastNumberToBoolean(arg2->floatval));
6860 if ((arg2->stringval == NULL) ||
6861 (arg2->stringval[0] == 0)) ret = 0;
6864 ret = (arg1->boolval == ret);
6869 case XPATH_LOCATIONSET:
6873 case XPATH_XSLT_TREE:
6878 switch (arg2->type) {
6879 case XPATH_UNDEFINED:
6881 xmlGenericError(xmlGenericErrorContext,
6882 "Equal: undefined\n");
6886 ret = (arg2->boolval==
6887 xmlXPathCastNumberToBoolean(arg1->floatval));
6890 valuePush(ctxt, arg2);
6891 xmlXPathNumberFunction(ctxt, 1);
6892 arg2 = valuePop(ctxt);
6893 /* no break on purpose */
6895 /* Hand check NaN and Infinity equalities */
6896 if (xmlXPathIsNaN(arg1->floatval) ||
6897 xmlXPathIsNaN(arg2->floatval)) {
6899 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6900 if (xmlXPathIsInf(arg2->floatval) == 1)
6904 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6905 if (xmlXPathIsInf(arg2->floatval) == -1)
6909 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6910 if (xmlXPathIsInf(arg1->floatval) == 1)
6914 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6915 if (xmlXPathIsInf(arg1->floatval) == -1)
6920 ret = (arg1->floatval == arg2->floatval);
6926 case XPATH_LOCATIONSET:
6930 case XPATH_XSLT_TREE:
6935 switch (arg2->type) {
6936 case XPATH_UNDEFINED:
6938 xmlGenericError(xmlGenericErrorContext,
6939 "Equal: undefined\n");
6943 if ((arg1->stringval == NULL) ||
6944 (arg1->stringval[0] == 0)) ret = 0;
6947 ret = (arg2->boolval == ret);
6950 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6953 valuePush(ctxt, arg1);
6954 xmlXPathNumberFunction(ctxt, 1);
6955 arg1 = valuePop(ctxt);
6956 /* Hand check NaN and Infinity equalities */
6957 if (xmlXPathIsNaN(arg1->floatval) ||
6958 xmlXPathIsNaN(arg2->floatval)) {
6960 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6961 if (xmlXPathIsInf(arg2->floatval) == 1)
6965 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6966 if (xmlXPathIsInf(arg2->floatval) == -1)
6970 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6971 if (xmlXPathIsInf(arg1->floatval) == 1)
6975 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6976 if (xmlXPathIsInf(arg1->floatval) == -1)
6981 ret = (arg1->floatval == arg2->floatval);
6987 case XPATH_LOCATIONSET:
6991 case XPATH_XSLT_TREE:
6998 case XPATH_LOCATIONSET:
7002 case XPATH_XSLT_TREE:
7005 xmlXPathReleaseObject(ctxt->context, arg1);
7006 xmlXPathReleaseObject(ctxt->context, arg2);
7011 * xmlXPathEqualValues:
7012 * @ctxt: the XPath Parser context
7014 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7016 * Returns 0 or 1 depending on the results of the test.
7019 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7020 xmlXPathObjectPtr arg1, arg2, argtmp;
7023 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7024 arg2 = valuePop(ctxt);
7025 arg1 = valuePop(ctxt);
7026 if ((arg1 == NULL) || (arg2 == NULL)) {
7028 xmlXPathReleaseObject(ctxt->context, arg1);
7030 xmlXPathReleaseObject(ctxt->context, arg2);
7031 XP_ERROR0(XPATH_INVALID_OPERAND);
7036 xmlGenericError(xmlGenericErrorContext,
7037 "Equal: by pointer\n");
7039 xmlXPathFreeObject(arg1);
7044 *If either argument is a nodeset, it's a 'special case'
7046 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7047 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7049 *Hack it to assure arg1 is the nodeset
7051 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7056 switch (arg2->type) {
7057 case XPATH_UNDEFINED:
7059 xmlGenericError(xmlGenericErrorContext,
7060 "Equal: undefined\n");
7064 case XPATH_XSLT_TREE:
7065 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7068 if ((arg1->nodesetval == NULL) ||
7069 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7072 ret = (ret == arg2->boolval);
7075 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7078 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7083 case XPATH_LOCATIONSET:
7087 xmlXPathReleaseObject(ctxt->context, arg1);
7088 xmlXPathReleaseObject(ctxt->context, arg2);
7092 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7096 * xmlXPathNotEqualValues:
7097 * @ctxt: the XPath Parser context
7099 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7101 * Returns 0 or 1 depending on the results of the test.
7104 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7105 xmlXPathObjectPtr arg1, arg2, argtmp;
7108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7109 arg2 = valuePop(ctxt);
7110 arg1 = valuePop(ctxt);
7111 if ((arg1 == NULL) || (arg2 == NULL)) {
7113 xmlXPathReleaseObject(ctxt->context, arg1);
7115 xmlXPathReleaseObject(ctxt->context, arg2);
7116 XP_ERROR0(XPATH_INVALID_OPERAND);
7121 xmlGenericError(xmlGenericErrorContext,
7122 "NotEqual: by pointer\n");
7124 xmlXPathReleaseObject(ctxt->context, arg1);
7129 *If either argument is a nodeset, it's a 'special case'
7131 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7132 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7134 *Hack it to assure arg1 is the nodeset
7136 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7141 switch (arg2->type) {
7142 case XPATH_UNDEFINED:
7144 xmlGenericError(xmlGenericErrorContext,
7145 "NotEqual: undefined\n");
7149 case XPATH_XSLT_TREE:
7150 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7153 if ((arg1->nodesetval == NULL) ||
7154 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7157 ret = (ret != arg2->boolval);
7160 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7163 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7168 case XPATH_LOCATIONSET:
7172 xmlXPathReleaseObject(ctxt->context, arg1);
7173 xmlXPathReleaseObject(ctxt->context, arg2);
7177 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7181 * xmlXPathCompareValues:
7182 * @ctxt: the XPath Parser context
7183 * @inf: less than (1) or greater than (0)
7184 * @strict: is the comparison strict
7186 * Implement the compare operation on XPath objects:
7187 * @arg1 < @arg2 (1, 1, ...
7188 * @arg1 <= @arg2 (1, 0, ...
7189 * @arg1 > @arg2 (0, 1, ...
7190 * @arg1 >= @arg2 (0, 0, ...
7192 * When neither object to be compared is a node-set and the operator is
7193 * <=, <, >=, >, then the objects are compared by converted both objects
7194 * to numbers and comparing the numbers according to IEEE 754. The <
7195 * comparison will be true if and only if the first number is less than the
7196 * second number. The <= comparison will be true if and only if the first
7197 * number is less than or equal to the second number. The > comparison
7198 * will be true if and only if the first number is greater than the second
7199 * number. The >= comparison will be true if and only if the first number
7200 * is greater than or equal to the second number.
7202 * Returns 1 if the comparison succeeded, 0 if it failed
7205 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7206 int ret = 0, arg1i = 0, arg2i = 0;
7207 xmlXPathObjectPtr arg1, arg2;
7209 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7210 arg2 = valuePop(ctxt);
7211 arg1 = valuePop(ctxt);
7212 if ((arg1 == NULL) || (arg2 == NULL)) {
7214 xmlXPathReleaseObject(ctxt->context, arg1);
7216 xmlXPathReleaseObject(ctxt->context, arg2);
7217 XP_ERROR0(XPATH_INVALID_OPERAND);
7220 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7221 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7223 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7224 * are not freed from within this routine; they will be freed from the
7225 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7227 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7228 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7229 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7231 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7232 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7235 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7242 if (arg1->type != XPATH_NUMBER) {
7243 valuePush(ctxt, arg1);
7244 xmlXPathNumberFunction(ctxt, 1);
7245 arg1 = valuePop(ctxt);
7247 if (arg1->type != XPATH_NUMBER) {
7248 xmlXPathFreeObject(arg1);
7249 xmlXPathFreeObject(arg2);
7250 XP_ERROR0(XPATH_INVALID_OPERAND);
7252 if (arg2->type != XPATH_NUMBER) {
7253 valuePush(ctxt, arg2);
7254 xmlXPathNumberFunction(ctxt, 1);
7255 arg2 = valuePop(ctxt);
7257 if (arg2->type != XPATH_NUMBER) {
7258 xmlXPathReleaseObject(ctxt->context, arg1);
7259 xmlXPathReleaseObject(ctxt->context, arg2);
7260 XP_ERROR0(XPATH_INVALID_OPERAND);
7263 * Add tests for infinity and nan
7264 * => feedback on 3.4 for Inf and NaN
7266 /* Hand check NaN and Infinity comparisons */
7267 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7270 arg1i=xmlXPathIsInf(arg1->floatval);
7271 arg2i=xmlXPathIsInf(arg2->floatval);
7272 if (inf && strict) {
7273 if ((arg1i == -1 && arg2i != -1) ||
7274 (arg2i == 1 && arg1i != 1)) {
7276 } else if (arg1i == 0 && arg2i == 0) {
7277 ret = (arg1->floatval < arg2->floatval);
7282 else if (inf && !strict) {
7283 if (arg1i == -1 || arg2i == 1) {
7285 } else if (arg1i == 0 && arg2i == 0) {
7286 ret = (arg1->floatval <= arg2->floatval);
7291 else if (!inf && strict) {
7292 if ((arg1i == 1 && arg2i != 1) ||
7293 (arg2i == -1 && arg1i != -1)) {
7295 } else if (arg1i == 0 && arg2i == 0) {
7296 ret = (arg1->floatval > arg2->floatval);
7301 else if (!inf && !strict) {
7302 if (arg1i == 1 || arg2i == -1) {
7304 } else if (arg1i == 0 && arg2i == 0) {
7305 ret = (arg1->floatval >= arg2->floatval);
7311 xmlXPathReleaseObject(ctxt->context, arg1);
7312 xmlXPathReleaseObject(ctxt->context, arg2);
7317 * xmlXPathValueFlipSign:
7318 * @ctxt: the XPath Parser context
7320 * Implement the unary - operation on an XPath object
7321 * The numeric operators convert their operands to numbers as if
7322 * by calling the number function.
7325 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7326 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7328 CHECK_TYPE(XPATH_NUMBER);
7329 if (xmlXPathIsNaN(ctxt->value->floatval))
7330 ctxt->value->floatval=xmlXPathNAN;
7331 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7332 ctxt->value->floatval=xmlXPathNINF;
7333 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7334 ctxt->value->floatval=xmlXPathPINF;
7335 else if (ctxt->value->floatval == 0) {
7336 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7337 ctxt->value->floatval = xmlXPathNZERO;
7339 ctxt->value->floatval = 0;
7342 ctxt->value->floatval = - ctxt->value->floatval;
7346 * xmlXPathAddValues:
7347 * @ctxt: the XPath Parser context
7349 * Implement the add operation on XPath objects:
7350 * The numeric operators convert their operands to numbers as if
7351 * by calling the number function.
7354 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7355 xmlXPathObjectPtr arg;
7358 arg = valuePop(ctxt);
7360 XP_ERROR(XPATH_INVALID_OPERAND);
7361 val = xmlXPathCastToNumber(arg);
7362 xmlXPathReleaseObject(ctxt->context, arg);
7364 CHECK_TYPE(XPATH_NUMBER);
7365 ctxt->value->floatval += val;
7369 * xmlXPathSubValues:
7370 * @ctxt: the XPath Parser context
7372 * Implement the subtraction operation on XPath objects:
7373 * The numeric operators convert their operands to numbers as if
7374 * by calling the number function.
7377 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7378 xmlXPathObjectPtr arg;
7381 arg = valuePop(ctxt);
7383 XP_ERROR(XPATH_INVALID_OPERAND);
7384 val = xmlXPathCastToNumber(arg);
7385 xmlXPathReleaseObject(ctxt->context, arg);
7387 CHECK_TYPE(XPATH_NUMBER);
7388 ctxt->value->floatval -= val;
7392 * xmlXPathMultValues:
7393 * @ctxt: the XPath Parser context
7395 * Implement the multiply operation on XPath objects:
7396 * The numeric operators convert their operands to numbers as if
7397 * by calling the number function.
7400 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7401 xmlXPathObjectPtr arg;
7404 arg = valuePop(ctxt);
7406 XP_ERROR(XPATH_INVALID_OPERAND);
7407 val = xmlXPathCastToNumber(arg);
7408 xmlXPathReleaseObject(ctxt->context, arg);
7410 CHECK_TYPE(XPATH_NUMBER);
7411 ctxt->value->floatval *= val;
7415 * xmlXPathDivValues:
7416 * @ctxt: the XPath Parser context
7418 * Implement the div operation on XPath objects @arg1 / @arg2:
7419 * The numeric operators convert their operands to numbers as if
7420 * by calling the number function.
7423 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7424 xmlXPathObjectPtr arg;
7427 arg = valuePop(ctxt);
7429 XP_ERROR(XPATH_INVALID_OPERAND);
7430 val = xmlXPathCastToNumber(arg);
7431 xmlXPathReleaseObject(ctxt->context, arg);
7433 CHECK_TYPE(XPATH_NUMBER);
7434 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7435 ctxt->value->floatval = xmlXPathNAN;
7436 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7437 if (ctxt->value->floatval == 0)
7438 ctxt->value->floatval = xmlXPathNAN;
7439 else if (ctxt->value->floatval > 0)
7440 ctxt->value->floatval = xmlXPathNINF;
7441 else if (ctxt->value->floatval < 0)
7442 ctxt->value->floatval = xmlXPathPINF;
7444 else if (val == 0) {
7445 if (ctxt->value->floatval == 0)
7446 ctxt->value->floatval = xmlXPathNAN;
7447 else if (ctxt->value->floatval > 0)
7448 ctxt->value->floatval = xmlXPathPINF;
7449 else if (ctxt->value->floatval < 0)
7450 ctxt->value->floatval = xmlXPathNINF;
7452 ctxt->value->floatval /= val;
7456 * xmlXPathModValues:
7457 * @ctxt: the XPath Parser context
7459 * Implement the mod operation on XPath objects: @arg1 / @arg2
7460 * The numeric operators convert their operands to numbers as if
7461 * by calling the number function.
7464 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7465 xmlXPathObjectPtr arg;
7468 arg = valuePop(ctxt);
7470 XP_ERROR(XPATH_INVALID_OPERAND);
7471 arg2 = xmlXPathCastToNumber(arg);
7472 xmlXPathReleaseObject(ctxt->context, arg);
7474 CHECK_TYPE(XPATH_NUMBER);
7475 arg1 = ctxt->value->floatval;
7477 ctxt->value->floatval = xmlXPathNAN;
7479 ctxt->value->floatval = fmod(arg1, arg2);
7483 /************************************************************************
7485 * The traversal functions *
7487 ************************************************************************/
7490 * A traversal function enumerates nodes along an axis.
7491 * Initially it must be called with NULL, and it indicates
7492 * termination on the axis by returning NULL.
7494 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7495 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7498 * xmlXPathTraversalFunctionExt:
7499 * A traversal function enumerates nodes along an axis.
7500 * Initially it must be called with NULL, and it indicates
7501 * termination on the axis by returning NULL.
7502 * The context node of the traversal is specified via @contextNode.
7504 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7505 (xmlNodePtr cur, xmlNodePtr contextNode);
7508 * xmlXPathNodeSetMergeFunction:
7509 * Used for merging node sets in xmlXPathCollectAndTest().
7511 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7512 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7517 * @ctxt: the XPath Parser context
7518 * @cur: the current node in the traversal
7520 * Traversal function for the "self" direction
7521 * The self axis contains just the context node itself
7523 * Returns the next element following that axis
7526 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7527 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7529 return(ctxt->context->node);
7534 * xmlXPathNextChild:
7535 * @ctxt: the XPath Parser context
7536 * @cur: the current node in the traversal
7538 * Traversal function for the "child" direction
7539 * The child axis contains the children of the context node in document order.
7541 * Returns the next element following that axis
7544 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7545 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7547 if (ctxt->context->node == NULL) return(NULL);
7548 switch (ctxt->context->node->type) {
7549 case XML_ELEMENT_NODE:
7551 case XML_CDATA_SECTION_NODE:
7552 case XML_ENTITY_REF_NODE:
7553 case XML_ENTITY_NODE:
7555 case XML_COMMENT_NODE:
7556 case XML_NOTATION_NODE:
7558 return(ctxt->context->node->children);
7559 case XML_DOCUMENT_NODE:
7560 case XML_DOCUMENT_TYPE_NODE:
7561 case XML_DOCUMENT_FRAG_NODE:
7562 case XML_HTML_DOCUMENT_NODE:
7563 #ifdef LIBXML_DOCB_ENABLED
7564 case XML_DOCB_DOCUMENT_NODE:
7566 return(((xmlDocPtr) ctxt->context->node)->children);
7567 case XML_ELEMENT_DECL:
7568 case XML_ATTRIBUTE_DECL:
7569 case XML_ENTITY_DECL:
7570 case XML_ATTRIBUTE_NODE:
7571 case XML_NAMESPACE_DECL:
7572 case XML_XINCLUDE_START:
7573 case XML_XINCLUDE_END:
7578 if ((cur->type == XML_DOCUMENT_NODE) ||
7579 (cur->type == XML_HTML_DOCUMENT_NODE))
7585 * xmlXPathNextChildElement:
7586 * @ctxt: the XPath Parser context
7587 * @cur: the current node in the traversal
7589 * Traversal function for the "child" direction and nodes of type element.
7590 * The child axis contains the children of the context node in document order.
7592 * Returns the next element following that axis
7595 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7596 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7598 cur = ctxt->context->node;
7599 if (cur == NULL) return(NULL);
7601 * Get the first element child.
7603 switch (cur->type) {
7604 case XML_ELEMENT_NODE:
7605 case XML_DOCUMENT_FRAG_NODE:
7606 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7607 case XML_ENTITY_NODE:
7608 cur = cur->children;
7610 if (cur->type == XML_ELEMENT_NODE)
7614 } while ((cur != NULL) &&
7615 (cur->type != XML_ELEMENT_NODE));
7619 case XML_DOCUMENT_NODE:
7620 case XML_HTML_DOCUMENT_NODE:
7621 #ifdef LIBXML_DOCB_ENABLED
7622 case XML_DOCB_DOCUMENT_NODE:
7624 return(xmlDocGetRootElement((xmlDocPtr) cur));
7631 * Get the next sibling element node.
7633 switch (cur->type) {
7634 case XML_ELEMENT_NODE:
7636 case XML_ENTITY_REF_NODE:
7637 case XML_ENTITY_NODE:
7638 case XML_CDATA_SECTION_NODE:
7640 case XML_COMMENT_NODE:
7641 case XML_XINCLUDE_END:
7643 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7647 if (cur->next != NULL) {
7648 if (cur->next->type == XML_ELEMENT_NODE)
7653 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7660 * xmlXPathNextDescendantOrSelfElemParent:
7661 * @ctxt: the XPath Parser context
7662 * @cur: the current node in the traversal
7664 * Traversal function for the "descendant-or-self" axis.
7665 * Additionally it returns only nodes which can be parents of
7669 * Returns the next element following that axis
7672 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7673 xmlNodePtr contextNode)
7676 if (contextNode == NULL)
7678 switch (contextNode->type) {
7679 case XML_ELEMENT_NODE:
7680 case XML_XINCLUDE_START:
7681 case XML_DOCUMENT_FRAG_NODE:
7682 case XML_DOCUMENT_NODE:
7683 #ifdef LIBXML_DOCB_ENABLED
7684 case XML_DOCB_DOCUMENT_NODE:
7686 case XML_HTML_DOCUMENT_NODE:
7687 return(contextNode);
7693 xmlNodePtr start = cur;
7695 while (cur != NULL) {
7696 switch (cur->type) {
7697 case XML_ELEMENT_NODE:
7698 /* TODO: OK to have XInclude here? */
7699 case XML_XINCLUDE_START:
7700 case XML_DOCUMENT_FRAG_NODE:
7703 if (cur->children != NULL) {
7704 cur = cur->children;
7708 /* Not sure if we need those here. */
7709 case XML_DOCUMENT_NODE:
7710 #ifdef LIBXML_DOCB_ENABLED
7711 case XML_DOCB_DOCUMENT_NODE:
7713 case XML_HTML_DOCUMENT_NODE:
7716 return(xmlDocGetRootElement((xmlDocPtr) cur));
7722 if ((cur == NULL) || (cur == contextNode))
7724 if (cur->next != NULL) {
7736 * xmlXPathNextDescendant:
7737 * @ctxt: the XPath Parser context
7738 * @cur: the current node in the traversal
7740 * Traversal function for the "descendant" direction
7741 * the descendant axis contains the descendants of the context node in document
7742 * order; a descendant is a child or a child of a child and so on.
7744 * Returns the next element following that axis
7747 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7748 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7750 if (ctxt->context->node == NULL)
7752 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7753 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7756 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7757 return(ctxt->context->doc->children);
7758 return(ctxt->context->node->children);
7761 if (cur->children != NULL) {
7763 * Do not descend on entities declarations
7765 if (cur->children->type != XML_ENTITY_DECL) {
7766 cur = cur->children;
7770 if (cur->type != XML_DTD_NODE)
7775 if (cur == ctxt->context->node) return(NULL);
7777 while (cur->next != NULL) {
7779 if ((cur->type != XML_ENTITY_DECL) &&
7780 (cur->type != XML_DTD_NODE))
7786 if (cur == NULL) break;
7787 if (cur == ctxt->context->node) return(NULL);
7788 if (cur->next != NULL) {
7792 } while (cur != NULL);
7797 * xmlXPathNextDescendantOrSelf:
7798 * @ctxt: the XPath Parser context
7799 * @cur: the current node in the traversal
7801 * Traversal function for the "descendant-or-self" direction
7802 * the descendant-or-self axis contains the context node and the descendants
7803 * of the context node in document order; thus the context node is the first
7804 * node on the axis, and the first child of the context node is the second node
7807 * Returns the next element following that axis
7810 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7811 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7813 if (ctxt->context->node == NULL)
7815 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7816 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7818 return(ctxt->context->node);
7821 return(xmlXPathNextDescendant(ctxt, cur));
7825 * xmlXPathNextParent:
7826 * @ctxt: the XPath Parser context
7827 * @cur: the current node in the traversal
7829 * Traversal function for the "parent" direction
7830 * The parent axis contains the parent of the context node, if there is one.
7832 * Returns the next element following that axis
7835 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7836 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7838 * the parent of an attribute or namespace node is the element
7839 * to which the attribute or namespace node is attached
7840 * Namespace handling !!!
7843 if (ctxt->context->node == NULL) return(NULL);
7844 switch (ctxt->context->node->type) {
7845 case XML_ELEMENT_NODE:
7847 case XML_CDATA_SECTION_NODE:
7848 case XML_ENTITY_REF_NODE:
7849 case XML_ENTITY_NODE:
7851 case XML_COMMENT_NODE:
7852 case XML_NOTATION_NODE:
7854 case XML_ELEMENT_DECL:
7855 case XML_ATTRIBUTE_DECL:
7856 case XML_XINCLUDE_START:
7857 case XML_XINCLUDE_END:
7858 case XML_ENTITY_DECL:
7859 if (ctxt->context->node->parent == NULL)
7860 return((xmlNodePtr) ctxt->context->doc);
7861 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7862 ((ctxt->context->node->parent->name[0] == ' ') ||
7863 (xmlStrEqual(ctxt->context->node->parent->name,
7864 BAD_CAST "fake node libxslt"))))
7866 return(ctxt->context->node->parent);
7867 case XML_ATTRIBUTE_NODE: {
7868 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7870 return(att->parent);
7872 case XML_DOCUMENT_NODE:
7873 case XML_DOCUMENT_TYPE_NODE:
7874 case XML_DOCUMENT_FRAG_NODE:
7875 case XML_HTML_DOCUMENT_NODE:
7876 #ifdef LIBXML_DOCB_ENABLED
7877 case XML_DOCB_DOCUMENT_NODE:
7880 case XML_NAMESPACE_DECL: {
7881 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7883 if ((ns->next != NULL) &&
7884 (ns->next->type != XML_NAMESPACE_DECL))
7885 return((xmlNodePtr) ns->next);
7894 * xmlXPathNextAncestor:
7895 * @ctxt: the XPath Parser context
7896 * @cur: the current node in the traversal
7898 * Traversal function for the "ancestor" direction
7899 * the ancestor axis contains the ancestors of the context node; the ancestors
7900 * of the context node consist of the parent of context node and the parent's
7901 * parent and so on; the nodes are ordered in reverse document order; thus the
7902 * parent is the first node on the axis, and the parent's parent is the second
7905 * Returns the next element following that axis
7908 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7909 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7911 * the parent of an attribute or namespace node is the element
7912 * to which the attribute or namespace node is attached
7916 if (ctxt->context->node == NULL) return(NULL);
7917 switch (ctxt->context->node->type) {
7918 case XML_ELEMENT_NODE:
7920 case XML_CDATA_SECTION_NODE:
7921 case XML_ENTITY_REF_NODE:
7922 case XML_ENTITY_NODE:
7924 case XML_COMMENT_NODE:
7926 case XML_ELEMENT_DECL:
7927 case XML_ATTRIBUTE_DECL:
7928 case XML_ENTITY_DECL:
7929 case XML_NOTATION_NODE:
7930 case XML_XINCLUDE_START:
7931 case XML_XINCLUDE_END:
7932 if (ctxt->context->node->parent == NULL)
7933 return((xmlNodePtr) ctxt->context->doc);
7934 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7935 ((ctxt->context->node->parent->name[0] == ' ') ||
7936 (xmlStrEqual(ctxt->context->node->parent->name,
7937 BAD_CAST "fake node libxslt"))))
7939 return(ctxt->context->node->parent);
7940 case XML_ATTRIBUTE_NODE: {
7941 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7943 return(tmp->parent);
7945 case XML_DOCUMENT_NODE:
7946 case XML_DOCUMENT_TYPE_NODE:
7947 case XML_DOCUMENT_FRAG_NODE:
7948 case XML_HTML_DOCUMENT_NODE:
7949 #ifdef LIBXML_DOCB_ENABLED
7950 case XML_DOCB_DOCUMENT_NODE:
7953 case XML_NAMESPACE_DECL: {
7954 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7956 if ((ns->next != NULL) &&
7957 (ns->next->type != XML_NAMESPACE_DECL))
7958 return((xmlNodePtr) ns->next);
7959 /* Bad, how did that namespace end up here ? */
7965 if (cur == ctxt->context->doc->children)
7966 return((xmlNodePtr) ctxt->context->doc);
7967 if (cur == (xmlNodePtr) ctxt->context->doc)
7969 switch (cur->type) {
7970 case XML_ELEMENT_NODE:
7972 case XML_CDATA_SECTION_NODE:
7973 case XML_ENTITY_REF_NODE:
7974 case XML_ENTITY_NODE:
7976 case XML_COMMENT_NODE:
7977 case XML_NOTATION_NODE:
7979 case XML_ELEMENT_DECL:
7980 case XML_ATTRIBUTE_DECL:
7981 case XML_ENTITY_DECL:
7982 case XML_XINCLUDE_START:
7983 case XML_XINCLUDE_END:
7984 if (cur->parent == NULL)
7986 if ((cur->parent->type == XML_ELEMENT_NODE) &&
7987 ((cur->parent->name[0] == ' ') ||
7988 (xmlStrEqual(cur->parent->name,
7989 BAD_CAST "fake node libxslt"))))
7991 return(cur->parent);
7992 case XML_ATTRIBUTE_NODE: {
7993 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7995 return(att->parent);
7997 case XML_NAMESPACE_DECL: {
7998 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8000 if ((ns->next != NULL) &&
8001 (ns->next->type != XML_NAMESPACE_DECL))
8002 return((xmlNodePtr) ns->next);
8003 /* Bad, how did that namespace end up here ? */
8006 case XML_DOCUMENT_NODE:
8007 case XML_DOCUMENT_TYPE_NODE:
8008 case XML_DOCUMENT_FRAG_NODE:
8009 case XML_HTML_DOCUMENT_NODE:
8010 #ifdef LIBXML_DOCB_ENABLED
8011 case XML_DOCB_DOCUMENT_NODE:
8019 * xmlXPathNextAncestorOrSelf:
8020 * @ctxt: the XPath Parser context
8021 * @cur: the current node in the traversal
8023 * Traversal function for the "ancestor-or-self" direction
8024 * he ancestor-or-self axis contains the context node and ancestors of
8025 * the context node in reverse document order; thus the context node is
8026 * the first node on the axis, and the context node's parent the second;
8027 * parent here is defined the same as with the parent axis.
8029 * Returns the next element following that axis
8032 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8033 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8035 return(ctxt->context->node);
8036 return(xmlXPathNextAncestor(ctxt, cur));
8040 * xmlXPathNextFollowingSibling:
8041 * @ctxt: the XPath Parser context
8042 * @cur: the current node in the traversal
8044 * Traversal function for the "following-sibling" direction
8045 * The following-sibling axis contains the following siblings of the context
8046 * node in document order.
8048 * Returns the next element following that axis
8051 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8052 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8053 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8054 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8056 if (cur == (xmlNodePtr) ctxt->context->doc)
8059 return(ctxt->context->node->next);
8064 * xmlXPathNextPrecedingSibling:
8065 * @ctxt: the XPath Parser context
8066 * @cur: the current node in the traversal
8068 * Traversal function for the "preceding-sibling" direction
8069 * The preceding-sibling axis contains the preceding siblings of the context
8070 * node in reverse document order; the first preceding sibling is first on the
8071 * axis; the sibling preceding that node is the second on the axis and so on.
8073 * Returns the next element following that axis
8076 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8077 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8078 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8079 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8081 if (cur == (xmlNodePtr) ctxt->context->doc)
8084 return(ctxt->context->node->prev);
8085 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8088 return(ctxt->context->node->prev);
8094 * xmlXPathNextFollowing:
8095 * @ctxt: the XPath Parser context
8096 * @cur: the current node in the traversal
8098 * Traversal function for the "following" direction
8099 * The following axis contains all nodes in the same document as the context
8100 * node that are after the context node in document order, excluding any
8101 * descendants and excluding attribute nodes and namespace nodes; the nodes
8102 * are ordered in document order
8104 * Returns the next element following that axis
8107 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8108 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8109 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8110 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8111 return(cur->children);
8114 cur = ctxt->context->node;
8115 if (cur->type == XML_NAMESPACE_DECL)
8117 if (cur->type == XML_ATTRIBUTE_NODE)
8120 if (cur == NULL) return(NULL) ; /* ERROR */
8121 if (cur->next != NULL) return(cur->next) ;
8124 if (cur == NULL) break;
8125 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8126 if (cur->next != NULL) return(cur->next);
8127 } while (cur != NULL);
8132 * xmlXPathIsAncestor:
8133 * @ancestor: the ancestor node
8134 * @node: the current node
8136 * Check that @ancestor is a @node's ancestor
8138 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8141 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8142 if ((ancestor == NULL) || (node == NULL)) return(0);
8143 /* nodes need to be in the same document */
8144 if (ancestor->doc != node->doc) return(0);
8145 /* avoid searching if ancestor or node is the root node */
8146 if (ancestor == (xmlNodePtr) node->doc) return(1);
8147 if (node == (xmlNodePtr) ancestor->doc) return(0);
8148 while (node->parent != NULL) {
8149 if (node->parent == ancestor)
8151 node = node->parent;
8157 * xmlXPathNextPreceding:
8158 * @ctxt: the XPath Parser context
8159 * @cur: the current node in the traversal
8161 * Traversal function for the "preceding" direction
8162 * the preceding axis contains all nodes in the same document as the context
8163 * node that are before the context node in document order, excluding any
8164 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8165 * ordered in reverse document order
8167 * Returns the next element following that axis
8170 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8172 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8174 cur = ctxt->context->node;
8175 if (cur->type == XML_NAMESPACE_DECL)
8177 if (cur->type == XML_ATTRIBUTE_NODE)
8178 return(cur->parent);
8182 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8185 if (cur->prev != NULL) {
8186 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8193 if (cur == ctxt->context->doc->children)
8195 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8200 * xmlXPathNextPrecedingInternal:
8201 * @ctxt: the XPath Parser context
8202 * @cur: the current node in the traversal
8204 * Traversal function for the "preceding" direction
8205 * the preceding axis contains all nodes in the same document as the context
8206 * node that are before the context node in document order, excluding any
8207 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8208 * ordered in reverse document order
8209 * This is a faster implementation but internal only since it requires a
8210 * state kept in the parser context: ctxt->ancestor.
8212 * Returns the next element following that axis
8215 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8218 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8220 cur = ctxt->context->node;
8223 if (cur->type == XML_NAMESPACE_DECL)
8225 ctxt->ancestor = cur->parent;
8227 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8229 while (cur->prev == NULL) {
8233 if (cur == ctxt->context->doc->children)
8235 if (cur != ctxt->ancestor)
8237 ctxt->ancestor = cur->parent;
8240 while (cur->last != NULL)
8246 * xmlXPathNextNamespace:
8247 * @ctxt: the XPath Parser context
8248 * @cur: the current attribute in the traversal
8250 * Traversal function for the "namespace" direction
8251 * the namespace axis contains the namespace nodes of the context node;
8252 * the order of nodes on this axis is implementation-defined; the axis will
8253 * be empty unless the context node is an element
8255 * We keep the XML namespace node at the end of the list.
8257 * Returns the next element following that axis
8260 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8261 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8262 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8263 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8264 if (ctxt->context->tmpNsList != NULL)
8265 xmlFree(ctxt->context->tmpNsList);
8266 ctxt->context->tmpNsList =
8267 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8268 ctxt->context->tmpNsNr = 0;
8269 if (ctxt->context->tmpNsList != NULL) {
8270 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8271 ctxt->context->tmpNsNr++;
8274 return((xmlNodePtr) xmlXPathXMLNamespace);
8276 if (ctxt->context->tmpNsNr > 0) {
8277 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8279 if (ctxt->context->tmpNsList != NULL)
8280 xmlFree(ctxt->context->tmpNsList);
8281 ctxt->context->tmpNsList = NULL;
8287 * xmlXPathNextAttribute:
8288 * @ctxt: the XPath Parser context
8289 * @cur: the current attribute in the traversal
8291 * Traversal function for the "attribute" direction
8292 * TODO: support DTD inherited default attributes
8294 * Returns the next element following that axis
8297 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8298 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8299 if (ctxt->context->node == NULL)
8301 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8304 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8306 return((xmlNodePtr)ctxt->context->node->properties);
8308 return((xmlNodePtr)cur->next);
8311 /************************************************************************
8313 * NodeTest Functions *
8315 ************************************************************************/
8317 #define IS_FUNCTION 200
8320 /************************************************************************
8322 * Implicit tree core function library *
8324 ************************************************************************/
8328 * @ctxt: the XPath Parser context
8330 * Initialize the context to the root of the document
8333 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8334 if ((ctxt == NULL) || (ctxt->context == NULL))
8336 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8337 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8338 ctxt->context->node));
8341 /************************************************************************
8343 * The explicit core function library *
8344 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8346 ************************************************************************/
8350 * xmlXPathLastFunction:
8351 * @ctxt: the XPath Parser context
8352 * @nargs: the number of arguments
8354 * Implement the last() XPath function
8356 * The last function returns the number of nodes in the context node list.
8359 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8361 if (ctxt->context->contextSize >= 0) {
8363 xmlXPathCacheNewFloat(ctxt->context,
8364 (double) ctxt->context->contextSize));
8366 xmlGenericError(xmlGenericErrorContext,
8367 "last() : %d\n", ctxt->context->contextSize);
8370 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8375 * xmlXPathPositionFunction:
8376 * @ctxt: the XPath Parser context
8377 * @nargs: the number of arguments
8379 * Implement the position() XPath function
8381 * The position function returns the position of the context node in the
8382 * context node list. The first position is 1, and so the last position
8383 * will be equal to last().
8386 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8388 if (ctxt->context->proximityPosition >= 0) {
8390 xmlXPathCacheNewFloat(ctxt->context,
8391 (double) ctxt->context->proximityPosition));
8393 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8394 ctxt->context->proximityPosition);
8397 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8402 * xmlXPathCountFunction:
8403 * @ctxt: the XPath Parser context
8404 * @nargs: the number of arguments
8406 * Implement the count() XPath function
8407 * number count(node-set)
8410 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8411 xmlXPathObjectPtr cur;
8414 if ((ctxt->value == NULL) ||
8415 ((ctxt->value->type != XPATH_NODESET) &&
8416 (ctxt->value->type != XPATH_XSLT_TREE)))
8417 XP_ERROR(XPATH_INVALID_TYPE);
8418 cur = valuePop(ctxt);
8420 if ((cur == NULL) || (cur->nodesetval == NULL))
8421 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8422 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8423 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8424 (double) cur->nodesetval->nodeNr));
8426 if ((cur->nodesetval->nodeNr != 1) ||
8427 (cur->nodesetval->nodeTab == NULL)) {
8428 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8433 tmp = cur->nodesetval->nodeTab[0];
8435 tmp = tmp->children;
8436 while (tmp != NULL) {
8441 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8444 xmlXPathReleaseObject(ctxt->context, cur);
8448 * xmlXPathGetElementsByIds:
8449 * @doc: the document
8450 * @ids: a whitespace separated list of IDs
8452 * Selects elements by their unique ID.
8454 * Returns a node-set of selected elements.
8456 static xmlNodeSetPtr
8457 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8459 const xmlChar *cur = ids;
8462 xmlNodePtr elem = NULL;
8464 if (ids == NULL) return(NULL);
8466 ret = xmlXPathNodeSetCreate(NULL);
8470 while (IS_BLANK_CH(*cur)) cur++;
8472 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8475 ID = xmlStrndup(ids, cur - ids);
8478 * We used to check the fact that the value passed
8479 * was an NCName, but this generated much troubles for
8480 * me and Aleksey Sanin, people blatantly violated that
8481 * constaint, like Visa3D spec.
8482 * if (xmlValidateNCName(ID, 1) == 0)
8484 attr = xmlGetID(doc, ID);
8486 if (attr->type == XML_ATTRIBUTE_NODE)
8487 elem = attr->parent;
8488 else if (attr->type == XML_ELEMENT_NODE)
8489 elem = (xmlNodePtr) attr;
8493 xmlXPathNodeSetAdd(ret, elem);
8498 while (IS_BLANK_CH(*cur)) cur++;
8505 * xmlXPathIdFunction:
8506 * @ctxt: the XPath Parser context
8507 * @nargs: the number of arguments
8509 * Implement the id() XPath function
8510 * node-set id(object)
8511 * The id function selects elements by their unique ID
8512 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8513 * then the result is the union of the result of applying id to the
8514 * string value of each of the nodes in the argument node-set. When the
8515 * argument to id is of any other type, the argument is converted to a
8516 * string as if by a call to the string function; the string is split
8517 * into a whitespace-separated list of tokens (whitespace is any sequence
8518 * of characters matching the production S); the result is a node-set
8519 * containing the elements in the same document as the context node that
8520 * have a unique ID equal to any of the tokens in the list.
8523 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8526 xmlXPathObjectPtr obj;
8529 obj = valuePop(ctxt);
8530 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8531 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8535 ret = xmlXPathNodeSetCreate(NULL);
8537 * FIXME -- in an out-of-memory condition this will behave badly.
8538 * The solution is not clear -- we already popped an item from
8539 * ctxt, so the object is in a corrupt state.
8542 if (obj->nodesetval != NULL) {
8543 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8545 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8546 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8547 ret = xmlXPathNodeSetMerge(ret, ns);
8548 xmlXPathFreeNodeSet(ns);
8553 xmlXPathReleaseObject(ctxt->context, obj);
8554 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8557 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8558 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8559 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8560 xmlXPathReleaseObject(ctxt->context, obj);
8565 * xmlXPathLocalNameFunction:
8566 * @ctxt: the XPath Parser context
8567 * @nargs: the number of arguments
8569 * Implement the local-name() XPath function
8570 * string local-name(node-set?)
8571 * The local-name function returns a string containing the local part
8572 * of the name of the node in the argument node-set that is first in
8573 * document order. If the node-set is empty or the first node has no
8574 * name, an empty string is returned. If the argument is omitted it
8575 * defaults to the context node.
8578 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8579 xmlXPathObjectPtr cur;
8581 if (ctxt == NULL) return;
8584 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8585 ctxt->context->node));
8590 if ((ctxt->value == NULL) ||
8591 ((ctxt->value->type != XPATH_NODESET) &&
8592 (ctxt->value->type != XPATH_XSLT_TREE)))
8593 XP_ERROR(XPATH_INVALID_TYPE);
8594 cur = valuePop(ctxt);
8596 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8597 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8599 int i = 0; /* Should be first in document order !!!!! */
8600 switch (cur->nodesetval->nodeTab[i]->type) {
8601 case XML_ELEMENT_NODE:
8602 case XML_ATTRIBUTE_NODE:
8604 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8605 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8608 xmlXPathCacheNewString(ctxt->context,
8609 cur->nodesetval->nodeTab[i]->name));
8611 case XML_NAMESPACE_DECL:
8612 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8613 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8616 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8619 xmlXPathReleaseObject(ctxt->context, cur);
8623 * xmlXPathNamespaceURIFunction:
8624 * @ctxt: the XPath Parser context
8625 * @nargs: the number of arguments
8627 * Implement the namespace-uri() XPath function
8628 * string namespace-uri(node-set?)
8629 * The namespace-uri function returns a string containing the
8630 * namespace URI of the expanded name of the node in the argument
8631 * node-set that is first in document order. If the node-set is empty,
8632 * the first node has no name, or the expanded name has no namespace
8633 * URI, an empty string is returned. If the argument is omitted it
8634 * defaults to the context node.
8637 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8638 xmlXPathObjectPtr cur;
8640 if (ctxt == NULL) return;
8643 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8644 ctxt->context->node));
8648 if ((ctxt->value == NULL) ||
8649 ((ctxt->value->type != XPATH_NODESET) &&
8650 (ctxt->value->type != XPATH_XSLT_TREE)))
8651 XP_ERROR(XPATH_INVALID_TYPE);
8652 cur = valuePop(ctxt);
8654 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8655 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8657 int i = 0; /* Should be first in document order !!!!! */
8658 switch (cur->nodesetval->nodeTab[i]->type) {
8659 case XML_ELEMENT_NODE:
8660 case XML_ATTRIBUTE_NODE:
8661 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8662 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8664 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8665 cur->nodesetval->nodeTab[i]->ns->href));
8668 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8671 xmlXPathReleaseObject(ctxt->context, cur);
8675 * xmlXPathNameFunction:
8676 * @ctxt: the XPath Parser context
8677 * @nargs: the number of arguments
8679 * Implement the name() XPath function
8680 * string name(node-set?)
8681 * The name function returns a string containing a QName representing
8682 * the name of the node in the argument node-set that is first in document
8683 * order. The QName must represent the name with respect to the namespace
8684 * declarations in effect on the node whose name is being represented.
8685 * Typically, this will be the form in which the name occurred in the XML
8686 * source. This need not be the case if there are namespace declarations
8687 * in effect on the node that associate multiple prefixes with the same
8688 * namespace. However, an implementation may include information about
8689 * the original prefix in its representation of nodes; in this case, an
8690 * implementation can ensure that the returned string is always the same
8691 * as the QName used in the XML source. If the argument it omitted it
8692 * defaults to the context node.
8693 * Libxml keep the original prefix so the "real qualified name" used is
8697 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8699 xmlXPathObjectPtr cur;
8702 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8703 ctxt->context->node));
8708 if ((ctxt->value == NULL) ||
8709 ((ctxt->value->type != XPATH_NODESET) &&
8710 (ctxt->value->type != XPATH_XSLT_TREE)))
8711 XP_ERROR(XPATH_INVALID_TYPE);
8712 cur = valuePop(ctxt);
8714 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8715 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8717 int i = 0; /* Should be first in document order !!!!! */
8719 switch (cur->nodesetval->nodeTab[i]->type) {
8720 case XML_ELEMENT_NODE:
8721 case XML_ATTRIBUTE_NODE:
8722 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8724 xmlXPathCacheNewCString(ctxt->context, ""));
8725 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8726 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8728 xmlXPathCacheNewString(ctxt->context,
8729 cur->nodesetval->nodeTab[i]->name));
8733 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8734 cur->nodesetval->nodeTab[i]->ns->prefix,
8736 if (fullname == cur->nodesetval->nodeTab[i]->name)
8737 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8738 if (fullname == NULL) {
8739 XP_ERROR(XPATH_MEMORY_ERROR);
8741 valuePush(ctxt, xmlXPathCacheWrapString(
8742 ctxt->context, fullname));
8746 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8747 cur->nodesetval->nodeTab[i]));
8748 xmlXPathLocalNameFunction(ctxt, 1);
8751 xmlXPathReleaseObject(ctxt->context, cur);
8756 * xmlXPathStringFunction:
8757 * @ctxt: the XPath Parser context
8758 * @nargs: the number of arguments
8760 * Implement the string() XPath function
8761 * string string(object?)
8762 * The string function converts an object to a string as follows:
8763 * - A node-set is converted to a string by returning the value of
8764 * the node in the node-set that is first in document order.
8765 * If the node-set is empty, an empty string is returned.
8766 * - A number is converted to a string as follows
8767 * + NaN is converted to the string NaN
8768 * + positive zero is converted to the string 0
8769 * + negative zero is converted to the string 0
8770 * + positive infinity is converted to the string Infinity
8771 * + negative infinity is converted to the string -Infinity
8772 * + if the number is an integer, the number is represented in
8773 * decimal form as a Number with no decimal point and no leading
8774 * zeros, preceded by a minus sign (-) if the number is negative
8775 * + otherwise, the number is represented in decimal form as a
8776 * Number including a decimal point with at least one digit
8777 * before the decimal point and at least one digit after the
8778 * decimal point, preceded by a minus sign (-) if the number
8779 * is negative; there must be no leading zeros before the decimal
8780 * point apart possibly from the one required digit immediately
8781 * before the decimal point; beyond the one required digit
8782 * after the decimal point there must be as many, but only as
8783 * many, more digits as are needed to uniquely distinguish the
8784 * number from all other IEEE 754 numeric values.
8785 * - The boolean false value is converted to the string false.
8786 * The boolean true value is converted to the string true.
8788 * If the argument is omitted, it defaults to a node-set with the
8789 * context node as its only member.
8792 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8793 xmlXPathObjectPtr cur;
8795 if (ctxt == NULL) return;
8798 xmlXPathCacheWrapString(ctxt->context,
8799 xmlXPathCastNodeToString(ctxt->context->node)));
8804 cur = valuePop(ctxt);
8805 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8806 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8810 * xmlXPathStringLengthFunction:
8811 * @ctxt: the XPath Parser context
8812 * @nargs: the number of arguments
8814 * Implement the string-length() XPath function
8815 * number string-length(string?)
8816 * The string-length returns the number of characters in the string
8817 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8818 * the context node converted to a string, in other words the value
8819 * of the context node.
8822 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8823 xmlXPathObjectPtr cur;
8826 if ((ctxt == NULL) || (ctxt->context == NULL))
8828 if (ctxt->context->node == NULL) {
8829 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8833 content = xmlXPathCastNodeToString(ctxt->context->node);
8834 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8835 xmlUTF8Strlen(content)));
8842 CHECK_TYPE(XPATH_STRING);
8843 cur = valuePop(ctxt);
8844 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8845 xmlUTF8Strlen(cur->stringval)));
8846 xmlXPathReleaseObject(ctxt->context, cur);
8850 * xmlXPathConcatFunction:
8851 * @ctxt: the XPath Parser context
8852 * @nargs: the number of arguments
8854 * Implement the concat() XPath function
8855 * string concat(string, string, string*)
8856 * The concat function returns the concatenation of its arguments.
8859 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8860 xmlXPathObjectPtr cur, newobj;
8863 if (ctxt == NULL) return;
8869 cur = valuePop(ctxt);
8870 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8871 xmlXPathReleaseObject(ctxt->context, cur);
8878 newobj = valuePop(ctxt);
8879 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8880 xmlXPathReleaseObject(ctxt->context, newobj);
8881 xmlXPathReleaseObject(ctxt->context, cur);
8882 XP_ERROR(XPATH_INVALID_TYPE);
8884 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8885 newobj->stringval = cur->stringval;
8886 cur->stringval = tmp;
8887 xmlXPathReleaseObject(ctxt->context, newobj);
8890 valuePush(ctxt, cur);
8894 * xmlXPathContainsFunction:
8895 * @ctxt: the XPath Parser context
8896 * @nargs: the number of arguments
8898 * Implement the contains() XPath function
8899 * boolean contains(string, string)
8900 * The contains function returns true if the first argument string
8901 * contains the second argument string, and otherwise returns false.
8904 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905 xmlXPathObjectPtr hay, needle;
8909 CHECK_TYPE(XPATH_STRING);
8910 needle = valuePop(ctxt);
8912 hay = valuePop(ctxt);
8914 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8915 xmlXPathReleaseObject(ctxt->context, hay);
8916 xmlXPathReleaseObject(ctxt->context, needle);
8917 XP_ERROR(XPATH_INVALID_TYPE);
8919 if (xmlStrstr(hay->stringval, needle->stringval))
8920 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8922 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8923 xmlXPathReleaseObject(ctxt->context, hay);
8924 xmlXPathReleaseObject(ctxt->context, needle);
8928 * xmlXPathStartsWithFunction:
8929 * @ctxt: the XPath Parser context
8930 * @nargs: the number of arguments
8932 * Implement the starts-with() XPath function
8933 * boolean starts-with(string, string)
8934 * The starts-with function returns true if the first argument string
8935 * starts with the second argument string, and otherwise returns false.
8938 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8939 xmlXPathObjectPtr hay, needle;
8944 CHECK_TYPE(XPATH_STRING);
8945 needle = valuePop(ctxt);
8947 hay = valuePop(ctxt);
8949 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8950 xmlXPathReleaseObject(ctxt->context, hay);
8951 xmlXPathReleaseObject(ctxt->context, needle);
8952 XP_ERROR(XPATH_INVALID_TYPE);
8954 n = xmlStrlen(needle->stringval);
8955 if (xmlStrncmp(hay->stringval, needle->stringval, n))
8956 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8958 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8959 xmlXPathReleaseObject(ctxt->context, hay);
8960 xmlXPathReleaseObject(ctxt->context, needle);
8964 * xmlXPathSubstringFunction:
8965 * @ctxt: the XPath Parser context
8966 * @nargs: the number of arguments
8968 * Implement the substring() XPath function
8969 * string substring(string, number, number?)
8970 * The substring function returns the substring of the first argument
8971 * starting at the position specified in the second argument with
8972 * length specified in the third argument. For example,
8973 * substring("12345",2,3) returns "234". If the third argument is not
8974 * specified, it returns the substring starting at the position specified
8975 * in the second argument and continuing to the end of the string. For
8976 * example, substring("12345",2) returns "2345". More precisely, each
8977 * character in the string (see [3.6 Strings]) is considered to have a
8978 * numeric position: the position of the first character is 1, the position
8979 * of the second character is 2 and so on. The returned substring contains
8980 * those characters for which the position of the character is greater than
8981 * or equal to the second argument and, if the third argument is specified,
8982 * less than the sum of the second and third arguments; the comparisons
8983 * and addition used for the above follow the standard IEEE 754 rules. Thus:
8984 * - substring("12345", 1.5, 2.6) returns "234"
8985 * - substring("12345", 0, 3) returns "12"
8986 * - substring("12345", 0 div 0, 3) returns ""
8987 * - substring("12345", 1, 0 div 0) returns ""
8988 * - substring("12345", -42, 1 div 0) returns "12345"
8989 * - substring("12345", -1 div 0, 1 div 0) returns ""
8992 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8993 xmlXPathObjectPtr str, start, len;
9005 * take care of possible last (position) argument
9009 CHECK_TYPE(XPATH_NUMBER);
9010 len = valuePop(ctxt);
9012 xmlXPathReleaseObject(ctxt->context, len);
9016 CHECK_TYPE(XPATH_NUMBER);
9017 start = valuePop(ctxt);
9018 in = start->floatval;
9019 xmlXPathReleaseObject(ctxt->context, start);
9021 CHECK_TYPE(XPATH_STRING);
9022 str = valuePop(ctxt);
9023 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9026 * If last pos not present, calculate last position
9034 /* Need to check for the special cases where either
9035 * the index is NaN, the length is NaN, or both
9036 * arguments are infinity (relying on Inf + -Inf = NaN)
9038 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9040 * To meet the requirements of the spec, the arguments
9041 * must be converted to integer format before
9042 * initial index calculations are done
9044 * First we go to integer form, rounding up
9045 * and checking for special cases
9048 if (((double)i)+0.5 <= in) i++;
9050 if (xmlXPathIsInf(le) == 1) {
9055 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9059 if (((double)l)+0.5 <= le) l++;
9062 /* Now we normalize inidices */
9070 /* number of chars to copy */
9073 ret = xmlUTF8Strsub(str->stringval, i, l);
9079 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9081 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9084 xmlXPathReleaseObject(ctxt->context, str);
9088 * xmlXPathSubstringBeforeFunction:
9089 * @ctxt: the XPath Parser context
9090 * @nargs: the number of arguments
9092 * Implement the substring-before() XPath function
9093 * string substring-before(string, string)
9094 * The substring-before function returns the substring of the first
9095 * argument string that precedes the first occurrence of the second
9096 * argument string in the first argument string, or the empty string
9097 * if the first argument string does not contain the second argument
9098 * string. For example, substring-before("1999/04/01","/") returns 1999.
9101 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9102 xmlXPathObjectPtr str;
9103 xmlXPathObjectPtr find;
9104 xmlBufferPtr target;
9105 const xmlChar *point;
9110 find = valuePop(ctxt);
9112 str = valuePop(ctxt);
9114 target = xmlBufferCreate();
9116 point = xmlStrstr(str->stringval, find->stringval);
9118 offset = (int)(point - str->stringval);
9119 xmlBufferAdd(target, str->stringval, offset);
9121 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9122 xmlBufferContent(target)));
9123 xmlBufferFree(target);
9125 xmlXPathReleaseObject(ctxt->context, str);
9126 xmlXPathReleaseObject(ctxt->context, find);
9130 * xmlXPathSubstringAfterFunction:
9131 * @ctxt: the XPath Parser context
9132 * @nargs: the number of arguments
9134 * Implement the substring-after() XPath function
9135 * string substring-after(string, string)
9136 * The substring-after function returns the substring of the first
9137 * argument string that follows the first occurrence of the second
9138 * argument string in the first argument string, or the empty stringi
9139 * if the first argument string does not contain the second argument
9140 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9141 * and substring-after("1999/04/01","19") returns 99/04/01.
9144 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9145 xmlXPathObjectPtr str;
9146 xmlXPathObjectPtr find;
9147 xmlBufferPtr target;
9148 const xmlChar *point;
9153 find = valuePop(ctxt);
9155 str = valuePop(ctxt);
9157 target = xmlBufferCreate();
9159 point = xmlStrstr(str->stringval, find->stringval);
9161 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9162 xmlBufferAdd(target, &str->stringval[offset],
9163 xmlStrlen(str->stringval) - offset);
9165 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9166 xmlBufferContent(target)));
9167 xmlBufferFree(target);
9169 xmlXPathReleaseObject(ctxt->context, str);
9170 xmlXPathReleaseObject(ctxt->context, find);
9174 * xmlXPathNormalizeFunction:
9175 * @ctxt: the XPath Parser context
9176 * @nargs: the number of arguments
9178 * Implement the normalize-space() XPath function
9179 * string normalize-space(string?)
9180 * The normalize-space function returns the argument string with white
9181 * space normalized by stripping leading and trailing whitespace
9182 * and replacing sequences of whitespace characters by a single
9183 * space. Whitespace characters are the same allowed by the S production
9184 * in XML. If the argument is omitted, it defaults to the context
9185 * node converted to a string, in other words the value of the context node.
9188 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9189 xmlXPathObjectPtr obj = NULL;
9190 xmlChar *source = NULL;
9191 xmlBufferPtr target;
9194 if (ctxt == NULL) return;
9196 /* Use current context node */
9198 xmlXPathCacheWrapString(ctxt->context,
9199 xmlXPathCastNodeToString(ctxt->context->node)));
9205 CHECK_TYPE(XPATH_STRING);
9206 obj = valuePop(ctxt);
9207 source = obj->stringval;
9209 target = xmlBufferCreate();
9210 if (target && source) {
9212 /* Skip leading whitespaces */
9213 while (IS_BLANK_CH(*source))
9216 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9219 if (IS_BLANK_CH(*source)) {
9223 xmlBufferAdd(target, &blank, 1);
9226 xmlBufferAdd(target, source, 1);
9230 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9231 xmlBufferContent(target)));
9232 xmlBufferFree(target);
9234 xmlXPathReleaseObject(ctxt->context, obj);
9238 * xmlXPathTranslateFunction:
9239 * @ctxt: the XPath Parser context
9240 * @nargs: the number of arguments
9242 * Implement the translate() XPath function
9243 * string translate(string, string, string)
9244 * The translate function returns the first argument string with
9245 * occurrences of characters in the second argument string replaced
9246 * by the character at the corresponding position in the third argument
9247 * string. For example, translate("bar","abc","ABC") returns the string
9248 * BAr. If there is a character in the second argument string with no
9249 * character at a corresponding position in the third argument string
9250 * (because the second argument string is longer than the third argument
9251 * string), then occurrences of that character in the first argument
9252 * string are removed. For example, translate("--aaa--","abc-","ABC")
9253 * returns "AAA". If a character occurs more than once in second
9254 * argument string, then the first occurrence determines the replacement
9255 * character. If the third argument string is longer than the second
9256 * argument string, then excess characters are ignored.
9259 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9260 xmlXPathObjectPtr str;
9261 xmlXPathObjectPtr from;
9262 xmlXPathObjectPtr to;
9263 xmlBufferPtr target;
9266 const xmlChar *point;
9272 to = valuePop(ctxt);
9274 from = valuePop(ctxt);
9276 str = valuePop(ctxt);
9278 target = xmlBufferCreate();
9280 max = xmlUTF8Strlen(to->stringval);
9281 for (cptr = str->stringval; (ch=*cptr); ) {
9282 offset = xmlUTF8Strloc(from->stringval, cptr);
9285 point = xmlUTF8Strpos(to->stringval, offset);
9287 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9290 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9292 /* Step to next character in input */
9295 /* if not simple ascii, verify proper format */
9296 if ( (ch & 0xc0) != 0xc0 ) {
9297 xmlGenericError(xmlGenericErrorContext,
9298 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9301 /* then skip over remaining bytes for this char */
9302 while ( (ch <<= 1) & 0x80 )
9303 if ( (*cptr++ & 0xc0) != 0x80 ) {
9304 xmlGenericError(xmlGenericErrorContext,
9305 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9308 if (ch & 0x80) /* must have had error encountered */
9313 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9314 xmlBufferContent(target)));
9315 xmlBufferFree(target);
9316 xmlXPathReleaseObject(ctxt->context, str);
9317 xmlXPathReleaseObject(ctxt->context, from);
9318 xmlXPathReleaseObject(ctxt->context, to);
9322 * xmlXPathBooleanFunction:
9323 * @ctxt: the XPath Parser context
9324 * @nargs: the number of arguments
9326 * Implement the boolean() XPath function
9327 * boolean boolean(object)
9328 * The boolean function converts its argument to a boolean as follows:
9329 * - a number is true if and only if it is neither positive or
9330 * negative zero nor NaN
9331 * - a node-set is true if and only if it is non-empty
9332 * - a string is true if and only if its length is non-zero
9335 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9336 xmlXPathObjectPtr cur;
9339 cur = valuePop(ctxt);
9340 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9341 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9342 valuePush(ctxt, cur);
9346 * xmlXPathNotFunction:
9347 * @ctxt: the XPath Parser context
9348 * @nargs: the number of arguments
9350 * Implement the not() XPath function
9351 * boolean not(boolean)
9352 * The not function returns true if its argument is false,
9353 * and false otherwise.
9356 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9359 CHECK_TYPE(XPATH_BOOLEAN);
9360 ctxt->value->boolval = ! ctxt->value->boolval;
9364 * xmlXPathTrueFunction:
9365 * @ctxt: the XPath Parser context
9366 * @nargs: the number of arguments
9368 * Implement the true() XPath function
9372 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9374 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9378 * xmlXPathFalseFunction:
9379 * @ctxt: the XPath Parser context
9380 * @nargs: the number of arguments
9382 * Implement the false() XPath function
9386 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9388 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9392 * xmlXPathLangFunction:
9393 * @ctxt: the XPath Parser context
9394 * @nargs: the number of arguments
9396 * Implement the lang() XPath function
9397 * boolean lang(string)
9398 * The lang function returns true or false depending on whether the
9399 * language of the context node as specified by xml:lang attributes
9400 * is the same as or is a sublanguage of the language specified by
9401 * the argument string. The language of the context node is determined
9402 * by the value of the xml:lang attribute on the context node, or, if
9403 * the context node has no xml:lang attribute, by the value of the
9404 * xml:lang attribute on the nearest ancestor of the context node that
9405 * has an xml:lang attribute. If there is no such attribute, then lang
9406 * returns false. If there is such an attribute, then lang returns
9407 * true if the attribute value is equal to the argument ignoring case,
9408 * or if there is some suffix starting with - such that the attribute
9409 * value is equal to the argument ignoring that suffix of the attribute
9410 * value and ignoring case.
9413 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9414 xmlXPathObjectPtr val = NULL;
9415 const xmlChar *theLang = NULL;
9416 const xmlChar *lang;
9422 CHECK_TYPE(XPATH_STRING);
9423 val = valuePop(ctxt);
9424 lang = val->stringval;
9425 theLang = xmlNodeGetLang(ctxt->context->node);
9426 if ((theLang != NULL) && (lang != NULL)) {
9427 for (i = 0;lang[i] != 0;i++)
9428 if (toupper(lang[i]) != toupper(theLang[i]))
9430 if ((theLang[i] == 0) || (theLang[i] == '-'))
9434 if (theLang != NULL)
9435 xmlFree((void *)theLang);
9437 xmlXPathReleaseObject(ctxt->context, val);
9438 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9442 * xmlXPathNumberFunction:
9443 * @ctxt: the XPath Parser context
9444 * @nargs: the number of arguments
9446 * Implement the number() XPath function
9447 * number number(object?)
9450 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9451 xmlXPathObjectPtr cur;
9454 if (ctxt == NULL) return;
9456 if (ctxt->context->node == NULL) {
9457 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9459 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9461 res = xmlXPathStringEvalNumber(content);
9462 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9469 cur = valuePop(ctxt);
9470 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9474 * xmlXPathSumFunction:
9475 * @ctxt: the XPath Parser context
9476 * @nargs: the number of arguments
9478 * Implement the sum() XPath function
9479 * number sum(node-set)
9480 * The sum function returns the sum of the values of the nodes in
9481 * the argument node-set.
9484 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9485 xmlXPathObjectPtr cur;
9490 if ((ctxt->value == NULL) ||
9491 ((ctxt->value->type != XPATH_NODESET) &&
9492 (ctxt->value->type != XPATH_XSLT_TREE)))
9493 XP_ERROR(XPATH_INVALID_TYPE);
9494 cur = valuePop(ctxt);
9496 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9497 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9498 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9501 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9502 xmlXPathReleaseObject(ctxt->context, cur);
9506 * To assure working code on multiple platforms, we want to only depend
9507 * upon the characteristic truncation of converting a floating point value
9508 * to an integer. Unfortunately, because of the different storage sizes
9509 * of our internal floating point value (double) and integer (int), we
9510 * can't directly convert (see bug 301162). This macro is a messy
9513 #define XTRUNC(f, v) \
9514 f = fmod((v), INT_MAX); \
9515 f = (v) - (f) + (double)((int)(f));
9518 * xmlXPathFloorFunction:
9519 * @ctxt: the XPath Parser context
9520 * @nargs: the number of arguments
9522 * Implement the floor() XPath function
9523 * number floor(number)
9524 * The floor function returns the largest (closest to positive infinity)
9525 * number that is not greater than the argument and that is an integer.
9528 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9533 CHECK_TYPE(XPATH_NUMBER);
9535 XTRUNC(f, ctxt->value->floatval);
9536 if (f != ctxt->value->floatval) {
9537 if (ctxt->value->floatval > 0)
9538 ctxt->value->floatval = f;
9540 ctxt->value->floatval = f - 1;
9545 * xmlXPathCeilingFunction:
9546 * @ctxt: the XPath Parser context
9547 * @nargs: the number of arguments
9549 * Implement the ceiling() XPath function
9550 * number ceiling(number)
9551 * The ceiling function returns the smallest (closest to negative infinity)
9552 * number that is not less than the argument and that is an integer.
9555 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9560 CHECK_TYPE(XPATH_NUMBER);
9563 ctxt->value->floatval = ceil(ctxt->value->floatval);
9565 XTRUNC(f, ctxt->value->floatval);
9566 if (f != ctxt->value->floatval) {
9567 if (ctxt->value->floatval > 0)
9568 ctxt->value->floatval = f + 1;
9570 if (ctxt->value->floatval < 0 && f == 0)
9571 ctxt->value->floatval = xmlXPathNZERO;
9573 ctxt->value->floatval = f;
9581 * xmlXPathRoundFunction:
9582 * @ctxt: the XPath Parser context
9583 * @nargs: the number of arguments
9585 * Implement the round() XPath function
9586 * number round(number)
9587 * The round function returns the number that is closest to the
9588 * argument and that is an integer. If there are two such numbers,
9589 * then the one that is even is returned.
9592 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9597 CHECK_TYPE(XPATH_NUMBER);
9599 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9600 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9601 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9602 (ctxt->value->floatval == 0.0))
9605 XTRUNC(f, ctxt->value->floatval);
9606 if (ctxt->value->floatval < 0) {
9607 if (ctxt->value->floatval < f - 0.5)
9608 ctxt->value->floatval = f - 1;
9610 ctxt->value->floatval = f;
9611 if (ctxt->value->floatval == 0)
9612 ctxt->value->floatval = xmlXPathNZERO;
9614 if (ctxt->value->floatval < f + 0.5)
9615 ctxt->value->floatval = f;
9617 ctxt->value->floatval = f + 1;
9621 /************************************************************************
9625 ************************************************************************/
9628 * a few forward declarations since we use a recursive call based
9631 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9632 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9633 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9634 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9635 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9639 * xmlXPathCurrentChar:
9640 * @ctxt: the XPath parser context
9641 * @cur: pointer to the beginning of the char
9642 * @len: pointer to the length of the char read
9644 * The current char value, if using UTF-8 this may actually span multiple
9645 * bytes in the input buffer.
9647 * Returns the current char value and its length
9651 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9661 * We are supposed to handle UTF8, check it's valid
9662 * From rfc2044: encoding of the Unicode values on UTF-8:
9664 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9665 * 0000 0000-0000 007F 0xxxxxxx
9666 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9667 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9669 * Check for the 0x110000 limit too
9673 if ((cur[1] & 0xc0) != 0x80)
9674 goto encoding_error;
9675 if ((c & 0xe0) == 0xe0) {
9677 if ((cur[2] & 0xc0) != 0x80)
9678 goto encoding_error;
9679 if ((c & 0xf0) == 0xf0) {
9680 if (((c & 0xf8) != 0xf0) ||
9681 ((cur[3] & 0xc0) != 0x80))
9682 goto encoding_error;
9685 val = (cur[0] & 0x7) << 18;
9686 val |= (cur[1] & 0x3f) << 12;
9687 val |= (cur[2] & 0x3f) << 6;
9688 val |= cur[3] & 0x3f;
9692 val = (cur[0] & 0xf) << 12;
9693 val |= (cur[1] & 0x3f) << 6;
9694 val |= cur[2] & 0x3f;
9699 val = (cur[0] & 0x1f) << 6;
9700 val |= cur[1] & 0x3f;
9702 if (!IS_CHAR(val)) {
9703 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9713 * If we detect an UTF8 error that probably means that the
9714 * input encoding didn't get properly advertised in the
9715 * declaration header. Report the error and switch the encoding
9716 * to ISO-Latin-1 (if you don't like this policy, just declare the
9720 XP_ERROR0(XPATH_ENCODING_ERROR);
9724 * xmlXPathParseNCName:
9725 * @ctxt: the XPath Parser context
9727 * parse an XML namespace non qualified name.
9729 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9731 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9732 * CombiningChar | Extender
9734 * Returns the namespace name or NULL
9738 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9743 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9745 * Accelerator for simple ASCII names
9748 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9749 ((*in >= 0x41) && (*in <= 0x5A)) ||
9752 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9753 ((*in >= 0x41) && (*in <= 0x5A)) ||
9754 ((*in >= 0x30) && (*in <= 0x39)) ||
9755 (*in == '_') || (*in == '.') ||
9758 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9759 (*in == '[') || (*in == ']') || (*in == ':') ||
9760 (*in == '@') || (*in == '*')) {
9761 count = in - ctxt->cur;
9764 ret = xmlStrndup(ctxt->cur, count);
9769 return(xmlXPathParseNameComplex(ctxt, 0));
9774 * xmlXPathParseQName:
9775 * @ctxt: the XPath Parser context
9776 * @prefix: a xmlChar **
9778 * parse an XML qualified name
9780 * [NS 5] QName ::= (Prefix ':')? LocalPart
9782 * [NS 6] Prefix ::= NCName
9784 * [NS 7] LocalPart ::= NCName
9786 * Returns the function returns the local part, and prefix is updated
9787 * to get the Prefix if any.
9791 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9792 xmlChar *ret = NULL;
9795 ret = xmlXPathParseNCName(ctxt);
9796 if (ret && CUR == ':') {
9799 ret = xmlXPathParseNCName(ctxt);
9805 * xmlXPathParseName:
9806 * @ctxt: the XPath Parser context
9810 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9811 * CombiningChar | Extender
9813 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9815 * Returns the namespace name or NULL
9819 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9824 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9826 * Accelerator for simple ASCII names
9829 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9830 ((*in >= 0x41) && (*in <= 0x5A)) ||
9831 (*in == '_') || (*in == ':')) {
9833 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9834 ((*in >= 0x41) && (*in <= 0x5A)) ||
9835 ((*in >= 0x30) && (*in <= 0x39)) ||
9836 (*in == '_') || (*in == '-') ||
9837 (*in == ':') || (*in == '.'))
9839 if ((*in > 0) && (*in < 0x80)) {
9840 count = in - ctxt->cur;
9841 ret = xmlStrndup(ctxt->cur, count);
9846 return(xmlXPathParseNameComplex(ctxt, 1));
9850 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9851 xmlChar buf[XML_MAX_NAMELEN + 5];
9856 * Handler for more complex cases
9859 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9860 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9861 (c == '*') || /* accelerators */
9862 (!IS_LETTER(c) && (c != '_') &&
9863 ((qualified) && (c != ':')))) {
9867 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9868 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9869 (c == '.') || (c == '-') ||
9870 (c == '_') || ((qualified) && (c == ':')) ||
9871 (IS_COMBINING(c)) ||
9872 (IS_EXTENDER(c)))) {
9873 COPY_BUF(l,buf,len,c);
9876 if (len >= XML_MAX_NAMELEN) {
9878 * Okay someone managed to make a huge name, so he's ready to pay
9879 * for the processing speed.
9884 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9885 if (buffer == NULL) {
9886 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9888 memcpy(buffer, buf, len);
9889 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9890 (c == '.') || (c == '-') ||
9891 (c == '_') || ((qualified) && (c == ':')) ||
9892 (IS_COMBINING(c)) ||
9894 if (len + 10 > max) {
9896 buffer = (xmlChar *) xmlRealloc(buffer,
9897 max * sizeof(xmlChar));
9898 if (buffer == NULL) {
9899 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9902 COPY_BUF(l,buffer,len,c);
9912 return(xmlStrndup(buf, len));
9918 * These are used as divisors for the fractional part of a number.
9919 * Since the table includes 1.0 (representing '0' fractional digits),
9920 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9922 static double my_pow10[MAX_FRAC+1] = {
9923 1.0, 10.0, 100.0, 1000.0, 10000.0,
9924 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9925 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9927 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9928 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9932 * xmlXPathStringEvalNumber:
9933 * @str: A string to scan
9935 * [30a] Float ::= Number ('e' Digits?)?
9937 * [30] Number ::= Digits ('.' Digits?)?
9939 * [31] Digits ::= [0-9]+
9941 * Compile a Number in the string
9942 * In complement of the Number expression, this function also handles
9943 * negative values : '-' Number.
9945 * Returns the double value.
9948 xmlXPathStringEvalNumber(const xmlChar *str) {
9949 const xmlChar *cur = str;
9954 int is_exponent_negative = 0;
9956 unsigned long tmp = 0;
9959 if (cur == NULL) return(0);
9960 while (IS_BLANK_CH(*cur)) cur++;
9961 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
9962 return(xmlXPathNAN);
9971 * tmp/temp is a workaround against a gcc compiler bug
9972 * http://veillard.com/gcc.bug
9975 while ((*cur >= '0') && (*cur <= '9')) {
9980 temp = (double) tmp;
9985 while ((*cur >= '0') && (*cur <= '9')) {
9986 ret = ret * 10 + (*cur - '0');
9994 double fraction = 0;
9997 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9998 return(xmlXPathNAN);
10000 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10002 fraction = fraction * 10 + v;
10006 fraction /= my_pow10[frac];
10007 ret = ret + fraction;
10008 while ((*cur >= '0') && (*cur <= '9'))
10011 if ((*cur == 'e') || (*cur == 'E')) {
10014 is_exponent_negative = 1;
10016 } else if (*cur == '+') {
10019 while ((*cur >= '0') && (*cur <= '9')) {
10020 exponent = exponent * 10 + (*cur - '0');
10024 while (IS_BLANK_CH(*cur)) cur++;
10025 if (*cur != 0) return(xmlXPathNAN);
10026 if (isneg) ret = -ret;
10027 if (is_exponent_negative) exponent = -exponent;
10028 ret *= pow(10.0, (double)exponent);
10033 * xmlXPathCompNumber:
10034 * @ctxt: the XPath Parser context
10036 * [30] Number ::= Digits ('.' Digits?)?
10038 * [31] Digits ::= [0-9]+
10040 * Compile a Number, then push it on the stack
10044 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10050 int is_exponent_negative = 0;
10052 unsigned long tmp = 0;
10057 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10058 XP_ERROR(XPATH_NUMBER_ERROR);
10062 * tmp/temp is a workaround against a gcc compiler bug
10063 * http://veillard.com/gcc.bug
10066 while ((CUR >= '0') && (CUR <= '9')) {
10071 temp = (double) tmp;
10076 while ((CUR >= '0') && (CUR <= '9')) {
10077 ret = ret * 10 + (CUR - '0');
10084 double fraction = 0;
10087 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10088 XP_ERROR(XPATH_NUMBER_ERROR);
10090 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10092 fraction = fraction * 10 + v;
10096 fraction /= my_pow10[frac];
10097 ret = ret + fraction;
10098 while ((CUR >= '0') && (CUR <= '9'))
10101 if ((CUR == 'e') || (CUR == 'E')) {
10104 is_exponent_negative = 1;
10106 } else if (CUR == '+') {
10109 while ((CUR >= '0') && (CUR <= '9')) {
10110 exponent = exponent * 10 + (CUR - '0');
10113 if (is_exponent_negative)
10114 exponent = -exponent;
10115 ret *= pow(10.0, (double) exponent);
10117 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10118 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10122 * xmlXPathParseLiteral:
10123 * @ctxt: the XPath Parser context
10127 * [29] Literal ::= '"' [^"]* '"'
10130 * Returns the value found or NULL in case of error
10133 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10135 xmlChar *ret = NULL;
10140 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10142 if (!IS_CHAR_CH(CUR)) {
10143 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10145 ret = xmlStrndup(q, CUR_PTR - q);
10148 } else if (CUR == '\'') {
10151 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10153 if (!IS_CHAR_CH(CUR)) {
10154 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10156 ret = xmlStrndup(q, CUR_PTR - q);
10160 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10166 * xmlXPathCompLiteral:
10167 * @ctxt: the XPath Parser context
10169 * Parse a Literal and push it on the stack.
10171 * [29] Literal ::= '"' [^"]* '"'
10174 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10177 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10179 xmlChar *ret = NULL;
10184 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10186 if (!IS_CHAR_CH(CUR)) {
10187 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10189 ret = xmlStrndup(q, CUR_PTR - q);
10192 } else if (CUR == '\'') {
10195 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10197 if (!IS_CHAR_CH(CUR)) {
10198 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10200 ret = xmlStrndup(q, CUR_PTR - q);
10204 XP_ERROR(XPATH_START_LITERAL_ERROR);
10206 if (ret == NULL) return;
10207 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10208 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10213 * xmlXPathCompVariableReference:
10214 * @ctxt: the XPath Parser context
10216 * Parse a VariableReference, evaluate it and push it on the stack.
10218 * The variable bindings consist of a mapping from variable names
10219 * to variable values. The value of a variable is an object, which can be
10220 * of any of the types that are possible for the value of an expression,
10221 * and may also be of additional types not specified here.
10223 * Early evaluation is possible since:
10224 * The variable bindings [...] used to evaluate a subexpression are
10225 * always the same as those used to evaluate the containing expression.
10227 * [36] VariableReference ::= '$' QName
10230 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10236 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10239 name = xmlXPathParseQName(ctxt, &prefix);
10240 if (name == NULL) {
10241 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10243 ctxt->comp->last = -1;
10244 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10247 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10248 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10253 * xmlXPathIsNodeType:
10254 * @name: a name string
10256 * Is the name given a NodeType one.
10258 * [38] NodeType ::= 'comment'
10260 * | 'processing-instruction'
10263 * Returns 1 if true 0 otherwise
10266 xmlXPathIsNodeType(const xmlChar *name) {
10270 if (xmlStrEqual(name, BAD_CAST "node"))
10272 if (xmlStrEqual(name, BAD_CAST "text"))
10274 if (xmlStrEqual(name, BAD_CAST "comment"))
10276 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10282 * xmlXPathCompFunctionCall:
10283 * @ctxt: the XPath Parser context
10285 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10286 * [17] Argument ::= Expr
10288 * Compile a function call, the evaluation of all arguments are
10289 * pushed on the stack
10292 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10298 name = xmlXPathParseQName(ctxt, &prefix);
10299 if (name == NULL) {
10301 XP_ERROR(XPATH_EXPR_ERROR);
10305 if (prefix == NULL)
10306 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10309 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10314 XP_ERROR(XPATH_EXPR_ERROR);
10320 * Optimization for count(): we don't need the node-set to be sorted.
10322 if ((prefix == NULL) && (name[0] == 'c') &&
10323 xmlStrEqual(name, BAD_CAST "count"))
10327 ctxt->comp->last = -1;
10330 int op1 = ctxt->comp->last;
10331 ctxt->comp->last = -1;
10332 xmlXPathCompileExpr(ctxt, sort);
10333 if (ctxt->error != XPATH_EXPRESSION_OK) {
10338 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10340 if (CUR == ')') break;
10342 XP_ERROR(XPATH_EXPR_ERROR);
10348 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10355 * xmlXPathCompPrimaryExpr:
10356 * @ctxt: the XPath Parser context
10358 * [15] PrimaryExpr ::= VariableReference
10364 * Compile a primary expression.
10367 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10369 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10370 else if (CUR == '(') {
10373 xmlXPathCompileExpr(ctxt, 1);
10376 XP_ERROR(XPATH_EXPR_ERROR);
10380 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10381 xmlXPathCompNumber(ctxt);
10382 } else if ((CUR == '\'') || (CUR == '"')) {
10383 xmlXPathCompLiteral(ctxt);
10385 xmlXPathCompFunctionCall(ctxt);
10391 * xmlXPathCompFilterExpr:
10392 * @ctxt: the XPath Parser context
10394 * [20] FilterExpr ::= PrimaryExpr
10395 * | FilterExpr Predicate
10397 * Compile a filter expression.
10398 * Square brackets are used to filter expressions in the same way that
10399 * they are used in location paths. It is an error if the expression to
10400 * be filtered does not evaluate to a node-set. The context node list
10401 * used for evaluating the expression in square brackets is the node-set
10402 * to be filtered listed in document order.
10406 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10407 xmlXPathCompPrimaryExpr(ctxt);
10411 while (CUR == '[') {
10412 xmlXPathCompPredicate(ctxt, 1);
10420 * xmlXPathScanName:
10421 * @ctxt: the XPath Parser context
10423 * Trickery: parse an XML name but without consuming the input flow
10424 * Needed to avoid insanity in the parser state.
10426 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10427 * CombiningChar | Extender
10429 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10431 * [6] Names ::= Name (S Name)*
10433 * Returns the Name parsed or NULL
10437 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10440 const xmlChar *cur;
10446 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10447 (!IS_LETTER(c) && (c != '_') &&
10452 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10453 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10454 (c == '.') || (c == '-') ||
10455 (c == '_') || (c == ':') ||
10456 (IS_COMBINING(c)) ||
10457 (IS_EXTENDER(c)))) {
10462 ret = xmlStrndup(cur, ctxt->cur - cur);
10468 * xmlXPathCompPathExpr:
10469 * @ctxt: the XPath Parser context
10471 * [19] PathExpr ::= LocationPath
10473 * | FilterExpr '/' RelativeLocationPath
10474 * | FilterExpr '//' RelativeLocationPath
10476 * Compile a path expression.
10477 * The / operator and // operators combine an arbitrary expression
10478 * and a relative location path. It is an error if the expression
10479 * does not evaluate to a node-set.
10480 * The / operator does composition in the same way as when / is
10481 * used in a location path. As in location paths, // is short for
10482 * /descendant-or-self::node()/.
10486 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10487 int lc = 1; /* Should we branch to LocationPath ? */
10488 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10491 if ((CUR == '$') || (CUR == '(') ||
10492 (IS_ASCII_DIGIT(CUR)) ||
10493 (CUR == '\'') || (CUR == '"') ||
10494 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10496 } else if (CUR == '*') {
10497 /* relative or absolute location path */
10499 } else if (CUR == '/') {
10500 /* relative or absolute location path */
10502 } else if (CUR == '@') {
10503 /* relative abbreviated attribute location path */
10505 } else if (CUR == '.') {
10506 /* relative abbreviated attribute location path */
10510 * Problem is finding if we have a name here whether it's:
10512 * - a function call in which case it's followed by '('
10513 * - an axis in which case it's followed by ':'
10515 * We do an a priori analysis here rather than having to
10516 * maintain parsed token content through the recursive function
10517 * calls. This looks uglier but makes the code easier to
10518 * read/write/debug.
10521 name = xmlXPathScanName(ctxt);
10522 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10524 xmlGenericError(xmlGenericErrorContext,
10525 "PathExpr: Axis\n");
10529 } else if (name != NULL) {
10530 int len =xmlStrlen(name);
10533 while (NXT(len) != 0) {
10534 if (NXT(len) == '/') {
10537 xmlGenericError(xmlGenericErrorContext,
10538 "PathExpr: AbbrRelLocation\n");
10542 } else if (IS_BLANK_CH(NXT(len))) {
10543 /* ignore blanks */
10545 } else if (NXT(len) == ':') {
10547 xmlGenericError(xmlGenericErrorContext,
10548 "PathExpr: AbbrRelLocation\n");
10552 } else if ((NXT(len) == '(')) {
10553 /* Note Type or Function */
10554 if (xmlXPathIsNodeType(name)) {
10556 xmlGenericError(xmlGenericErrorContext,
10557 "PathExpr: Type search\n");
10562 xmlGenericError(xmlGenericErrorContext,
10563 "PathExpr: function call\n");
10568 } else if ((NXT(len) == '[')) {
10571 xmlGenericError(xmlGenericErrorContext,
10572 "PathExpr: AbbrRelLocation\n");
10576 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10577 (NXT(len) == '=')) {
10586 if (NXT(len) == 0) {
10588 xmlGenericError(xmlGenericErrorContext,
10589 "PathExpr: AbbrRelLocation\n");
10596 /* make sure all cases are covered explicitly */
10597 XP_ERROR(XPATH_EXPR_ERROR);
10603 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10605 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10607 xmlXPathCompLocationPath(ctxt);
10609 xmlXPathCompFilterExpr(ctxt);
10611 if ((CUR == '/') && (NXT(1) == '/')) {
10615 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10616 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10617 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10619 xmlXPathCompRelativeLocationPath(ctxt);
10620 } else if (CUR == '/') {
10621 xmlXPathCompRelativeLocationPath(ctxt);
10628 * xmlXPathCompUnionExpr:
10629 * @ctxt: the XPath Parser context
10631 * [18] UnionExpr ::= PathExpr
10632 * | UnionExpr '|' PathExpr
10634 * Compile an union expression.
10638 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10639 xmlXPathCompPathExpr(ctxt);
10642 while (CUR == '|') {
10643 int op1 = ctxt->comp->last;
10644 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10648 xmlXPathCompPathExpr(ctxt);
10650 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10657 * xmlXPathCompUnaryExpr:
10658 * @ctxt: the XPath Parser context
10660 * [27] UnaryExpr ::= UnionExpr
10663 * Compile an unary expression.
10667 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10672 while (CUR == '-') {
10679 xmlXPathCompUnionExpr(ctxt);
10683 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10685 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10690 * xmlXPathCompMultiplicativeExpr:
10691 * @ctxt: the XPath Parser context
10693 * [26] MultiplicativeExpr ::= UnaryExpr
10694 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10695 * | MultiplicativeExpr 'div' UnaryExpr
10696 * | MultiplicativeExpr 'mod' UnaryExpr
10697 * [34] MultiplyOperator ::= '*'
10699 * Compile an Additive expression.
10703 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10704 xmlXPathCompUnaryExpr(ctxt);
10707 while ((CUR == '*') ||
10708 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10709 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10711 int op1 = ctxt->comp->last;
10716 } else if (CUR == 'd') {
10719 } else if (CUR == 'm') {
10724 xmlXPathCompUnaryExpr(ctxt);
10726 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10732 * xmlXPathCompAdditiveExpr:
10733 * @ctxt: the XPath Parser context
10735 * [25] AdditiveExpr ::= MultiplicativeExpr
10736 * | AdditiveExpr '+' MultiplicativeExpr
10737 * | AdditiveExpr '-' MultiplicativeExpr
10739 * Compile an Additive expression.
10743 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10745 xmlXPathCompMultiplicativeExpr(ctxt);
10748 while ((CUR == '+') || (CUR == '-')) {
10750 int op1 = ctxt->comp->last;
10752 if (CUR == '+') plus = 1;
10756 xmlXPathCompMultiplicativeExpr(ctxt);
10758 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10764 * xmlXPathCompRelationalExpr:
10765 * @ctxt: the XPath Parser context
10767 * [24] RelationalExpr ::= AdditiveExpr
10768 * | RelationalExpr '<' AdditiveExpr
10769 * | RelationalExpr '>' AdditiveExpr
10770 * | RelationalExpr '<=' AdditiveExpr
10771 * | RelationalExpr '>=' AdditiveExpr
10773 * A <= B > C is allowed ? Answer from James, yes with
10774 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10775 * which is basically what got implemented.
10777 * Compile a Relational expression, then push the result
10782 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10783 xmlXPathCompAdditiveExpr(ctxt);
10786 while ((CUR == '<') ||
10788 ((CUR == '<') && (NXT(1) == '=')) ||
10789 ((CUR == '>') && (NXT(1) == '='))) {
10791 int op1 = ctxt->comp->last;
10793 if (CUR == '<') inf = 1;
10795 if (NXT(1) == '=') strict = 0;
10800 xmlXPathCompAdditiveExpr(ctxt);
10802 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10808 * xmlXPathCompEqualityExpr:
10809 * @ctxt: the XPath Parser context
10811 * [23] EqualityExpr ::= RelationalExpr
10812 * | EqualityExpr '=' RelationalExpr
10813 * | EqualityExpr '!=' RelationalExpr
10815 * A != B != C is allowed ? Answer from James, yes with
10816 * (RelationalExpr = RelationalExpr) = RelationalExpr
10817 * (RelationalExpr != RelationalExpr) != RelationalExpr
10818 * which is basically what got implemented.
10820 * Compile an Equality expression.
10824 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10825 xmlXPathCompRelationalExpr(ctxt);
10828 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10830 int op1 = ctxt->comp->last;
10832 if (CUR == '=') eq = 1;
10837 xmlXPathCompRelationalExpr(ctxt);
10839 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10845 * xmlXPathCompAndExpr:
10846 * @ctxt: the XPath Parser context
10848 * [22] AndExpr ::= EqualityExpr
10849 * | AndExpr 'and' EqualityExpr
10851 * Compile an AND expression.
10855 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10856 xmlXPathCompEqualityExpr(ctxt);
10859 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10860 int op1 = ctxt->comp->last;
10863 xmlXPathCompEqualityExpr(ctxt);
10865 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10871 * xmlXPathCompileExpr:
10872 * @ctxt: the XPath Parser context
10874 * [14] Expr ::= OrExpr
10875 * [21] OrExpr ::= AndExpr
10876 * | OrExpr 'or' AndExpr
10878 * Parse and compile an expression
10881 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10882 xmlXPathCompAndExpr(ctxt);
10885 while ((CUR == 'o') && (NXT(1) == 'r')) {
10886 int op1 = ctxt->comp->last;
10889 xmlXPathCompAndExpr(ctxt);
10891 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10894 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10895 /* more ops could be optimized too */
10897 * This is the main place to eliminate sorting for
10898 * operations which don't require a sorted node-set.
10901 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10906 * xmlXPathCompPredicate:
10907 * @ctxt: the XPath Parser context
10908 * @filter: act as a filter
10910 * [8] Predicate ::= '[' PredicateExpr ']'
10911 * [9] PredicateExpr ::= Expr
10913 * Compile a predicate expression
10916 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10917 int op1 = ctxt->comp->last;
10921 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10926 ctxt->comp->last = -1;
10928 * This call to xmlXPathCompileExpr() will deactivate sorting
10929 * of the predicate result.
10930 * TODO: Sorting is still activated for filters, since I'm not
10931 * sure if needed. Normally sorting should not be needed, since
10932 * a filter can only diminish the number of items in a sequence,
10933 * but won't change its order; so if the initial sequence is sorted,
10934 * subsequent sorting is not needed.
10937 xmlXPathCompileExpr(ctxt, 0);
10939 xmlXPathCompileExpr(ctxt, 1);
10943 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10947 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10949 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10956 * xmlXPathCompNodeTest:
10957 * @ctxt: the XPath Parser context
10958 * @test: pointer to a xmlXPathTestVal
10959 * @type: pointer to a xmlXPathTypeVal
10960 * @prefix: placeholder for a possible name prefix
10962 * [7] NodeTest ::= NameTest
10963 * | NodeType '(' ')'
10964 * | 'processing-instruction' '(' Literal ')'
10966 * [37] NameTest ::= '*'
10969 * [38] NodeType ::= 'comment'
10971 * | 'processing-instruction'
10974 * Returns the name found and updates @test, @type and @prefix appropriately
10977 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10978 xmlXPathTypeVal *type, const xmlChar **prefix,
10982 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10986 *type = (xmlXPathTypeVal) 0;
10987 *test = (xmlXPathTestVal) 0;
10991 if ((name == NULL) && (CUR == '*')) {
10996 *test = NODE_TEST_ALL;
11001 name = xmlXPathParseNCName(ctxt);
11002 if (name == NULL) {
11003 XP_ERRORNULL(XPATH_EXPR_ERROR);
11006 blanks = IS_BLANK_CH(CUR);
11011 * NodeType or PI search
11013 if (xmlStrEqual(name, BAD_CAST "comment"))
11014 *type = NODE_TYPE_COMMENT;
11015 else if (xmlStrEqual(name, BAD_CAST "node"))
11016 *type = NODE_TYPE_NODE;
11017 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11018 *type = NODE_TYPE_PI;
11019 else if (xmlStrEqual(name, BAD_CAST "text"))
11020 *type = NODE_TYPE_TEXT;
11024 XP_ERRORNULL(XPATH_EXPR_ERROR);
11027 *test = NODE_TEST_TYPE;
11030 if (*type == NODE_TYPE_PI) {
11032 * Specific case: search a PI by name.
11038 name = xmlXPathParseLiteral(ctxt);
11040 *test = NODE_TEST_PI;
11047 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11052 *test = NODE_TEST_NAME;
11053 if ((!blanks) && (CUR == ':')) {
11057 * Since currently the parser context don't have a
11058 * namespace list associated:
11059 * The namespace name for this prefix can be computed
11060 * only at evaluation time. The compilation is done
11061 * outside of any context.
11064 *prefix = xmlXPathNsLookup(ctxt->context, name);
11067 if (*prefix == NULL) {
11068 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11079 *test = NODE_TEST_ALL;
11083 name = xmlXPathParseNCName(ctxt);
11084 if (name == NULL) {
11085 XP_ERRORNULL(XPATH_EXPR_ERROR);
11092 * xmlXPathIsAxisName:
11093 * @name: a preparsed name token
11095 * [6] AxisName ::= 'ancestor'
11096 * | 'ancestor-or-self'
11100 * | 'descendant-or-self'
11102 * | 'following-sibling'
11106 * | 'preceding-sibling'
11109 * Returns the axis or 0
11111 static xmlXPathAxisVal
11112 xmlXPathIsAxisName(const xmlChar *name) {
11113 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11116 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11117 ret = AXIS_ANCESTOR;
11118 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11119 ret = AXIS_ANCESTOR_OR_SELF;
11120 if (xmlStrEqual(name, BAD_CAST "attribute"))
11121 ret = AXIS_ATTRIBUTE;
11124 if (xmlStrEqual(name, BAD_CAST "child"))
11128 if (xmlStrEqual(name, BAD_CAST "descendant"))
11129 ret = AXIS_DESCENDANT;
11130 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11131 ret = AXIS_DESCENDANT_OR_SELF;
11134 if (xmlStrEqual(name, BAD_CAST "following"))
11135 ret = AXIS_FOLLOWING;
11136 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11137 ret = AXIS_FOLLOWING_SIBLING;
11140 if (xmlStrEqual(name, BAD_CAST "namespace"))
11141 ret = AXIS_NAMESPACE;
11144 if (xmlStrEqual(name, BAD_CAST "parent"))
11146 if (xmlStrEqual(name, BAD_CAST "preceding"))
11147 ret = AXIS_PRECEDING;
11148 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11149 ret = AXIS_PRECEDING_SIBLING;
11152 if (xmlStrEqual(name, BAD_CAST "self"))
11160 * xmlXPathCompStep:
11161 * @ctxt: the XPath Parser context
11163 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11164 * | AbbreviatedStep
11166 * [12] AbbreviatedStep ::= '.' | '..'
11168 * [5] AxisSpecifier ::= AxisName '::'
11169 * | AbbreviatedAxisSpecifier
11171 * [13] AbbreviatedAxisSpecifier ::= '@'?
11173 * Modified for XPtr range support as:
11175 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11176 * | AbbreviatedStep
11177 * | 'range-to' '(' Expr ')' Predicate*
11179 * Compile one step in a Location Path
11180 * A location step of . is short for self::node(). This is
11181 * particularly useful in conjunction with //. For example, the
11182 * location path .//para is short for
11183 * self::node()/descendant-or-self::node()/child::para
11184 * and so will select all para descendant elements of the context
11186 * Similarly, a location step of .. is short for parent::node().
11187 * For example, ../title is short for parent::node()/child::title
11188 * and so will select the title children of the parent of the context
11192 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11193 #ifdef LIBXML_XPTR_ENABLED
11199 if ((CUR == '.') && (NXT(1) == '.')) {
11202 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11203 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11204 } else if (CUR == '.') {
11208 xmlChar *name = NULL;
11209 const xmlChar *prefix = NULL;
11210 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11211 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11212 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11216 * The modification needed for XPointer change to the production
11218 #ifdef LIBXML_XPTR_ENABLED
11220 name = xmlXPathParseNCName(ctxt);
11221 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11222 op2 = ctxt->comp->last;
11226 XP_ERROR(XPATH_EXPR_ERROR);
11231 xmlXPathCompileExpr(ctxt, 1);
11232 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11237 XP_ERROR(XPATH_EXPR_ERROR);
11241 goto eval_predicates;
11249 name = xmlXPathParseNCName(ctxt);
11250 if (name != NULL) {
11251 axis = xmlXPathIsAxisName(name);
11254 if ((CUR == ':') && (NXT(1) == ':')) {
11259 /* an element name can conflict with an axis one :-\ */
11265 } else if (CUR == '@') {
11267 axis = AXIS_ATTRIBUTE;
11273 if (ctxt->error != XPATH_EXPRESSION_OK) {
11278 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11282 if ((prefix != NULL) && (ctxt->context != NULL) &&
11283 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11284 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11285 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11289 xmlGenericError(xmlGenericErrorContext,
11290 "Basis : computing new set\n");
11294 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11295 if (ctxt->value == NULL)
11296 xmlGenericError(xmlGenericErrorContext, "no value\n");
11297 else if (ctxt->value->nodesetval == NULL)
11298 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11300 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11303 #ifdef LIBXML_XPTR_ENABLED
11306 op1 = ctxt->comp->last;
11307 ctxt->comp->last = -1;
11310 while (CUR == '[') {
11311 xmlXPathCompPredicate(ctxt, 0);
11314 #ifdef LIBXML_XPTR_ENABLED
11316 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11319 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11320 test, type, (void *)prefix, (void *)name);
11324 xmlGenericError(xmlGenericErrorContext, "Step : ");
11325 if (ctxt->value == NULL)
11326 xmlGenericError(xmlGenericErrorContext, "no value\n");
11327 else if (ctxt->value->nodesetval == NULL)
11328 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11330 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11331 ctxt->value->nodesetval);
11336 * xmlXPathCompRelativeLocationPath:
11337 * @ctxt: the XPath Parser context
11339 * [3] RelativeLocationPath ::= Step
11340 * | RelativeLocationPath '/' Step
11341 * | AbbreviatedRelativeLocationPath
11342 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11344 * Compile a relative location path.
11347 xmlXPathCompRelativeLocationPath
11348 (xmlXPathParserContextPtr ctxt) {
11350 if ((CUR == '/') && (NXT(1) == '/')) {
11353 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11354 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11355 } else if (CUR == '/') {
11359 xmlXPathCompStep(ctxt);
11362 while (CUR == '/') {
11363 if ((CUR == '/') && (NXT(1) == '/')) {
11366 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11367 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11368 xmlXPathCompStep(ctxt);
11369 } else if (CUR == '/') {
11372 xmlXPathCompStep(ctxt);
11379 * xmlXPathCompLocationPath:
11380 * @ctxt: the XPath Parser context
11382 * [1] LocationPath ::= RelativeLocationPath
11383 * | AbsoluteLocationPath
11384 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11385 * | AbbreviatedAbsoluteLocationPath
11386 * [10] AbbreviatedAbsoluteLocationPath ::=
11387 * '//' RelativeLocationPath
11389 * Compile a location path
11391 * // is short for /descendant-or-self::node()/. For example,
11392 * //para is short for /descendant-or-self::node()/child::para and
11393 * so will select any para element in the document (even a para element
11394 * that is a document element will be selected by //para since the
11395 * document element node is a child of the root node); div//para is
11396 * short for div/descendant-or-self::node()/child::para and so will
11397 * select all para descendants of div children.
11400 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11403 xmlXPathCompRelativeLocationPath(ctxt);
11405 while (CUR == '/') {
11406 if ((CUR == '/') && (NXT(1) == '/')) {
11409 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11410 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11411 xmlXPathCompRelativeLocationPath(ctxt);
11412 } else if (CUR == '/') {
11416 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11417 (CUR == '@') || (CUR == '*')))
11418 xmlXPathCompRelativeLocationPath(ctxt);
11425 /************************************************************************
11427 * XPath precompiled expression evaluation *
11429 ************************************************************************/
11432 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11436 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11439 xmlGenericError(xmlGenericErrorContext, "new step : ");
11440 switch (op->value) {
11441 case AXIS_ANCESTOR:
11442 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11444 case AXIS_ANCESTOR_OR_SELF:
11445 xmlGenericError(xmlGenericErrorContext,
11446 "axis 'ancestors-or-self' ");
11448 case AXIS_ATTRIBUTE:
11449 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11452 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11454 case AXIS_DESCENDANT:
11455 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11457 case AXIS_DESCENDANT_OR_SELF:
11458 xmlGenericError(xmlGenericErrorContext,
11459 "axis 'descendant-or-self' ");
11461 case AXIS_FOLLOWING:
11462 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11464 case AXIS_FOLLOWING_SIBLING:
11465 xmlGenericError(xmlGenericErrorContext,
11466 "axis 'following-siblings' ");
11468 case AXIS_NAMESPACE:
11469 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11472 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11474 case AXIS_PRECEDING:
11475 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11477 case AXIS_PRECEDING_SIBLING:
11478 xmlGenericError(xmlGenericErrorContext,
11479 "axis 'preceding-sibling' ");
11482 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11485 xmlGenericError(xmlGenericErrorContext,
11486 " context contains %d nodes\n", nbNodes);
11487 switch (op->value2) {
11488 case NODE_TEST_NONE:
11489 xmlGenericError(xmlGenericErrorContext,
11490 " searching for none !!!\n");
11492 case NODE_TEST_TYPE:
11493 xmlGenericError(xmlGenericErrorContext,
11494 " searching for type %d\n", op->value3);
11497 xmlGenericError(xmlGenericErrorContext,
11498 " searching for PI !!!\n");
11500 case NODE_TEST_ALL:
11501 xmlGenericError(xmlGenericErrorContext,
11502 " searching for *\n");
11505 xmlGenericError(xmlGenericErrorContext,
11506 " searching for namespace %s\n",
11509 case NODE_TEST_NAME:
11510 xmlGenericError(xmlGenericErrorContext,
11511 " searching for name %s\n", op->value5);
11513 xmlGenericError(xmlGenericErrorContext,
11514 " with namespace %s\n", op->value4);
11517 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11519 #endif /* DEBUG_STEP */
11522 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11523 xmlXPathStepOpPtr op,
11528 if (op->ch1 != -1) {
11529 xmlXPathCompExprPtr comp = ctxt->comp;
11531 * Process inner predicates first.
11533 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11535 * TODO: raise an internal error.
11538 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11539 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11541 if (contextSize <= 0)
11544 if (op->ch2 != -1) {
11545 xmlXPathContextPtr xpctxt = ctxt->context;
11546 xmlNodePtr contextNode, oldContextNode;
11547 xmlDocPtr oldContextDoc;
11548 int i, res, contextPos = 0, newContextSize;
11549 xmlXPathStepOpPtr exprOp;
11550 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11552 #ifdef LIBXML_XPTR_ENABLED
11554 * URGENT TODO: Check the following:
11555 * We don't expect location sets if evaluating prediates, right?
11556 * Only filters should expect location sets, right?
11561 * "For each node in the node-set to be filtered, the
11562 * PredicateExpr is evaluated with that node as the
11563 * context node, with the number of nodes in the
11564 * node-set as the context size, and with the proximity
11565 * position of the node in the node-set with respect to
11566 * the axis as the context position;"
11567 * @oldset is the node-set" to be filtered.
11570 * "only predicates change the context position and
11571 * context size (see [2.4 Predicates])."
11573 * node-set context pos
11577 * After applying predicate [position() > 1] :
11578 * node-set context pos
11582 oldContextNode = xpctxt->node;
11583 oldContextDoc = xpctxt->doc;
11585 * Get the expression of this predicate.
11587 exprOp = &ctxt->comp->steps[op->ch2];
11588 newContextSize = 0;
11589 for (i = 0; i < set->nodeNr; i++) {
11590 if (set->nodeTab[i] == NULL)
11593 contextNode = set->nodeTab[i];
11594 xpctxt->node = contextNode;
11595 xpctxt->contextSize = contextSize;
11596 xpctxt->proximityPosition = ++contextPos;
11599 * Also set the xpath document in case things like
11600 * key() are evaluated in the predicate.
11602 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11603 (contextNode->doc != NULL))
11604 xpctxt->doc = contextNode->doc;
11606 * Evaluate the predicate expression with 1 context node
11607 * at a time; this node is packaged into a node set; this
11608 * node set is handed over to the evaluation mechanism.
11610 if (contextObj == NULL)
11611 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11613 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11616 valuePush(ctxt, contextObj);
11618 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11620 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11621 xmlXPathNodeSetClear(set, hasNsNodes);
11622 newContextSize = 0;
11623 goto evaluation_exit;
11630 * Remove the entry from the initial node set.
11632 set->nodeTab[i] = NULL;
11633 if (contextNode->type == XML_NAMESPACE_DECL)
11634 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11636 if (ctxt->value == contextObj) {
11638 * Don't free the temporary XPath object holding the
11639 * context node, in order to avoid massive recreation
11640 * inside this loop.
11643 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11646 * TODO: The object was lost in the evaluation machinery.
11647 * Can this happen? Maybe in internal-error cases.
11653 if (contextObj != NULL) {
11654 if (ctxt->value == contextObj)
11656 xmlXPathReleaseObject(xpctxt, contextObj);
11659 if (exprRes != NULL)
11660 xmlXPathReleaseObject(ctxt->context, exprRes);
11662 * Reset/invalidate the context.
11664 xpctxt->node = oldContextNode;
11665 xpctxt->doc = oldContextDoc;
11666 xpctxt->contextSize = -1;
11667 xpctxt->proximityPosition = -1;
11668 return(newContextSize);
11670 return(contextSize);
11674 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11675 xmlXPathStepOpPtr op,
11682 if (op->ch1 != -1) {
11683 xmlXPathCompExprPtr comp = ctxt->comp;
11684 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11686 * TODO: raise an internal error.
11689 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11690 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11692 if (contextSize <= 0)
11696 * Check if the node set contains a sufficient number of nodes for
11697 * the requested range.
11699 if (contextSize < minPos) {
11700 xmlXPathNodeSetClear(set, hasNsNodes);
11703 if (op->ch2 == -1) {
11705 * TODO: Can this ever happen?
11707 return (contextSize);
11709 xmlDocPtr oldContextDoc;
11710 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11711 xmlXPathStepOpPtr exprOp;
11712 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11713 xmlNodePtr oldContextNode, contextNode = NULL;
11714 xmlXPathContextPtr xpctxt = ctxt->context;
11716 #ifdef LIBXML_XPTR_ENABLED
11718 * URGENT TODO: Check the following:
11719 * We don't expect location sets if evaluating prediates, right?
11720 * Only filters should expect location sets, right?
11722 #endif /* LIBXML_XPTR_ENABLED */
11725 * Save old context.
11727 oldContextNode = xpctxt->node;
11728 oldContextDoc = xpctxt->doc;
11730 * Get the expression of this predicate.
11732 exprOp = &ctxt->comp->steps[op->ch2];
11733 for (i = 0; i < set->nodeNr; i++) {
11734 if (set->nodeTab[i] == NULL)
11737 contextNode = set->nodeTab[i];
11738 xpctxt->node = contextNode;
11739 xpctxt->contextSize = contextSize;
11740 xpctxt->proximityPosition = ++contextPos;
11743 * Initialize the new set.
11744 * Also set the xpath document in case things like
11745 * key() evaluation are attempted on the predicate
11747 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11748 (contextNode->doc != NULL))
11749 xpctxt->doc = contextNode->doc;
11751 * Evaluate the predicate expression with 1 context node
11752 * at a time; this node is packaged into a node set; this
11753 * node set is handed over to the evaluation mechanism.
11755 if (contextObj == NULL)
11756 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11758 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11761 valuePush(ctxt, contextObj);
11762 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11764 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11765 xmlXPathObjectPtr tmp;
11766 /* pop the result */
11767 tmp = valuePop(ctxt);
11768 xmlXPathReleaseObject(xpctxt, tmp);
11769 /* then pop off contextObj, which will be freed later */
11771 goto evaluation_error;
11777 if (res && (pos >= minPos) && (pos <= maxPos)) {
11779 * Fits in the requested range.
11782 if (minPos == maxPos) {
11784 * Only 1 node was requested.
11786 if (contextNode->type == XML_NAMESPACE_DECL) {
11788 * As always: take care of those nasty
11791 set->nodeTab[i] = NULL;
11793 xmlXPathNodeSetClear(set, hasNsNodes);
11795 set->nodeTab[0] = contextNode;
11796 goto evaluation_exit;
11798 if (pos == maxPos) {
11802 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11803 goto evaluation_exit;
11807 * Remove the entry from the initial node set.
11809 set->nodeTab[i] = NULL;
11810 if (contextNode->type == XML_NAMESPACE_DECL)
11811 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11813 if (exprRes != NULL) {
11814 xmlXPathReleaseObject(ctxt->context, exprRes);
11817 if (ctxt->value == contextObj) {
11819 * Don't free the temporary XPath object holding the
11820 * context node, in order to avoid massive recreation
11821 * inside this loop.
11824 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11827 * The object was lost in the evaluation machinery.
11828 * Can this happen? Maybe in case of internal-errors.
11833 goto evaluation_exit;
11836 xmlXPathNodeSetClear(set, hasNsNodes);
11837 newContextSize = 0;
11840 if (contextObj != NULL) {
11841 if (ctxt->value == contextObj)
11843 xmlXPathReleaseObject(xpctxt, contextObj);
11845 if (exprRes != NULL)
11846 xmlXPathReleaseObject(ctxt->context, exprRes);
11848 * Reset/invalidate the context.
11850 xpctxt->node = oldContextNode;
11851 xpctxt->doc = oldContextDoc;
11852 xpctxt->contextSize = -1;
11853 xpctxt->proximityPosition = -1;
11854 return(newContextSize);
11856 return(contextSize);
11860 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11861 xmlXPathStepOpPtr op,
11865 xmlXPathStepOpPtr exprOp;
11868 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11872 * If not -1, then ch1 will point to:
11873 * 1) For predicates (XPATH_OP_PREDICATE):
11874 * - an inner predicate operator
11875 * 2) For filters (XPATH_OP_FILTER):
11876 * - an inner filter operater OR
11877 * - an expression selecting the node set.
11878 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11880 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11883 if (op->ch2 != -1) {
11884 exprOp = &ctxt->comp->steps[op->ch2];
11888 if ((exprOp != NULL) &&
11889 (exprOp->op == XPATH_OP_VALUE) &&
11890 (exprOp->value4 != NULL) &&
11891 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11894 * We have a "[n]" predicate here.
11895 * TODO: Unfortunately this simplistic test here is not
11896 * able to detect a position() predicate in compound
11897 * expressions like "[@attr = 'a" and position() = 1],
11898 * and even not the usage of position() in
11899 * "[position() = 1]"; thus - obviously - a position-range,
11900 * like it "[position() < 5]", is also not detected.
11901 * Maybe we could rewrite the AST to ease the optimization.
11903 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11905 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11915 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11916 xmlXPathStepOpPtr op,
11917 xmlNodePtr * first, xmlNodePtr * last,
11921 #define XP_TEST_HIT \
11922 if (hasAxisRange != 0) { \
11923 if (++pos == maxPos) { \
11924 addNode(seq, cur); \
11925 goto axis_range_end; } \
11927 addNode(seq, cur); \
11928 if (breakOnFirstHit) goto first_hit; }
11930 #define XP_TEST_HIT_NS \
11931 if (hasAxisRange != 0) { \
11932 if (++pos == maxPos) { \
11934 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11935 goto axis_range_end; } \
11938 xmlXPathNodeSetAddNs(seq, \
11939 xpctxt->node, (xmlNsPtr) cur); \
11940 if (breakOnFirstHit) goto first_hit; }
11942 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11943 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11944 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11945 const xmlChar *prefix = op->value4;
11946 const xmlChar *name = op->value5;
11947 const xmlChar *URI = NULL;
11950 int nbMatches = 0, prevMatches = 0;
11952 int total = 0, hasNsNodes = 0;
11953 /* The popped object holding the context nodes */
11954 xmlXPathObjectPtr obj;
11955 /* The set of context nodes for the node tests */
11956 xmlNodeSetPtr contextSeq;
11958 xmlNodePtr contextNode;
11959 /* The context node for a compound traversal */
11960 xmlNodePtr outerContextNode;
11961 /* The final resulting node set wrt to all context nodes */
11962 xmlNodeSetPtr outSeq;
11964 * The temporary resulting node set wrt 1 context node.
11965 * Used to feed predicate evaluation.
11969 /* First predicate operator */
11970 xmlXPathStepOpPtr predOp;
11971 int maxPos; /* The requested position() (when a "[n]" predicate) */
11972 int hasPredicateRange, hasAxisRange, pos, size, newSize;
11973 int breakOnFirstHit;
11975 xmlXPathTraversalFunction next = NULL;
11976 /* compound axis traversal */
11977 xmlXPathTraversalFunctionExt outerNext = NULL;
11978 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11979 xmlXPathNodeSetMergeFunction mergeAndClear;
11980 xmlNodePtr oldContextNode;
11981 xmlXPathContextPtr xpctxt = ctxt->context;
11984 CHECK_TYPE0(XPATH_NODESET);
11985 obj = valuePop(ctxt);
11987 * Setup namespaces.
11989 if (prefix != NULL) {
11990 URI = xmlXPathNsLookup(xpctxt, prefix);
11992 xmlXPathReleaseObject(xpctxt, obj);
11993 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11999 * MAYBE FUTURE TODO: merging optimizations:
12000 * - If the nodes to be traversed wrt to the initial nodes and
12001 * the current axis cannot overlap, then we could avoid searching
12002 * for duplicates during the merge.
12003 * But the question is how/when to evaluate if they cannot overlap.
12004 * Example: if we know that for two initial nodes, the one is
12005 * not in the ancestor-or-self axis of the other, then we could safely
12006 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12007 * the descendant-or-self axis.
12009 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12011 case AXIS_ANCESTOR:
12013 next = xmlXPathNextAncestor;
12015 case AXIS_ANCESTOR_OR_SELF:
12017 next = xmlXPathNextAncestorOrSelf;
12019 case AXIS_ATTRIBUTE:
12022 next = xmlXPathNextAttribute;
12023 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12027 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12029 * This iterator will give us only nodes which can
12030 * hold element nodes.
12032 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12034 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12035 (type == NODE_TYPE_NODE))
12038 * Optimization if an element node type is 'element'.
12040 next = xmlXPathNextChildElement;
12042 next = xmlXPathNextChild;
12043 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12045 case AXIS_DESCENDANT:
12047 next = xmlXPathNextDescendant;
12049 case AXIS_DESCENDANT_OR_SELF:
12051 next = xmlXPathNextDescendantOrSelf;
12053 case AXIS_FOLLOWING:
12055 next = xmlXPathNextFollowing;
12057 case AXIS_FOLLOWING_SIBLING:
12059 next = xmlXPathNextFollowingSibling;
12061 case AXIS_NAMESPACE:
12064 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12065 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12069 next = xmlXPathNextParent;
12071 case AXIS_PRECEDING:
12073 next = xmlXPathNextPrecedingInternal;
12075 case AXIS_PRECEDING_SIBLING:
12077 next = xmlXPathNextPrecedingSibling;
12082 next = xmlXPathNextSelf;
12083 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12088 xmlXPathDebugDumpStepAxis(op,
12089 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12092 if (next == NULL) {
12093 xmlXPathReleaseObject(xpctxt, obj);
12096 contextSeq = obj->nodesetval;
12097 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12098 xmlXPathReleaseObject(xpctxt, obj);
12099 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12103 * Predicate optimization ---------------------------------------------
12104 * If this step has a last predicate, which contains a position(),
12105 * then we'll optimize (although not exactly "position()", but only
12106 * the short-hand form, i.e., "[n]".
12108 * Example - expression "/foo[parent::bar][1]":
12110 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12112 * PREDICATE -- op->ch2 (predOp)
12113 * PREDICATE -- predOp->ch1 = [parent::bar]
12115 * COLLECT 'parent' 'name' 'node' bar
12117 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12122 hasPredicateRange = 0;
12124 if (op->ch2 != -1) {
12126 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12128 predOp = &ctxt->comp->steps[op->ch2];
12129 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12130 if (predOp->ch1 != -1) {
12132 * Use the next inner predicate operator.
12134 predOp = &ctxt->comp->steps[predOp->ch1];
12135 hasPredicateRange = 1;
12138 * There's no other predicate than the [n] predicate.
12145 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12147 * Axis traversal -----------------------------------------------------
12151 * - For the attribute axis, the principal node type is attribute.
12152 * - For the namespace axis, the principal node type is namespace.
12153 * - For other axes, the principal node type is element.
12155 * A node test * is true for any node of the
12156 * principal node type. For example, child::* will
12157 * select all element children of the context node
12159 oldContextNode = xpctxt->node;
12160 addNode = xmlXPathNodeSetAddUnique;
12163 outerContextNode = NULL;
12164 contextNode = NULL;
12168 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12169 if (outerNext != NULL) {
12171 * This is a compound traversal.
12173 if (contextNode == NULL) {
12175 * Set the context for the outer traversal.
12177 outerContextNode = contextSeq->nodeTab[contextIdx++];
12178 contextNode = outerNext(NULL, outerContextNode);
12180 contextNode = outerNext(contextNode, outerContextNode);
12181 if (contextNode == NULL)
12184 * Set the context for the main traversal.
12186 xpctxt->node = contextNode;
12188 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12191 seq = xmlXPathNodeSetCreate(NULL);
12198 * Traverse the axis and test the nodes.
12204 cur = next(ctxt, cur);
12209 * QUESTION TODO: What does the "first" and "last" stuff do?
12211 if ((first != NULL) && (*first != NULL)) {
12214 if (((total % 256) == 0) &&
12215 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12216 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12218 (xmlXPathCmpNodes(*first, cur) >= 0))
12224 if ((last != NULL) && (*last != NULL)) {
12227 if (((total % 256) == 0) &&
12228 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12229 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12231 (xmlXPathCmpNodes(cur, *last) >= 0))
12241 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12245 case NODE_TEST_NONE:
12249 case NODE_TEST_TYPE:
12251 * TODO: Don't we need to use
12252 * xmlXPathNodeSetAddNs() for namespace nodes here?
12253 * Surprisingly, some c14n tests fail, if we do this.
12255 if (type == NODE_TYPE_NODE) {
12256 switch (cur->type) {
12257 case XML_DOCUMENT_NODE:
12258 case XML_HTML_DOCUMENT_NODE:
12259 #ifdef LIBXML_DOCB_ENABLED
12260 case XML_DOCB_DOCUMENT_NODE:
12262 case XML_ELEMENT_NODE:
12263 case XML_ATTRIBUTE_NODE:
12265 case XML_COMMENT_NODE:
12266 case XML_CDATA_SECTION_NODE:
12267 case XML_TEXT_NODE:
12268 case XML_NAMESPACE_DECL:
12274 } else if (cur->type == type) {
12275 if (type == XML_NAMESPACE_DECL)
12279 } else if ((type == NODE_TYPE_TEXT) &&
12280 (cur->type == XML_CDATA_SECTION_NODE))
12286 if ((cur->type == XML_PI_NODE) &&
12287 ((name == NULL) || xmlStrEqual(name, cur->name)))
12292 case NODE_TEST_ALL:
12293 if (axis == AXIS_ATTRIBUTE) {
12294 if (cur->type == XML_ATTRIBUTE_NODE)
12298 } else if (axis == AXIS_NAMESPACE) {
12299 if (cur->type == XML_NAMESPACE_DECL)
12304 if (cur->type == XML_ELEMENT_NODE) {
12305 if (prefix == NULL)
12309 } else if ((cur->ns != NULL) &&
12310 (xmlStrEqual(URI, cur->ns->href)))
12317 case NODE_TEST_NS:{
12321 case NODE_TEST_NAME:
12322 if (axis == AXIS_ATTRIBUTE) {
12323 if (cur->type != XML_ATTRIBUTE_NODE)
12325 } else if (axis == AXIS_NAMESPACE) {
12326 if (cur->type != XML_NAMESPACE_DECL)
12329 if (cur->type != XML_ELEMENT_NODE)
12332 switch (cur->type) {
12333 case XML_ELEMENT_NODE:
12334 if (xmlStrEqual(name, cur->name)) {
12335 if (prefix == NULL) {
12336 if (cur->ns == NULL)
12341 if ((cur->ns != NULL) &&
12342 (xmlStrEqual(URI, cur->ns->href)))
12349 case XML_ATTRIBUTE_NODE:{
12350 xmlAttrPtr attr = (xmlAttrPtr) cur;
12352 if (xmlStrEqual(name, attr->name)) {
12353 if (prefix == NULL) {
12354 if ((attr->ns == NULL) ||
12355 (attr->ns->prefix == NULL))
12360 if ((attr->ns != NULL) &&
12370 case XML_NAMESPACE_DECL:
12371 if (cur->type == XML_NAMESPACE_DECL) {
12372 xmlNsPtr ns = (xmlNsPtr) cur;
12374 if ((ns->prefix != NULL) && (name != NULL)
12375 && (xmlStrEqual(ns->prefix, name)))
12385 } /* switch(test) */
12386 } while (cur != NULL);
12388 goto apply_predicates;
12390 axis_range_end: /* ----------------------------------------------------- */
12392 * We have a "/foo[n]", and position() = n was reached.
12393 * Note that we can have as well "/foo/::parent::foo[1]", so
12394 * a duplicate-aware merge is still needed.
12395 * Merge with the result.
12397 if (outSeq == NULL) {
12401 outSeq = mergeAndClear(outSeq, seq, 0);
12403 * Break if only a true/false result was requested.
12409 first_hit: /* ---------------------------------------------------------- */
12411 * Break if only a true/false result was requested and
12412 * no predicates existed and a node test succeeded.
12414 if (outSeq == NULL) {
12418 outSeq = mergeAndClear(outSeq, seq, 0);
12423 nbMatches += seq->nodeNr;
12426 apply_predicates: /* --------------------------------------------------- */
12428 * Apply predicates.
12430 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12432 * E.g. when we have a "/foo[some expression][n]".
12435 * QUESTION TODO: The old predicate evaluation took into
12436 * account location-sets.
12437 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12438 * Do we expect such a set here?
12439 * All what I learned now from the evaluation semantics
12440 * does not indicate that a location-set will be processed
12441 * here, so this looks OK.
12444 * Iterate over all predicates, starting with the outermost
12446 * TODO: Problem: we cannot execute the inner predicates first
12447 * since we cannot go back *up* the operator tree!
12449 * 1) Use of recursive functions (like is it currently done
12450 * via xmlXPathCompOpEval())
12451 * 2) Add a predicate evaluation information stack to the
12453 * 3) Change the way the operators are linked; we need a
12454 * "parent" field on xmlXPathStepOp
12456 * For the moment, I'll try to solve this with a recursive
12457 * function: xmlXPathCompOpEvalPredicate().
12459 size = seq->nodeNr;
12460 if (hasPredicateRange != 0)
12461 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12462 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12464 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12465 predOp, seq, size, hasNsNodes);
12467 if (ctxt->error != XPATH_EXPRESSION_OK) {
12472 * Add the filtered set of nodes to the result node set.
12474 if (newSize == 0) {
12476 * The predicates filtered all nodes out.
12478 xmlXPathNodeSetClear(seq, hasNsNodes);
12479 } else if (seq->nodeNr > 0) {
12481 * Add to result set.
12483 if (outSeq == NULL) {
12484 if (size != newSize) {
12486 * We need to merge and clear here, since
12487 * the sequence will contained NULLed entries.
12489 outSeq = mergeAndClear(NULL, seq, 1);
12495 outSeq = mergeAndClear(outSeq, seq,
12496 (size != newSize) ? 1: 0);
12498 * Break if only a true/false result was requested.
12503 } else if (seq->nodeNr > 0) {
12505 * Add to result set.
12507 if (outSeq == NULL) {
12511 outSeq = mergeAndClear(outSeq, seq, 0);
12517 if ((obj->boolval) && (obj->user != NULL)) {
12519 * QUESTION TODO: What does this do and why?
12520 * TODO: Do we have to do this also for the "error"
12521 * cleanup further down?
12523 ctxt->value->boolval = 1;
12524 ctxt->value->user = obj->user;
12528 xmlXPathReleaseObject(xpctxt, obj);
12531 * Ensure we return at least an emtpy set.
12533 if (outSeq == NULL) {
12534 if ((seq != NULL) && (seq->nodeNr == 0))
12537 outSeq = xmlXPathNodeSetCreate(NULL);
12538 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12540 if ((seq != NULL) && (seq != outSeq)) {
12541 xmlXPathFreeNodeSet(seq);
12544 * Hand over the result. Better to push the set also in
12547 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12549 * Reset the context node.
12551 xpctxt->node = oldContextNode;
12554 xmlGenericError(xmlGenericErrorContext,
12555 "\nExamined %d nodes, found %d nodes at that step\n",
12563 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12564 xmlXPathStepOpPtr op, xmlNodePtr * first);
12567 * xmlXPathCompOpEvalFirst:
12568 * @ctxt: the XPath parser context with the compiled expression
12569 * @op: an XPath compiled operation
12570 * @first: the first elem found so far
12572 * Evaluate the Precompiled XPath operation searching only the first
12573 * element in document order
12575 * Returns the number of examined objects.
12578 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12579 xmlXPathStepOpPtr op, xmlNodePtr * first)
12581 int total = 0, cur;
12582 xmlXPathCompExprPtr comp;
12583 xmlXPathObjectPtr arg1, arg2;
12590 case XPATH_OP_UNION:
12592 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12595 if ((ctxt->value != NULL)
12596 && (ctxt->value->type == XPATH_NODESET)
12597 && (ctxt->value->nodesetval != NULL)
12598 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12600 * limit tree traversing to first node in the result
12603 * OPTIMIZE TODO: This implicitely sorts
12604 * the result, even if not needed. E.g. if the argument
12605 * of the count() function, no sorting is needed.
12606 * OPTIMIZE TODO: How do we know if the node-list wasn't
12609 if (ctxt->value->nodesetval->nodeNr > 1)
12610 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12611 *first = ctxt->value->nodesetval->nodeTab[0];
12614 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12617 CHECK_TYPE0(XPATH_NODESET);
12618 arg2 = valuePop(ctxt);
12620 CHECK_TYPE0(XPATH_NODESET);
12621 arg1 = valuePop(ctxt);
12623 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12625 valuePush(ctxt, arg1);
12626 xmlXPathReleaseObject(ctxt->context, arg2);
12629 xmlXPathCompSwap(op);
12630 return (total + cur);
12631 case XPATH_OP_ROOT:
12632 xmlXPathRoot(ctxt);
12634 case XPATH_OP_NODE:
12636 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12639 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12641 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12642 ctxt->context->node));
12644 case XPATH_OP_RESET:
12646 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12649 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12651 ctxt->context->node = NULL;
12653 case XPATH_OP_COLLECT:{
12657 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12660 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12663 case XPATH_OP_VALUE:
12665 xmlXPathCacheObjectCopy(ctxt->context,
12666 (xmlXPathObjectPtr) op->value4));
12668 case XPATH_OP_SORT:
12671 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12674 if ((ctxt->value != NULL)
12675 && (ctxt->value->type == XPATH_NODESET)
12676 && (ctxt->value->nodesetval != NULL)
12677 && (ctxt->value->nodesetval->nodeNr > 1))
12678 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12680 #ifdef XP_OPTIMIZED_FILTER_FIRST
12681 case XPATH_OP_FILTER:
12682 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12686 return (xmlXPathCompOpEval(ctxt, op));
12691 * xmlXPathCompOpEvalLast:
12692 * @ctxt: the XPath parser context with the compiled expression
12693 * @op: an XPath compiled operation
12694 * @last: the last elem found so far
12696 * Evaluate the Precompiled XPath operation searching only the last
12697 * element in document order
12699 * Returns the number of nodes traversed
12702 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12705 int total = 0, cur;
12706 xmlXPathCompExprPtr comp;
12707 xmlXPathObjectPtr arg1, arg2;
12718 case XPATH_OP_UNION:
12719 bakd = ctxt->context->doc;
12720 bak = ctxt->context->node;
12721 pp = ctxt->context->proximityPosition;
12722 cs = ctxt->context->contextSize;
12724 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12726 if ((ctxt->value != NULL)
12727 && (ctxt->value->type == XPATH_NODESET)
12728 && (ctxt->value->nodesetval != NULL)
12729 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12731 * limit tree traversing to first node in the result
12733 if (ctxt->value->nodesetval->nodeNr > 1)
12734 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12736 ctxt->value->nodesetval->nodeTab[ctxt->value->
12737 nodesetval->nodeNr -
12740 ctxt->context->doc = bakd;
12741 ctxt->context->node = bak;
12742 ctxt->context->proximityPosition = pp;
12743 ctxt->context->contextSize = cs;
12745 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12747 if ((ctxt->value != NULL)
12748 && (ctxt->value->type == XPATH_NODESET)
12749 && (ctxt->value->nodesetval != NULL)
12750 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12752 CHECK_TYPE0(XPATH_NODESET);
12753 arg2 = valuePop(ctxt);
12755 CHECK_TYPE0(XPATH_NODESET);
12756 arg1 = valuePop(ctxt);
12758 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12760 valuePush(ctxt, arg1);
12761 xmlXPathReleaseObject(ctxt->context, arg2);
12764 xmlXPathCompSwap(op);
12765 return (total + cur);
12766 case XPATH_OP_ROOT:
12767 xmlXPathRoot(ctxt);
12769 case XPATH_OP_NODE:
12771 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12774 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12776 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12777 ctxt->context->node));
12779 case XPATH_OP_RESET:
12781 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12784 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12786 ctxt->context->node = NULL;
12788 case XPATH_OP_COLLECT:{
12792 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12795 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12798 case XPATH_OP_VALUE:
12800 xmlXPathCacheObjectCopy(ctxt->context,
12801 (xmlXPathObjectPtr) op->value4));
12803 case XPATH_OP_SORT:
12806 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12809 if ((ctxt->value != NULL)
12810 && (ctxt->value->type == XPATH_NODESET)
12811 && (ctxt->value->nodesetval != NULL)
12812 && (ctxt->value->nodesetval->nodeNr > 1))
12813 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12816 return (xmlXPathCompOpEval(ctxt, op));
12820 #ifdef XP_OPTIMIZED_FILTER_FIRST
12822 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12823 xmlXPathStepOpPtr op, xmlNodePtr * first)
12826 xmlXPathCompExprPtr comp;
12827 xmlXPathObjectPtr res;
12828 xmlXPathObjectPtr obj;
12829 xmlNodeSetPtr oldset;
12830 xmlNodePtr oldnode;
12837 * Optimization for ()[last()] selection i.e. the last elem
12839 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12840 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12841 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12842 int f = comp->steps[op->ch2].ch1;
12845 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12846 (comp->steps[f].value5 == NULL) &&
12847 (comp->steps[f].value == 0) &&
12848 (comp->steps[f].value4 != NULL) &&
12850 (comp->steps[f].value4, BAD_CAST "last"))) {
12851 xmlNodePtr last = NULL;
12854 xmlXPathCompOpEvalLast(ctxt,
12855 &comp->steps[op->ch1],
12859 * The nodeset should be in document order,
12860 * Keep only the last value
12862 if ((ctxt->value != NULL) &&
12863 (ctxt->value->type == XPATH_NODESET) &&
12864 (ctxt->value->nodesetval != NULL) &&
12865 (ctxt->value->nodesetval->nodeTab != NULL) &&
12866 (ctxt->value->nodesetval->nodeNr > 1)) {
12867 ctxt->value->nodesetval->nodeTab[0] =
12868 ctxt->value->nodesetval->nodeTab[ctxt->
12873 ctxt->value->nodesetval->nodeNr = 1;
12874 *first = *(ctxt->value->nodesetval->nodeTab);
12881 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12885 if (ctxt->value == NULL)
12888 #ifdef LIBXML_XPTR_ENABLED
12889 oldnode = ctxt->context->node;
12891 * Hum are we filtering the result of an XPointer expression
12893 if (ctxt->value->type == XPATH_LOCATIONSET) {
12894 xmlXPathObjectPtr tmp = NULL;
12895 xmlLocationSetPtr newlocset = NULL;
12896 xmlLocationSetPtr oldlocset;
12899 * Extract the old locset, and then evaluate the result of the
12900 * expression for all the element in the locset. use it to grow
12903 CHECK_TYPE0(XPATH_LOCATIONSET);
12904 obj = valuePop(ctxt);
12905 oldlocset = obj->user;
12906 ctxt->context->node = NULL;
12908 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12909 ctxt->context->contextSize = 0;
12910 ctxt->context->proximityPosition = 0;
12912 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12913 res = valuePop(ctxt);
12915 xmlXPathReleaseObject(ctxt->context, res);
12917 valuePush(ctxt, obj);
12921 newlocset = xmlXPtrLocationSetCreate(NULL);
12923 for (i = 0; i < oldlocset->locNr; i++) {
12925 * Run the evaluation with a node list made of a
12926 * single item in the nodelocset.
12928 ctxt->context->node = oldlocset->locTab[i]->user;
12929 ctxt->context->contextSize = oldlocset->locNr;
12930 ctxt->context->proximityPosition = i + 1;
12932 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12933 ctxt->context->node);
12935 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12936 ctxt->context->node);
12938 valuePush(ctxt, tmp);
12940 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12941 if (ctxt->error != XPATH_EXPRESSION_OK) {
12942 xmlXPathFreeObject(obj);
12946 * The result of the evaluation need to be tested to
12947 * decided whether the filter succeeded or not
12949 res = valuePop(ctxt);
12950 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
12951 xmlXPtrLocationSetAdd(newlocset,
12952 xmlXPathCacheObjectCopy(ctxt->context,
12953 oldlocset->locTab[i]));
12959 xmlXPathReleaseObject(ctxt->context, res);
12961 if (ctxt->value == tmp) {
12963 xmlXPathNodeSetClear(tmp->nodesetval, 1);
12965 * REVISIT TODO: Don't create a temporary nodeset
12966 * for everly iteration.
12968 /* OLD: xmlXPathFreeObject(res); */
12971 ctxt->context->node = NULL;
12973 * Only put the first node in the result, then leave.
12975 if (newlocset->locNr > 0) {
12976 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
12981 xmlXPathReleaseObject(ctxt->context, tmp);
12984 * The result is used as the new evaluation locset.
12986 xmlXPathReleaseObject(ctxt->context, obj);
12987 ctxt->context->node = NULL;
12988 ctxt->context->contextSize = -1;
12989 ctxt->context->proximityPosition = -1;
12990 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12991 ctxt->context->node = oldnode;
12994 #endif /* LIBXML_XPTR_ENABLED */
12997 * Extract the old set, and then evaluate the result of the
12998 * expression for all the element in the set. use it to grow
13001 CHECK_TYPE0(XPATH_NODESET);
13002 obj = valuePop(ctxt);
13003 oldset = obj->nodesetval;
13005 oldnode = ctxt->context->node;
13006 oldDoc = ctxt->context->doc;
13007 ctxt->context->node = NULL;
13009 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13010 ctxt->context->contextSize = 0;
13011 ctxt->context->proximityPosition = 0;
13012 /* QUESTION TODO: Why was this code commented out?
13015 xmlXPathCompOpEval(ctxt,
13016 &comp->steps[op->ch2]);
13018 res = valuePop(ctxt);
13020 xmlXPathFreeObject(res);
13022 valuePush(ctxt, obj);
13023 ctxt->context->node = oldnode;
13026 xmlNodeSetPtr newset;
13027 xmlXPathObjectPtr tmp = NULL;
13029 * Initialize the new set.
13030 * Also set the xpath document in case things like
13031 * key() evaluation are attempted on the predicate
13033 newset = xmlXPathNodeSetCreate(NULL);
13034 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13036 for (i = 0; i < oldset->nodeNr; i++) {
13038 * Run the evaluation with a node list made of
13039 * a single item in the nodeset.
13041 ctxt->context->node = oldset->nodeTab[i];
13042 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13043 (oldset->nodeTab[i]->doc != NULL))
13044 ctxt->context->doc = oldset->nodeTab[i]->doc;
13046 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13047 ctxt->context->node);
13049 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13050 ctxt->context->node);
13052 valuePush(ctxt, tmp);
13053 ctxt->context->contextSize = oldset->nodeNr;
13054 ctxt->context->proximityPosition = i + 1;
13056 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13057 if (ctxt->error != XPATH_EXPRESSION_OK) {
13058 xmlXPathFreeNodeSet(newset);
13059 xmlXPathFreeObject(obj);
13063 * The result of the evaluation needs to be tested to
13064 * decide whether the filter succeeded or not
13066 res = valuePop(ctxt);
13067 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13068 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13074 xmlXPathReleaseObject(ctxt->context, res);
13076 if (ctxt->value == tmp) {
13079 * Don't free the temporary nodeset
13080 * in order to avoid massive recreation inside this
13083 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13086 ctxt->context->node = NULL;
13088 * Only put the first node in the result, then leave.
13090 if (newset->nodeNr > 0) {
13091 *first = *(newset->nodeTab);
13096 xmlXPathReleaseObject(ctxt->context, tmp);
13099 * The result is used as the new evaluation set.
13101 xmlXPathReleaseObject(ctxt->context, obj);
13102 ctxt->context->node = NULL;
13103 ctxt->context->contextSize = -1;
13104 ctxt->context->proximityPosition = -1;
13105 /* may want to move this past the '}' later */
13106 ctxt->context->doc = oldDoc;
13107 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13109 ctxt->context->node = oldnode;
13112 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13115 * xmlXPathCompOpEval:
13116 * @ctxt: the XPath parser context with the compiled expression
13117 * @op: an XPath compiled operation
13119 * Evaluate the Precompiled XPath operation
13120 * Returns the number of nodes traversed
13123 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13127 xmlXPathCompExprPtr comp;
13128 xmlXPathObjectPtr arg1, arg2;
13140 bakd = ctxt->context->doc;
13141 bak = ctxt->context->node;
13142 pp = ctxt->context->proximityPosition;
13143 cs = ctxt->context->contextSize;
13144 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13146 xmlXPathBooleanFunction(ctxt, 1);
13147 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13149 arg2 = valuePop(ctxt);
13150 ctxt->context->doc = bakd;
13151 ctxt->context->node = bak;
13152 ctxt->context->proximityPosition = pp;
13153 ctxt->context->contextSize = cs;
13154 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13156 xmlXPathFreeObject(arg2);
13159 xmlXPathBooleanFunction(ctxt, 1);
13160 arg1 = valuePop(ctxt);
13161 arg1->boolval &= arg2->boolval;
13162 valuePush(ctxt, arg1);
13163 xmlXPathReleaseObject(ctxt->context, arg2);
13166 bakd = ctxt->context->doc;
13167 bak = ctxt->context->node;
13168 pp = ctxt->context->proximityPosition;
13169 cs = ctxt->context->contextSize;
13170 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13172 xmlXPathBooleanFunction(ctxt, 1);
13173 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13175 arg2 = valuePop(ctxt);
13176 ctxt->context->doc = bakd;
13177 ctxt->context->node = bak;
13178 ctxt->context->proximityPosition = pp;
13179 ctxt->context->contextSize = cs;
13180 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13182 xmlXPathFreeObject(arg2);
13185 xmlXPathBooleanFunction(ctxt, 1);
13186 arg1 = valuePop(ctxt);
13187 arg1->boolval |= arg2->boolval;
13188 valuePush(ctxt, arg1);
13189 xmlXPathReleaseObject(ctxt->context, arg2);
13191 case XPATH_OP_EQUAL:
13192 bakd = ctxt->context->doc;
13193 bak = ctxt->context->node;
13194 pp = ctxt->context->proximityPosition;
13195 cs = ctxt->context->contextSize;
13196 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13198 ctxt->context->doc = bakd;
13199 ctxt->context->node = bak;
13200 ctxt->context->proximityPosition = pp;
13201 ctxt->context->contextSize = cs;
13202 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13205 equal = xmlXPathEqualValues(ctxt);
13207 equal = xmlXPathNotEqualValues(ctxt);
13208 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13211 bakd = ctxt->context->doc;
13212 bak = ctxt->context->node;
13213 pp = ctxt->context->proximityPosition;
13214 cs = ctxt->context->contextSize;
13215 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13217 ctxt->context->doc = bakd;
13218 ctxt->context->node = bak;
13219 ctxt->context->proximityPosition = pp;
13220 ctxt->context->contextSize = cs;
13221 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13223 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13224 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13226 case XPATH_OP_PLUS:
13227 bakd = ctxt->context->doc;
13228 bak = ctxt->context->node;
13229 pp = ctxt->context->proximityPosition;
13230 cs = ctxt->context->contextSize;
13231 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13233 if (op->ch2 != -1) {
13234 ctxt->context->doc = bakd;
13235 ctxt->context->node = bak;
13236 ctxt->context->proximityPosition = pp;
13237 ctxt->context->contextSize = cs;
13238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13241 if (op->value == 0)
13242 xmlXPathSubValues(ctxt);
13243 else if (op->value == 1)
13244 xmlXPathAddValues(ctxt);
13245 else if (op->value == 2)
13246 xmlXPathValueFlipSign(ctxt);
13247 else if (op->value == 3) {
13249 CHECK_TYPE0(XPATH_NUMBER);
13252 case XPATH_OP_MULT:
13253 bakd = ctxt->context->doc;
13254 bak = ctxt->context->node;
13255 pp = ctxt->context->proximityPosition;
13256 cs = ctxt->context->contextSize;
13257 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13259 ctxt->context->doc = bakd;
13260 ctxt->context->node = bak;
13261 ctxt->context->proximityPosition = pp;
13262 ctxt->context->contextSize = cs;
13263 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13265 if (op->value == 0)
13266 xmlXPathMultValues(ctxt);
13267 else if (op->value == 1)
13268 xmlXPathDivValues(ctxt);
13269 else if (op->value == 2)
13270 xmlXPathModValues(ctxt);
13272 case XPATH_OP_UNION:
13273 bakd = ctxt->context->doc;
13274 bak = ctxt->context->node;
13275 pp = ctxt->context->proximityPosition;
13276 cs = ctxt->context->contextSize;
13277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13279 ctxt->context->doc = bakd;
13280 ctxt->context->node = bak;
13281 ctxt->context->proximityPosition = pp;
13282 ctxt->context->contextSize = cs;
13283 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13285 CHECK_TYPE0(XPATH_NODESET);
13286 arg2 = valuePop(ctxt);
13288 CHECK_TYPE0(XPATH_NODESET);
13289 arg1 = valuePop(ctxt);
13291 if ((arg1->nodesetval == NULL) ||
13292 ((arg2->nodesetval != NULL) &&
13293 (arg2->nodesetval->nodeNr != 0)))
13295 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13299 valuePush(ctxt, arg1);
13300 xmlXPathReleaseObject(ctxt->context, arg2);
13302 case XPATH_OP_ROOT:
13303 xmlXPathRoot(ctxt);
13305 case XPATH_OP_NODE:
13307 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13310 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13312 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13313 ctxt->context->node));
13315 case XPATH_OP_RESET:
13317 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13320 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13322 ctxt->context->node = NULL;
13324 case XPATH_OP_COLLECT:{
13328 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13331 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13334 case XPATH_OP_VALUE:
13336 xmlXPathCacheObjectCopy(ctxt->context,
13337 (xmlXPathObjectPtr) op->value4));
13339 case XPATH_OP_VARIABLE:{
13340 xmlXPathObjectPtr val;
13344 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13345 if (op->value5 == NULL) {
13346 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13348 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13351 valuePush(ctxt, val);
13353 const xmlChar *URI;
13355 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13357 xmlGenericError(xmlGenericErrorContext,
13358 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13359 (char *) op->value4, (char *)op->value5);
13362 val = xmlXPathVariableLookupNS(ctxt->context,
13365 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13368 valuePush(ctxt, val);
13372 case XPATH_OP_FUNCTION:{
13373 xmlXPathFunction func;
13374 const xmlChar *oldFunc, *oldFuncURI;
13379 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13380 if (ctxt->valueNr < op->value) {
13381 xmlGenericError(xmlGenericErrorContext,
13382 "xmlXPathCompOpEval: parameter error\n");
13383 ctxt->error = XPATH_INVALID_OPERAND;
13386 for (i = 0; i < op->value; i++)
13387 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13388 xmlGenericError(xmlGenericErrorContext,
13389 "xmlXPathCompOpEval: parameter error\n");
13390 ctxt->error = XPATH_INVALID_OPERAND;
13393 if (op->cache != NULL)
13394 XML_CAST_FPTR(func) = op->cache;
13396 const xmlChar *URI = NULL;
13398 if (op->value5 == NULL)
13400 xmlXPathFunctionLookup(ctxt->context,
13403 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13405 xmlGenericError(xmlGenericErrorContext,
13406 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13407 (char *)op->value4, (char *)op->value5);
13410 func = xmlXPathFunctionLookupNS(ctxt->context,
13413 if (func == NULL) {
13414 xmlGenericError(xmlGenericErrorContext,
13415 "xmlXPathCompOpEval: function %s not found\n",
13416 (char *)op->value4);
13417 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13419 op->cache = XML_CAST_FPTR(func);
13420 op->cacheURI = (void *) URI;
13422 oldFunc = ctxt->context->function;
13423 oldFuncURI = ctxt->context->functionURI;
13424 ctxt->context->function = op->value4;
13425 ctxt->context->functionURI = op->cacheURI;
13426 func(ctxt, op->value);
13427 ctxt->context->function = oldFunc;
13428 ctxt->context->functionURI = oldFuncURI;
13432 bakd = ctxt->context->doc;
13433 bak = ctxt->context->node;
13434 pp = ctxt->context->proximityPosition;
13435 cs = ctxt->context->contextSize;
13437 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13438 ctxt->context->contextSize = cs;
13439 ctxt->context->proximityPosition = pp;
13440 ctxt->context->node = bak;
13441 ctxt->context->doc = bakd;
13443 if (op->ch2 != -1) {
13444 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13445 ctxt->context->doc = bakd;
13446 ctxt->context->node = bak;
13450 case XPATH_OP_PREDICATE:
13451 case XPATH_OP_FILTER:{
13452 xmlXPathObjectPtr res;
13453 xmlXPathObjectPtr obj, tmp;
13454 xmlNodeSetPtr newset = NULL;
13455 xmlNodeSetPtr oldset;
13456 xmlNodePtr oldnode;
13461 * Optimization for ()[1] selection i.e. the first elem
13463 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13464 #ifdef XP_OPTIMIZED_FILTER_FIRST
13466 * FILTER TODO: Can we assume that the inner processing
13467 * will result in an ordered list if we have an
13469 * What about an additional field or flag on
13470 * xmlXPathObject like @sorted ? This way we wouln'd need
13471 * to assume anything, so it would be more robust and
13472 * easier to optimize.
13474 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13475 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13477 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13479 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13480 xmlXPathObjectPtr val;
13482 val = comp->steps[op->ch2].value4;
13483 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13484 (val->floatval == 1.0)) {
13485 xmlNodePtr first = NULL;
13488 xmlXPathCompOpEvalFirst(ctxt,
13489 &comp->steps[op->ch1],
13493 * The nodeset should be in document order,
13494 * Keep only the first value
13496 if ((ctxt->value != NULL) &&
13497 (ctxt->value->type == XPATH_NODESET) &&
13498 (ctxt->value->nodesetval != NULL) &&
13499 (ctxt->value->nodesetval->nodeNr > 1))
13500 ctxt->value->nodesetval->nodeNr = 1;
13505 * Optimization for ()[last()] selection i.e. the last elem
13507 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13508 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13509 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13510 int f = comp->steps[op->ch2].ch1;
13513 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13514 (comp->steps[f].value5 == NULL) &&
13515 (comp->steps[f].value == 0) &&
13516 (comp->steps[f].value4 != NULL) &&
13518 (comp->steps[f].value4, BAD_CAST "last"))) {
13519 xmlNodePtr last = NULL;
13522 xmlXPathCompOpEvalLast(ctxt,
13523 &comp->steps[op->ch1],
13527 * The nodeset should be in document order,
13528 * Keep only the last value
13530 if ((ctxt->value != NULL) &&
13531 (ctxt->value->type == XPATH_NODESET) &&
13532 (ctxt->value->nodesetval != NULL) &&
13533 (ctxt->value->nodesetval->nodeTab != NULL) &&
13534 (ctxt->value->nodesetval->nodeNr > 1)) {
13535 ctxt->value->nodesetval->nodeTab[0] =
13536 ctxt->value->nodesetval->nodeTab[ctxt->
13541 ctxt->value->nodesetval->nodeNr = 1;
13547 * Process inner predicates first.
13548 * Example "index[parent::book][1]":
13550 * PREDICATE <-- we are here "[1]"
13551 * PREDICATE <-- process "[parent::book]" first
13553 * COLLECT 'parent' 'name' 'node' book
13555 * ELEM Object is a number : 1
13559 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13563 if (ctxt->value == NULL)
13566 oldnode = ctxt->context->node;
13568 #ifdef LIBXML_XPTR_ENABLED
13570 * Hum are we filtering the result of an XPointer expression
13572 if (ctxt->value->type == XPATH_LOCATIONSET) {
13573 xmlLocationSetPtr newlocset = NULL;
13574 xmlLocationSetPtr oldlocset;
13577 * Extract the old locset, and then evaluate the result of the
13578 * expression for all the element in the locset. use it to grow
13581 CHECK_TYPE0(XPATH_LOCATIONSET);
13582 obj = valuePop(ctxt);
13583 oldlocset = obj->user;
13584 ctxt->context->node = NULL;
13586 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13587 ctxt->context->contextSize = 0;
13588 ctxt->context->proximityPosition = 0;
13591 xmlXPathCompOpEval(ctxt,
13592 &comp->steps[op->ch2]);
13593 res = valuePop(ctxt);
13595 xmlXPathReleaseObject(ctxt->context, res);
13597 valuePush(ctxt, obj);
13601 newlocset = xmlXPtrLocationSetCreate(NULL);
13603 for (i = 0; i < oldlocset->locNr; i++) {
13605 * Run the evaluation with a node list made of a
13606 * single item in the nodelocset.
13608 ctxt->context->node = oldlocset->locTab[i]->user;
13609 ctxt->context->contextSize = oldlocset->locNr;
13610 ctxt->context->proximityPosition = i + 1;
13611 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13612 ctxt->context->node);
13613 valuePush(ctxt, tmp);
13617 xmlXPathCompOpEval(ctxt,
13618 &comp->steps[op->ch2]);
13619 if (ctxt->error != XPATH_EXPRESSION_OK) {
13620 xmlXPathFreeObject(obj);
13625 * The result of the evaluation need to be tested to
13626 * decided whether the filter succeeded or not
13628 res = valuePop(ctxt);
13629 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13630 xmlXPtrLocationSetAdd(newlocset,
13632 (oldlocset->locTab[i]));
13639 xmlXPathReleaseObject(ctxt->context, res);
13641 if (ctxt->value == tmp) {
13642 res = valuePop(ctxt);
13643 xmlXPathReleaseObject(ctxt->context, res);
13646 ctxt->context->node = NULL;
13650 * The result is used as the new evaluation locset.
13652 xmlXPathReleaseObject(ctxt->context, obj);
13653 ctxt->context->node = NULL;
13654 ctxt->context->contextSize = -1;
13655 ctxt->context->proximityPosition = -1;
13656 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13657 ctxt->context->node = oldnode;
13660 #endif /* LIBXML_XPTR_ENABLED */
13663 * Extract the old set, and then evaluate the result of the
13664 * expression for all the element in the set. use it to grow
13667 CHECK_TYPE0(XPATH_NODESET);
13668 obj = valuePop(ctxt);
13669 oldset = obj->nodesetval;
13671 oldnode = ctxt->context->node;
13672 oldDoc = ctxt->context->doc;
13673 ctxt->context->node = NULL;
13675 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13676 ctxt->context->contextSize = 0;
13677 ctxt->context->proximityPosition = 0;
13681 xmlXPathCompOpEval(ctxt,
13682 &comp->steps[op->ch2]);
13684 res = valuePop(ctxt);
13686 xmlXPathFreeObject(res);
13688 valuePush(ctxt, obj);
13689 ctxt->context->node = oldnode;
13694 * Initialize the new set.
13695 * Also set the xpath document in case things like
13696 * key() evaluation are attempted on the predicate
13698 newset = xmlXPathNodeSetCreate(NULL);
13701 * "For each node in the node-set to be filtered, the
13702 * PredicateExpr is evaluated with that node as the
13703 * context node, with the number of nodes in the
13704 * node-set as the context size, and with the proximity
13705 * position of the node in the node-set with respect to
13706 * the axis as the context position;"
13707 * @oldset is the node-set" to be filtered.
13710 * "only predicates change the context position and
13711 * context size (see [2.4 Predicates])."
13713 * node-set context pos
13717 * After applying predicate [position() > 1] :
13718 * node-set context pos
13722 * removed the first node in the node-set, then
13723 * the context position of the
13725 for (i = 0; i < oldset->nodeNr; i++) {
13727 * Run the evaluation with a node list made of
13728 * a single item in the nodeset.
13730 ctxt->context->node = oldset->nodeTab[i];
13731 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13732 (oldset->nodeTab[i]->doc != NULL))
13733 ctxt->context->doc = oldset->nodeTab[i]->doc;
13735 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13736 ctxt->context->node);
13738 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13739 ctxt->context->node);
13741 valuePush(ctxt, tmp);
13742 ctxt->context->contextSize = oldset->nodeNr;
13743 ctxt->context->proximityPosition = i + 1;
13745 * Evaluate the predicate against the context node.
13746 * Can/should we optimize position() predicates
13747 * here (e.g. "[1]")?
13751 xmlXPathCompOpEval(ctxt,
13752 &comp->steps[op->ch2]);
13753 if (ctxt->error != XPATH_EXPRESSION_OK) {
13754 xmlXPathFreeNodeSet(newset);
13755 xmlXPathFreeObject(obj);
13760 * The result of the evaluation needs to be tested to
13761 * decide whether the filter succeeded or not
13764 * OPTIMIZE TODO: Can we use
13765 * xmlXPathNodeSetAdd*Unique()* instead?
13767 res = valuePop(ctxt);
13768 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13769 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13776 xmlXPathReleaseObject(ctxt->context, res);
13778 if (ctxt->value == tmp) {
13780 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13782 * Don't free the temporary nodeset
13783 * in order to avoid massive recreation inside this
13788 ctxt->context->node = NULL;
13791 xmlXPathReleaseObject(ctxt->context, tmp);
13793 * The result is used as the new evaluation set.
13795 xmlXPathReleaseObject(ctxt->context, obj);
13796 ctxt->context->node = NULL;
13797 ctxt->context->contextSize = -1;
13798 ctxt->context->proximityPosition = -1;
13799 /* may want to move this past the '}' later */
13800 ctxt->context->doc = oldDoc;
13802 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13804 ctxt->context->node = oldnode;
13807 case XPATH_OP_SORT:
13809 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13811 if ((ctxt->value != NULL) &&
13812 (ctxt->value->type == XPATH_NODESET) &&
13813 (ctxt->value->nodesetval != NULL) &&
13814 (ctxt->value->nodesetval->nodeNr > 1))
13816 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13819 #ifdef LIBXML_XPTR_ENABLED
13820 case XPATH_OP_RANGETO:{
13821 xmlXPathObjectPtr range;
13822 xmlXPathObjectPtr res, obj;
13823 xmlXPathObjectPtr tmp;
13824 xmlLocationSetPtr newlocset = NULL;
13825 xmlLocationSetPtr oldlocset;
13826 xmlNodeSetPtr oldset;
13831 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13835 if (ctxt->value->type == XPATH_LOCATIONSET) {
13837 * Extract the old locset, and then evaluate the result of the
13838 * expression for all the element in the locset. use it to grow
13841 CHECK_TYPE0(XPATH_LOCATIONSET);
13842 obj = valuePop(ctxt);
13843 oldlocset = obj->user;
13845 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13846 ctxt->context->node = NULL;
13847 ctxt->context->contextSize = 0;
13848 ctxt->context->proximityPosition = 0;
13849 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13850 res = valuePop(ctxt);
13852 xmlXPathReleaseObject(ctxt->context, res);
13854 valuePush(ctxt, obj);
13858 newlocset = xmlXPtrLocationSetCreate(NULL);
13860 for (i = 0; i < oldlocset->locNr; i++) {
13862 * Run the evaluation with a node list made of a
13863 * single item in the nodelocset.
13865 ctxt->context->node = oldlocset->locTab[i]->user;
13866 ctxt->context->contextSize = oldlocset->locNr;
13867 ctxt->context->proximityPosition = i + 1;
13868 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13869 ctxt->context->node);
13870 valuePush(ctxt, tmp);
13874 xmlXPathCompOpEval(ctxt,
13875 &comp->steps[op->ch2]);
13876 if (ctxt->error != XPATH_EXPRESSION_OK) {
13877 xmlXPathFreeObject(obj);
13881 res = valuePop(ctxt);
13882 if (res->type == XPATH_LOCATIONSET) {
13883 xmlLocationSetPtr rloc =
13884 (xmlLocationSetPtr)res->user;
13885 for (j=0; j<rloc->locNr; j++) {
13886 range = xmlXPtrNewRange(
13887 oldlocset->locTab[i]->user,
13888 oldlocset->locTab[i]->index,
13889 rloc->locTab[j]->user2,
13890 rloc->locTab[j]->index2);
13891 if (range != NULL) {
13892 xmlXPtrLocationSetAdd(newlocset, range);
13896 range = xmlXPtrNewRangeNodeObject(
13897 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13898 if (range != NULL) {
13899 xmlXPtrLocationSetAdd(newlocset,range);
13907 xmlXPathReleaseObject(ctxt->context, res);
13909 if (ctxt->value == tmp) {
13910 res = valuePop(ctxt);
13911 xmlXPathReleaseObject(ctxt->context, res);
13914 ctxt->context->node = NULL;
13916 } else { /* Not a location set */
13917 CHECK_TYPE0(XPATH_NODESET);
13918 obj = valuePop(ctxt);
13919 oldset = obj->nodesetval;
13920 ctxt->context->node = NULL;
13922 newlocset = xmlXPtrLocationSetCreate(NULL);
13924 if (oldset != NULL) {
13925 for (i = 0; i < oldset->nodeNr; i++) {
13927 * Run the evaluation with a node list made of a single item
13930 ctxt->context->node = oldset->nodeTab[i];
13932 * OPTIMIZE TODO: Avoid recreation for every iteration.
13934 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13935 ctxt->context->node);
13936 valuePush(ctxt, tmp);
13940 xmlXPathCompOpEval(ctxt,
13941 &comp->steps[op->ch2]);
13942 if (ctxt->error != XPATH_EXPRESSION_OK) {
13943 xmlXPathFreeObject(obj);
13947 res = valuePop(ctxt);
13949 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
13951 if (range != NULL) {
13952 xmlXPtrLocationSetAdd(newlocset, range);
13959 xmlXPathReleaseObject(ctxt->context, res);
13961 if (ctxt->value == tmp) {
13962 res = valuePop(ctxt);
13963 xmlXPathReleaseObject(ctxt->context, res);
13966 ctxt->context->node = NULL;
13972 * The result is used as the new evaluation set.
13974 xmlXPathReleaseObject(ctxt->context, obj);
13975 ctxt->context->node = NULL;
13976 ctxt->context->contextSize = -1;
13977 ctxt->context->proximityPosition = -1;
13978 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13981 #endif /* LIBXML_XPTR_ENABLED */
13983 xmlGenericError(xmlGenericErrorContext,
13984 "XPath: unknown precompiled operation %d\n", op->op);
13989 * xmlXPathCompOpEvalToBoolean:
13990 * @ctxt: the XPath parser context
13992 * Evaluates if the expression evaluates to true.
13994 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13997 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
13998 xmlXPathStepOpPtr op,
14001 xmlXPathObjectPtr resObj = NULL;
14004 /* comp = ctxt->comp; */
14008 case XPATH_OP_VALUE:
14009 resObj = (xmlXPathObjectPtr) op->value4;
14011 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14012 return(xmlXPathCastToBoolean(resObj));
14013 case XPATH_OP_SORT:
14015 * We don't need sorting for boolean results. Skip this one.
14017 if (op->ch1 != -1) {
14018 op = &ctxt->comp->steps[op->ch1];
14022 case XPATH_OP_COLLECT:
14026 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14027 if (ctxt->error != XPATH_EXPRESSION_OK)
14030 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14031 if (ctxt->error != XPATH_EXPRESSION_OK)
14034 resObj = valuePop(ctxt);
14035 if (resObj == NULL)
14040 * Fallback to call xmlXPathCompOpEval().
14042 xmlXPathCompOpEval(ctxt, op);
14043 if (ctxt->error != XPATH_EXPRESSION_OK)
14046 resObj = valuePop(ctxt);
14047 if (resObj == NULL)
14055 if (resObj->type == XPATH_BOOLEAN) {
14056 res = resObj->boolval;
14057 } else if (isPredicate) {
14059 * For predicates a result of type "number" is handled
14062 * "If the result is a number, the result will be converted
14063 * to true if the number is equal to the context position
14064 * and will be converted to false otherwise;"
14066 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14068 res = xmlXPathCastToBoolean(resObj);
14070 xmlXPathReleaseObject(ctxt->context, resObj);
14077 #ifdef XPATH_STREAMING
14079 * xmlXPathRunStreamEval:
14080 * @ctxt: the XPath parser context with the compiled expression
14082 * Evaluate the Precompiled Streamable XPath expression in the given context.
14085 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14086 xmlXPathObjectPtr *resultSeq, int toBool)
14088 int max_depth, min_depth;
14091 int eval_all_nodes;
14092 xmlNodePtr cur = NULL, limit = NULL;
14093 xmlStreamCtxtPtr patstream = NULL;
14097 if ((ctxt == NULL) || (comp == NULL))
14099 max_depth = xmlPatternMaxDepth(comp);
14100 if (max_depth == -1)
14102 if (max_depth == -2)
14104 min_depth = xmlPatternMinDepth(comp);
14105 if (min_depth == -1)
14107 from_root = xmlPatternFromRoot(comp);
14111 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14115 if (resultSeq == NULL)
14117 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14118 if (*resultSeq == NULL)
14123 * handle the special cases of "/" amd "." being matched
14125 if (min_depth == 0) {
14130 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14131 (xmlNodePtr) ctxt->doc);
14133 /* Select "self::node()" */
14136 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14139 if (max_depth == 0) {
14144 cur = (xmlNodePtr)ctxt->doc;
14145 } else if (ctxt->node != NULL) {
14146 switch (ctxt->node->type) {
14147 case XML_ELEMENT_NODE:
14148 case XML_DOCUMENT_NODE:
14149 case XML_DOCUMENT_FRAG_NODE:
14150 case XML_HTML_DOCUMENT_NODE:
14151 #ifdef LIBXML_DOCB_ENABLED
14152 case XML_DOCB_DOCUMENT_NODE:
14156 case XML_ATTRIBUTE_NODE:
14157 case XML_TEXT_NODE:
14158 case XML_CDATA_SECTION_NODE:
14159 case XML_ENTITY_REF_NODE:
14160 case XML_ENTITY_NODE:
14162 case XML_COMMENT_NODE:
14163 case XML_NOTATION_NODE:
14165 case XML_DOCUMENT_TYPE_NODE:
14166 case XML_ELEMENT_DECL:
14167 case XML_ATTRIBUTE_DECL:
14168 case XML_ENTITY_DECL:
14169 case XML_NAMESPACE_DECL:
14170 case XML_XINCLUDE_START:
14171 case XML_XINCLUDE_END:
14180 patstream = xmlPatternGetStreamCtxt(comp);
14181 if (patstream == NULL) {
14183 * QUESTION TODO: Is this an error?
14188 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14191 ret = xmlStreamPush(patstream, NULL, NULL);
14193 } else if (ret == 1) {
14196 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14200 goto scan_children;
14205 switch (cur->type) {
14206 case XML_ELEMENT_NODE:
14207 case XML_TEXT_NODE:
14208 case XML_CDATA_SECTION_NODE:
14209 case XML_COMMENT_NODE:
14211 if (cur->type == XML_ELEMENT_NODE) {
14212 ret = xmlStreamPush(patstream, cur->name,
14213 (cur->ns ? cur->ns->href : NULL));
14214 } else if (eval_all_nodes)
14215 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14221 } else if (ret == 1) {
14224 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14226 if ((cur->children == NULL) || (depth >= max_depth)) {
14227 ret = xmlStreamPop(patstream);
14228 while (cur->next != NULL) {
14230 if ((cur->type != XML_ENTITY_DECL) &&
14231 (cur->type != XML_DTD_NODE))
14240 if ((cur->children != NULL) && (depth < max_depth)) {
14242 * Do not descend on entities declarations
14244 if (cur->children->type != XML_ENTITY_DECL) {
14245 cur = cur->children;
14250 if (cur->type != XML_DTD_NODE)
14258 while (cur->next != NULL) {
14260 if ((cur->type != XML_ENTITY_DECL) &&
14261 (cur->type != XML_DTD_NODE))
14268 if ((cur == NULL) || (cur == limit))
14270 if (cur->type == XML_ELEMENT_NODE) {
14271 ret = xmlStreamPop(patstream);
14272 } else if ((eval_all_nodes) &&
14273 ((cur->type == XML_TEXT_NODE) ||
14274 (cur->type == XML_CDATA_SECTION_NODE) ||
14275 (cur->type == XML_COMMENT_NODE) ||
14276 (cur->type == XML_PI_NODE)))
14278 ret = xmlStreamPop(patstream);
14280 if (cur->next != NULL) {
14284 } while (cur != NULL);
14286 } while ((cur != NULL) && (depth >= 0));
14291 printf("stream eval: checked %d nodes selected %d\n",
14292 nb_nodes, retObj->nodesetval->nodeNr);
14296 xmlFreeStreamCtxt(patstream);
14301 xmlFreeStreamCtxt(patstream);
14304 #endif /* XPATH_STREAMING */
14308 * @ctxt: the XPath parser context with the compiled expression
14309 * @toBool: evaluate to a boolean result
14311 * Evaluate the Precompiled XPath expression in the given context.
14314 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14316 xmlXPathCompExprPtr comp;
14318 if ((ctxt == NULL) || (ctxt->comp == NULL))
14321 if (ctxt->valueTab == NULL) {
14322 /* Allocate the value stack */
14323 ctxt->valueTab = (xmlXPathObjectPtr *)
14324 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14325 if (ctxt->valueTab == NULL) {
14326 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14330 ctxt->valueMax = 10;
14331 ctxt->value = NULL;
14333 #ifdef XPATH_STREAMING
14334 if (ctxt->comp->stream) {
14339 * Evaluation to boolean result.
14341 res = xmlXPathRunStreamEval(ctxt->context,
14342 ctxt->comp->stream, NULL, 1);
14346 xmlXPathObjectPtr resObj = NULL;
14349 * Evaluation to a sequence.
14351 res = xmlXPathRunStreamEval(ctxt->context,
14352 ctxt->comp->stream, &resObj, 0);
14354 if ((res != -1) && (resObj != NULL)) {
14355 valuePush(ctxt, resObj);
14358 if (resObj != NULL)
14359 xmlXPathReleaseObject(ctxt->context, resObj);
14362 * QUESTION TODO: This falls back to normal XPath evaluation
14363 * if res == -1. Is this intended?
14368 if (comp->last < 0) {
14369 xmlGenericError(xmlGenericErrorContext,
14370 "xmlXPathRunEval: last is less than zero\n");
14374 return(xmlXPathCompOpEvalToBoolean(ctxt,
14375 &comp->steps[comp->last], 0));
14377 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14382 /************************************************************************
14384 * Public interfaces *
14386 ************************************************************************/
14389 * xmlXPathEvalPredicate:
14390 * @ctxt: the XPath context
14391 * @res: the Predicate Expression evaluation result
14393 * Evaluate a predicate result for the current node.
14394 * A PredicateExpr is evaluated by evaluating the Expr and converting
14395 * the result to a boolean. If the result is a number, the result will
14396 * be converted to true if the number is equal to the position of the
14397 * context node in the context node list (as returned by the position
14398 * function) and will be converted to false otherwise; if the result
14399 * is not a number, then the result will be converted as if by a call
14400 * to the boolean function.
14402 * Returns 1 if predicate is true, 0 otherwise
14405 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14406 if ((ctxt == NULL) || (res == NULL)) return(0);
14407 switch (res->type) {
14408 case XPATH_BOOLEAN:
14409 return(res->boolval);
14411 return(res->floatval == ctxt->proximityPosition);
14412 case XPATH_NODESET:
14413 case XPATH_XSLT_TREE:
14414 if (res->nodesetval == NULL)
14416 return(res->nodesetval->nodeNr != 0);
14418 return((res->stringval != NULL) &&
14419 (xmlStrlen(res->stringval) != 0));
14427 * xmlXPathEvaluatePredicateResult:
14428 * @ctxt: the XPath Parser context
14429 * @res: the Predicate Expression evaluation result
14431 * Evaluate a predicate result for the current node.
14432 * A PredicateExpr is evaluated by evaluating the Expr and converting
14433 * the result to a boolean. If the result is a number, the result will
14434 * be converted to true if the number is equal to the position of the
14435 * context node in the context node list (as returned by the position
14436 * function) and will be converted to false otherwise; if the result
14437 * is not a number, then the result will be converted as if by a call
14438 * to the boolean function.
14440 * Returns 1 if predicate is true, 0 otherwise
14443 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14444 xmlXPathObjectPtr res) {
14445 if ((ctxt == NULL) || (res == NULL)) return(0);
14446 switch (res->type) {
14447 case XPATH_BOOLEAN:
14448 return(res->boolval);
14450 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14451 return((res->floatval == ctxt->context->proximityPosition) &&
14452 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14454 return(res->floatval == ctxt->context->proximityPosition);
14456 case XPATH_NODESET:
14457 case XPATH_XSLT_TREE:
14458 if (res->nodesetval == NULL)
14460 return(res->nodesetval->nodeNr != 0);
14462 return((res->stringval != NULL) && (res->stringval[0] != 0));
14463 #ifdef LIBXML_XPTR_ENABLED
14464 case XPATH_LOCATIONSET:{
14465 xmlLocationSetPtr ptr = res->user;
14468 return (ptr->locNr != 0);
14477 #ifdef XPATH_STREAMING
14479 * xmlXPathTryStreamCompile:
14480 * @ctxt: an XPath context
14481 * @str: the XPath expression
14483 * Try to compile the XPath expression as a streamable subset.
14485 * Returns the compiled expression or NULL if failed to compile.
14487 static xmlXPathCompExprPtr
14488 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14490 * Optimization: use streaming patterns when the XPath expression can
14491 * be compiled to a stream lookup
14493 xmlPatternPtr stream;
14494 xmlXPathCompExprPtr comp;
14495 xmlDictPtr dict = NULL;
14496 const xmlChar **namespaces = NULL;
14500 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14501 (!xmlStrchr(str, '@'))) {
14502 const xmlChar *tmp;
14505 * We don't try to handle expressions using the verbose axis
14506 * specifiers ("::"), just the simplied form at this point.
14507 * Additionally, if there is no list of namespaces available and
14508 * there's a ":" in the expression, indicating a prefixed QName,
14509 * then we won't try to compile either. xmlPatterncompile() needs
14510 * to have a list of namespaces at compilation time in order to
14511 * compile prefixed name tests.
14513 tmp = xmlStrchr(str, ':');
14514 if ((tmp != NULL) &&
14515 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14518 if (ctxt != NULL) {
14520 if (ctxt->nsNr > 0) {
14521 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14522 if (namespaces == NULL) {
14523 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14526 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14527 ns = ctxt->namespaces[j];
14528 namespaces[i++] = ns->href;
14529 namespaces[i++] = ns->prefix;
14531 namespaces[i++] = NULL;
14532 namespaces[i] = NULL;
14536 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14538 if (namespaces != NULL) {
14539 xmlFree((xmlChar **)namespaces);
14541 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14542 comp = xmlXPathNewCompExpr();
14543 if (comp == NULL) {
14544 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14547 comp->stream = stream;
14550 xmlDictReference(comp->dict);
14553 xmlFreePattern(stream);
14557 #endif /* XPATH_STREAMING */
14560 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14565 if ((*expr == '/') && (*(++expr) == '/'))
14571 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14574 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14575 * internal representation.
14577 if (op->ch1 != -1) {
14578 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14579 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14580 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14581 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14584 * This is a "child::foo"
14586 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14588 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14589 (prevop->ch1 != -1) &&
14590 ((xmlXPathAxisVal) prevop->value ==
14591 AXIS_DESCENDANT_OR_SELF) &&
14592 (prevop->ch2 == -1) &&
14593 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14594 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14595 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14598 * This is a "/descendant-or-self::node()" without predicates.
14601 op->ch1 = prevop->ch1;
14602 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14606 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14609 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14613 * xmlXPathCtxtCompile:
14614 * @ctxt: an XPath context
14615 * @str: the XPath expression
14617 * Compile an XPath expression
14619 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14620 * the caller has to free the object.
14622 xmlXPathCompExprPtr
14623 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14624 xmlXPathParserContextPtr pctxt;
14625 xmlXPathCompExprPtr comp;
14627 #ifdef XPATH_STREAMING
14628 comp = xmlXPathTryStreamCompile(ctxt, str);
14635 pctxt = xmlXPathNewParserContext(str, ctxt);
14638 xmlXPathCompileExpr(pctxt, 1);
14640 if( pctxt->error != XPATH_EXPRESSION_OK )
14642 xmlXPathFreeParserContext(pctxt);
14646 if (*pctxt->cur != 0) {
14648 * aleksey: in some cases this line prints *second* error message
14649 * (see bug #78858) and probably this should be fixed.
14650 * However, we are not sure that all error messages are printed
14651 * out in other places. It's not critical so we leave it as-is for now
14653 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14656 comp = pctxt->comp;
14657 pctxt->comp = NULL;
14659 xmlXPathFreeParserContext(pctxt);
14661 if (comp != NULL) {
14662 comp->expr = xmlStrdup(str);
14663 #ifdef DEBUG_EVAL_COUNTS
14664 comp->string = xmlStrdup(str);
14667 if ((comp->expr != NULL) &&
14668 (comp->nbStep > 2) &&
14669 (comp->last >= 0) &&
14670 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14672 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14680 * @str: the XPath expression
14682 * Compile an XPath expression
14684 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14685 * the caller has to free the object.
14687 xmlXPathCompExprPtr
14688 xmlXPathCompile(const xmlChar *str) {
14689 return(xmlXPathCtxtCompile(NULL, str));
14693 * xmlXPathCompiledEvalInternal:
14694 * @comp: the compiled XPath expression
14695 * @ctxt: the XPath context
14696 * @resObj: the resulting XPath object or NULL
14697 * @toBool: 1 if only a boolean result is requested
14699 * Evaluate the Precompiled XPath expression in the given context.
14700 * The caller has to free @resObj.
14702 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14703 * the caller has to free the object.
14706 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14707 xmlXPathContextPtr ctxt,
14708 xmlXPathObjectPtr *resObj,
14711 xmlXPathParserContextPtr pctxt;
14712 #ifndef LIBXML_THREAD_ENABLED
14713 static int reentance = 0;
14717 CHECK_CTXT_NEG(ctxt)
14723 #ifndef LIBXML_THREAD_ENABLED
14726 xmlXPathDisableOptimizer = 1;
14729 #ifdef DEBUG_EVAL_COUNTS
14731 if ((comp->string != NULL) && (comp->nb > 100)) {
14732 fprintf(stderr, "100 x %s\n", comp->string);
14736 pctxt = xmlXPathCompParserContext(comp, ctxt);
14737 res = xmlXPathRunEval(pctxt, toBool);
14740 if (pctxt->value == NULL) {
14741 xmlGenericError(xmlGenericErrorContext,
14742 "xmlXPathCompiledEval: evaluation failed\n");
14745 *resObj = valuePop(pctxt);
14750 * Pop all remaining objects from the stack.
14752 if (pctxt->valueNr > 0) {
14753 xmlXPathObjectPtr tmp;
14757 tmp = valuePop(pctxt);
14760 xmlXPathReleaseObject(ctxt, tmp);
14762 } while (tmp != NULL);
14763 if ((stack != 0) &&
14764 ((toBool) || ((resObj) && (*resObj))))
14766 xmlGenericError(xmlGenericErrorContext,
14767 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14772 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14773 xmlXPathFreeObject(*resObj);
14776 pctxt->comp = NULL;
14777 xmlXPathFreeParserContext(pctxt);
14778 #ifndef LIBXML_THREAD_ENABLED
14786 * xmlXPathCompiledEval:
14787 * @comp: the compiled XPath expression
14788 * @ctx: the XPath context
14790 * Evaluate the Precompiled XPath expression in the given context.
14792 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14793 * the caller has to free the object.
14796 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14798 xmlXPathObjectPtr res = NULL;
14800 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14805 * xmlXPathCompiledEvalToBoolean:
14806 * @comp: the compiled XPath expression
14807 * @ctxt: the XPath context
14809 * Applies the XPath boolean() function on the result of the given
14810 * compiled expression.
14812 * Returns 1 if the expression evaluated to true, 0 if to false and
14813 * -1 in API and internal errors.
14816 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14817 xmlXPathContextPtr ctxt)
14819 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14823 * xmlXPathEvalExpr:
14824 * @ctxt: the XPath Parser context
14826 * Parse and evaluate an XPath expression in the given context,
14827 * then push the result on the context stack
14830 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14831 #ifdef XPATH_STREAMING
14832 xmlXPathCompExprPtr comp;
14835 if (ctxt == NULL) return;
14837 #ifdef XPATH_STREAMING
14838 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14839 if (comp != NULL) {
14840 if (ctxt->comp != NULL)
14841 xmlXPathFreeCompExpr(ctxt->comp);
14843 if (ctxt->cur != NULL)
14844 while (*ctxt->cur != 0) ctxt->cur++;
14848 xmlXPathCompileExpr(ctxt, 1);
14850 * In this scenario the expression string will sit in ctxt->base.
14852 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14853 (ctxt->comp != NULL) &&
14854 (ctxt->base != NULL) &&
14855 (ctxt->comp->nbStep > 2) &&
14856 (ctxt->comp->last >= 0) &&
14857 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14859 xmlXPathRewriteDOSExpression(ctxt->comp,
14860 &ctxt->comp->steps[ctxt->comp->last]);
14864 xmlXPathRunEval(ctxt, 0);
14869 * @str: the XPath expression
14870 * @ctx: the XPath context
14872 * Evaluate the XPath Location Path in the given context.
14874 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14875 * the caller has to free the object.
14878 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14879 xmlXPathParserContextPtr ctxt;
14880 xmlXPathObjectPtr res, tmp, init = NULL;
14887 ctxt = xmlXPathNewParserContext(str, ctx);
14890 xmlXPathEvalExpr(ctxt);
14892 if (ctxt->value == NULL) {
14893 xmlGenericError(xmlGenericErrorContext,
14894 "xmlXPathEval: evaluation failed\n");
14896 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14897 #ifdef XPATH_STREAMING
14898 && (ctxt->comp->stream == NULL)
14901 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14904 res = valuePop(ctxt);
14908 tmp = valuePop(ctxt);
14912 xmlXPathReleaseObject(ctx, tmp);
14914 } while (tmp != NULL);
14915 if ((stack != 0) && (res != NULL)) {
14916 xmlGenericError(xmlGenericErrorContext,
14917 "xmlXPathEval: %d object left on the stack\n",
14920 if (ctxt->error != XPATH_EXPRESSION_OK) {
14921 xmlXPathFreeObject(res);
14925 xmlXPathFreeParserContext(ctxt);
14930 * xmlXPathEvalExpression:
14931 * @str: the XPath expression
14932 * @ctxt: the XPath context
14934 * Evaluate the XPath expression in the given context.
14936 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14937 * the caller has to free the object.
14940 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
14941 xmlXPathParserContextPtr pctxt;
14942 xmlXPathObjectPtr res, tmp;
14949 pctxt = xmlXPathNewParserContext(str, ctxt);
14952 xmlXPathEvalExpr(pctxt);
14954 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
14955 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14958 res = valuePop(pctxt);
14961 tmp = valuePop(pctxt);
14963 xmlXPathReleaseObject(ctxt, tmp);
14966 } while (tmp != NULL);
14967 if ((stack != 0) && (res != NULL)) {
14968 xmlGenericError(xmlGenericErrorContext,
14969 "xmlXPathEvalExpression: %d object left on the stack\n",
14972 xmlXPathFreeParserContext(pctxt);
14976 /************************************************************************
14978 * Extra functions not pertaining to the XPath spec *
14980 ************************************************************************/
14982 * xmlXPathEscapeUriFunction:
14983 * @ctxt: the XPath Parser context
14984 * @nargs: the number of arguments
14986 * Implement the escape-uri() XPath function
14987 * string escape-uri(string $str, bool $escape-reserved)
14989 * This function applies the URI escaping rules defined in section 2 of [RFC
14990 * 2396] to the string supplied as $uri-part, which typically represents all
14991 * or part of a URI. The effect of the function is to replace any special
14992 * character in the string by an escape sequence of the form %xx%yy...,
14993 * where xxyy... is the hexadecimal representation of the octets used to
14994 * represent the character in UTF-8.
14996 * The set of characters that are escaped depends on the setting of the
14997 * boolean argument $escape-reserved.
14999 * If $escape-reserved is true, all characters are escaped other than lower
15000 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15001 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15002 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15003 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15006 * If $escape-reserved is false, the behavior differs in that characters
15007 * referred to in [RFC 2396] as reserved characters are not escaped. These
15008 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15010 * [RFC 2396] does not define whether escaped URIs should use lower case or
15011 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15012 * compared using string comparison functions, this function must always use
15013 * the upper-case letters A-F.
15015 * Generally, $escape-reserved should be set to true when escaping a string
15016 * that is to form a single part of a URI, and to false when escaping an
15017 * entire URI or URI reference.
15019 * In the case of non-ascii characters, the string is encoded according to
15020 * utf-8 and then converted according to RFC 2396.
15023 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15024 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15025 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15026 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15030 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15031 xmlXPathObjectPtr str;
15032 int escape_reserved;
15033 xmlBufferPtr target;
15039 escape_reserved = xmlXPathPopBoolean(ctxt);
15042 str = valuePop(ctxt);
15044 target = xmlBufferCreate();
15050 for (cptr = str->stringval; *cptr; cptr++) {
15051 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15052 (*cptr >= 'a' && *cptr <= 'z') ||
15053 (*cptr >= '0' && *cptr <= '9') ||
15054 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15055 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15056 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15058 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15059 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15060 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15061 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15062 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15063 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15064 (!escape_reserved &&
15065 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15066 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15067 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15069 xmlBufferAdd(target, cptr, 1);
15071 if ((*cptr >> 4) < 10)
15072 escape[1] = '0' + (*cptr >> 4);
15074 escape[1] = 'A' - 10 + (*cptr >> 4);
15075 if ((*cptr & 0xF) < 10)
15076 escape[2] = '0' + (*cptr & 0xF);
15078 escape[2] = 'A' - 10 + (*cptr & 0xF);
15080 xmlBufferAdd(target, &escape[0], 3);
15084 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15085 xmlBufferContent(target)));
15086 xmlBufferFree(target);
15087 xmlXPathReleaseObject(ctxt->context, str);
15091 * xmlXPathRegisterAllFunctions:
15092 * @ctxt: the XPath context
15094 * Registers all default XPath functions in this context
15097 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15099 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15100 xmlXPathBooleanFunction);
15101 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15102 xmlXPathCeilingFunction);
15103 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15104 xmlXPathCountFunction);
15105 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15106 xmlXPathConcatFunction);
15107 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15108 xmlXPathContainsFunction);
15109 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15110 xmlXPathIdFunction);
15111 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15112 xmlXPathFalseFunction);
15113 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15114 xmlXPathFloorFunction);
15115 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15116 xmlXPathLastFunction);
15117 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15118 xmlXPathLangFunction);
15119 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15120 xmlXPathLocalNameFunction);
15121 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15122 xmlXPathNotFunction);
15123 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15124 xmlXPathNameFunction);
15125 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15126 xmlXPathNamespaceURIFunction);
15127 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15128 xmlXPathNormalizeFunction);
15129 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15130 xmlXPathNumberFunction);
15131 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15132 xmlXPathPositionFunction);
15133 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15134 xmlXPathRoundFunction);
15135 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15136 xmlXPathStringFunction);
15137 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15138 xmlXPathStringLengthFunction);
15139 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15140 xmlXPathStartsWithFunction);
15141 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15142 xmlXPathSubstringFunction);
15143 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15144 xmlXPathSubstringBeforeFunction);
15145 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15146 xmlXPathSubstringAfterFunction);
15147 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15148 xmlXPathSumFunction);
15149 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15150 xmlXPathTrueFunction);
15151 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15152 xmlXPathTranslateFunction);
15154 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15155 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15156 xmlXPathEscapeUriFunction);
15159 #endif /* LIBXML_XPATH_ENABLED */
15160 #define bottom_xpath
15161 #include "elfgcchack.h"