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 "Stack usage errror\n",
256 "?? Unknown error ??\n" /* Must be last in the list! */
258 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
259 sizeof(xmlXPathErrorMessages[0])) - 1)
262 * @ctxt: an XPath context
263 * @extra: extra informations
265 * Handle a redefinition of attribute error
268 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
274 xmlStrPrintf(buf, 200,
275 BAD_CAST "Memory allocation failed : %s\n",
277 ctxt->lastError.message = (char *) xmlStrdup(buf);
279 ctxt->lastError.message = (char *)
280 xmlStrdup(BAD_CAST "Memory allocation failed\n");
282 ctxt->lastError.domain = XML_FROM_XPATH;
283 ctxt->lastError.code = XML_ERR_NO_MEMORY;
284 if (ctxt->error != NULL)
285 ctxt->error(ctxt->userData, &ctxt->lastError);
288 __xmlRaiseError(NULL, NULL, NULL,
289 NULL, NULL, XML_FROM_XPATH,
290 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
291 extra, NULL, NULL, 0, 0,
292 "Memory allocation failed : %s\n", extra);
294 __xmlRaiseError(NULL, NULL, NULL,
295 NULL, NULL, XML_FROM_XPATH,
296 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
297 NULL, NULL, NULL, 0, 0,
298 "Memory allocation failed\n");
303 * xmlXPathPErrMemory:
304 * @ctxt: an XPath parser context
305 * @extra: extra informations
307 * Handle a redefinition of attribute error
310 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
313 xmlXPathErrMemory(NULL, extra);
315 ctxt->error = XPATH_MEMORY_ERROR;
316 xmlXPathErrMemory(ctxt->context, extra);
322 * @ctxt: a XPath parser context
323 * @error: the error code
325 * Handle an XPath error
328 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
330 if ((error < 0) || (error > MAXERRNO))
333 __xmlRaiseError(NULL, NULL, NULL,
334 NULL, NULL, XML_FROM_XPATH,
335 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
336 XML_ERR_ERROR, NULL, 0,
337 NULL, NULL, NULL, 0, 0,
338 "%s", xmlXPathErrorMessages[error]);
342 if (ctxt->context == NULL) {
343 __xmlRaiseError(NULL, NULL, NULL,
344 NULL, NULL, XML_FROM_XPATH,
345 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
346 XML_ERR_ERROR, NULL, 0,
347 (const char *) ctxt->base, NULL, NULL,
348 ctxt->cur - ctxt->base, 0,
349 "%s", xmlXPathErrorMessages[error]);
353 /* cleanup current last error */
354 xmlResetError(&ctxt->context->lastError);
356 ctxt->context->lastError.domain = XML_FROM_XPATH;
357 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
359 ctxt->context->lastError.level = XML_ERR_ERROR;
360 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
361 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
362 ctxt->context->lastError.node = ctxt->context->debugNode;
363 if (ctxt->context->error != NULL) {
364 ctxt->context->error(ctxt->context->userData,
365 &ctxt->context->lastError);
367 __xmlRaiseError(NULL, NULL, NULL,
368 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
369 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
370 XML_ERR_ERROR, NULL, 0,
371 (const char *) ctxt->base, NULL, NULL,
372 ctxt->cur - ctxt->base, 0,
373 "%s", xmlXPathErrorMessages[error]);
380 * @ctxt: the XPath Parser context
381 * @file: the file name
382 * @line: the line number
383 * @no: the error number
385 * Formats an error message.
388 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
389 int line ATTRIBUTE_UNUSED, int no) {
390 xmlXPathErr(ctxt, no);
393 /************************************************************************
397 ************************************************************************/
402 * Pointer-list for various purposes.
404 typedef struct _xmlPointerList xmlPointerList;
405 typedef xmlPointerList *xmlPointerListPtr;
406 struct _xmlPointerList {
412 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
413 * and here, we should make the functions public.
416 xmlPointerListAddSize(xmlPointerListPtr list,
420 if (list->items == NULL) {
421 if (initialSize <= 0)
423 list->items = (void **) xmlMalloc(
424 initialSize * sizeof(void *));
425 if (list->items == NULL) {
426 xmlXPathErrMemory(NULL,
427 "xmlPointerListCreate: allocating item\n");
431 list->size = initialSize;
432 } else if (list->size <= list->number) {
434 list->items = (void **) xmlRealloc(list->items,
435 list->size * sizeof(void *));
436 if (list->items == NULL) {
437 xmlXPathErrMemory(NULL,
438 "xmlPointerListCreate: re-allocating item\n");
443 list->items[list->number++] = item;
448 * xsltPointerListCreate:
450 * Creates an xsltPointerList structure.
452 * Returns a xsltPointerList structure or NULL in case of an error.
454 static xmlPointerListPtr
455 xmlPointerListCreate(int initialSize)
457 xmlPointerListPtr ret;
459 ret = xmlMalloc(sizeof(xmlPointerList));
461 xmlXPathErrMemory(NULL,
462 "xmlPointerListCreate: allocating item\n");
465 memset(ret, 0, sizeof(xmlPointerList));
466 if (initialSize > 0) {
467 xmlPointerListAddSize(ret, NULL, initialSize);
474 * xsltPointerListFree:
476 * Frees the xsltPointerList structure. This does not free
477 * the content of the list.
480 xmlPointerListFree(xmlPointerListPtr list)
484 if (list->items != NULL)
485 xmlFree(list->items);
489 /************************************************************************
493 ************************************************************************/
510 XPATH_OP_RESET, /* 10 */
512 XPATH_OP_VALUE, /* 12 */
517 XPATH_OP_FILTER, /* 17 */
518 XPATH_OP_SORT /* 18 */
519 #ifdef LIBXML_XPTR_ENABLED
526 AXIS_ANCESTOR_OR_SELF,
530 AXIS_DESCENDANT_OR_SELF,
532 AXIS_FOLLOWING_SIBLING,
536 AXIS_PRECEDING_SIBLING,
551 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
552 NODE_TYPE_TEXT = XML_TEXT_NODE,
553 NODE_TYPE_PI = XML_PI_NODE
556 #define XP_REWRITE_DOS_CHILD_ELEM 1
558 typedef struct _xmlXPathStepOp xmlXPathStepOp;
559 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
560 struct _xmlXPathStepOp {
561 xmlXPathOp op; /* The identifier of the operation */
562 int ch1; /* First child */
563 int ch2; /* Second child */
574 struct _xmlXPathCompExpr {
575 int nbStep; /* Number of steps in this expression */
576 int maxStep; /* Maximum number of steps allocated */
577 xmlXPathStepOp *steps; /* ops for computation of this expression */
578 int last; /* index of last step in expression */
579 xmlChar *expr; /* the expression being computed */
580 xmlDictPtr dict; /* the dictionnary to use if any */
581 #ifdef DEBUG_EVAL_COUNTS
585 #ifdef XPATH_STREAMING
586 xmlPatternPtr stream;
590 /************************************************************************
592 * Forward declarations *
594 ************************************************************************/
596 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
598 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
600 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
601 xmlXPathStepOpPtr op, xmlNodePtr *first);
603 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
604 xmlXPathStepOpPtr op,
607 /************************************************************************
609 * Parser Type functions *
611 ************************************************************************/
614 * xmlXPathNewCompExpr:
616 * Create a new Xpath component
618 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
620 static xmlXPathCompExprPtr
621 xmlXPathNewCompExpr(void) {
622 xmlXPathCompExprPtr cur;
624 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
626 xmlXPathErrMemory(NULL, "allocating component\n");
629 memset(cur, 0, sizeof(xmlXPathCompExpr));
632 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
633 sizeof(xmlXPathStepOp));
634 if (cur->steps == NULL) {
635 xmlXPathErrMemory(NULL, "allocating steps\n");
639 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
641 #ifdef DEBUG_EVAL_COUNTS
648 * xmlXPathFreeCompExpr:
649 * @comp: an XPATH comp
651 * Free up the memory allocated by @comp
654 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
656 xmlXPathStepOpPtr op;
661 if (comp->dict == NULL) {
662 for (i = 0; i < comp->nbStep; i++) {
663 op = &comp->steps[i];
664 if (op->value4 != NULL) {
665 if (op->op == XPATH_OP_VALUE)
666 xmlXPathFreeObject(op->value4);
670 if (op->value5 != NULL)
674 for (i = 0; i < comp->nbStep; i++) {
675 op = &comp->steps[i];
676 if (op->value4 != NULL) {
677 if (op->op == XPATH_OP_VALUE)
678 xmlXPathFreeObject(op->value4);
681 xmlDictFree(comp->dict);
683 if (comp->steps != NULL) {
684 xmlFree(comp->steps);
686 #ifdef DEBUG_EVAL_COUNTS
687 if (comp->string != NULL) {
688 xmlFree(comp->string);
691 #ifdef XPATH_STREAMING
692 if (comp->stream != NULL) {
693 xmlFreePatternList(comp->stream);
696 if (comp->expr != NULL) {
704 * xmlXPathCompExprAdd:
705 * @comp: the compiled expression
706 * @ch1: first child index
707 * @ch2: second child index
709 * @value: the first int value
710 * @value2: the second int value
711 * @value3: the third int value
712 * @value4: the first string value
713 * @value5: the second string value
715 * Add a step to an XPath Compiled Expression
717 * Returns -1 in case of failure, the index otherwise
720 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
721 xmlXPathOp op, int value,
722 int value2, int value3, void *value4, void *value5) {
723 if (comp->nbStep >= comp->maxStep) {
724 xmlXPathStepOp *real;
727 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
728 comp->maxStep * sizeof(xmlXPathStepOp));
731 xmlXPathErrMemory(NULL, "adding step\n");
736 comp->last = comp->nbStep;
737 comp->steps[comp->nbStep].rewriteType = 0;
738 comp->steps[comp->nbStep].ch1 = ch1;
739 comp->steps[comp->nbStep].ch2 = ch2;
740 comp->steps[comp->nbStep].op = op;
741 comp->steps[comp->nbStep].value = value;
742 comp->steps[comp->nbStep].value2 = value2;
743 comp->steps[comp->nbStep].value3 = value3;
744 if ((comp->dict != NULL) &&
745 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
746 (op == XPATH_OP_COLLECT))) {
747 if (value4 != NULL) {
748 comp->steps[comp->nbStep].value4 = (xmlChar *)
749 (void *)xmlDictLookup(comp->dict, value4, -1);
752 comp->steps[comp->nbStep].value4 = NULL;
753 if (value5 != NULL) {
754 comp->steps[comp->nbStep].value5 = (xmlChar *)
755 (void *)xmlDictLookup(comp->dict, value5, -1);
758 comp->steps[comp->nbStep].value5 = NULL;
760 comp->steps[comp->nbStep].value4 = value4;
761 comp->steps[comp->nbStep].value5 = value5;
763 comp->steps[comp->nbStep].cache = NULL;
764 return(comp->nbStep++);
769 * @comp: the compiled expression
770 * @op: operation index
772 * Swaps 2 operations in the compiled expression
775 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
778 #ifndef LIBXML_THREAD_ENABLED
780 * Since this manipulates possibly shared variables, this is
781 * disabled if one detects that the library is used in a multithreaded
784 if (xmlXPathDisableOptimizer)
793 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
794 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
795 (op), (val), (val2), (val3), (val4), (val5))
796 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
797 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
798 (op), (val), (val2), (val3), (val4), (val5))
800 #define PUSH_LEAVE_EXPR(op, val, val2) \
801 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
803 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
804 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
806 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
807 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
808 (val), (val2), 0 ,NULL ,NULL)
810 /************************************************************************
812 * XPath object cache structures *
814 ************************************************************************/
816 /* #define XP_DEFAULT_CACHE_ON */
818 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
820 typedef struct _xmlXPathContextCache xmlXPathContextCache;
821 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
822 struct _xmlXPathContextCache {
823 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
824 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
825 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
826 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
827 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
833 #ifdef XP_DEBUG_OBJ_USAGE
835 int dbgCachedNodeset;
843 int dbgCachedXSLTTree;
844 int dbgCachedUndefined;
848 int dbgReusedNodeset;
856 int dbgReusedXSLTTree;
857 int dbgReusedUndefined;
862 /************************************************************************
864 * Debugging related functions *
866 ************************************************************************/
869 xmlGenericError(xmlGenericErrorContext, \
870 "Internal error at %s:%d\n", \
873 #ifdef LIBXML_DEBUG_ENABLED
875 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
879 for (i = 0;((i < depth) && (i < 25));i++)
880 shift[2 * i] = shift[2 * i + 1] = ' ';
881 shift[2 * i] = shift[2 * i + 1] = 0;
883 fprintf(output, "%s", shift);
884 fprintf(output, "Node is NULL !\n");
889 if ((cur->type == XML_DOCUMENT_NODE) ||
890 (cur->type == XML_HTML_DOCUMENT_NODE)) {
891 fprintf(output, "%s", shift);
892 fprintf(output, " /\n");
893 } else if (cur->type == XML_ATTRIBUTE_NODE)
894 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
896 xmlDebugDumpOneNode(output, cur, depth);
899 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
904 for (i = 0;((i < depth) && (i < 25));i++)
905 shift[2 * i] = shift[2 * i + 1] = ' ';
906 shift[2 * i] = shift[2 * i + 1] = 0;
908 fprintf(output, "%s", shift);
909 fprintf(output, "Node is NULL !\n");
914 while (cur != NULL) {
917 xmlDebugDumpOneNode(output, tmp, depth);
922 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
926 for (i = 0;((i < depth) && (i < 25));i++)
927 shift[2 * i] = shift[2 * i + 1] = ' ';
928 shift[2 * i] = shift[2 * i + 1] = 0;
931 fprintf(output, "%s", shift);
932 fprintf(output, "NodeSet is NULL !\n");
938 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
939 for (i = 0;i < cur->nodeNr;i++) {
940 fprintf(output, "%s", shift);
941 fprintf(output, "%d", i + 1);
942 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
948 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
952 for (i = 0;((i < depth) && (i < 25));i++)
953 shift[2 * i] = shift[2 * i + 1] = ' ';
954 shift[2 * i] = shift[2 * i + 1] = 0;
956 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
957 fprintf(output, "%s", shift);
958 fprintf(output, "Value Tree is NULL !\n");
963 fprintf(output, "%s", shift);
964 fprintf(output, "%d", i + 1);
965 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
967 #if defined(LIBXML_XPTR_ENABLED)
969 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
973 for (i = 0;((i < depth) && (i < 25));i++)
974 shift[2 * i] = shift[2 * i + 1] = ' ';
975 shift[2 * i] = shift[2 * i + 1] = 0;
978 fprintf(output, "%s", shift);
979 fprintf(output, "LocationSet is NULL !\n");
984 for (i = 0;i < cur->locNr;i++) {
985 fprintf(output, "%s", shift);
986 fprintf(output, "%d : ", i + 1);
987 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
990 #endif /* LIBXML_XPTR_ENABLED */
993 * xmlXPathDebugDumpObject:
994 * @output: the FILE * to dump the output
995 * @cur: the object to inspect
996 * @depth: indentation level
998 * Dump the content of the object for debugging purposes
1001 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1005 if (output == NULL) return;
1007 for (i = 0;((i < depth) && (i < 25));i++)
1008 shift[2 * i] = shift[2 * i + 1] = ' ';
1009 shift[2 * i] = shift[2 * i + 1] = 0;
1012 fprintf(output, "%s", shift);
1015 fprintf(output, "Object is empty (NULL)\n");
1019 case XPATH_UNDEFINED:
1020 fprintf(output, "Object is uninitialized\n");
1023 fprintf(output, "Object is a Node Set :\n");
1024 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1026 case XPATH_XSLT_TREE:
1027 fprintf(output, "Object is an XSLT value tree :\n");
1028 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1031 fprintf(output, "Object is a Boolean : ");
1032 if (cur->boolval) fprintf(output, "true\n");
1033 else fprintf(output, "false\n");
1036 switch (xmlXPathIsInf(cur->floatval)) {
1038 fprintf(output, "Object is a number : Infinity\n");
1041 fprintf(output, "Object is a number : -Infinity\n");
1044 if (xmlXPathIsNaN(cur->floatval)) {
1045 fprintf(output, "Object is a number : NaN\n");
1046 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1047 fprintf(output, "Object is a number : 0\n");
1049 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1054 fprintf(output, "Object is a string : ");
1055 xmlDebugDumpString(output, cur->stringval);
1056 fprintf(output, "\n");
1059 fprintf(output, "Object is a point : index %d in node", cur->index);
1060 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1061 fprintf(output, "\n");
1064 if ((cur->user2 == NULL) ||
1065 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1066 fprintf(output, "Object is a collapsed range :\n");
1067 fprintf(output, "%s", shift);
1068 if (cur->index >= 0)
1069 fprintf(output, "index %d in ", cur->index);
1070 fprintf(output, "node\n");
1071 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1074 fprintf(output, "Object is a range :\n");
1075 fprintf(output, "%s", shift);
1076 fprintf(output, "From ");
1077 if (cur->index >= 0)
1078 fprintf(output, "index %d in ", cur->index);
1079 fprintf(output, "node\n");
1080 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1082 fprintf(output, "%s", shift);
1083 fprintf(output, "To ");
1084 if (cur->index2 >= 0)
1085 fprintf(output, "index %d in ", cur->index2);
1086 fprintf(output, "node\n");
1087 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1089 fprintf(output, "\n");
1092 case XPATH_LOCATIONSET:
1093 #if defined(LIBXML_XPTR_ENABLED)
1094 fprintf(output, "Object is a Location Set:\n");
1095 xmlXPathDebugDumpLocationSet(output,
1096 (xmlLocationSetPtr) cur->user, depth);
1100 fprintf(output, "Object is user defined\n");
1106 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1107 xmlXPathStepOpPtr op, int depth) {
1111 for (i = 0;((i < depth) && (i < 25));i++)
1112 shift[2 * i] = shift[2 * i + 1] = ' ';
1113 shift[2 * i] = shift[2 * i + 1] = 0;
1115 fprintf(output, "%s", shift);
1117 fprintf(output, "Step is NULL\n");
1122 fprintf(output, "END"); break;
1124 fprintf(output, "AND"); break;
1126 fprintf(output, "OR"); break;
1127 case XPATH_OP_EQUAL:
1129 fprintf(output, "EQUAL =");
1131 fprintf(output, "EQUAL !=");
1135 fprintf(output, "CMP <");
1137 fprintf(output, "CMP >");
1139 fprintf(output, "=");
1143 fprintf(output, "PLUS -");
1144 else if (op->value == 1)
1145 fprintf(output, "PLUS +");
1146 else if (op->value == 2)
1147 fprintf(output, "PLUS unary -");
1148 else if (op->value == 3)
1149 fprintf(output, "PLUS unary - -");
1153 fprintf(output, "MULT *");
1154 else if (op->value == 1)
1155 fprintf(output, "MULT div");
1157 fprintf(output, "MULT mod");
1159 case XPATH_OP_UNION:
1160 fprintf(output, "UNION"); break;
1162 fprintf(output, "ROOT"); break;
1164 fprintf(output, "NODE"); break;
1165 case XPATH_OP_RESET:
1166 fprintf(output, "RESET"); break;
1168 fprintf(output, "SORT"); break;
1169 case XPATH_OP_COLLECT: {
1170 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1171 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1172 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1173 const xmlChar *prefix = op->value4;
1174 const xmlChar *name = op->value5;
1176 fprintf(output, "COLLECT ");
1179 fprintf(output, " 'ancestors' "); break;
1180 case AXIS_ANCESTOR_OR_SELF:
1181 fprintf(output, " 'ancestors-or-self' "); break;
1182 case AXIS_ATTRIBUTE:
1183 fprintf(output, " 'attributes' "); break;
1185 fprintf(output, " 'child' "); break;
1186 case AXIS_DESCENDANT:
1187 fprintf(output, " 'descendant' "); break;
1188 case AXIS_DESCENDANT_OR_SELF:
1189 fprintf(output, " 'descendant-or-self' "); break;
1190 case AXIS_FOLLOWING:
1191 fprintf(output, " 'following' "); break;
1192 case AXIS_FOLLOWING_SIBLING:
1193 fprintf(output, " 'following-siblings' "); break;
1194 case AXIS_NAMESPACE:
1195 fprintf(output, " 'namespace' "); break;
1197 fprintf(output, " 'parent' "); break;
1198 case AXIS_PRECEDING:
1199 fprintf(output, " 'preceding' "); break;
1200 case AXIS_PRECEDING_SIBLING:
1201 fprintf(output, " 'preceding-sibling' "); break;
1203 fprintf(output, " 'self' "); break;
1206 case NODE_TEST_NONE:
1207 fprintf(output, "'none' "); break;
1208 case NODE_TEST_TYPE:
1209 fprintf(output, "'type' "); break;
1211 fprintf(output, "'PI' "); break;
1213 fprintf(output, "'all' "); break;
1215 fprintf(output, "'namespace' "); break;
1216 case NODE_TEST_NAME:
1217 fprintf(output, "'name' "); break;
1220 case NODE_TYPE_NODE:
1221 fprintf(output, "'node' "); break;
1222 case NODE_TYPE_COMMENT:
1223 fprintf(output, "'comment' "); break;
1224 case NODE_TYPE_TEXT:
1225 fprintf(output, "'text' "); break;
1227 fprintf(output, "'PI' "); break;
1230 fprintf(output, "%s:", prefix);
1232 fprintf(output, "%s", (const char *) name);
1236 case XPATH_OP_VALUE: {
1237 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1239 fprintf(output, "ELEM ");
1240 xmlXPathDebugDumpObject(output, object, 0);
1243 case XPATH_OP_VARIABLE: {
1244 const xmlChar *prefix = op->value5;
1245 const xmlChar *name = op->value4;
1248 fprintf(output, "VARIABLE %s:%s", prefix, name);
1250 fprintf(output, "VARIABLE %s", name);
1253 case XPATH_OP_FUNCTION: {
1254 int nbargs = op->value;
1255 const xmlChar *prefix = op->value5;
1256 const xmlChar *name = op->value4;
1259 fprintf(output, "FUNCTION %s:%s(%d args)",
1260 prefix, name, nbargs);
1262 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1265 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1266 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1267 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1268 #ifdef LIBXML_XPTR_ENABLED
1269 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1272 fprintf(output, "UNKNOWN %d\n", op->op); return;
1274 fprintf(output, "\n");
1277 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1279 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1283 * xmlXPathDebugDumpCompExpr:
1284 * @output: the FILE * for the output
1285 * @comp: the precompiled XPath expression
1286 * @depth: the indentation level.
1288 * Dumps the tree of the compiled XPath expression.
1291 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1296 if ((output == NULL) || (comp == NULL)) return;
1298 for (i = 0;((i < depth) && (i < 25));i++)
1299 shift[2 * i] = shift[2 * i + 1] = ' ';
1300 shift[2 * i] = shift[2 * i + 1] = 0;
1302 fprintf(output, "%s", shift);
1304 fprintf(output, "Compiled Expression : %d elements\n",
1307 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1310 #ifdef XP_DEBUG_OBJ_USAGE
1313 * XPath object usage related debugging variables.
1315 static int xmlXPathDebugObjCounterUndefined = 0;
1316 static int xmlXPathDebugObjCounterNodeset = 0;
1317 static int xmlXPathDebugObjCounterBool = 0;
1318 static int xmlXPathDebugObjCounterNumber = 0;
1319 static int xmlXPathDebugObjCounterString = 0;
1320 static int xmlXPathDebugObjCounterPoint = 0;
1321 static int xmlXPathDebugObjCounterRange = 0;
1322 static int xmlXPathDebugObjCounterLocset = 0;
1323 static int xmlXPathDebugObjCounterUsers = 0;
1324 static int xmlXPathDebugObjCounterXSLTTree = 0;
1325 static int xmlXPathDebugObjCounterAll = 0;
1327 static int xmlXPathDebugObjTotalUndefined = 0;
1328 static int xmlXPathDebugObjTotalNodeset = 0;
1329 static int xmlXPathDebugObjTotalBool = 0;
1330 static int xmlXPathDebugObjTotalNumber = 0;
1331 static int xmlXPathDebugObjTotalString = 0;
1332 static int xmlXPathDebugObjTotalPoint = 0;
1333 static int xmlXPathDebugObjTotalRange = 0;
1334 static int xmlXPathDebugObjTotalLocset = 0;
1335 static int xmlXPathDebugObjTotalUsers = 0;
1336 static int xmlXPathDebugObjTotalXSLTTree = 0;
1337 static int xmlXPathDebugObjTotalAll = 0;
1339 static int xmlXPathDebugObjMaxUndefined = 0;
1340 static int xmlXPathDebugObjMaxNodeset = 0;
1341 static int xmlXPathDebugObjMaxBool = 0;
1342 static int xmlXPathDebugObjMaxNumber = 0;
1343 static int xmlXPathDebugObjMaxString = 0;
1344 static int xmlXPathDebugObjMaxPoint = 0;
1345 static int xmlXPathDebugObjMaxRange = 0;
1346 static int xmlXPathDebugObjMaxLocset = 0;
1347 static int xmlXPathDebugObjMaxUsers = 0;
1348 static int xmlXPathDebugObjMaxXSLTTree = 0;
1349 static int xmlXPathDebugObjMaxAll = 0;
1351 /* REVISIT TODO: Make this static when committing */
1353 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1356 if (ctxt->cache != NULL) {
1357 xmlXPathContextCachePtr cache =
1358 (xmlXPathContextCachePtr) ctxt->cache;
1360 cache->dbgCachedAll = 0;
1361 cache->dbgCachedNodeset = 0;
1362 cache->dbgCachedString = 0;
1363 cache->dbgCachedBool = 0;
1364 cache->dbgCachedNumber = 0;
1365 cache->dbgCachedPoint = 0;
1366 cache->dbgCachedRange = 0;
1367 cache->dbgCachedLocset = 0;
1368 cache->dbgCachedUsers = 0;
1369 cache->dbgCachedXSLTTree = 0;
1370 cache->dbgCachedUndefined = 0;
1372 cache->dbgReusedAll = 0;
1373 cache->dbgReusedNodeset = 0;
1374 cache->dbgReusedString = 0;
1375 cache->dbgReusedBool = 0;
1376 cache->dbgReusedNumber = 0;
1377 cache->dbgReusedPoint = 0;
1378 cache->dbgReusedRange = 0;
1379 cache->dbgReusedLocset = 0;
1380 cache->dbgReusedUsers = 0;
1381 cache->dbgReusedXSLTTree = 0;
1382 cache->dbgReusedUndefined = 0;
1386 xmlXPathDebugObjCounterUndefined = 0;
1387 xmlXPathDebugObjCounterNodeset = 0;
1388 xmlXPathDebugObjCounterBool = 0;
1389 xmlXPathDebugObjCounterNumber = 0;
1390 xmlXPathDebugObjCounterString = 0;
1391 xmlXPathDebugObjCounterPoint = 0;
1392 xmlXPathDebugObjCounterRange = 0;
1393 xmlXPathDebugObjCounterLocset = 0;
1394 xmlXPathDebugObjCounterUsers = 0;
1395 xmlXPathDebugObjCounterXSLTTree = 0;
1396 xmlXPathDebugObjCounterAll = 0;
1398 xmlXPathDebugObjTotalUndefined = 0;
1399 xmlXPathDebugObjTotalNodeset = 0;
1400 xmlXPathDebugObjTotalBool = 0;
1401 xmlXPathDebugObjTotalNumber = 0;
1402 xmlXPathDebugObjTotalString = 0;
1403 xmlXPathDebugObjTotalPoint = 0;
1404 xmlXPathDebugObjTotalRange = 0;
1405 xmlXPathDebugObjTotalLocset = 0;
1406 xmlXPathDebugObjTotalUsers = 0;
1407 xmlXPathDebugObjTotalXSLTTree = 0;
1408 xmlXPathDebugObjTotalAll = 0;
1410 xmlXPathDebugObjMaxUndefined = 0;
1411 xmlXPathDebugObjMaxNodeset = 0;
1412 xmlXPathDebugObjMaxBool = 0;
1413 xmlXPathDebugObjMaxNumber = 0;
1414 xmlXPathDebugObjMaxString = 0;
1415 xmlXPathDebugObjMaxPoint = 0;
1416 xmlXPathDebugObjMaxRange = 0;
1417 xmlXPathDebugObjMaxLocset = 0;
1418 xmlXPathDebugObjMaxUsers = 0;
1419 xmlXPathDebugObjMaxXSLTTree = 0;
1420 xmlXPathDebugObjMaxAll = 0;
1425 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1426 xmlXPathObjectType objType)
1431 if (ctxt->cache != NULL) {
1432 xmlXPathContextCachePtr cache =
1433 (xmlXPathContextCachePtr) ctxt->cache;
1437 cache->dbgReusedAll++;
1439 case XPATH_UNDEFINED:
1440 cache->dbgReusedUndefined++;
1443 cache->dbgReusedNodeset++;
1446 cache->dbgReusedBool++;
1449 cache->dbgReusedNumber++;
1452 cache->dbgReusedString++;
1455 cache->dbgReusedPoint++;
1458 cache->dbgReusedRange++;
1460 case XPATH_LOCATIONSET:
1461 cache->dbgReusedLocset++;
1464 cache->dbgReusedUsers++;
1466 case XPATH_XSLT_TREE:
1467 cache->dbgReusedXSLTTree++;
1476 case XPATH_UNDEFINED:
1478 xmlXPathDebugObjTotalUndefined++;
1479 xmlXPathDebugObjCounterUndefined++;
1480 if (xmlXPathDebugObjCounterUndefined >
1481 xmlXPathDebugObjMaxUndefined)
1482 xmlXPathDebugObjMaxUndefined =
1483 xmlXPathDebugObjCounterUndefined;
1487 xmlXPathDebugObjTotalNodeset++;
1488 xmlXPathDebugObjCounterNodeset++;
1489 if (xmlXPathDebugObjCounterNodeset >
1490 xmlXPathDebugObjMaxNodeset)
1491 xmlXPathDebugObjMaxNodeset =
1492 xmlXPathDebugObjCounterNodeset;
1496 xmlXPathDebugObjTotalBool++;
1497 xmlXPathDebugObjCounterBool++;
1498 if (xmlXPathDebugObjCounterBool >
1499 xmlXPathDebugObjMaxBool)
1500 xmlXPathDebugObjMaxBool =
1501 xmlXPathDebugObjCounterBool;
1505 xmlXPathDebugObjTotalNumber++;
1506 xmlXPathDebugObjCounterNumber++;
1507 if (xmlXPathDebugObjCounterNumber >
1508 xmlXPathDebugObjMaxNumber)
1509 xmlXPathDebugObjMaxNumber =
1510 xmlXPathDebugObjCounterNumber;
1514 xmlXPathDebugObjTotalString++;
1515 xmlXPathDebugObjCounterString++;
1516 if (xmlXPathDebugObjCounterString >
1517 xmlXPathDebugObjMaxString)
1518 xmlXPathDebugObjMaxString =
1519 xmlXPathDebugObjCounterString;
1523 xmlXPathDebugObjTotalPoint++;
1524 xmlXPathDebugObjCounterPoint++;
1525 if (xmlXPathDebugObjCounterPoint >
1526 xmlXPathDebugObjMaxPoint)
1527 xmlXPathDebugObjMaxPoint =
1528 xmlXPathDebugObjCounterPoint;
1532 xmlXPathDebugObjTotalRange++;
1533 xmlXPathDebugObjCounterRange++;
1534 if (xmlXPathDebugObjCounterRange >
1535 xmlXPathDebugObjMaxRange)
1536 xmlXPathDebugObjMaxRange =
1537 xmlXPathDebugObjCounterRange;
1539 case XPATH_LOCATIONSET:
1541 xmlXPathDebugObjTotalLocset++;
1542 xmlXPathDebugObjCounterLocset++;
1543 if (xmlXPathDebugObjCounterLocset >
1544 xmlXPathDebugObjMaxLocset)
1545 xmlXPathDebugObjMaxLocset =
1546 xmlXPathDebugObjCounterLocset;
1550 xmlXPathDebugObjTotalUsers++;
1551 xmlXPathDebugObjCounterUsers++;
1552 if (xmlXPathDebugObjCounterUsers >
1553 xmlXPathDebugObjMaxUsers)
1554 xmlXPathDebugObjMaxUsers =
1555 xmlXPathDebugObjCounterUsers;
1557 case XPATH_XSLT_TREE:
1559 xmlXPathDebugObjTotalXSLTTree++;
1560 xmlXPathDebugObjCounterXSLTTree++;
1561 if (xmlXPathDebugObjCounterXSLTTree >
1562 xmlXPathDebugObjMaxXSLTTree)
1563 xmlXPathDebugObjMaxXSLTTree =
1564 xmlXPathDebugObjCounterXSLTTree;
1570 xmlXPathDebugObjTotalAll++;
1571 xmlXPathDebugObjCounterAll++;
1572 if (xmlXPathDebugObjCounterAll >
1573 xmlXPathDebugObjMaxAll)
1574 xmlXPathDebugObjMaxAll =
1575 xmlXPathDebugObjCounterAll;
1579 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1580 xmlXPathObjectType objType)
1585 if (ctxt->cache != NULL) {
1586 xmlXPathContextCachePtr cache =
1587 (xmlXPathContextCachePtr) ctxt->cache;
1591 cache->dbgCachedAll++;
1593 case XPATH_UNDEFINED:
1594 cache->dbgCachedUndefined++;
1597 cache->dbgCachedNodeset++;
1600 cache->dbgCachedBool++;
1603 cache->dbgCachedNumber++;
1606 cache->dbgCachedString++;
1609 cache->dbgCachedPoint++;
1612 cache->dbgCachedRange++;
1614 case XPATH_LOCATIONSET:
1615 cache->dbgCachedLocset++;
1618 cache->dbgCachedUsers++;
1620 case XPATH_XSLT_TREE:
1621 cache->dbgCachedXSLTTree++;
1630 case XPATH_UNDEFINED:
1631 xmlXPathDebugObjCounterUndefined--;
1634 xmlXPathDebugObjCounterNodeset--;
1637 xmlXPathDebugObjCounterBool--;
1640 xmlXPathDebugObjCounterNumber--;
1643 xmlXPathDebugObjCounterString--;
1646 xmlXPathDebugObjCounterPoint--;
1649 xmlXPathDebugObjCounterRange--;
1651 case XPATH_LOCATIONSET:
1652 xmlXPathDebugObjCounterLocset--;
1655 xmlXPathDebugObjCounterUsers--;
1657 case XPATH_XSLT_TREE:
1658 xmlXPathDebugObjCounterXSLTTree--;
1663 xmlXPathDebugObjCounterAll--;
1666 /* REVISIT TODO: Make this static when committing */
1668 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
1670 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
1671 reqXSLTTree, reqUndefined;
1672 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
1673 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
1674 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
1675 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
1676 int leftObjs = xmlXPathDebugObjCounterAll;
1678 reqAll = xmlXPathDebugObjTotalAll;
1679 reqNodeset = xmlXPathDebugObjTotalNodeset;
1680 reqString = xmlXPathDebugObjTotalString;
1681 reqBool = xmlXPathDebugObjTotalBool;
1682 reqNumber = xmlXPathDebugObjTotalNumber;
1683 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
1684 reqUndefined = xmlXPathDebugObjTotalUndefined;
1686 printf("# XPath object usage:\n");
1689 if (ctxt->cache != NULL) {
1690 xmlXPathContextCachePtr cache =
1691 (xmlXPathContextCachePtr) ctxt->cache;
1693 reAll = cache->dbgReusedAll;
1695 reNodeset = cache->dbgReusedNodeset;
1696 reqNodeset += reNodeset;
1697 reString = cache->dbgReusedString;
1698 reqString += reString;
1699 reBool = cache->dbgReusedBool;
1701 reNumber = cache->dbgReusedNumber;
1702 reqNumber += reNumber;
1703 reXSLTTree = cache->dbgReusedXSLTTree;
1704 reqXSLTTree += reXSLTTree;
1705 reUndefined = cache->dbgReusedUndefined;
1706 reqUndefined += reUndefined;
1708 caAll = cache->dbgCachedAll;
1709 caBool = cache->dbgCachedBool;
1710 caNodeset = cache->dbgCachedNodeset;
1711 caString = cache->dbgCachedString;
1712 caNumber = cache->dbgCachedNumber;
1713 caXSLTTree = cache->dbgCachedXSLTTree;
1714 caUndefined = cache->dbgCachedUndefined;
1716 if (cache->nodesetObjs)
1717 leftObjs -= cache->nodesetObjs->number;
1718 if (cache->stringObjs)
1719 leftObjs -= cache->stringObjs->number;
1720 if (cache->booleanObjs)
1721 leftObjs -= cache->booleanObjs->number;
1722 if (cache->numberObjs)
1723 leftObjs -= cache->numberObjs->number;
1724 if (cache->miscObjs)
1725 leftObjs -= cache->miscObjs->number;
1730 printf("# total : %d\n", reqAll);
1731 printf("# left : %d\n", leftObjs);
1732 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
1733 printf("# reused : %d\n", reAll);
1734 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
1736 printf("# node-sets\n");
1737 printf("# total : %d\n", reqNodeset);
1738 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
1739 printf("# reused : %d\n", reNodeset);
1740 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
1742 printf("# strings\n");
1743 printf("# total : %d\n", reqString);
1744 printf("# created: %d\n", xmlXPathDebugObjTotalString);
1745 printf("# reused : %d\n", reString);
1746 printf("# max : %d\n", xmlXPathDebugObjMaxString);
1748 printf("# booleans\n");
1749 printf("# total : %d\n", reqBool);
1750 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
1751 printf("# reused : %d\n", reBool);
1752 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
1754 printf("# numbers\n");
1755 printf("# total : %d\n", reqNumber);
1756 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
1757 printf("# reused : %d\n", reNumber);
1758 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
1760 printf("# XSLT result tree fragments\n");
1761 printf("# total : %d\n", reqXSLTTree);
1762 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
1763 printf("# reused : %d\n", reXSLTTree);
1764 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
1766 printf("# undefined\n");
1767 printf("# total : %d\n", reqUndefined);
1768 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
1769 printf("# reused : %d\n", reUndefined);
1770 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
1774 #endif /* XP_DEBUG_OBJ_USAGE */
1776 #endif /* LIBXML_DEBUG_ENABLED */
1778 /************************************************************************
1780 * XPath object caching *
1782 ************************************************************************/
1787 * Create a new object cache
1789 * Returns the xmlXPathCache just allocated.
1791 static xmlXPathContextCachePtr
1792 xmlXPathNewCache(void)
1794 xmlXPathContextCachePtr ret;
1796 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1798 xmlXPathErrMemory(NULL, "creating object cache\n");
1801 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
1802 ret->maxNodeset = 100;
1803 ret->maxString = 100;
1804 ret->maxBoolean = 100;
1805 ret->maxNumber = 100;
1811 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1814 xmlXPathObjectPtr obj;
1819 for (i = 0; i < list->number; i++) {
1820 obj = list->items[i];
1822 * Note that it is already assured that we don't need to
1823 * look out for namespace nodes in the node-set.
1825 if (obj->nodesetval != NULL) {
1826 if (obj->nodesetval->nodeTab != NULL)
1827 xmlFree(obj->nodesetval->nodeTab);
1828 xmlFree(obj->nodesetval);
1831 #ifdef XP_DEBUG_OBJ_USAGE
1832 xmlXPathDebugObjCounterAll--;
1835 xmlPointerListFree(list);
1839 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1843 if (cache->nodesetObjs)
1844 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1845 if (cache->stringObjs)
1846 xmlXPathCacheFreeObjectList(cache->stringObjs);
1847 if (cache->booleanObjs)
1848 xmlXPathCacheFreeObjectList(cache->booleanObjs);
1849 if (cache->numberObjs)
1850 xmlXPathCacheFreeObjectList(cache->numberObjs);
1851 if (cache->miscObjs)
1852 xmlXPathCacheFreeObjectList(cache->miscObjs);
1857 * xmlXPathContextSetCache:
1859 * @ctxt: the XPath context
1860 * @active: enables/disables (creates/frees) the cache
1861 * @value: a value with semantics dependant on @options
1862 * @options: options (currently only the value 0 is used)
1864 * Creates/frees an object cache on the XPath context.
1865 * If activates XPath objects (xmlXPathObject) will be cached internally
1868 * 0: This will set the XPath object caching:
1870 * This will set the maximum number of XPath objects
1871 * to be cached per slot
1872 * There are 5 slots for: node-set, string, number, boolean, and
1873 * misc objects. Use <0 for the default number (100).
1874 * Other values for @options have currently no effect.
1876 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1879 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1887 xmlXPathContextCachePtr cache;
1889 if (ctxt->cache == NULL) {
1890 ctxt->cache = xmlXPathNewCache();
1891 if (ctxt->cache == NULL)
1894 cache = (xmlXPathContextCachePtr) ctxt->cache;
1898 cache->maxNodeset = value;
1899 cache->maxString = value;
1900 cache->maxNumber = value;
1901 cache->maxBoolean = value;
1902 cache->maxMisc = value;
1904 } else if (ctxt->cache != NULL) {
1905 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1912 * xmlXPathCacheWrapNodeSet:
1913 * @ctxt: the XPath context
1914 * @val: the NodePtr value
1916 * This is the cached version of xmlXPathWrapNodeSet().
1917 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1919 * Returns the created or reused object.
1921 static xmlXPathObjectPtr
1922 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1924 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1925 xmlXPathContextCachePtr cache =
1926 (xmlXPathContextCachePtr) ctxt->cache;
1928 if ((cache->miscObjs != NULL) &&
1929 (cache->miscObjs->number != 0))
1931 xmlXPathObjectPtr ret;
1933 ret = (xmlXPathObjectPtr)
1934 cache->miscObjs->items[--cache->miscObjs->number];
1935 ret->type = XPATH_NODESET;
1936 ret->nodesetval = val;
1937 #ifdef XP_DEBUG_OBJ_USAGE
1938 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
1944 return(xmlXPathWrapNodeSet(val));
1949 * xmlXPathCacheWrapString:
1950 * @ctxt: the XPath context
1951 * @val: the xmlChar * value
1953 * This is the cached version of xmlXPathWrapString().
1954 * Wraps the @val string into an XPath object.
1956 * Returns the created or reused object.
1958 static xmlXPathObjectPtr
1959 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1961 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1962 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1964 if ((cache->stringObjs != NULL) &&
1965 (cache->stringObjs->number != 0))
1968 xmlXPathObjectPtr ret;
1970 ret = (xmlXPathObjectPtr)
1971 cache->stringObjs->items[--cache->stringObjs->number];
1972 ret->type = XPATH_STRING;
1973 ret->stringval = val;
1974 #ifdef XP_DEBUG_OBJ_USAGE
1975 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1978 } else if ((cache->miscObjs != NULL) &&
1979 (cache->miscObjs->number != 0))
1981 xmlXPathObjectPtr ret;
1983 * Fallback to misc-cache.
1985 ret = (xmlXPathObjectPtr)
1986 cache->miscObjs->items[--cache->miscObjs->number];
1988 ret->type = XPATH_STRING;
1989 ret->stringval = val;
1990 #ifdef XP_DEBUG_OBJ_USAGE
1991 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
1996 return(xmlXPathWrapString(val));
2000 * xmlXPathCacheNewNodeSet:
2001 * @ctxt: the XPath context
2002 * @val: the NodePtr value
2004 * This is the cached version of xmlXPathNewNodeSet().
2005 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2006 * it with the single Node @val
2008 * Returns the created or reused object.
2010 static xmlXPathObjectPtr
2011 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2013 if ((ctxt != NULL) && (ctxt->cache)) {
2014 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2016 if ((cache->nodesetObjs != NULL) &&
2017 (cache->nodesetObjs->number != 0))
2019 xmlXPathObjectPtr ret;
2021 * Use the nodset-cache.
2023 ret = (xmlXPathObjectPtr)
2024 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2025 ret->type = XPATH_NODESET;
2028 if ((ret->nodesetval->nodeMax == 0) ||
2029 (val->type == XML_NAMESPACE_DECL))
2031 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2033 ret->nodesetval->nodeTab[0] = val;
2034 ret->nodesetval->nodeNr = 1;
2037 #ifdef XP_DEBUG_OBJ_USAGE
2038 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2041 } else if ((cache->miscObjs != NULL) &&
2042 (cache->miscObjs->number != 0))
2044 xmlXPathObjectPtr ret;
2046 * Fallback to misc-cache.
2049 ret = (xmlXPathObjectPtr)
2050 cache->miscObjs->items[--cache->miscObjs->number];
2052 ret->type = XPATH_NODESET;
2054 ret->nodesetval = xmlXPathNodeSetCreate(val);
2055 #ifdef XP_DEBUG_OBJ_USAGE
2056 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2061 return(xmlXPathNewNodeSet(val));
2065 * xmlXPathCacheNewCString:
2066 * @ctxt: the XPath context
2067 * @val: the char * value
2069 * This is the cached version of xmlXPathNewCString().
2070 * Acquire an xmlXPathObjectPtr of type string and of value @val
2072 * Returns the created or reused object.
2074 static xmlXPathObjectPtr
2075 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2077 if ((ctxt != NULL) && (ctxt->cache)) {
2078 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2080 if ((cache->stringObjs != NULL) &&
2081 (cache->stringObjs->number != 0))
2083 xmlXPathObjectPtr ret;
2085 ret = (xmlXPathObjectPtr)
2086 cache->stringObjs->items[--cache->stringObjs->number];
2088 ret->type = XPATH_STRING;
2089 ret->stringval = xmlStrdup(BAD_CAST val);
2090 #ifdef XP_DEBUG_OBJ_USAGE
2091 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2094 } else if ((cache->miscObjs != NULL) &&
2095 (cache->miscObjs->number != 0))
2097 xmlXPathObjectPtr ret;
2099 ret = (xmlXPathObjectPtr)
2100 cache->miscObjs->items[--cache->miscObjs->number];
2102 ret->type = XPATH_STRING;
2103 ret->stringval = xmlStrdup(BAD_CAST val);
2104 #ifdef XP_DEBUG_OBJ_USAGE
2105 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2110 return(xmlXPathNewCString(val));
2114 * xmlXPathCacheNewString:
2115 * @ctxt: the XPath context
2116 * @val: the xmlChar * value
2118 * This is the cached version of xmlXPathNewString().
2119 * Acquire an xmlXPathObjectPtr of type string and of value @val
2121 * Returns the created or reused object.
2123 static xmlXPathObjectPtr
2124 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2126 if ((ctxt != NULL) && (ctxt->cache)) {
2127 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2129 if ((cache->stringObjs != NULL) &&
2130 (cache->stringObjs->number != 0))
2132 xmlXPathObjectPtr ret;
2134 ret = (xmlXPathObjectPtr)
2135 cache->stringObjs->items[--cache->stringObjs->number];
2136 ret->type = XPATH_STRING;
2138 ret->stringval = xmlStrdup(val);
2140 ret->stringval = xmlStrdup((const xmlChar *)"");
2141 #ifdef XP_DEBUG_OBJ_USAGE
2142 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2145 } else if ((cache->miscObjs != NULL) &&
2146 (cache->miscObjs->number != 0))
2148 xmlXPathObjectPtr ret;
2150 ret = (xmlXPathObjectPtr)
2151 cache->miscObjs->items[--cache->miscObjs->number];
2153 ret->type = XPATH_STRING;
2155 ret->stringval = xmlStrdup(val);
2157 ret->stringval = xmlStrdup((const xmlChar *)"");
2158 #ifdef XP_DEBUG_OBJ_USAGE
2159 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2164 return(xmlXPathNewString(val));
2168 * xmlXPathCacheNewBoolean:
2169 * @ctxt: the XPath context
2170 * @val: the boolean value
2172 * This is the cached version of xmlXPathNewBoolean().
2173 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2175 * Returns the created or reused object.
2177 static xmlXPathObjectPtr
2178 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2180 if ((ctxt != NULL) && (ctxt->cache)) {
2181 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2183 if ((cache->booleanObjs != NULL) &&
2184 (cache->booleanObjs->number != 0))
2186 xmlXPathObjectPtr ret;
2188 ret = (xmlXPathObjectPtr)
2189 cache->booleanObjs->items[--cache->booleanObjs->number];
2190 ret->type = XPATH_BOOLEAN;
2191 ret->boolval = (val != 0);
2192 #ifdef XP_DEBUG_OBJ_USAGE
2193 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2196 } else if ((cache->miscObjs != NULL) &&
2197 (cache->miscObjs->number != 0))
2199 xmlXPathObjectPtr ret;
2201 ret = (xmlXPathObjectPtr)
2202 cache->miscObjs->items[--cache->miscObjs->number];
2204 ret->type = XPATH_BOOLEAN;
2205 ret->boolval = (val != 0);
2206 #ifdef XP_DEBUG_OBJ_USAGE
2207 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2212 return(xmlXPathNewBoolean(val));
2216 * xmlXPathCacheNewFloat:
2217 * @ctxt: the XPath context
2218 * @val: the double value
2220 * This is the cached version of xmlXPathNewFloat().
2221 * Acquires an xmlXPathObjectPtr of type double and of value @val
2223 * Returns the created or reused object.
2225 static xmlXPathObjectPtr
2226 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2228 if ((ctxt != NULL) && (ctxt->cache)) {
2229 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2231 if ((cache->numberObjs != NULL) &&
2232 (cache->numberObjs->number != 0))
2234 xmlXPathObjectPtr ret;
2236 ret = (xmlXPathObjectPtr)
2237 cache->numberObjs->items[--cache->numberObjs->number];
2238 ret->type = XPATH_NUMBER;
2239 ret->floatval = val;
2240 #ifdef XP_DEBUG_OBJ_USAGE
2241 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2244 } else if ((cache->miscObjs != NULL) &&
2245 (cache->miscObjs->number != 0))
2247 xmlXPathObjectPtr ret;
2249 ret = (xmlXPathObjectPtr)
2250 cache->miscObjs->items[--cache->miscObjs->number];
2252 ret->type = XPATH_NUMBER;
2253 ret->floatval = val;
2254 #ifdef XP_DEBUG_OBJ_USAGE
2255 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2260 return(xmlXPathNewFloat(val));
2264 * xmlXPathCacheConvertString:
2265 * @ctxt: the XPath context
2266 * @val: an XPath object
2268 * This is the cached version of xmlXPathConvertString().
2269 * Converts an existing object to its string() equivalent
2271 * Returns a created or reused object, the old one is freed (cached)
2272 * (or the operation is done directly on @val)
2275 static xmlXPathObjectPtr
2276 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2277 xmlChar *res = NULL;
2280 return(xmlXPathCacheNewCString(ctxt, ""));
2282 switch (val->type) {
2283 case XPATH_UNDEFINED:
2285 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2289 case XPATH_XSLT_TREE:
2290 res = xmlXPathCastNodeSetToString(val->nodesetval);
2295 res = xmlXPathCastBooleanToString(val->boolval);
2298 res = xmlXPathCastNumberToString(val->floatval);
2303 case XPATH_LOCATIONSET:
2307 xmlXPathReleaseObject(ctxt, val);
2309 return(xmlXPathCacheNewCString(ctxt, ""));
2310 return(xmlXPathCacheWrapString(ctxt, res));
2314 * xmlXPathCacheObjectCopy:
2315 * @ctxt: the XPath context
2316 * @val: the original object
2318 * This is the cached version of xmlXPathObjectCopy().
2319 * Acquire a copy of a given object
2321 * Returns a created or reused created object.
2323 static xmlXPathObjectPtr
2324 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2329 if (XP_HAS_CACHE(ctxt)) {
2330 switch (val->type) {
2332 return(xmlXPathCacheWrapNodeSet(ctxt,
2333 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2335 return(xmlXPathCacheNewString(ctxt, val->stringval));
2337 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2339 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2344 return(xmlXPathObjectCopy(val));
2348 * xmlXPathCacheConvertBoolean:
2349 * @ctxt: the XPath context
2350 * @val: an XPath object
2352 * This is the cached version of xmlXPathConvertBoolean().
2353 * Converts an existing object to its boolean() equivalent
2355 * Returns a created or reused object, the old one is freed (or the operation
2356 * is done directly on @val)
2358 static xmlXPathObjectPtr
2359 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2360 xmlXPathObjectPtr ret;
2363 return(xmlXPathCacheNewBoolean(ctxt, 0));
2364 if (val->type == XPATH_BOOLEAN)
2366 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2367 xmlXPathReleaseObject(ctxt, val);
2372 * xmlXPathCacheConvertNumber:
2373 * @ctxt: the XPath context
2374 * @val: an XPath object
2376 * This is the cached version of xmlXPathConvertNumber().
2377 * Converts an existing object to its number() equivalent
2379 * Returns a created or reused object, the old one is freed (or the operation
2380 * is done directly on @val)
2382 static xmlXPathObjectPtr
2383 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2384 xmlXPathObjectPtr ret;
2387 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2388 if (val->type == XPATH_NUMBER)
2390 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2391 xmlXPathReleaseObject(ctxt, val);
2395 /************************************************************************
2397 * Parser stacks related functions and macros *
2399 ************************************************************************/
2403 * @ctxt: an XPath parser context
2405 * Set the callee evaluation frame
2407 * Returns the previous frame value to be restored once done
2410 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2415 ret = ctxt->valueFrame;
2416 ctxt->valueFrame = ctxt->valueNr;
2422 * @ctxt: an XPath parser context
2423 * @frame: the previous frame value
2425 * Remove the callee evaluation frame
2428 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2431 if (ctxt->valueNr < ctxt->valueFrame) {
2432 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2434 ctxt->valueFrame = frame;
2439 * @ctxt: an XPath evaluation context
2441 * Pops the top XPath object from the value stack
2443 * Returns the XPath object just removed
2446 valuePop(xmlXPathParserContextPtr ctxt)
2448 xmlXPathObjectPtr ret;
2450 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2453 if (ctxt->valueNr <= ctxt->valueFrame) {
2454 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2459 if (ctxt->valueNr > 0)
2460 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2463 ret = ctxt->valueTab[ctxt->valueNr];
2464 ctxt->valueTab[ctxt->valueNr] = NULL;
2469 * @ctxt: an XPath evaluation context
2470 * @value: the XPath object
2472 * Pushes a new XPath object on top of the value stack
2474 * returns the number of items on the value stack
2477 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2479 if ((ctxt == NULL) || (value == NULL)) return(-1);
2480 if (ctxt->valueNr >= ctxt->valueMax) {
2481 xmlXPathObjectPtr *tmp;
2483 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2484 2 * ctxt->valueMax *
2485 sizeof(ctxt->valueTab[0]));
2487 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
2488 ctxt->error = XPATH_MEMORY_ERROR;
2491 ctxt->valueMax *= 2;
2492 ctxt->valueTab = tmp;
2494 ctxt->valueTab[ctxt->valueNr] = value;
2495 ctxt->value = value;
2496 return (ctxt->valueNr++);
2500 * xmlXPathPopBoolean:
2501 * @ctxt: an XPath parser context
2503 * Pops a boolean from the stack, handling conversion if needed.
2504 * Check error with #xmlXPathCheckError.
2506 * Returns the boolean
2509 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2510 xmlXPathObjectPtr obj;
2513 obj = valuePop(ctxt);
2515 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2518 if (obj->type != XPATH_BOOLEAN)
2519 ret = xmlXPathCastToBoolean(obj);
2522 xmlXPathReleaseObject(ctxt->context, obj);
2527 * xmlXPathPopNumber:
2528 * @ctxt: an XPath parser context
2530 * Pops a number from the stack, handling conversion if needed.
2531 * Check error with #xmlXPathCheckError.
2533 * Returns the number
2536 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2537 xmlXPathObjectPtr obj;
2540 obj = valuePop(ctxt);
2542 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2545 if (obj->type != XPATH_NUMBER)
2546 ret = xmlXPathCastToNumber(obj);
2548 ret = obj->floatval;
2549 xmlXPathReleaseObject(ctxt->context, obj);
2554 * xmlXPathPopString:
2555 * @ctxt: an XPath parser context
2557 * Pops a string from the stack, handling conversion if needed.
2558 * Check error with #xmlXPathCheckError.
2560 * Returns the string
2563 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2564 xmlXPathObjectPtr obj;
2567 obj = valuePop(ctxt);
2569 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2572 ret = xmlXPathCastToString(obj); /* this does required strdup */
2573 /* TODO: needs refactoring somewhere else */
2574 if (obj->stringval == ret)
2575 obj->stringval = NULL;
2576 xmlXPathReleaseObject(ctxt->context, obj);
2581 * xmlXPathPopNodeSet:
2582 * @ctxt: an XPath parser context
2584 * Pops a node-set from the stack, handling conversion if needed.
2585 * Check error with #xmlXPathCheckError.
2587 * Returns the node-set
2590 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2591 xmlXPathObjectPtr obj;
2594 if (ctxt == NULL) return(NULL);
2595 if (ctxt->value == NULL) {
2596 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2599 if (!xmlXPathStackIsNodeSet(ctxt)) {
2600 xmlXPathSetTypeError(ctxt);
2603 obj = valuePop(ctxt);
2604 ret = obj->nodesetval;
2606 /* to fix memory leak of not clearing obj->user */
2607 if (obj->boolval && obj->user != NULL)
2608 xmlFreeNodeList((xmlNodePtr) obj->user);
2610 obj->nodesetval = NULL;
2611 xmlXPathReleaseObject(ctxt->context, obj);
2616 * xmlXPathPopExternal:
2617 * @ctxt: an XPath parser context
2619 * Pops an external object from the stack, handling conversion if needed.
2620 * Check error with #xmlXPathCheckError.
2622 * Returns the object
2625 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2626 xmlXPathObjectPtr obj;
2629 if ((ctxt == NULL) || (ctxt->value == NULL)) {
2630 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2633 if (ctxt->value->type != XPATH_USERS) {
2634 xmlXPathSetTypeError(ctxt);
2637 obj = valuePop(ctxt);
2640 xmlXPathReleaseObject(ctxt->context, obj);
2645 * Macros for accessing the content. Those should be used only by the parser,
2648 * Dirty macros, i.e. one need to make assumption on the context to use them
2650 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2651 * CUR returns the current xmlChar value, i.e. a 8 bit value
2652 * in ISO-Latin or UTF-8.
2653 * This should be used internally by the parser
2654 * only to compare to ASCII values otherwise it would break when
2655 * running with UTF-8 encoding.
2656 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2657 * to compare on ASCII based substring.
2658 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2659 * strings within the parser.
2660 * CURRENT Returns the current char value, with the full decoding of
2661 * UTF-8 if we are using this mode. It returns an int.
2662 * NEXT Skip to the next character, this does the proper decoding
2663 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2664 * It returns the pointer to the current xmlChar.
2667 #define CUR (*ctxt->cur)
2668 #define SKIP(val) ctxt->cur += (val)
2669 #define NXT(val) ctxt->cur[(val)]
2670 #define CUR_PTR ctxt->cur
2671 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2673 #define COPY_BUF(l,b,i,v) \
2674 if (l == 1) b[i++] = (xmlChar) v; \
2675 else i += xmlCopyChar(l,&b[i],v)
2677 #define NEXTL(l) ctxt->cur += l
2679 #define SKIP_BLANKS \
2680 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2682 #define CURRENT (*ctxt->cur)
2683 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2690 #define DBL_EPSILON 1E-9
2693 #define UPPER_DOUBLE 1E9
2694 #define LOWER_DOUBLE 1E-5
2695 #define LOWER_DOUBLE_EXP 5
2697 #define INTEGER_DIGITS DBL_DIG
2698 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2699 #define EXPONENT_DIGITS (3 + 2)
2702 * xmlXPathFormatNumber:
2703 * @number: number to format
2704 * @buffer: output buffer
2705 * @buffersize: size of output buffer
2707 * Convert the number into a string representation.
2710 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2712 switch (xmlXPathIsInf(number)) {
2714 if (buffersize > (int)sizeof("Infinity"))
2715 snprintf(buffer, buffersize, "Infinity");
2718 if (buffersize > (int)sizeof("-Infinity"))
2719 snprintf(buffer, buffersize, "-Infinity");
2722 if (xmlXPathIsNaN(number)) {
2723 if (buffersize > (int)sizeof("NaN"))
2724 snprintf(buffer, buffersize, "NaN");
2725 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
2726 snprintf(buffer, buffersize, "0");
2727 } else if (number == ((int) number)) {
2730 int value = (int) number;
2736 snprintf(work, 29, "%d", value);
2738 while ((*cur) && (ptr - buffer < buffersize)) {
2742 if (ptr - buffer < buffersize) {
2744 } else if (buffersize > 0) {
2750 For the dimension of work,
2751 DBL_DIG is number of significant digits
2752 EXPONENT is only needed for "scientific notation"
2753 3 is sign, decimal point, and terminating zero
2754 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2755 Note that this dimension is slightly (a few characters)
2756 larger than actually necessary.
2758 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2759 int integer_place, fraction_place;
2761 char *after_fraction;
2762 double absolute_value;
2765 absolute_value = fabs(number);
2768 * First choose format - scientific or regular floating point.
2769 * In either case, result is in work, and after_fraction points
2770 * just past the fractional part.
2772 if ( ((absolute_value > UPPER_DOUBLE) ||
2773 (absolute_value < LOWER_DOUBLE)) &&
2774 (absolute_value != 0.0) ) {
2775 /* Use scientific notation */
2776 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2777 fraction_place = DBL_DIG - 1;
2778 size = snprintf(work, sizeof(work),"%*.*e",
2779 integer_place, fraction_place, number);
2780 while ((size > 0) && (work[size] != 'e')) size--;
2784 /* Use regular notation */
2785 if (absolute_value > 0.0) {
2786 integer_place = (int)log10(absolute_value);
2787 if (integer_place > 0)
2788 fraction_place = DBL_DIG - integer_place - 1;
2790 fraction_place = DBL_DIG - integer_place;
2794 size = snprintf(work, sizeof(work), "%0.*f",
2795 fraction_place, number);
2798 /* Remove fractional trailing zeroes */
2799 after_fraction = work + size;
2800 ptr = after_fraction;
2801 while (*(--ptr) == '0')
2805 while ((*ptr++ = *after_fraction++) != 0);
2807 /* Finally copy result back to caller */
2808 size = strlen(work) + 1;
2809 if (size > buffersize) {
2810 work[buffersize - 1] = 0;
2813 memmove(buffer, work, size);
2820 /************************************************************************
2822 * Routines to handle NodeSets *
2824 ************************************************************************/
2827 * xmlXPathOrderDocElems:
2828 * @doc: an input document
2830 * Call this routine to speed up XPath computation on static documents.
2831 * This stamps all the element nodes with the document order
2832 * Like for line information, the order is kept in the element->content
2833 * field, the value stored is actually - the node number (starting at -1)
2834 * to be able to differentiate from line numbers.
2836 * Returns the number of elements found in the document or -1 in case
2840 xmlXPathOrderDocElems(xmlDocPtr doc) {
2846 cur = doc->children;
2847 while (cur != NULL) {
2848 if (cur->type == XML_ELEMENT_NODE) {
2849 cur->content = (void *) (-(++count));
2850 if (cur->children != NULL) {
2851 cur = cur->children;
2855 if (cur->next != NULL) {
2863 if (cur == (xmlNodePtr) doc) {
2867 if (cur->next != NULL) {
2871 } while (cur != NULL);
2878 * @node1: the first node
2879 * @node2: the second node
2881 * Compare two nodes w.r.t document order
2883 * Returns -2 in case of error 1 if first point < second point, 0 if
2884 * it's the same node, -1 otherwise
2887 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2889 int attr1 = 0, attr2 = 0;
2890 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2891 xmlNodePtr cur, root;
2893 if ((node1 == NULL) || (node2 == NULL))
2896 * a couple of optimizations which will avoid computations in most cases
2898 if (node1 == node2) /* trivial case */
2900 if (node1->type == XML_ATTRIBUTE_NODE) {
2903 node1 = node1->parent;
2905 if (node2->type == XML_ATTRIBUTE_NODE) {
2908 node2 = node2->parent;
2910 if (node1 == node2) {
2911 if (attr1 == attr2) {
2912 /* not required, but we keep attributes in order */
2914 cur = attrNode2->prev;
2915 while (cur != NULL) {
2916 if (cur == attrNode1)
2928 if ((node1->type == XML_NAMESPACE_DECL) ||
2929 (node2->type == XML_NAMESPACE_DECL))
2931 if (node1 == node2->prev)
2933 if (node1 == node2->next)
2937 * Speedup using document order if availble.
2939 if ((node1->type == XML_ELEMENT_NODE) &&
2940 (node2->type == XML_ELEMENT_NODE) &&
2941 (0 > (long) node1->content) &&
2942 (0 > (long) node2->content) &&
2943 (node1->doc == node2->doc)) {
2946 l1 = -((long) node1->content);
2947 l2 = -((long) node2->content);
2955 * compute depth to root
2957 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2963 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2969 * Distinct document (or distinct entities :-( ) case.
2975 * get the nearest common ancestor.
2977 while (depth1 > depth2) {
2979 node1 = node1->parent;
2981 while (depth2 > depth1) {
2983 node2 = node2->parent;
2985 while (node1->parent != node2->parent) {
2986 node1 = node1->parent;
2987 node2 = node2->parent;
2988 /* should not happen but just in case ... */
2989 if ((node1 == NULL) || (node2 == NULL))
2995 if (node1 == node2->prev)
2997 if (node1 == node2->next)
3000 * Speedup using document order if availble.
3002 if ((node1->type == XML_ELEMENT_NODE) &&
3003 (node2->type == XML_ELEMENT_NODE) &&
3004 (0 > (long) node1->content) &&
3005 (0 > (long) node2->content) &&
3006 (node1->doc == node2->doc)) {
3009 l1 = -((long) node1->content);
3010 l2 = -((long) node2->content);
3017 for (cur = node1->next;cur != NULL;cur = cur->next)
3020 return(-1); /* assume there is no sibling list corruption */
3023 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3025 * xmlXPathCmpNodesExt:
3026 * @node1: the first node
3027 * @node2: the second node
3029 * Compare two nodes w.r.t document order.
3030 * This one is optimized for handling of non-element nodes.
3032 * Returns -2 in case of error 1 if first point < second point, 0 if
3033 * it's the same node, -1 otherwise
3036 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
3038 int misc = 0, precedence1 = 0, precedence2 = 0;
3039 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
3040 xmlNodePtr cur, root;
3043 if ((node1 == NULL) || (node2 == NULL))
3050 * a couple of optimizations which will avoid computations in most cases
3052 switch (node1->type) {
3053 case XML_ELEMENT_NODE:
3054 if (node2->type == XML_ELEMENT_NODE) {
3055 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
3056 (0 > (long) node2->content) &&
3057 (node1->doc == node2->doc))
3059 l1 = -((long) node1->content);
3060 l2 = -((long) node2->content);
3066 goto turtle_comparison;
3069 case XML_ATTRIBUTE_NODE:
3070 precedence1 = 1; /* element is owner */
3072 node1 = node1->parent;
3076 case XML_CDATA_SECTION_NODE:
3077 case XML_COMMENT_NODE:
3081 * Find nearest element node.
3083 if (node1->prev != NULL) {
3085 node1 = node1->prev;
3086 if (node1->type == XML_ELEMENT_NODE) {
3087 precedence1 = 3; /* element in prev-sibl axis */
3090 if (node1->prev == NULL) {
3091 precedence1 = 2; /* element is parent */
3093 * URGENT TODO: Are there any cases, where the
3094 * parent of such a node is not an element node?
3096 node1 = node1->parent;
3101 precedence1 = 2; /* element is parent */
3102 node1 = node1->parent;
3104 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
3105 (0 <= (long) node1->content)) {
3107 * Fallback for whatever case.
3115 case XML_NAMESPACE_DECL:
3117 * TODO: why do we return 1 for namespace nodes?
3123 switch (node2->type) {
3124 case XML_ELEMENT_NODE:
3126 case XML_ATTRIBUTE_NODE:
3127 precedence2 = 1; /* element is owner */
3129 node2 = node2->parent;
3133 case XML_CDATA_SECTION_NODE:
3134 case XML_COMMENT_NODE:
3137 if (node2->prev != NULL) {
3139 node2 = node2->prev;
3140 if (node2->type == XML_ELEMENT_NODE) {
3141 precedence2 = 3; /* element in prev-sibl axis */
3144 if (node2->prev == NULL) {
3145 precedence2 = 2; /* element is parent */
3146 node2 = node2->parent;
3151 precedence2 = 2; /* element is parent */
3152 node2 = node2->parent;
3154 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
3155 (0 <= (long) node1->content))
3163 case XML_NAMESPACE_DECL:
3169 if (node1 == node2) {
3170 if (precedence1 == precedence2) {
3172 * The ugly case; but normally there aren't many
3173 * adjacent non-element nodes around.
3175 cur = miscNode2->prev;
3176 while (cur != NULL) {
3177 if (cur == miscNode1)
3179 if (cur->type == XML_ELEMENT_NODE)
3186 * Evaluate based on higher precedence wrt to the element.
3187 * TODO: This assumes attributes are sorted before content.
3188 * Is this 100% correct?
3190 if (precedence1 < precedence2)
3197 * Special case: One of the helper-elements is contained by the other.
3200 * <node1>Text-1(precedence1 == 2)</node1>
3202 * Text-6(precedence2 == 3)
3205 if ((precedence2 == 3) && (precedence1 > 1)) {
3206 cur = node1->parent;
3213 if ((precedence1 == 3) && (precedence2 > 1)) {
3214 cur = node2->parent;
3224 * Speedup using document order if availble.
3226 if ((node1->type == XML_ELEMENT_NODE) &&
3227 (node2->type == XML_ELEMENT_NODE) &&
3228 (0 > (long) node1->content) &&
3229 (0 > (long) node2->content) &&
3230 (node1->doc == node2->doc)) {
3232 l1 = -((long) node1->content);
3233 l2 = -((long) node2->content);
3242 if (node1 == node2->prev)
3244 if (node1 == node2->next)
3247 * compute depth to root
3249 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3255 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3261 * Distinct document (or distinct entities :-( ) case.
3267 * get the nearest common ancestor.
3269 while (depth1 > depth2) {
3271 node1 = node1->parent;
3273 while (depth2 > depth1) {
3275 node2 = node2->parent;
3277 while (node1->parent != node2->parent) {
3278 node1 = node1->parent;
3279 node2 = node2->parent;
3280 /* should not happen but just in case ... */
3281 if ((node1 == NULL) || (node2 == NULL))
3287 if (node1 == node2->prev)
3289 if (node1 == node2->next)
3292 * Speedup using document order if availble.
3294 if ((node1->type == XML_ELEMENT_NODE) &&
3295 (node2->type == XML_ELEMENT_NODE) &&
3296 (0 > (long) node1->content) &&
3297 (0 > (long) node2->content) &&
3298 (node1->doc == node2->doc)) {
3300 l1 = -((long) node1->content);
3301 l2 = -((long) node2->content);
3308 for (cur = node1->next;cur != NULL;cur = cur->next)
3311 return(-1); /* assume there is no sibling list corruption */
3313 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3316 * xmlXPathNodeSetSort:
3317 * @set: the node set
3319 * Sort the node set in document order
3322 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3323 int i, j, incr, len;
3329 /* Use Shell's sort to sort the node-set */
3331 for (incr = len / 2; incr > 0; incr /= 2) {
3332 for (i = incr; i < len; i++) {
3335 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3336 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3337 set->nodeTab[j + incr]) == -1)
3339 if (xmlXPathCmpNodes(set->nodeTab[j],
3340 set->nodeTab[j + incr]) == -1)
3343 tmp = set->nodeTab[j];
3344 set->nodeTab[j] = set->nodeTab[j + incr];
3345 set->nodeTab[j + incr] = tmp;
3354 #define XML_NODESET_DEFAULT 10
3356 * xmlXPathNodeSetDupNs:
3357 * @node: the parent node of the namespace XPath node
3358 * @ns: the libxml namespace declaration node.
3360 * Namespace node in libxml don't match the XPath semantic. In a node set
3361 * the namespace nodes are duplicated and the next pointer is set to the
3362 * parent node in the XPath semantic.
3364 * Returns the newly created object.
3367 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3370 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3372 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3373 return((xmlNodePtr) ns);
3376 * Allocate a new Namespace and fill the fields.
3378 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3380 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3383 memset(cur, 0, sizeof(xmlNs));
3384 cur->type = XML_NAMESPACE_DECL;
3385 if (ns->href != NULL)
3386 cur->href = xmlStrdup(ns->href);
3387 if (ns->prefix != NULL)
3388 cur->prefix = xmlStrdup(ns->prefix);
3389 cur->next = (xmlNsPtr) node;
3390 return((xmlNodePtr) cur);
3394 * xmlXPathNodeSetFreeNs:
3395 * @ns: the XPath namespace node found in a nodeset.
3397 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3398 * the namespace nodes are duplicated and the next pointer is set to the
3399 * parent node in the XPath semantic. Check if such a node needs to be freed
3402 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3403 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3406 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3407 if (ns->href != NULL)
3408 xmlFree((xmlChar *)ns->href);
3409 if (ns->prefix != NULL)
3410 xmlFree((xmlChar *)ns->prefix);
3416 * xmlXPathNodeSetCreate:
3417 * @val: an initial xmlNodePtr, or NULL
3419 * Create a new xmlNodeSetPtr of type double and of value @val
3421 * Returns the newly created object.
3424 xmlXPathNodeSetCreate(xmlNodePtr val) {
3427 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3429 xmlXPathErrMemory(NULL, "creating nodeset\n");
3432 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3434 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3435 sizeof(xmlNodePtr));
3436 if (ret->nodeTab == NULL) {
3437 xmlXPathErrMemory(NULL, "creating nodeset\n");
3441 memset(ret->nodeTab, 0 ,
3442 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3443 ret->nodeMax = XML_NODESET_DEFAULT;
3444 if (val->type == XML_NAMESPACE_DECL) {
3445 xmlNsPtr ns = (xmlNsPtr) val;
3447 ret->nodeTab[ret->nodeNr++] =
3448 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3450 ret->nodeTab[ret->nodeNr++] = val;
3456 * xmlXPathNodeSetCreateSize:
3457 * @size: the initial size of the set
3459 * Create a new xmlNodeSetPtr of type double and of value @val
3461 * Returns the newly created object.
3463 static xmlNodeSetPtr
3464 xmlXPathNodeSetCreateSize(int size) {
3467 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3469 xmlXPathErrMemory(NULL, "creating nodeset\n");
3472 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3473 if (size < XML_NODESET_DEFAULT)
3474 size = XML_NODESET_DEFAULT;
3475 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3476 if (ret->nodeTab == NULL) {
3477 xmlXPathErrMemory(NULL, "creating nodeset\n");
3481 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3482 ret->nodeMax = size;
3487 * xmlXPathNodeSetContains:
3488 * @cur: the node-set
3491 * checks whether @cur contains @val
3493 * Returns true (1) if @cur contains @val, false (0) otherwise
3496 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3499 if ((cur == NULL) || (val == NULL)) return(0);
3500 if (val->type == XML_NAMESPACE_DECL) {
3501 for (i = 0; i < cur->nodeNr; i++) {
3502 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3505 ns1 = (xmlNsPtr) val;
3506 ns2 = (xmlNsPtr) cur->nodeTab[i];
3509 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3510 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3515 for (i = 0; i < cur->nodeNr; i++) {
3516 if (cur->nodeTab[i] == val)
3524 * xmlXPathNodeSetAddNs:
3525 * @cur: the initial node set
3526 * @node: the hosting node
3527 * @ns: a the namespace node
3529 * add a new namespace node to an existing NodeSet
3532 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3536 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3537 (ns->type != XML_NAMESPACE_DECL) ||
3538 (node->type != XML_ELEMENT_NODE))
3541 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3543 * prevent duplicates
3545 for (i = 0;i < cur->nodeNr;i++) {
3546 if ((cur->nodeTab[i] != NULL) &&
3547 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3548 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3549 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3554 * grow the nodeTab if needed
3556 if (cur->nodeMax == 0) {
3557 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3558 sizeof(xmlNodePtr));
3559 if (cur->nodeTab == NULL) {
3560 xmlXPathErrMemory(NULL, "growing nodeset\n");
3563 memset(cur->nodeTab, 0 ,
3564 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3565 cur->nodeMax = XML_NODESET_DEFAULT;
3566 } else if (cur->nodeNr == cur->nodeMax) {
3569 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3570 sizeof(xmlNodePtr));
3572 xmlXPathErrMemory(NULL, "growing nodeset\n");
3576 cur->nodeTab = temp;
3578 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3582 * xmlXPathNodeSetAdd:
3583 * @cur: the initial node set
3584 * @val: a new xmlNodePtr
3586 * add a new xmlNodePtr to an existing NodeSet
3589 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3592 if ((cur == NULL) || (val == NULL)) return;
3595 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3596 return; /* an XSLT fake node */
3599 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3603 for (i = 0;i < cur->nodeNr;i++)
3604 if (cur->nodeTab[i] == val) return;
3607 * grow the nodeTab if needed
3609 if (cur->nodeMax == 0) {
3610 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3611 sizeof(xmlNodePtr));
3612 if (cur->nodeTab == NULL) {
3613 xmlXPathErrMemory(NULL, "growing nodeset\n");
3616 memset(cur->nodeTab, 0 ,
3617 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3618 cur->nodeMax = XML_NODESET_DEFAULT;
3619 } else if (cur->nodeNr == cur->nodeMax) {
3622 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3623 sizeof(xmlNodePtr));
3625 xmlXPathErrMemory(NULL, "growing nodeset\n");
3629 cur->nodeTab = temp;
3631 if (val->type == XML_NAMESPACE_DECL) {
3632 xmlNsPtr ns = (xmlNsPtr) val;
3634 cur->nodeTab[cur->nodeNr++] =
3635 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3637 cur->nodeTab[cur->nodeNr++] = val;
3641 * xmlXPathNodeSetAddUnique:
3642 * @cur: the initial node set
3643 * @val: a new xmlNodePtr
3645 * add a new xmlNodePtr to an existing NodeSet, optimized version
3646 * when we are sure the node is not already in the set.
3649 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3650 if ((cur == NULL) || (val == NULL)) return;
3653 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
3654 return; /* an XSLT fake node */
3657 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3659 * grow the nodeTab if needed
3661 if (cur->nodeMax == 0) {
3662 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3663 sizeof(xmlNodePtr));
3664 if (cur->nodeTab == NULL) {
3665 xmlXPathErrMemory(NULL, "growing nodeset\n");
3668 memset(cur->nodeTab, 0 ,
3669 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3670 cur->nodeMax = XML_NODESET_DEFAULT;
3671 } else if (cur->nodeNr == cur->nodeMax) {
3674 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3675 sizeof(xmlNodePtr));
3677 xmlXPathErrMemory(NULL, "growing nodeset\n");
3680 cur->nodeTab = temp;
3683 if (val->type == XML_NAMESPACE_DECL) {
3684 xmlNsPtr ns = (xmlNsPtr) val;
3686 cur->nodeTab[cur->nodeNr++] =
3687 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3689 cur->nodeTab[cur->nodeNr++] = val;
3693 * xmlXPathNodeSetMerge:
3694 * @val1: the first NodeSet or NULL
3695 * @val2: the second NodeSet
3697 * Merges two nodesets, all nodes from @val2 are added to @val1
3698 * if @val1 is NULL, a new set is created and copied from @val2
3700 * Returns @val1 once extended or NULL in case of error.
3703 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3704 int i, j, initNr, skip;
3707 if (val2 == NULL) return(val1);
3709 val1 = xmlXPathNodeSetCreate(NULL);
3714 * TODO: The optimization won't work in every case, since
3715 * those nasty namespace nodes need to be added with
3716 * xmlXPathNodeSetDupNs() to the set; thus a pure
3717 * memcpy is not possible.
3718 * If there was a flag on the nodesetval, indicating that
3719 * some temporary nodes are in, that would be helpfull.
3722 * Optimization: Create an equally sized node-set
3723 * and memcpy the content.
3725 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3728 if (val2->nodeNr != 0) {
3729 if (val2->nodeNr == 1)
3730 *(val1->nodeTab) = *(val2->nodeTab);
3732 memcpy(val1->nodeTab, val2->nodeTab,
3733 val2->nodeNr * sizeof(xmlNodePtr));
3735 val1->nodeNr = val2->nodeNr;
3741 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3742 initNr = val1->nodeNr;
3744 for (i = 0;i < val2->nodeNr;i++) {
3745 n2 = val2->nodeTab[i];
3747 * check against duplicates
3750 for (j = 0; j < initNr; j++) {
3751 n1 = val1->nodeTab[j];
3755 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3756 (n2->type == XML_NAMESPACE_DECL)) {
3757 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3758 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3759 ((xmlNsPtr) n2)->prefix)))
3770 * grow the nodeTab if needed
3772 if (val1->nodeMax == 0) {
3773 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3774 sizeof(xmlNodePtr));
3775 if (val1->nodeTab == NULL) {
3776 xmlXPathErrMemory(NULL, "merging nodeset\n");
3779 memset(val1->nodeTab, 0 ,
3780 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3781 val1->nodeMax = XML_NODESET_DEFAULT;
3782 } else if (val1->nodeNr == val1->nodeMax) {
3785 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3786 sizeof(xmlNodePtr));
3788 xmlXPathErrMemory(NULL, "merging nodeset\n");
3791 val1->nodeTab = temp;
3794 if (n2->type == XML_NAMESPACE_DECL) {
3795 xmlNsPtr ns = (xmlNsPtr) n2;
3797 val1->nodeTab[val1->nodeNr++] =
3798 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3800 val1->nodeTab[val1->nodeNr++] = n2;
3806 #if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3808 * xmlXPathNodeSetMergeUnique:
3809 * @val1: the first NodeSet or NULL
3810 * @val2: the second NodeSet
3812 * Merges two nodesets, all nodes from @val2 are added to @val1
3813 * if @val1 is NULL, a new set is created and copied from @val2
3815 * Returns @val1 once extended or NULL in case of error.
3817 static xmlNodeSetPtr
3818 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3821 if (val2 == NULL) return(val1);
3823 val1 = xmlXPathNodeSetCreate(NULL);
3828 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3830 for (i = 0;i < val2->nodeNr;i++) {
3832 * grow the nodeTab if needed
3834 if (val1->nodeMax == 0) {
3835 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3836 sizeof(xmlNodePtr));
3837 if (val1->nodeTab == NULL) {
3838 xmlXPathErrMemory(NULL, "merging nodeset\n");
3841 memset(val1->nodeTab, 0 ,
3842 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3843 val1->nodeMax = XML_NODESET_DEFAULT;
3844 } else if (val1->nodeNr == val1->nodeMax) {
3848 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
3849 sizeof(xmlNodePtr));
3851 xmlXPathErrMemory(NULL, "merging nodeset\n");
3854 val1->nodeTab = temp;
3856 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3857 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
3859 val1->nodeTab[val1->nodeNr++] =
3860 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3862 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
3867 #endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
3870 * xmlXPathNodeSetMergeAndClear:
3871 * @set1: the first NodeSet or NULL
3872 * @set2: the second NodeSet
3873 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3875 * Merges two nodesets, all nodes from @set2 are added to @set1
3876 * if @set1 is NULL, a new set is created and copied from @set2.
3877 * Checks for duplicate nodes. Clears set2.
3879 * Returns @set1 once extended or NULL in case of error.
3881 static xmlNodeSetPtr
3882 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3885 if ((set1 == NULL) && (hasNullEntries == 0)) {
3887 * Note that doing a memcpy of the list, namespace nodes are
3888 * just assigned to set1, since set2 is cleared anyway.
3890 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3893 if (set2->nodeNr != 0) {
3894 memcpy(set1->nodeTab, set2->nodeTab,
3895 set2->nodeNr * sizeof(xmlNodePtr));
3896 set1->nodeNr = set2->nodeNr;
3899 int i, j, initNbSet1;
3903 set1 = xmlXPathNodeSetCreate(NULL);
3907 initNbSet1 = set1->nodeNr;
3908 for (i = 0;i < set2->nodeNr;i++) {
3909 n2 = set2->nodeTab[i];
3911 * Skip NULLed entries.
3918 for (j = 0; j < initNbSet1; j++) {
3919 n1 = set1->nodeTab[j];
3922 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3923 (n2->type == XML_NAMESPACE_DECL))
3925 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3926 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3927 ((xmlNsPtr) n2)->prefix)))
3930 * Free the namespace node.
3932 set2->nodeTab[i] = NULL;
3933 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3939 * grow the nodeTab if needed
3941 if (set1->nodeMax == 0) {
3942 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3943 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3944 if (set1->nodeTab == NULL) {
3945 xmlXPathErrMemory(NULL, "merging nodeset\n");
3948 memset(set1->nodeTab, 0,
3949 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3950 set1->nodeMax = XML_NODESET_DEFAULT;
3951 } else if (set1->nodeNr >= set1->nodeMax) {
3954 temp = (xmlNodePtr *) xmlRealloc(
3955 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3957 xmlXPathErrMemory(NULL, "merging nodeset\n");
3960 set1->nodeTab = temp;
3963 if (n2->type == XML_NAMESPACE_DECL) {
3964 xmlNsPtr ns = (xmlNsPtr) n2;
3966 set1->nodeTab[set1->nodeNr++] =
3967 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3969 set1->nodeTab[set1->nodeNr++] = n2;
3979 * xmlXPathNodeSetMergeAndClearNoDupls:
3980 * @set1: the first NodeSet or NULL
3981 * @set2: the second NodeSet
3982 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3984 * Merges two nodesets, all nodes from @set2 are added to @set1
3985 * if @set1 is NULL, a new set is created and copied from @set2.
3986 * Doesn't chack for duplicate nodes. Clears set2.
3988 * Returns @set1 once extended or NULL in case of error.
3990 static xmlNodeSetPtr
3991 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3996 if ((set1 == NULL) && (hasNullEntries == 0)) {
3998 * Note that doing a memcpy of the list, namespace nodes are
3999 * just assigned to set1, since set2 is cleared anyway.
4001 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4004 if (set2->nodeNr != 0) {
4005 memcpy(set1->nodeTab, set2->nodeTab,
4006 set2->nodeNr * sizeof(xmlNodePtr));
4007 set1->nodeNr = set2->nodeNr;
4014 set1 = xmlXPathNodeSetCreate(NULL);
4018 for (i = 0;i < set2->nodeNr;i++) {
4019 n2 = set2->nodeTab[i];
4021 * Skip NULLed entries.
4025 if (set1->nodeMax == 0) {
4026 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4027 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4028 if (set1->nodeTab == NULL) {
4029 xmlXPathErrMemory(NULL, "merging nodeset\n");
4032 memset(set1->nodeTab, 0,
4033 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4034 set1->nodeMax = XML_NODESET_DEFAULT;
4035 } else if (set1->nodeNr >= set1->nodeMax) {
4038 temp = (xmlNodePtr *) xmlRealloc(
4039 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4041 xmlXPathErrMemory(NULL, "merging nodeset\n");
4044 set1->nodeTab = temp;
4047 set1->nodeTab[set1->nodeNr++] = n2;
4055 * xmlXPathNodeSetDel:
4056 * @cur: the initial node set
4057 * @val: an xmlNodePtr
4059 * Removes an xmlNodePtr from an existing NodeSet
4062 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4065 if (cur == NULL) return;
4066 if (val == NULL) return;
4069 * find node in nodeTab
4071 for (i = 0;i < cur->nodeNr;i++)
4072 if (cur->nodeTab[i] == val) break;
4074 if (i >= cur->nodeNr) { /* not found */
4076 xmlGenericError(xmlGenericErrorContext,
4077 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4082 if ((cur->nodeTab[i] != NULL) &&
4083 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4084 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4086 for (;i < cur->nodeNr;i++)
4087 cur->nodeTab[i] = cur->nodeTab[i + 1];
4088 cur->nodeTab[cur->nodeNr] = NULL;
4092 * xmlXPathNodeSetRemove:
4093 * @cur: the initial node set
4094 * @val: the index to remove
4096 * Removes an entry from an existing NodeSet list.
4099 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4100 if (cur == NULL) return;
4101 if (val >= cur->nodeNr) return;
4102 if ((cur->nodeTab[val] != NULL) &&
4103 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4104 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4106 for (;val < cur->nodeNr;val++)
4107 cur->nodeTab[val] = cur->nodeTab[val + 1];
4108 cur->nodeTab[cur->nodeNr] = NULL;
4112 * xmlXPathFreeNodeSet:
4113 * @obj: the xmlNodeSetPtr to free
4115 * Free the NodeSet compound (not the actual nodes !).
4118 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4119 if (obj == NULL) return;
4120 if (obj->nodeTab != NULL) {
4123 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4124 for (i = 0;i < obj->nodeNr;i++)
4125 if ((obj->nodeTab[i] != NULL) &&
4126 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4127 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4128 xmlFree(obj->nodeTab);
4134 * xmlXPathNodeSetClear:
4135 * @set: the node set to clear
4137 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4138 * are feed), but does *not* free the list itself. Sets the length of the
4142 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4144 if ((set == NULL) || (set->nodeNr <= 0))
4146 else if (hasNsNodes) {
4150 for (i = 0; i < set->nodeNr; i++) {
4151 node = set->nodeTab[i];
4152 if ((node != NULL) &&
4153 (node->type == XML_NAMESPACE_DECL))
4154 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4161 * xmlXPathNodeSetClearFromPos:
4162 * @set: the node set to be cleared
4163 * @pos: the start position to clear from
4165 * Clears the list from temporary XPath objects (e.g. namespace nodes
4166 * are feed) starting with the entry at @pos, but does *not* free the list
4167 * itself. Sets the length of the list to @pos.
4170 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4172 if ((set == NULL) || (set->nodeNr <= 0) || (pos >= set->nodeNr))
4174 else if ((hasNsNodes)) {
4178 for (i = pos; i < set->nodeNr; i++) {
4179 node = set->nodeTab[i];
4180 if ((node != NULL) &&
4181 (node->type == XML_NAMESPACE_DECL))
4182 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4189 * xmlXPathFreeValueTree:
4190 * @obj: the xmlNodeSetPtr to free
4192 * Free the NodeSet compound and the actual tree, this is different
4193 * from xmlXPathFreeNodeSet()
4196 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4199 if (obj == NULL) return;
4201 if (obj->nodeTab != NULL) {
4202 for (i = 0;i < obj->nodeNr;i++) {
4203 if (obj->nodeTab[i] != NULL) {
4204 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4205 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4207 xmlFreeNodeList(obj->nodeTab[i]);
4211 xmlFree(obj->nodeTab);
4216 #if defined(DEBUG) || defined(DEBUG_STEP)
4218 * xmlGenericErrorContextNodeSet:
4219 * @output: a FILE * for the output
4220 * @obj: the xmlNodeSetPtr to display
4222 * Quick display of a NodeSet
4225 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4228 if (output == NULL) output = xmlGenericErrorContext;
4230 fprintf(output, "NodeSet == NULL !\n");
4233 if (obj->nodeNr == 0) {
4234 fprintf(output, "NodeSet is empty\n");
4237 if (obj->nodeTab == NULL) {
4238 fprintf(output, " nodeTab == NULL !\n");
4241 for (i = 0; i < obj->nodeNr; i++) {
4242 if (obj->nodeTab[i] == NULL) {
4243 fprintf(output, " NULL !\n");
4246 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4247 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4248 fprintf(output, " /");
4249 else if (obj->nodeTab[i]->name == NULL)
4250 fprintf(output, " noname!");
4251 else fprintf(output, " %s", obj->nodeTab[i]->name);
4253 fprintf(output, "\n");
4258 * xmlXPathNewNodeSet:
4259 * @val: the NodePtr value
4261 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4262 * it with the single Node @val
4264 * Returns the newly created object.
4267 xmlXPathNewNodeSet(xmlNodePtr val) {
4268 xmlXPathObjectPtr ret;
4270 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4272 xmlXPathErrMemory(NULL, "creating nodeset\n");
4275 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4276 ret->type = XPATH_NODESET;
4278 ret->nodesetval = xmlXPathNodeSetCreate(val);
4279 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4280 #ifdef XP_DEBUG_OBJ_USAGE
4281 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4287 * xmlXPathNewValueTree:
4288 * @val: the NodePtr value
4290 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4291 * it with the tree root @val
4293 * Returns the newly created object.
4296 xmlXPathNewValueTree(xmlNodePtr val) {
4297 xmlXPathObjectPtr ret;
4299 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4301 xmlXPathErrMemory(NULL, "creating result value tree\n");
4304 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4305 ret->type = XPATH_XSLT_TREE;
4307 ret->user = (void *) val;
4308 ret->nodesetval = xmlXPathNodeSetCreate(val);
4309 #ifdef XP_DEBUG_OBJ_USAGE
4310 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4316 * xmlXPathNewNodeSetList:
4317 * @val: an existing NodeSet
4319 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4320 * it with the Nodeset @val
4322 * Returns the newly created object.
4325 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4327 xmlXPathObjectPtr ret;
4332 else if (val->nodeTab == NULL)
4333 ret = xmlXPathNewNodeSet(NULL);
4335 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4337 for (i = 1; i < val->nodeNr; ++i)
4338 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
4345 * xmlXPathWrapNodeSet:
4346 * @val: the NodePtr value
4348 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4350 * Returns the newly created object.
4353 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4354 xmlXPathObjectPtr ret;
4356 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4358 xmlXPathErrMemory(NULL, "creating node set object\n");
4361 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4362 ret->type = XPATH_NODESET;
4363 ret->nodesetval = val;
4364 #ifdef XP_DEBUG_OBJ_USAGE
4365 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4371 * xmlXPathFreeNodeSetList:
4372 * @obj: an existing NodeSetList object
4374 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4375 * the list contrary to xmlXPathFreeObject().
4378 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4379 if (obj == NULL) return;
4380 #ifdef XP_DEBUG_OBJ_USAGE
4381 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4387 * xmlXPathDifference:
4388 * @nodes1: a node-set
4389 * @nodes2: a node-set
4391 * Implements the EXSLT - Sets difference() function:
4392 * node-set set:difference (node-set, node-set)
4394 * Returns the difference between the two node sets, or nodes1 if
4398 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4403 if (xmlXPathNodeSetIsEmpty(nodes2))
4406 ret = xmlXPathNodeSetCreate(NULL);
4407 if (xmlXPathNodeSetIsEmpty(nodes1))
4410 l1 = xmlXPathNodeSetGetLength(nodes1);
4412 for (i = 0; i < l1; i++) {
4413 cur = xmlXPathNodeSetItem(nodes1, i);
4414 if (!xmlXPathNodeSetContains(nodes2, cur))
4415 xmlXPathNodeSetAddUnique(ret, cur);
4421 * xmlXPathIntersection:
4422 * @nodes1: a node-set
4423 * @nodes2: a node-set
4425 * Implements the EXSLT - Sets intersection() function:
4426 * node-set set:intersection (node-set, node-set)
4428 * Returns a node set comprising the nodes that are within both the
4429 * node sets passed as arguments
4432 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4433 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4439 if (xmlXPathNodeSetIsEmpty(nodes1))
4441 if (xmlXPathNodeSetIsEmpty(nodes2))
4444 l1 = xmlXPathNodeSetGetLength(nodes1);
4446 for (i = 0; i < l1; i++) {
4447 cur = xmlXPathNodeSetItem(nodes1, i);
4448 if (xmlXPathNodeSetContains(nodes2, cur))
4449 xmlXPathNodeSetAddUnique(ret, cur);
4455 * xmlXPathDistinctSorted:
4456 * @nodes: a node-set, sorted by document order
4458 * Implements the EXSLT - Sets distinct() function:
4459 * node-set set:distinct (node-set)
4461 * Returns a subset of the nodes contained in @nodes, or @nodes if
4465 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4467 xmlHashTablePtr hash;
4472 if (xmlXPathNodeSetIsEmpty(nodes))
4475 ret = xmlXPathNodeSetCreate(NULL);
4478 l = xmlXPathNodeSetGetLength(nodes);
4479 hash = xmlHashCreate (l);
4480 for (i = 0; i < l; i++) {
4481 cur = xmlXPathNodeSetItem(nodes, i);
4482 strval = xmlXPathCastNodeToString(cur);
4483 if (xmlHashLookup(hash, strval) == NULL) {
4484 xmlHashAddEntry(hash, strval, strval);
4485 xmlXPathNodeSetAddUnique(ret, cur);
4490 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4496 * @nodes: a node-set
4498 * Implements the EXSLT - Sets distinct() function:
4499 * node-set set:distinct (node-set)
4500 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4501 * is called with the sorted node-set
4503 * Returns a subset of the nodes contained in @nodes, or @nodes if
4507 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4508 if (xmlXPathNodeSetIsEmpty(nodes))
4511 xmlXPathNodeSetSort(nodes);
4512 return(xmlXPathDistinctSorted(nodes));
4516 * xmlXPathHasSameNodes:
4517 * @nodes1: a node-set
4518 * @nodes2: a node-set
4520 * Implements the EXSLT - Sets has-same-nodes function:
4521 * boolean set:has-same-node(node-set, node-set)
4523 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4527 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4531 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4532 xmlXPathNodeSetIsEmpty(nodes2))
4535 l = xmlXPathNodeSetGetLength(nodes1);
4536 for (i = 0; i < l; i++) {
4537 cur = xmlXPathNodeSetItem(nodes1, i);
4538 if (xmlXPathNodeSetContains(nodes2, cur))
4545 * xmlXPathNodeLeadingSorted:
4546 * @nodes: a node-set, sorted by document order
4549 * Implements the EXSLT - Sets leading() function:
4550 * node-set set:leading (node-set, node-set)
4552 * Returns the nodes in @nodes that precede @node in document order,
4553 * @nodes if @node is NULL or an empty node-set if @nodes
4554 * doesn't contain @node
4557 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4565 ret = xmlXPathNodeSetCreate(NULL);
4568 if (xmlXPathNodeSetIsEmpty(nodes) ||
4569 (!xmlXPathNodeSetContains(nodes, node)))
4572 l = xmlXPathNodeSetGetLength(nodes);
4573 for (i = 0; i < l; i++) {
4574 cur = xmlXPathNodeSetItem(nodes, i);
4577 xmlXPathNodeSetAddUnique(ret, cur);
4583 * xmlXPathNodeLeading:
4584 * @nodes: a node-set
4587 * Implements the EXSLT - Sets leading() function:
4588 * node-set set:leading (node-set, node-set)
4589 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4592 * Returns the nodes in @nodes that precede @node in document order,
4593 * @nodes if @node is NULL or an empty node-set if @nodes
4594 * doesn't contain @node
4597 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4598 xmlXPathNodeSetSort(nodes);
4599 return(xmlXPathNodeLeadingSorted(nodes, node));
4603 * xmlXPathLeadingSorted:
4604 * @nodes1: a node-set, sorted by document order
4605 * @nodes2: a node-set, sorted by document order
4607 * Implements the EXSLT - Sets leading() function:
4608 * node-set set:leading (node-set, node-set)
4610 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4611 * in document order, @nodes1 if @nodes2 is NULL or empty or
4612 * an empty node-set if @nodes1 doesn't contain @nodes2
4615 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4616 if (xmlXPathNodeSetIsEmpty(nodes2))
4618 return(xmlXPathNodeLeadingSorted(nodes1,
4619 xmlXPathNodeSetItem(nodes2, 1)));
4624 * @nodes1: a node-set
4625 * @nodes2: a node-set
4627 * Implements the EXSLT - Sets leading() function:
4628 * node-set set:leading (node-set, node-set)
4629 * @nodes1 and @nodes2 are sorted by document order, then
4630 * #exslSetsLeadingSorted is called.
4632 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4633 * in document order, @nodes1 if @nodes2 is NULL or empty or
4634 * an empty node-set if @nodes1 doesn't contain @nodes2
4637 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4638 if (xmlXPathNodeSetIsEmpty(nodes2))
4640 if (xmlXPathNodeSetIsEmpty(nodes1))
4641 return(xmlXPathNodeSetCreate(NULL));
4642 xmlXPathNodeSetSort(nodes1);
4643 xmlXPathNodeSetSort(nodes2);
4644 return(xmlXPathNodeLeadingSorted(nodes1,
4645 xmlXPathNodeSetItem(nodes2, 1)));
4649 * xmlXPathNodeTrailingSorted:
4650 * @nodes: a node-set, sorted by document order
4653 * Implements the EXSLT - Sets trailing() function:
4654 * node-set set:trailing (node-set, node-set)
4656 * Returns the nodes in @nodes that follow @node in document order,
4657 * @nodes if @node is NULL or an empty node-set if @nodes
4658 * doesn't contain @node
4661 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4669 ret = xmlXPathNodeSetCreate(NULL);
4672 if (xmlXPathNodeSetIsEmpty(nodes) ||
4673 (!xmlXPathNodeSetContains(nodes, node)))
4676 l = xmlXPathNodeSetGetLength(nodes);
4677 for (i = l - 1; i >= 0; i--) {
4678 cur = xmlXPathNodeSetItem(nodes, i);
4681 xmlXPathNodeSetAddUnique(ret, cur);
4683 xmlXPathNodeSetSort(ret); /* bug 413451 */
4688 * xmlXPathNodeTrailing:
4689 * @nodes: a node-set
4692 * Implements the EXSLT - Sets trailing() function:
4693 * node-set set:trailing (node-set, node-set)
4694 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4697 * Returns the nodes in @nodes that follow @node in document order,
4698 * @nodes if @node is NULL or an empty node-set if @nodes
4699 * doesn't contain @node
4702 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4703 xmlXPathNodeSetSort(nodes);
4704 return(xmlXPathNodeTrailingSorted(nodes, node));
4708 * xmlXPathTrailingSorted:
4709 * @nodes1: a node-set, sorted by document order
4710 * @nodes2: a node-set, sorted by document order
4712 * Implements the EXSLT - Sets trailing() function:
4713 * node-set set:trailing (node-set, node-set)
4715 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4716 * in document order, @nodes1 if @nodes2 is NULL or empty or
4717 * an empty node-set if @nodes1 doesn't contain @nodes2
4720 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4721 if (xmlXPathNodeSetIsEmpty(nodes2))
4723 return(xmlXPathNodeTrailingSorted(nodes1,
4724 xmlXPathNodeSetItem(nodes2, 0)));
4729 * @nodes1: a node-set
4730 * @nodes2: a node-set
4732 * Implements the EXSLT - Sets trailing() function:
4733 * node-set set:trailing (node-set, node-set)
4734 * @nodes1 and @nodes2 are sorted by document order, then
4735 * #xmlXPathTrailingSorted is called.
4737 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4738 * in document order, @nodes1 if @nodes2 is NULL or empty or
4739 * an empty node-set if @nodes1 doesn't contain @nodes2
4742 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4743 if (xmlXPathNodeSetIsEmpty(nodes2))
4745 if (xmlXPathNodeSetIsEmpty(nodes1))
4746 return(xmlXPathNodeSetCreate(NULL));
4747 xmlXPathNodeSetSort(nodes1);
4748 xmlXPathNodeSetSort(nodes2);
4749 return(xmlXPathNodeTrailingSorted(nodes1,
4750 xmlXPathNodeSetItem(nodes2, 0)));
4753 /************************************************************************
4755 * Routines to handle extra functions *
4757 ************************************************************************/
4760 * xmlXPathRegisterFunc:
4761 * @ctxt: the XPath context
4762 * @name: the function name
4763 * @f: the function implementation or NULL
4765 * Register a new function. If @f is NULL it unregisters the function
4767 * Returns 0 in case of success, -1 in case of error
4770 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4771 xmlXPathFunction f) {
4772 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4776 * xmlXPathRegisterFuncNS:
4777 * @ctxt: the XPath context
4778 * @name: the function name
4779 * @ns_uri: the function namespace URI
4780 * @f: the function implementation or NULL
4782 * Register a new function. If @f is NULL it unregisters the function
4784 * Returns 0 in case of success, -1 in case of error
4787 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4788 const xmlChar *ns_uri, xmlXPathFunction f) {
4794 if (ctxt->funcHash == NULL)
4795 ctxt->funcHash = xmlHashCreate(0);
4796 if (ctxt->funcHash == NULL)
4799 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4800 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4804 * xmlXPathRegisterFuncLookup:
4805 * @ctxt: the XPath context
4806 * @f: the lookup function
4807 * @funcCtxt: the lookup data
4809 * Registers an external mechanism to do function lookup.
4812 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4813 xmlXPathFuncLookupFunc f,
4817 ctxt->funcLookupFunc = f;
4818 ctxt->funcLookupData = funcCtxt;
4822 * xmlXPathFunctionLookup:
4823 * @ctxt: the XPath context
4824 * @name: the function name
4826 * Search in the Function array of the context for the given
4829 * Returns the xmlXPathFunction or NULL if not found
4832 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4836 if (ctxt->funcLookupFunc != NULL) {
4837 xmlXPathFunction ret;
4838 xmlXPathFuncLookupFunc f;
4840 f = ctxt->funcLookupFunc;
4841 ret = f(ctxt->funcLookupData, name, NULL);
4845 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4849 * xmlXPathFunctionLookupNS:
4850 * @ctxt: the XPath context
4851 * @name: the function name
4852 * @ns_uri: the function namespace URI
4854 * Search in the Function array of the context for the given
4857 * Returns the xmlXPathFunction or NULL if not found
4860 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4861 const xmlChar *ns_uri) {
4862 xmlXPathFunction ret;
4869 if (ctxt->funcLookupFunc != NULL) {
4870 xmlXPathFuncLookupFunc f;
4872 f = ctxt->funcLookupFunc;
4873 ret = f(ctxt->funcLookupData, name, ns_uri);
4878 if (ctxt->funcHash == NULL)
4881 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4886 * xmlXPathRegisteredFuncsCleanup:
4887 * @ctxt: the XPath context
4889 * Cleanup the XPath context data associated to registered functions
4892 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4896 xmlHashFree(ctxt->funcHash, NULL);
4897 ctxt->funcHash = NULL;
4900 /************************************************************************
4902 * Routines to handle Variables *
4904 ************************************************************************/
4907 * xmlXPathRegisterVariable:
4908 * @ctxt: the XPath context
4909 * @name: the variable name
4910 * @value: the variable value or NULL
4912 * Register a new variable value. If @value is NULL it unregisters
4915 * Returns 0 in case of success, -1 in case of error
4918 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4919 xmlXPathObjectPtr value) {
4920 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4924 * xmlXPathRegisterVariableNS:
4925 * @ctxt: the XPath context
4926 * @name: the variable name
4927 * @ns_uri: the variable namespace URI
4928 * @value: the variable value or NULL
4930 * Register a new variable value. If @value is NULL it unregisters
4933 * Returns 0 in case of success, -1 in case of error
4936 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4937 const xmlChar *ns_uri,
4938 xmlXPathObjectPtr value) {
4944 if (ctxt->varHash == NULL)
4945 ctxt->varHash = xmlHashCreate(0);
4946 if (ctxt->varHash == NULL)
4949 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4950 (xmlHashDeallocator)xmlXPathFreeObject));
4951 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4953 (xmlHashDeallocator)xmlXPathFreeObject));
4957 * xmlXPathRegisterVariableLookup:
4958 * @ctxt: the XPath context
4959 * @f: the lookup function
4960 * @data: the lookup data
4962 * register an external mechanism to do variable lookup
4965 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4966 xmlXPathVariableLookupFunc f, void *data) {
4969 ctxt->varLookupFunc = f;
4970 ctxt->varLookupData = data;
4974 * xmlXPathVariableLookup:
4975 * @ctxt: the XPath context
4976 * @name: the variable name
4978 * Search in the Variable array of the context for the given
4981 * Returns a copy of the value or NULL if not found
4984 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4988 if (ctxt->varLookupFunc != NULL) {
4989 xmlXPathObjectPtr ret;
4991 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4992 (ctxt->varLookupData, name, NULL);
4995 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4999 * xmlXPathVariableLookupNS:
5000 * @ctxt: the XPath context
5001 * @name: the variable name
5002 * @ns_uri: the variable namespace URI
5004 * Search in the Variable array of the context for the given
5007 * Returns the a copy of the value or NULL if not found
5010 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5011 const xmlChar *ns_uri) {
5015 if (ctxt->varLookupFunc != NULL) {
5016 xmlXPathObjectPtr ret;
5018 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5019 (ctxt->varLookupData, name, ns_uri);
5020 if (ret != NULL) return(ret);
5023 if (ctxt->varHash == NULL)
5028 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5029 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5033 * xmlXPathRegisteredVariablesCleanup:
5034 * @ctxt: the XPath context
5036 * Cleanup the XPath context data associated to registered variables
5039 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5043 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5044 ctxt->varHash = NULL;
5048 * xmlXPathRegisterNs:
5049 * @ctxt: the XPath context
5050 * @prefix: the namespace prefix cannot be NULL or empty string
5051 * @ns_uri: the namespace name
5053 * Register a new namespace. If @ns_uri is NULL it unregisters
5056 * Returns 0 in case of success, -1 in case of error
5059 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5060 const xmlChar *ns_uri) {
5068 if (ctxt->nsHash == NULL)
5069 ctxt->nsHash = xmlHashCreate(10);
5070 if (ctxt->nsHash == NULL)
5073 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5074 (xmlHashDeallocator)xmlFree));
5075 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5076 (xmlHashDeallocator)xmlFree));
5081 * @ctxt: the XPath context
5082 * @prefix: the namespace prefix value
5084 * Search in the namespace declaration array of the context for the given
5085 * namespace name associated to the given prefix
5087 * Returns the value or NULL if not found
5090 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5096 #ifdef XML_XML_NAMESPACE
5097 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5098 return(XML_XML_NAMESPACE);
5101 if (ctxt->namespaces != NULL) {
5104 for (i = 0;i < ctxt->nsNr;i++) {
5105 if ((ctxt->namespaces[i] != NULL) &&
5106 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5107 return(ctxt->namespaces[i]->href);
5111 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5115 * xmlXPathRegisteredNsCleanup:
5116 * @ctxt: the XPath context
5118 * Cleanup the XPath context data associated to registered variables
5121 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5125 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5126 ctxt->nsHash = NULL;
5129 /************************************************************************
5131 * Routines to handle Values *
5133 ************************************************************************/
5135 /* Allocations are terrible, one needs to optimize all this !!! */
5139 * @val: the double value
5141 * Create a new xmlXPathObjectPtr of type double and of value @val
5143 * Returns the newly created object.
5146 xmlXPathNewFloat(double val) {
5147 xmlXPathObjectPtr ret;
5149 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5151 xmlXPathErrMemory(NULL, "creating float object\n");
5154 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5155 ret->type = XPATH_NUMBER;
5156 ret->floatval = val;
5157 #ifdef XP_DEBUG_OBJ_USAGE
5158 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5164 * xmlXPathNewBoolean:
5165 * @val: the boolean value
5167 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5169 * Returns the newly created object.
5172 xmlXPathNewBoolean(int val) {
5173 xmlXPathObjectPtr ret;
5175 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5177 xmlXPathErrMemory(NULL, "creating boolean object\n");
5180 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5181 ret->type = XPATH_BOOLEAN;
5182 ret->boolval = (val != 0);
5183 #ifdef XP_DEBUG_OBJ_USAGE
5184 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5190 * xmlXPathNewString:
5191 * @val: the xmlChar * value
5193 * Create a new xmlXPathObjectPtr of type string and of value @val
5195 * Returns the newly created object.
5198 xmlXPathNewString(const xmlChar *val) {
5199 xmlXPathObjectPtr ret;
5201 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5203 xmlXPathErrMemory(NULL, "creating string object\n");
5206 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5207 ret->type = XPATH_STRING;
5209 ret->stringval = xmlStrdup(val);
5211 ret->stringval = xmlStrdup((const xmlChar *)"");
5212 #ifdef XP_DEBUG_OBJ_USAGE
5213 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5219 * xmlXPathWrapString:
5220 * @val: the xmlChar * value
5222 * Wraps the @val string into an XPath object.
5224 * Returns the newly created object.
5227 xmlXPathWrapString (xmlChar *val) {
5228 xmlXPathObjectPtr ret;
5230 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5232 xmlXPathErrMemory(NULL, "creating string object\n");
5235 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5236 ret->type = XPATH_STRING;
5237 ret->stringval = val;
5238 #ifdef XP_DEBUG_OBJ_USAGE
5239 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5245 * xmlXPathNewCString:
5246 * @val: the char * value
5248 * Create a new xmlXPathObjectPtr of type string and of value @val
5250 * Returns the newly created object.
5253 xmlXPathNewCString(const char *val) {
5254 xmlXPathObjectPtr ret;
5256 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5258 xmlXPathErrMemory(NULL, "creating string object\n");
5261 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5262 ret->type = XPATH_STRING;
5263 ret->stringval = xmlStrdup(BAD_CAST val);
5264 #ifdef XP_DEBUG_OBJ_USAGE
5265 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5271 * xmlXPathWrapCString:
5272 * @val: the char * value
5274 * Wraps a string into an XPath object.
5276 * Returns the newly created object.
5279 xmlXPathWrapCString (char * val) {
5280 return(xmlXPathWrapString((xmlChar *)(val)));
5284 * xmlXPathWrapExternal:
5285 * @val: the user data
5287 * Wraps the @val data into an XPath object.
5289 * Returns the newly created object.
5292 xmlXPathWrapExternal (void *val) {
5293 xmlXPathObjectPtr ret;
5295 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5297 xmlXPathErrMemory(NULL, "creating user object\n");
5300 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5301 ret->type = XPATH_USERS;
5303 #ifdef XP_DEBUG_OBJ_USAGE
5304 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5310 * xmlXPathObjectCopy:
5311 * @val: the original object
5313 * allocate a new copy of a given object
5315 * Returns the newly created object.
5318 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5319 xmlXPathObjectPtr ret;
5324 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5326 xmlXPathErrMemory(NULL, "copying object\n");
5329 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5330 #ifdef XP_DEBUG_OBJ_USAGE
5331 xmlXPathDebugObjUsageRequested(NULL, val->type);
5333 switch (val->type) {
5340 ret->stringval = xmlStrdup(val->stringval);
5342 case XPATH_XSLT_TREE:
5345 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5346 this previous handling is no longer correct, and can cause some serious
5347 problems (ref. bug 145547)
5349 if ((val->nodesetval != NULL) &&
5350 (val->nodesetval->nodeTab != NULL)) {
5351 xmlNodePtr cur, tmp;
5355 top = xmlNewDoc(NULL);
5356 top->name = (char *)
5357 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5361 cur = val->nodesetval->nodeTab[0]->children;
5362 while (cur != NULL) {
5363 tmp = xmlDocCopyNode(cur, top, 1);
5364 xmlAddChild((xmlNodePtr) top, tmp);
5369 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5371 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5372 /* Deallocate the copied tree value */
5376 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5377 /* Do not deallocate the copied tree value */
5380 case XPATH_LOCATIONSET:
5381 #ifdef LIBXML_XPTR_ENABLED
5383 xmlLocationSetPtr loc = val->user;
5384 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5389 ret->user = val->user;
5391 case XPATH_UNDEFINED:
5392 xmlGenericError(xmlGenericErrorContext,
5393 "xmlXPathObjectCopy: unsupported type %d\n",
5401 * xmlXPathFreeObject:
5402 * @obj: the object to free
5404 * Free up an xmlXPathObjectPtr object.
5407 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5408 if (obj == NULL) return;
5409 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5412 if (obj->user != NULL) {
5413 xmlXPathFreeNodeSet(obj->nodesetval);
5414 xmlFreeNodeList((xmlNodePtr) obj->user);
5417 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5418 if (obj->nodesetval != NULL)
5419 xmlXPathFreeValueTree(obj->nodesetval);
5421 if (obj->nodesetval != NULL)
5422 xmlXPathFreeNodeSet(obj->nodesetval);
5424 #ifdef LIBXML_XPTR_ENABLED
5425 } else if (obj->type == XPATH_LOCATIONSET) {
5426 if (obj->user != NULL)
5427 xmlXPtrFreeLocationSet(obj->user);
5429 } else if (obj->type == XPATH_STRING) {
5430 if (obj->stringval != NULL)
5431 xmlFree(obj->stringval);
5433 #ifdef XP_DEBUG_OBJ_USAGE
5434 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5440 * xmlXPathReleaseObject:
5441 * @obj: the xmlXPathObjectPtr to free or to cache
5443 * Depending on the state of the cache this frees the given
5444 * XPath object or stores it in the cache.
5447 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5449 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5450 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5451 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5453 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5457 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5458 xmlXPathFreeObject(obj);
5460 xmlXPathContextCachePtr cache =
5461 (xmlXPathContextCachePtr) ctxt->cache;
5463 switch (obj->type) {
5465 case XPATH_XSLT_TREE:
5466 if (obj->nodesetval != NULL) {
5469 * It looks like the @boolval is used for
5470 * evaluation if this an XSLT Result Tree Fragment.
5471 * TODO: Check if this assumption is correct.
5473 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5474 xmlXPathFreeValueTree(obj->nodesetval);
5475 obj->nodesetval = NULL;
5476 } else if ((obj->nodesetval->nodeMax <= 40) &&
5477 (XP_CACHE_WANTS(cache->nodesetObjs,
5478 cache->maxNodeset)))
5480 XP_CACHE_ADD(cache->nodesetObjs, obj);
5483 xmlXPathFreeNodeSet(obj->nodesetval);
5484 obj->nodesetval = NULL;
5489 if (obj->stringval != NULL)
5490 xmlFree(obj->stringval);
5492 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5493 XP_CACHE_ADD(cache->stringObjs, obj);
5498 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5499 XP_CACHE_ADD(cache->booleanObjs, obj);
5504 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5505 XP_CACHE_ADD(cache->numberObjs, obj);
5509 #ifdef LIBXML_XPTR_ENABLED
5510 case XPATH_LOCATIONSET:
5511 if (obj->user != NULL) {
5512 xmlXPtrFreeLocationSet(obj->user);
5521 * Fallback to adding to the misc-objects slot.
5523 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5524 XP_CACHE_ADD(cache->miscObjs, obj);
5530 #ifdef XP_DEBUG_OBJ_USAGE
5531 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5534 if (obj->nodesetval != NULL) {
5535 xmlNodeSetPtr tmpset = obj->nodesetval;
5538 * TODO: Due to those nasty ns-nodes, we need to traverse
5539 * the list and free the ns-nodes.
5540 * URGENT TODO: Check if it's actually slowing things down.
5541 * Maybe we shouldn't try to preserve the list.
5543 if (tmpset->nodeNr > 1) {
5547 for (i = 0; i < tmpset->nodeNr; i++) {
5548 node = tmpset->nodeTab[i];
5549 if ((node != NULL) &&
5550 (node->type == XML_NAMESPACE_DECL))
5552 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5555 } else if (tmpset->nodeNr == 1) {
5556 if ((tmpset->nodeTab[0] != NULL) &&
5557 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5558 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5561 memset(obj, 0, sizeof(xmlXPathObject));
5562 obj->nodesetval = tmpset;
5564 memset(obj, 0, sizeof(xmlXPathObject));
5570 * Cache is full; free the object.
5572 if (obj->nodesetval != NULL)
5573 xmlXPathFreeNodeSet(obj->nodesetval);
5574 #ifdef XP_DEBUG_OBJ_USAGE
5575 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5583 /************************************************************************
5585 * Type Casting Routines *
5587 ************************************************************************/
5590 * xmlXPathCastBooleanToString:
5593 * Converts a boolean to its string value.
5595 * Returns a newly allocated string.
5598 xmlXPathCastBooleanToString (int val) {
5601 ret = xmlStrdup((const xmlChar *) "true");
5603 ret = xmlStrdup((const xmlChar *) "false");
5608 * xmlXPathCastNumberToString:
5611 * Converts a number to its string value.
5613 * Returns a newly allocated string.
5616 xmlXPathCastNumberToString (double val) {
5618 switch (xmlXPathIsInf(val)) {
5620 ret = xmlStrdup((const xmlChar *) "Infinity");
5623 ret = xmlStrdup((const xmlChar *) "-Infinity");
5626 if (xmlXPathIsNaN(val)) {
5627 ret = xmlStrdup((const xmlChar *) "NaN");
5628 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5629 ret = xmlStrdup((const xmlChar *) "0");
5631 /* could be improved */
5633 xmlXPathFormatNumber(val, buf, 99);
5635 ret = xmlStrdup((const xmlChar *) buf);
5642 * xmlXPathCastNodeToString:
5645 * Converts a node to its string value.
5647 * Returns a newly allocated string.
5650 xmlXPathCastNodeToString (xmlNodePtr node) {
5652 if ((ret = xmlNodeGetContent(node)) == NULL)
5653 ret = xmlStrdup((const xmlChar *) "");
5658 * xmlXPathCastNodeSetToString:
5661 * Converts a node-set to its string value.
5663 * Returns a newly allocated string.
5666 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5667 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5668 return(xmlStrdup((const xmlChar *) ""));
5671 xmlXPathNodeSetSort(ns);
5672 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5676 * xmlXPathCastToString:
5677 * @val: an XPath object
5679 * Converts an existing object to its string() equivalent
5681 * Returns the allocated string value of the object, NULL in case of error.
5682 * It's up to the caller to free the string memory with xmlFree().
5685 xmlXPathCastToString(xmlXPathObjectPtr val) {
5686 xmlChar *ret = NULL;
5689 return(xmlStrdup((const xmlChar *) ""));
5690 switch (val->type) {
5691 case XPATH_UNDEFINED:
5693 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5695 ret = xmlStrdup((const xmlChar *) "");
5698 case XPATH_XSLT_TREE:
5699 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5702 return(xmlStrdup(val->stringval));
5704 ret = xmlXPathCastBooleanToString(val->boolval);
5706 case XPATH_NUMBER: {
5707 ret = xmlXPathCastNumberToString(val->floatval);
5713 case XPATH_LOCATIONSET:
5715 ret = xmlStrdup((const xmlChar *) "");
5722 * xmlXPathConvertString:
5723 * @val: an XPath object
5725 * Converts an existing object to its string() equivalent
5727 * Returns the new object, the old one is freed (or the operation
5728 * is done directly on @val)
5731 xmlXPathConvertString(xmlXPathObjectPtr val) {
5732 xmlChar *res = NULL;
5735 return(xmlXPathNewCString(""));
5737 switch (val->type) {
5738 case XPATH_UNDEFINED:
5740 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5744 case XPATH_XSLT_TREE:
5745 res = xmlXPathCastNodeSetToString(val->nodesetval);
5750 res = xmlXPathCastBooleanToString(val->boolval);
5753 res = xmlXPathCastNumberToString(val->floatval);
5758 case XPATH_LOCATIONSET:
5762 xmlXPathFreeObject(val);
5764 return(xmlXPathNewCString(""));
5765 return(xmlXPathWrapString(res));
5769 * xmlXPathCastBooleanToNumber:
5772 * Converts a boolean to its number value
5774 * Returns the number value
5777 xmlXPathCastBooleanToNumber(int val) {
5784 * xmlXPathCastStringToNumber:
5787 * Converts a string to its number value
5789 * Returns the number value
5792 xmlXPathCastStringToNumber(const xmlChar * val) {
5793 return(xmlXPathStringEvalNumber(val));
5797 * xmlXPathCastNodeToNumber:
5800 * Converts a node to its number value
5802 * Returns the number value
5805 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5810 return(xmlXPathNAN);
5811 strval = xmlXPathCastNodeToString(node);
5813 return(xmlXPathNAN);
5814 ret = xmlXPathCastStringToNumber(strval);
5821 * xmlXPathCastNodeSetToNumber:
5824 * Converts a node-set to its number value
5826 * Returns the number value
5829 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5834 return(xmlXPathNAN);
5835 str = xmlXPathCastNodeSetToString(ns);
5836 ret = xmlXPathCastStringToNumber(str);
5842 * xmlXPathCastToNumber:
5843 * @val: an XPath object
5845 * Converts an XPath object to its number value
5847 * Returns the number value
5850 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5854 return(xmlXPathNAN);
5855 switch (val->type) {
5856 case XPATH_UNDEFINED:
5858 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5863 case XPATH_XSLT_TREE:
5864 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5867 ret = xmlXPathCastStringToNumber(val->stringval);
5870 ret = val->floatval;
5873 ret = xmlXPathCastBooleanToNumber(val->boolval);
5878 case XPATH_LOCATIONSET:
5887 * xmlXPathConvertNumber:
5888 * @val: an XPath object
5890 * Converts an existing object to its number() equivalent
5892 * Returns the new object, the old one is freed (or the operation
5893 * is done directly on @val)
5896 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5897 xmlXPathObjectPtr ret;
5900 return(xmlXPathNewFloat(0.0));
5901 if (val->type == XPATH_NUMBER)
5903 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5904 xmlXPathFreeObject(val);
5909 * xmlXPathCastNumberToBoolean:
5912 * Converts a number to its boolean value
5914 * Returns the boolean value
5917 xmlXPathCastNumberToBoolean (double val) {
5918 if (xmlXPathIsNaN(val) || (val == 0.0))
5924 * xmlXPathCastStringToBoolean:
5927 * Converts a string to its boolean value
5929 * Returns the boolean value
5932 xmlXPathCastStringToBoolean (const xmlChar *val) {
5933 if ((val == NULL) || (xmlStrlen(val) == 0))
5939 * xmlXPathCastNodeSetToBoolean:
5942 * Converts a node-set to its boolean value
5944 * Returns the boolean value
5947 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5948 if ((ns == NULL) || (ns->nodeNr == 0))
5954 * xmlXPathCastToBoolean:
5955 * @val: an XPath object
5957 * Converts an XPath object to its boolean value
5959 * Returns the boolean value
5962 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5967 switch (val->type) {
5968 case XPATH_UNDEFINED:
5970 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
5975 case XPATH_XSLT_TREE:
5976 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5979 ret = xmlXPathCastStringToBoolean(val->stringval);
5982 ret = xmlXPathCastNumberToBoolean(val->floatval);
5990 case XPATH_LOCATIONSET:
6000 * xmlXPathConvertBoolean:
6001 * @val: an XPath object
6003 * Converts an existing object to its boolean() equivalent
6005 * Returns the new object, the old one is freed (or the operation
6006 * is done directly on @val)
6009 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6010 xmlXPathObjectPtr ret;
6013 return(xmlXPathNewBoolean(0));
6014 if (val->type == XPATH_BOOLEAN)
6016 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6017 xmlXPathFreeObject(val);
6021 /************************************************************************
6023 * Routines to handle XPath contexts *
6025 ************************************************************************/
6028 * xmlXPathNewContext:
6029 * @doc: the XML document
6031 * Create a new xmlXPathContext
6033 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6036 xmlXPathNewContext(xmlDocPtr doc) {
6037 xmlXPathContextPtr ret;
6039 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6041 xmlXPathErrMemory(NULL, "creating context\n");
6044 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6048 ret->varHash = NULL;
6054 ret->funcHash = xmlHashCreate(0);
6063 ret->contextSize = -1;
6064 ret->proximityPosition = -1;
6066 #ifdef XP_DEFAULT_CACHE_ON
6067 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6068 xmlXPathFreeContext(ret);
6073 xmlXPathRegisterAllFunctions(ret);
6079 * xmlXPathFreeContext:
6080 * @ctxt: the context to free
6082 * Free up an xmlXPathContext
6085 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6086 if (ctxt == NULL) return;
6088 if (ctxt->cache != NULL)
6089 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6090 xmlXPathRegisteredNsCleanup(ctxt);
6091 xmlXPathRegisteredFuncsCleanup(ctxt);
6092 xmlXPathRegisteredVariablesCleanup(ctxt);
6093 xmlResetError(&ctxt->lastError);
6097 /************************************************************************
6099 * Routines to handle XPath parser contexts *
6101 ************************************************************************/
6103 #define CHECK_CTXT(ctxt) \
6104 if (ctxt == NULL) { \
6105 __xmlRaiseError(NULL, NULL, NULL, \
6106 NULL, NULL, XML_FROM_XPATH, \
6107 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6108 __FILE__, __LINE__, \
6109 NULL, NULL, NULL, 0, 0, \
6110 "NULL context pointer\n"); \
6114 #define CHECK_CTXT_NEG(ctxt) \
6115 if (ctxt == NULL) { \
6116 __xmlRaiseError(NULL, NULL, NULL, \
6117 NULL, NULL, XML_FROM_XPATH, \
6118 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6119 __FILE__, __LINE__, \
6120 NULL, NULL, NULL, 0, 0, \
6121 "NULL context pointer\n"); \
6126 #define CHECK_CONTEXT(ctxt) \
6127 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6128 (ctxt->doc->children == NULL)) { \
6129 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6135 * xmlXPathNewParserContext:
6136 * @str: the XPath expression
6137 * @ctxt: the XPath context
6139 * Create a new xmlXPathParserContext
6141 * Returns the xmlXPathParserContext just allocated.
6143 xmlXPathParserContextPtr
6144 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6145 xmlXPathParserContextPtr ret;
6147 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6149 xmlXPathErrMemory(ctxt, "creating parser context\n");
6152 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6153 ret->cur = ret->base = str;
6154 ret->context = ctxt;
6156 ret->comp = xmlXPathNewCompExpr();
6157 if (ret->comp == NULL) {
6158 xmlFree(ret->valueTab);
6162 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6163 ret->comp->dict = ctxt->dict;
6164 xmlDictReference(ret->comp->dict);
6171 * xmlXPathCompParserContext:
6172 * @comp: the XPath compiled expression
6173 * @ctxt: the XPath context
6175 * Create a new xmlXPathParserContext when processing a compiled expression
6177 * Returns the xmlXPathParserContext just allocated.
6179 static xmlXPathParserContextPtr
6180 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6181 xmlXPathParserContextPtr ret;
6183 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6185 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6188 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6190 /* Allocate the value stack */
6191 ret->valueTab = (xmlXPathObjectPtr *)
6192 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6193 if (ret->valueTab == NULL) {
6195 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6201 ret->valueFrame = 0;
6203 ret->context = ctxt;
6210 * xmlXPathFreeParserContext:
6211 * @ctxt: the context to free
6213 * Free up an xmlXPathParserContext
6216 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6217 if (ctxt->valueTab != NULL) {
6218 xmlFree(ctxt->valueTab);
6220 if (ctxt->comp != NULL) {
6221 #ifdef XPATH_STREAMING
6222 if (ctxt->comp->stream != NULL) {
6223 xmlFreePatternList(ctxt->comp->stream);
6224 ctxt->comp->stream = NULL;
6227 xmlXPathFreeCompExpr(ctxt->comp);
6232 /************************************************************************
6234 * The implicit core function library *
6236 ************************************************************************/
6239 * xmlXPathNodeValHash:
6240 * @node: a node pointer
6242 * Function computing the beginning of the string value of the node,
6243 * used to speed up comparisons
6245 * Returns an int usable as a hash
6248 xmlXPathNodeValHash(xmlNodePtr node) {
6250 const xmlChar * string = NULL;
6251 xmlNodePtr tmp = NULL;
6252 unsigned int ret = 0;
6257 if (node->type == XML_DOCUMENT_NODE) {
6258 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6260 node = node->children;
6268 switch (node->type) {
6269 case XML_COMMENT_NODE:
6271 case XML_CDATA_SECTION_NODE:
6273 string = node->content;
6278 return(((unsigned int) string[0]) +
6279 (((unsigned int) string[1]) << 8));
6280 case XML_NAMESPACE_DECL:
6281 string = ((xmlNsPtr)node)->href;
6286 return(((unsigned int) string[0]) +
6287 (((unsigned int) string[1]) << 8));
6288 case XML_ATTRIBUTE_NODE:
6289 tmp = ((xmlAttrPtr) node)->children;
6291 case XML_ELEMENT_NODE:
6292 tmp = node->children;
6297 while (tmp != NULL) {
6298 switch (tmp->type) {
6299 case XML_COMMENT_NODE:
6301 case XML_CDATA_SECTION_NODE:
6303 string = tmp->content;
6305 case XML_NAMESPACE_DECL:
6306 string = ((xmlNsPtr)tmp)->href;
6311 if ((string != NULL) && (string[0] != 0)) {
6313 return(ret + (((unsigned int) string[0]) << 8));
6315 if (string[1] == 0) {
6317 ret = (unsigned int) string[0];
6319 return(((unsigned int) string[0]) +
6320 (((unsigned int) string[1]) << 8));
6326 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6327 if (tmp->children->type != XML_ENTITY_DECL) {
6328 tmp = tmp->children;
6335 if (tmp->next != NULL) {
6348 if (tmp->next != NULL) {
6352 } while (tmp != NULL);
6358 * xmlXPathStringHash:
6361 * Function computing the beginning of the string value of the node,
6362 * used to speed up comparisons
6364 * Returns an int usable as a hash
6367 xmlXPathStringHash(const xmlChar * string) {
6369 return((unsigned int) 0);
6372 return(((unsigned int) string[0]) +
6373 (((unsigned int) string[1]) << 8));
6377 * xmlXPathCompareNodeSetFloat:
6378 * @ctxt: the XPath Parser context
6379 * @inf: less than (1) or greater than (0)
6380 * @strict: is the comparison strict
6381 * @arg: the node set
6384 * Implement the compare operation between a nodeset and a number
6385 * @ns < @val (1, 1, ...
6386 * @ns <= @val (1, 0, ...
6387 * @ns > @val (0, 1, ...
6388 * @ns >= @val (0, 0, ...
6390 * If one object to be compared is a node-set and the other is a number,
6391 * then the comparison will be true if and only if there is a node in the
6392 * node-set such that the result of performing the comparison on the number
6393 * to be compared and on the result of converting the string-value of that
6394 * node to a number using the number function is true.
6396 * Returns 0 or 1 depending on the results of the test.
6399 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6400 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6405 if ((f == NULL) || (arg == NULL) ||
6406 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6407 xmlXPathReleaseObject(ctxt->context, arg);
6408 xmlXPathReleaseObject(ctxt->context, f);
6411 ns = arg->nodesetval;
6413 for (i = 0;i < ns->nodeNr;i++) {
6414 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6417 xmlXPathCacheNewString(ctxt->context, str2));
6419 xmlXPathNumberFunction(ctxt, 1);
6420 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6421 ret = xmlXPathCompareValues(ctxt, inf, strict);
6427 xmlXPathReleaseObject(ctxt->context, arg);
6428 xmlXPathReleaseObject(ctxt->context, f);
6433 * xmlXPathCompareNodeSetString:
6434 * @ctxt: the XPath Parser context
6435 * @inf: less than (1) or greater than (0)
6436 * @strict: is the comparison strict
6437 * @arg: the node set
6440 * Implement the compare operation between a nodeset and a string
6441 * @ns < @val (1, 1, ...
6442 * @ns <= @val (1, 0, ...
6443 * @ns > @val (0, 1, ...
6444 * @ns >= @val (0, 0, ...
6446 * If one object to be compared is a node-set and the other is a string,
6447 * then the comparison will be true if and only if there is a node in
6448 * the node-set such that the result of performing the comparison on the
6449 * string-value of the node and the other string is true.
6451 * Returns 0 or 1 depending on the results of the test.
6454 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6455 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6460 if ((s == NULL) || (arg == NULL) ||
6461 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6462 xmlXPathReleaseObject(ctxt->context, arg);
6463 xmlXPathReleaseObject(ctxt->context, s);
6466 ns = arg->nodesetval;
6468 for (i = 0;i < ns->nodeNr;i++) {
6469 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6472 xmlXPathCacheNewString(ctxt->context, str2));
6474 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6475 ret = xmlXPathCompareValues(ctxt, inf, strict);
6481 xmlXPathReleaseObject(ctxt->context, arg);
6482 xmlXPathReleaseObject(ctxt->context, s);
6487 * xmlXPathCompareNodeSets:
6488 * @inf: less than (1) or greater than (0)
6489 * @strict: is the comparison strict
6490 * @arg1: the first node set object
6491 * @arg2: the second node set object
6493 * Implement the compare operation on nodesets:
6495 * If both objects to be compared are node-sets, then the comparison
6496 * will be true if and only if there is a node in the first node-set
6497 * and a node in the second node-set such that the result of performing
6498 * the comparison on the string-values of the two nodes is true.
6500 * When neither object to be compared is a node-set and the operator
6501 * is <=, <, >= or >, then the objects are compared by converting both
6502 * objects to numbers and comparing the numbers according to IEEE 754.
6504 * The number function converts its argument to a number as follows:
6505 * - a string that consists of optional whitespace followed by an
6506 * optional minus sign followed by a Number followed by whitespace
6507 * is converted to the IEEE 754 number that is nearest (according
6508 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6509 * represented by the string; any other string is converted to NaN
6511 * Conclusion all nodes need to be converted first to their string value
6512 * and then the comparison must be done when possible
6515 xmlXPathCompareNodeSets(int inf, int strict,
6516 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6524 if ((arg1 == NULL) ||
6525 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6526 xmlXPathFreeObject(arg2);
6529 if ((arg2 == NULL) ||
6530 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6531 xmlXPathFreeObject(arg1);
6532 xmlXPathFreeObject(arg2);
6536 ns1 = arg1->nodesetval;
6537 ns2 = arg2->nodesetval;
6539 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6540 xmlXPathFreeObject(arg1);
6541 xmlXPathFreeObject(arg2);
6544 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6545 xmlXPathFreeObject(arg1);
6546 xmlXPathFreeObject(arg2);
6550 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6551 if (values2 == NULL) {
6552 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6553 xmlXPathFreeObject(arg1);
6554 xmlXPathFreeObject(arg2);
6557 for (i = 0;i < ns1->nodeNr;i++) {
6558 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6559 if (xmlXPathIsNaN(val1))
6561 for (j = 0;j < ns2->nodeNr;j++) {
6563 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6565 if (xmlXPathIsNaN(values2[j]))
6568 ret = (val1 < values2[j]);
6569 else if (inf && !strict)
6570 ret = (val1 <= values2[j]);
6571 else if (!inf && strict)
6572 ret = (val1 > values2[j]);
6573 else if (!inf && !strict)
6574 ret = (val1 >= values2[j]);
6583 xmlXPathFreeObject(arg1);
6584 xmlXPathFreeObject(arg2);
6589 * xmlXPathCompareNodeSetValue:
6590 * @ctxt: the XPath Parser context
6591 * @inf: less than (1) or greater than (0)
6592 * @strict: is the comparison strict
6593 * @arg: the node set
6596 * Implement the compare operation between a nodeset and a value
6597 * @ns < @val (1, 1, ...
6598 * @ns <= @val (1, 0, ...
6599 * @ns > @val (0, 1, ...
6600 * @ns >= @val (0, 0, ...
6602 * If one object to be compared is a node-set and the other is a boolean,
6603 * then the comparison will be true if and only if the result of performing
6604 * the comparison on the boolean and on the result of converting
6605 * the node-set to a boolean using the boolean function is true.
6607 * Returns 0 or 1 depending on the results of the test.
6610 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6611 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6612 if ((val == NULL) || (arg == NULL) ||
6613 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6618 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6620 case XPATH_XSLT_TREE:
6621 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6623 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6625 valuePush(ctxt, arg);
6626 xmlXPathBooleanFunction(ctxt, 1);
6627 valuePush(ctxt, val);
6628 return(xmlXPathCompareValues(ctxt, inf, strict));
6636 * xmlXPathEqualNodeSetString:
6637 * @arg: the nodeset object argument
6638 * @str: the string to compare to.
6639 * @neq: flag to show whether for '=' (0) or '!=' (1)
6641 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6642 * If one object to be compared is a node-set and the other is a string,
6643 * then the comparison will be true if and only if there is a node in
6644 * the node-set such that the result of performing the comparison on the
6645 * string-value of the node and the other string is true.
6647 * Returns 0 or 1 depending on the results of the test.
6650 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6657 if ((str == NULL) || (arg == NULL) ||
6658 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6660 ns = arg->nodesetval;
6662 * A NULL nodeset compared with a string is always false
6663 * (since there is no node equal, and no node not equal)
6665 if ((ns == NULL) || (ns->nodeNr <= 0) )
6667 hash = xmlXPathStringHash(str);
6668 for (i = 0; i < ns->nodeNr; i++) {
6669 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6670 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6671 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6676 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6694 * xmlXPathEqualNodeSetFloat:
6695 * @arg: the nodeset object argument
6696 * @f: the float to compare to
6697 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6699 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6700 * If one object to be compared is a node-set and the other is a number,
6701 * then the comparison will be true if and only if there is a node in
6702 * the node-set such that the result of performing the comparison on the
6703 * number to be compared and on the result of converting the string-value
6704 * of that node to a number using the number function is true.
6706 * Returns 0 or 1 depending on the results of the test.
6709 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6710 xmlXPathObjectPtr arg, double f, int neq) {
6714 xmlXPathObjectPtr val;
6717 if ((arg == NULL) ||
6718 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6721 ns = arg->nodesetval;
6723 for (i=0;i<ns->nodeNr;i++) {
6724 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6726 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6728 xmlXPathNumberFunction(ctxt, 1);
6729 val = valuePop(ctxt);
6731 xmlXPathReleaseObject(ctxt->context, val);
6732 if (!xmlXPathIsNaN(v)) {
6733 if ((!neq) && (v==f)) {
6736 } else if ((neq) && (v!=f)) {
6740 } else { /* NaN is unequal to any value */
6753 * xmlXPathEqualNodeSets:
6754 * @arg1: first nodeset object argument
6755 * @arg2: second nodeset object argument
6756 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6758 * Implement the equal / not equal operation on XPath nodesets:
6759 * @arg1 == @arg2 or @arg1 != @arg2
6760 * If both objects to be compared are node-sets, then the comparison
6761 * will be true if and only if there is a node in the first node-set and
6762 * a node in the second node-set such that the result of performing the
6763 * comparison on the string-values of the two nodes is true.
6765 * (needless to say, this is a costly operation)
6767 * Returns 0 or 1 depending on the results of the test.
6770 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6772 unsigned int *hashs1;
6773 unsigned int *hashs2;
6780 if ((arg1 == NULL) ||
6781 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6783 if ((arg2 == NULL) ||
6784 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6787 ns1 = arg1->nodesetval;
6788 ns2 = arg2->nodesetval;
6790 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6792 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6796 * for equal, check if there is a node pertaining to both sets
6799 for (i = 0;i < ns1->nodeNr;i++)
6800 for (j = 0;j < ns2->nodeNr;j++)
6801 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6804 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6805 if (values1 == NULL) {
6806 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6809 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6810 if (hashs1 == NULL) {
6811 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6815 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6816 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6817 if (values2 == NULL) {
6818 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6823 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6824 if (hashs2 == NULL) {
6825 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6831 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6832 for (i = 0;i < ns1->nodeNr;i++) {
6833 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6834 for (j = 0;j < ns2->nodeNr;j++) {
6836 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6837 if (hashs1[i] != hashs2[j]) {
6844 if (values1[i] == NULL)
6845 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6846 if (values2[j] == NULL)
6847 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6848 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6856 for (i = 0;i < ns1->nodeNr;i++)
6857 if (values1[i] != NULL)
6858 xmlFree(values1[i]);
6859 for (j = 0;j < ns2->nodeNr;j++)
6860 if (values2[j] != NULL)
6861 xmlFree(values2[j]);
6870 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6871 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6874 *At this point we are assured neither arg1 nor arg2
6875 *is a nodeset, so we can just pick the appropriate routine.
6877 switch (arg1->type) {
6878 case XPATH_UNDEFINED:
6880 xmlGenericError(xmlGenericErrorContext,
6881 "Equal: undefined\n");
6885 switch (arg2->type) {
6886 case XPATH_UNDEFINED:
6888 xmlGenericError(xmlGenericErrorContext,
6889 "Equal: undefined\n");
6894 xmlGenericError(xmlGenericErrorContext,
6895 "Equal: %d boolean %d \n",
6896 arg1->boolval, arg2->boolval);
6898 ret = (arg1->boolval == arg2->boolval);
6901 ret = (arg1->boolval ==
6902 xmlXPathCastNumberToBoolean(arg2->floatval));
6905 if ((arg2->stringval == NULL) ||
6906 (arg2->stringval[0] == 0)) ret = 0;
6909 ret = (arg1->boolval == ret);
6914 case XPATH_LOCATIONSET:
6918 case XPATH_XSLT_TREE:
6923 switch (arg2->type) {
6924 case XPATH_UNDEFINED:
6926 xmlGenericError(xmlGenericErrorContext,
6927 "Equal: undefined\n");
6931 ret = (arg2->boolval==
6932 xmlXPathCastNumberToBoolean(arg1->floatval));
6935 valuePush(ctxt, arg2);
6936 xmlXPathNumberFunction(ctxt, 1);
6937 arg2 = valuePop(ctxt);
6938 /* no break on purpose */
6940 /* Hand check NaN and Infinity equalities */
6941 if (xmlXPathIsNaN(arg1->floatval) ||
6942 xmlXPathIsNaN(arg2->floatval)) {
6944 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
6945 if (xmlXPathIsInf(arg2->floatval) == 1)
6949 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
6950 if (xmlXPathIsInf(arg2->floatval) == -1)
6954 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
6955 if (xmlXPathIsInf(arg1->floatval) == 1)
6959 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
6960 if (xmlXPathIsInf(arg1->floatval) == -1)
6965 ret = (arg1->floatval == arg2->floatval);
6971 case XPATH_LOCATIONSET:
6975 case XPATH_XSLT_TREE:
6980 switch (arg2->type) {
6981 case XPATH_UNDEFINED:
6983 xmlGenericError(xmlGenericErrorContext,
6984 "Equal: undefined\n");
6988 if ((arg1->stringval == NULL) ||
6989 (arg1->stringval[0] == 0)) ret = 0;
6992 ret = (arg2->boolval == ret);
6995 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6998 valuePush(ctxt, arg1);
6999 xmlXPathNumberFunction(ctxt, 1);
7000 arg1 = valuePop(ctxt);
7001 /* Hand check NaN and Infinity equalities */
7002 if (xmlXPathIsNaN(arg1->floatval) ||
7003 xmlXPathIsNaN(arg2->floatval)) {
7005 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7006 if (xmlXPathIsInf(arg2->floatval) == 1)
7010 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7011 if (xmlXPathIsInf(arg2->floatval) == -1)
7015 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7016 if (xmlXPathIsInf(arg1->floatval) == 1)
7020 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7021 if (xmlXPathIsInf(arg1->floatval) == -1)
7026 ret = (arg1->floatval == arg2->floatval);
7032 case XPATH_LOCATIONSET:
7036 case XPATH_XSLT_TREE:
7043 case XPATH_LOCATIONSET:
7047 case XPATH_XSLT_TREE:
7050 xmlXPathReleaseObject(ctxt->context, arg1);
7051 xmlXPathReleaseObject(ctxt->context, arg2);
7056 * xmlXPathEqualValues:
7057 * @ctxt: the XPath Parser context
7059 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7061 * Returns 0 or 1 depending on the results of the test.
7064 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7065 xmlXPathObjectPtr arg1, arg2, argtmp;
7068 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7069 arg2 = valuePop(ctxt);
7070 arg1 = valuePop(ctxt);
7071 if ((arg1 == NULL) || (arg2 == NULL)) {
7073 xmlXPathReleaseObject(ctxt->context, arg1);
7075 xmlXPathReleaseObject(ctxt->context, arg2);
7076 XP_ERROR0(XPATH_INVALID_OPERAND);
7081 xmlGenericError(xmlGenericErrorContext,
7082 "Equal: by pointer\n");
7084 xmlXPathFreeObject(arg1);
7089 *If either argument is a nodeset, it's a 'special case'
7091 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7092 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7094 *Hack it to assure arg1 is the nodeset
7096 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7101 switch (arg2->type) {
7102 case XPATH_UNDEFINED:
7104 xmlGenericError(xmlGenericErrorContext,
7105 "Equal: undefined\n");
7109 case XPATH_XSLT_TREE:
7110 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7113 if ((arg1->nodesetval == NULL) ||
7114 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7117 ret = (ret == arg2->boolval);
7120 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7123 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7128 case XPATH_LOCATIONSET:
7132 xmlXPathReleaseObject(ctxt->context, arg1);
7133 xmlXPathReleaseObject(ctxt->context, arg2);
7137 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7141 * xmlXPathNotEqualValues:
7142 * @ctxt: the XPath Parser context
7144 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7146 * Returns 0 or 1 depending on the results of the test.
7149 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7150 xmlXPathObjectPtr arg1, arg2, argtmp;
7153 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7154 arg2 = valuePop(ctxt);
7155 arg1 = valuePop(ctxt);
7156 if ((arg1 == NULL) || (arg2 == NULL)) {
7158 xmlXPathReleaseObject(ctxt->context, arg1);
7160 xmlXPathReleaseObject(ctxt->context, arg2);
7161 XP_ERROR0(XPATH_INVALID_OPERAND);
7166 xmlGenericError(xmlGenericErrorContext,
7167 "NotEqual: by pointer\n");
7169 xmlXPathReleaseObject(ctxt->context, arg1);
7174 *If either argument is a nodeset, it's a 'special case'
7176 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7177 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7179 *Hack it to assure arg1 is the nodeset
7181 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7186 switch (arg2->type) {
7187 case XPATH_UNDEFINED:
7189 xmlGenericError(xmlGenericErrorContext,
7190 "NotEqual: undefined\n");
7194 case XPATH_XSLT_TREE:
7195 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7198 if ((arg1->nodesetval == NULL) ||
7199 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7202 ret = (ret != arg2->boolval);
7205 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7208 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7213 case XPATH_LOCATIONSET:
7217 xmlXPathReleaseObject(ctxt->context, arg1);
7218 xmlXPathReleaseObject(ctxt->context, arg2);
7222 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7226 * xmlXPathCompareValues:
7227 * @ctxt: the XPath Parser context
7228 * @inf: less than (1) or greater than (0)
7229 * @strict: is the comparison strict
7231 * Implement the compare operation on XPath objects:
7232 * @arg1 < @arg2 (1, 1, ...
7233 * @arg1 <= @arg2 (1, 0, ...
7234 * @arg1 > @arg2 (0, 1, ...
7235 * @arg1 >= @arg2 (0, 0, ...
7237 * When neither object to be compared is a node-set and the operator is
7238 * <=, <, >=, >, then the objects are compared by converted both objects
7239 * to numbers and comparing the numbers according to IEEE 754. The <
7240 * comparison will be true if and only if the first number is less than the
7241 * second number. The <= comparison will be true if and only if the first
7242 * number is less than or equal to the second number. The > comparison
7243 * will be true if and only if the first number is greater than the second
7244 * number. The >= comparison will be true if and only if the first number
7245 * is greater than or equal to the second number.
7247 * Returns 1 if the comparison succeeded, 0 if it failed
7250 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7251 int ret = 0, arg1i = 0, arg2i = 0;
7252 xmlXPathObjectPtr arg1, arg2;
7254 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7255 arg2 = valuePop(ctxt);
7256 arg1 = valuePop(ctxt);
7257 if ((arg1 == NULL) || (arg2 == NULL)) {
7259 xmlXPathReleaseObject(ctxt->context, arg1);
7261 xmlXPathReleaseObject(ctxt->context, arg2);
7262 XP_ERROR0(XPATH_INVALID_OPERAND);
7265 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7266 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7268 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7269 * are not freed from within this routine; they will be freed from the
7270 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7272 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7273 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7274 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7276 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7277 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7280 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7287 if (arg1->type != XPATH_NUMBER) {
7288 valuePush(ctxt, arg1);
7289 xmlXPathNumberFunction(ctxt, 1);
7290 arg1 = valuePop(ctxt);
7292 if (arg1->type != XPATH_NUMBER) {
7293 xmlXPathFreeObject(arg1);
7294 xmlXPathFreeObject(arg2);
7295 XP_ERROR0(XPATH_INVALID_OPERAND);
7297 if (arg2->type != XPATH_NUMBER) {
7298 valuePush(ctxt, arg2);
7299 xmlXPathNumberFunction(ctxt, 1);
7300 arg2 = valuePop(ctxt);
7302 if (arg2->type != XPATH_NUMBER) {
7303 xmlXPathReleaseObject(ctxt->context, arg1);
7304 xmlXPathReleaseObject(ctxt->context, arg2);
7305 XP_ERROR0(XPATH_INVALID_OPERAND);
7308 * Add tests for infinity and nan
7309 * => feedback on 3.4 for Inf and NaN
7311 /* Hand check NaN and Infinity comparisons */
7312 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7315 arg1i=xmlXPathIsInf(arg1->floatval);
7316 arg2i=xmlXPathIsInf(arg2->floatval);
7317 if (inf && strict) {
7318 if ((arg1i == -1 && arg2i != -1) ||
7319 (arg2i == 1 && arg1i != 1)) {
7321 } else if (arg1i == 0 && arg2i == 0) {
7322 ret = (arg1->floatval < arg2->floatval);
7327 else if (inf && !strict) {
7328 if (arg1i == -1 || arg2i == 1) {
7330 } else if (arg1i == 0 && arg2i == 0) {
7331 ret = (arg1->floatval <= arg2->floatval);
7336 else if (!inf && strict) {
7337 if ((arg1i == 1 && arg2i != 1) ||
7338 (arg2i == -1 && arg1i != -1)) {
7340 } else if (arg1i == 0 && arg2i == 0) {
7341 ret = (arg1->floatval > arg2->floatval);
7346 else if (!inf && !strict) {
7347 if (arg1i == 1 || arg2i == -1) {
7349 } else if (arg1i == 0 && arg2i == 0) {
7350 ret = (arg1->floatval >= arg2->floatval);
7356 xmlXPathReleaseObject(ctxt->context, arg1);
7357 xmlXPathReleaseObject(ctxt->context, arg2);
7362 * xmlXPathValueFlipSign:
7363 * @ctxt: the XPath Parser context
7365 * Implement the unary - operation on an XPath object
7366 * The numeric operators convert their operands to numbers as if
7367 * by calling the number function.
7370 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7371 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7373 CHECK_TYPE(XPATH_NUMBER);
7374 if (xmlXPathIsNaN(ctxt->value->floatval))
7375 ctxt->value->floatval=xmlXPathNAN;
7376 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7377 ctxt->value->floatval=xmlXPathNINF;
7378 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7379 ctxt->value->floatval=xmlXPathPINF;
7380 else if (ctxt->value->floatval == 0) {
7381 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7382 ctxt->value->floatval = xmlXPathNZERO;
7384 ctxt->value->floatval = 0;
7387 ctxt->value->floatval = - ctxt->value->floatval;
7391 * xmlXPathAddValues:
7392 * @ctxt: the XPath Parser context
7394 * Implement the add operation on XPath objects:
7395 * The numeric operators convert their operands to numbers as if
7396 * by calling the number function.
7399 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7400 xmlXPathObjectPtr arg;
7403 arg = valuePop(ctxt);
7405 XP_ERROR(XPATH_INVALID_OPERAND);
7406 val = xmlXPathCastToNumber(arg);
7407 xmlXPathReleaseObject(ctxt->context, arg);
7409 CHECK_TYPE(XPATH_NUMBER);
7410 ctxt->value->floatval += val;
7414 * xmlXPathSubValues:
7415 * @ctxt: the XPath Parser context
7417 * Implement the subtraction operation on XPath objects:
7418 * The numeric operators convert their operands to numbers as if
7419 * by calling the number function.
7422 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7423 xmlXPathObjectPtr arg;
7426 arg = valuePop(ctxt);
7428 XP_ERROR(XPATH_INVALID_OPERAND);
7429 val = xmlXPathCastToNumber(arg);
7430 xmlXPathReleaseObject(ctxt->context, arg);
7432 CHECK_TYPE(XPATH_NUMBER);
7433 ctxt->value->floatval -= val;
7437 * xmlXPathMultValues:
7438 * @ctxt: the XPath Parser context
7440 * Implement the multiply operation on XPath objects:
7441 * The numeric operators convert their operands to numbers as if
7442 * by calling the number function.
7445 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7446 xmlXPathObjectPtr arg;
7449 arg = valuePop(ctxt);
7451 XP_ERROR(XPATH_INVALID_OPERAND);
7452 val = xmlXPathCastToNumber(arg);
7453 xmlXPathReleaseObject(ctxt->context, arg);
7455 CHECK_TYPE(XPATH_NUMBER);
7456 ctxt->value->floatval *= val;
7460 * xmlXPathDivValues:
7461 * @ctxt: the XPath Parser context
7463 * Implement the div operation on XPath objects @arg1 / @arg2:
7464 * The numeric operators convert their operands to numbers as if
7465 * by calling the number function.
7468 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7469 xmlXPathObjectPtr arg;
7472 arg = valuePop(ctxt);
7474 XP_ERROR(XPATH_INVALID_OPERAND);
7475 val = xmlXPathCastToNumber(arg);
7476 xmlXPathReleaseObject(ctxt->context, arg);
7478 CHECK_TYPE(XPATH_NUMBER);
7479 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7480 ctxt->value->floatval = xmlXPathNAN;
7481 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7482 if (ctxt->value->floatval == 0)
7483 ctxt->value->floatval = xmlXPathNAN;
7484 else if (ctxt->value->floatval > 0)
7485 ctxt->value->floatval = xmlXPathNINF;
7486 else if (ctxt->value->floatval < 0)
7487 ctxt->value->floatval = xmlXPathPINF;
7489 else if (val == 0) {
7490 if (ctxt->value->floatval == 0)
7491 ctxt->value->floatval = xmlXPathNAN;
7492 else if (ctxt->value->floatval > 0)
7493 ctxt->value->floatval = xmlXPathPINF;
7494 else if (ctxt->value->floatval < 0)
7495 ctxt->value->floatval = xmlXPathNINF;
7497 ctxt->value->floatval /= val;
7501 * xmlXPathModValues:
7502 * @ctxt: the XPath Parser context
7504 * Implement the mod operation on XPath objects: @arg1 / @arg2
7505 * The numeric operators convert their operands to numbers as if
7506 * by calling the number function.
7509 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7510 xmlXPathObjectPtr arg;
7513 arg = valuePop(ctxt);
7515 XP_ERROR(XPATH_INVALID_OPERAND);
7516 arg2 = xmlXPathCastToNumber(arg);
7517 xmlXPathReleaseObject(ctxt->context, arg);
7519 CHECK_TYPE(XPATH_NUMBER);
7520 arg1 = ctxt->value->floatval;
7522 ctxt->value->floatval = xmlXPathNAN;
7524 ctxt->value->floatval = fmod(arg1, arg2);
7528 /************************************************************************
7530 * The traversal functions *
7532 ************************************************************************/
7535 * A traversal function enumerates nodes along an axis.
7536 * Initially it must be called with NULL, and it indicates
7537 * termination on the axis by returning NULL.
7539 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7540 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7543 * xmlXPathTraversalFunctionExt:
7544 * A traversal function enumerates nodes along an axis.
7545 * Initially it must be called with NULL, and it indicates
7546 * termination on the axis by returning NULL.
7547 * The context node of the traversal is specified via @contextNode.
7549 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7550 (xmlNodePtr cur, xmlNodePtr contextNode);
7553 * xmlXPathNodeSetMergeFunction:
7554 * Used for merging node sets in xmlXPathCollectAndTest().
7556 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7557 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7562 * @ctxt: the XPath Parser context
7563 * @cur: the current node in the traversal
7565 * Traversal function for the "self" direction
7566 * The self axis contains just the context node itself
7568 * Returns the next element following that axis
7571 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7572 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7574 return(ctxt->context->node);
7579 * xmlXPathNextChild:
7580 * @ctxt: the XPath Parser context
7581 * @cur: the current node in the traversal
7583 * Traversal function for the "child" direction
7584 * The child axis contains the children of the context node in document order.
7586 * Returns the next element following that axis
7589 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7590 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7592 if (ctxt->context->node == NULL) return(NULL);
7593 switch (ctxt->context->node->type) {
7594 case XML_ELEMENT_NODE:
7596 case XML_CDATA_SECTION_NODE:
7597 case XML_ENTITY_REF_NODE:
7598 case XML_ENTITY_NODE:
7600 case XML_COMMENT_NODE:
7601 case XML_NOTATION_NODE:
7603 return(ctxt->context->node->children);
7604 case XML_DOCUMENT_NODE:
7605 case XML_DOCUMENT_TYPE_NODE:
7606 case XML_DOCUMENT_FRAG_NODE:
7607 case XML_HTML_DOCUMENT_NODE:
7608 #ifdef LIBXML_DOCB_ENABLED
7609 case XML_DOCB_DOCUMENT_NODE:
7611 return(((xmlDocPtr) ctxt->context->node)->children);
7612 case XML_ELEMENT_DECL:
7613 case XML_ATTRIBUTE_DECL:
7614 case XML_ENTITY_DECL:
7615 case XML_ATTRIBUTE_NODE:
7616 case XML_NAMESPACE_DECL:
7617 case XML_XINCLUDE_START:
7618 case XML_XINCLUDE_END:
7623 if ((cur->type == XML_DOCUMENT_NODE) ||
7624 (cur->type == XML_HTML_DOCUMENT_NODE))
7630 * xmlXPathNextChildElement:
7631 * @ctxt: the XPath Parser context
7632 * @cur: the current node in the traversal
7634 * Traversal function for the "child" direction and nodes of type element.
7635 * The child axis contains the children of the context node in document order.
7637 * Returns the next element following that axis
7640 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7641 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7643 cur = ctxt->context->node;
7644 if (cur == NULL) return(NULL);
7646 * Get the first element child.
7648 switch (cur->type) {
7649 case XML_ELEMENT_NODE:
7650 case XML_DOCUMENT_FRAG_NODE:
7651 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7652 case XML_ENTITY_NODE:
7653 cur = cur->children;
7655 if (cur->type == XML_ELEMENT_NODE)
7659 } while ((cur != NULL) &&
7660 (cur->type != XML_ELEMENT_NODE));
7664 case XML_DOCUMENT_NODE:
7665 case XML_HTML_DOCUMENT_NODE:
7666 #ifdef LIBXML_DOCB_ENABLED
7667 case XML_DOCB_DOCUMENT_NODE:
7669 return(xmlDocGetRootElement((xmlDocPtr) cur));
7676 * Get the next sibling element node.
7678 switch (cur->type) {
7679 case XML_ELEMENT_NODE:
7681 case XML_ENTITY_REF_NODE:
7682 case XML_ENTITY_NODE:
7683 case XML_CDATA_SECTION_NODE:
7685 case XML_COMMENT_NODE:
7686 case XML_XINCLUDE_END:
7688 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7692 if (cur->next != NULL) {
7693 if (cur->next->type == XML_ELEMENT_NODE)
7698 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7705 * xmlXPathNextDescendantOrSelfElemParent:
7706 * @ctxt: the XPath Parser context
7707 * @cur: the current node in the traversal
7709 * Traversal function for the "descendant-or-self" axis.
7710 * Additionally it returns only nodes which can be parents of
7714 * Returns the next element following that axis
7717 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7718 xmlNodePtr contextNode)
7721 if (contextNode == NULL)
7723 switch (contextNode->type) {
7724 case XML_ELEMENT_NODE:
7725 case XML_XINCLUDE_START:
7726 case XML_DOCUMENT_FRAG_NODE:
7727 case XML_DOCUMENT_NODE:
7728 #ifdef LIBXML_DOCB_ENABLED
7729 case XML_DOCB_DOCUMENT_NODE:
7731 case XML_HTML_DOCUMENT_NODE:
7732 return(contextNode);
7738 xmlNodePtr start = cur;
7740 while (cur != NULL) {
7741 switch (cur->type) {
7742 case XML_ELEMENT_NODE:
7743 /* TODO: OK to have XInclude here? */
7744 case XML_XINCLUDE_START:
7745 case XML_DOCUMENT_FRAG_NODE:
7748 if (cur->children != NULL) {
7749 cur = cur->children;
7753 /* Not sure if we need those here. */
7754 case XML_DOCUMENT_NODE:
7755 #ifdef LIBXML_DOCB_ENABLED
7756 case XML_DOCB_DOCUMENT_NODE:
7758 case XML_HTML_DOCUMENT_NODE:
7761 return(xmlDocGetRootElement((xmlDocPtr) cur));
7767 if ((cur == NULL) || (cur == contextNode))
7769 if (cur->next != NULL) {
7781 * xmlXPathNextDescendant:
7782 * @ctxt: the XPath Parser context
7783 * @cur: the current node in the traversal
7785 * Traversal function for the "descendant" direction
7786 * the descendant axis contains the descendants of the context node in document
7787 * order; a descendant is a child or a child of a child and so on.
7789 * Returns the next element following that axis
7792 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7793 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7795 if (ctxt->context->node == NULL)
7797 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7798 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7801 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7802 return(ctxt->context->doc->children);
7803 return(ctxt->context->node->children);
7806 if (cur->children != NULL) {
7808 * Do not descend on entities declarations
7810 if (cur->children->type != XML_ENTITY_DECL) {
7811 cur = cur->children;
7815 if (cur->type != XML_DTD_NODE)
7820 if (cur == ctxt->context->node) return(NULL);
7822 while (cur->next != NULL) {
7824 if ((cur->type != XML_ENTITY_DECL) &&
7825 (cur->type != XML_DTD_NODE))
7831 if (cur == NULL) break;
7832 if (cur == ctxt->context->node) return(NULL);
7833 if (cur->next != NULL) {
7837 } while (cur != NULL);
7842 * xmlXPathNextDescendantOrSelf:
7843 * @ctxt: the XPath Parser context
7844 * @cur: the current node in the traversal
7846 * Traversal function for the "descendant-or-self" direction
7847 * the descendant-or-self axis contains the context node and the descendants
7848 * of the context node in document order; thus the context node is the first
7849 * node on the axis, and the first child of the context node is the second node
7852 * Returns the next element following that axis
7855 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7856 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7858 if (ctxt->context->node == NULL)
7860 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7861 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7863 return(ctxt->context->node);
7866 return(xmlXPathNextDescendant(ctxt, cur));
7870 * xmlXPathNextParent:
7871 * @ctxt: the XPath Parser context
7872 * @cur: the current node in the traversal
7874 * Traversal function for the "parent" direction
7875 * The parent axis contains the parent of the context node, if there is one.
7877 * Returns the next element following that axis
7880 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7881 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7883 * the parent of an attribute or namespace node is the element
7884 * to which the attribute or namespace node is attached
7885 * Namespace handling !!!
7888 if (ctxt->context->node == NULL) return(NULL);
7889 switch (ctxt->context->node->type) {
7890 case XML_ELEMENT_NODE:
7892 case XML_CDATA_SECTION_NODE:
7893 case XML_ENTITY_REF_NODE:
7894 case XML_ENTITY_NODE:
7896 case XML_COMMENT_NODE:
7897 case XML_NOTATION_NODE:
7899 case XML_ELEMENT_DECL:
7900 case XML_ATTRIBUTE_DECL:
7901 case XML_XINCLUDE_START:
7902 case XML_XINCLUDE_END:
7903 case XML_ENTITY_DECL:
7904 if (ctxt->context->node->parent == NULL)
7905 return((xmlNodePtr) ctxt->context->doc);
7906 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7907 ((ctxt->context->node->parent->name[0] == ' ') ||
7908 (xmlStrEqual(ctxt->context->node->parent->name,
7909 BAD_CAST "fake node libxslt"))))
7911 return(ctxt->context->node->parent);
7912 case XML_ATTRIBUTE_NODE: {
7913 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7915 return(att->parent);
7917 case XML_DOCUMENT_NODE:
7918 case XML_DOCUMENT_TYPE_NODE:
7919 case XML_DOCUMENT_FRAG_NODE:
7920 case XML_HTML_DOCUMENT_NODE:
7921 #ifdef LIBXML_DOCB_ENABLED
7922 case XML_DOCB_DOCUMENT_NODE:
7925 case XML_NAMESPACE_DECL: {
7926 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7928 if ((ns->next != NULL) &&
7929 (ns->next->type != XML_NAMESPACE_DECL))
7930 return((xmlNodePtr) ns->next);
7939 * xmlXPathNextAncestor:
7940 * @ctxt: the XPath Parser context
7941 * @cur: the current node in the traversal
7943 * Traversal function for the "ancestor" direction
7944 * the ancestor axis contains the ancestors of the context node; the ancestors
7945 * of the context node consist of the parent of context node and the parent's
7946 * parent and so on; the nodes are ordered in reverse document order; thus the
7947 * parent is the first node on the axis, and the parent's parent is the second
7950 * Returns the next element following that axis
7953 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7954 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7956 * the parent of an attribute or namespace node is the element
7957 * to which the attribute or namespace node is attached
7961 if (ctxt->context->node == NULL) return(NULL);
7962 switch (ctxt->context->node->type) {
7963 case XML_ELEMENT_NODE:
7965 case XML_CDATA_SECTION_NODE:
7966 case XML_ENTITY_REF_NODE:
7967 case XML_ENTITY_NODE:
7969 case XML_COMMENT_NODE:
7971 case XML_ELEMENT_DECL:
7972 case XML_ATTRIBUTE_DECL:
7973 case XML_ENTITY_DECL:
7974 case XML_NOTATION_NODE:
7975 case XML_XINCLUDE_START:
7976 case XML_XINCLUDE_END:
7977 if (ctxt->context->node->parent == NULL)
7978 return((xmlNodePtr) ctxt->context->doc);
7979 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7980 ((ctxt->context->node->parent->name[0] == ' ') ||
7981 (xmlStrEqual(ctxt->context->node->parent->name,
7982 BAD_CAST "fake node libxslt"))))
7984 return(ctxt->context->node->parent);
7985 case XML_ATTRIBUTE_NODE: {
7986 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7988 return(tmp->parent);
7990 case XML_DOCUMENT_NODE:
7991 case XML_DOCUMENT_TYPE_NODE:
7992 case XML_DOCUMENT_FRAG_NODE:
7993 case XML_HTML_DOCUMENT_NODE:
7994 #ifdef LIBXML_DOCB_ENABLED
7995 case XML_DOCB_DOCUMENT_NODE:
7998 case XML_NAMESPACE_DECL: {
7999 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8001 if ((ns->next != NULL) &&
8002 (ns->next->type != XML_NAMESPACE_DECL))
8003 return((xmlNodePtr) ns->next);
8004 /* Bad, how did that namespace end up here ? */
8010 if (cur == ctxt->context->doc->children)
8011 return((xmlNodePtr) ctxt->context->doc);
8012 if (cur == (xmlNodePtr) ctxt->context->doc)
8014 switch (cur->type) {
8015 case XML_ELEMENT_NODE:
8017 case XML_CDATA_SECTION_NODE:
8018 case XML_ENTITY_REF_NODE:
8019 case XML_ENTITY_NODE:
8021 case XML_COMMENT_NODE:
8022 case XML_NOTATION_NODE:
8024 case XML_ELEMENT_DECL:
8025 case XML_ATTRIBUTE_DECL:
8026 case XML_ENTITY_DECL:
8027 case XML_XINCLUDE_START:
8028 case XML_XINCLUDE_END:
8029 if (cur->parent == NULL)
8031 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8032 ((cur->parent->name[0] == ' ') ||
8033 (xmlStrEqual(cur->parent->name,
8034 BAD_CAST "fake node libxslt"))))
8036 return(cur->parent);
8037 case XML_ATTRIBUTE_NODE: {
8038 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8040 return(att->parent);
8042 case XML_NAMESPACE_DECL: {
8043 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8045 if ((ns->next != NULL) &&
8046 (ns->next->type != XML_NAMESPACE_DECL))
8047 return((xmlNodePtr) ns->next);
8048 /* Bad, how did that namespace end up here ? */
8051 case XML_DOCUMENT_NODE:
8052 case XML_DOCUMENT_TYPE_NODE:
8053 case XML_DOCUMENT_FRAG_NODE:
8054 case XML_HTML_DOCUMENT_NODE:
8055 #ifdef LIBXML_DOCB_ENABLED
8056 case XML_DOCB_DOCUMENT_NODE:
8064 * xmlXPathNextAncestorOrSelf:
8065 * @ctxt: the XPath Parser context
8066 * @cur: the current node in the traversal
8068 * Traversal function for the "ancestor-or-self" direction
8069 * he ancestor-or-self axis contains the context node and ancestors of
8070 * the context node in reverse document order; thus the context node is
8071 * the first node on the axis, and the context node's parent the second;
8072 * parent here is defined the same as with the parent axis.
8074 * Returns the next element following that axis
8077 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8078 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8080 return(ctxt->context->node);
8081 return(xmlXPathNextAncestor(ctxt, cur));
8085 * xmlXPathNextFollowingSibling:
8086 * @ctxt: the XPath Parser context
8087 * @cur: the current node in the traversal
8089 * Traversal function for the "following-sibling" direction
8090 * The following-sibling axis contains the following siblings of the context
8091 * node in document order.
8093 * Returns the next element following that axis
8096 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8097 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8098 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8099 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8101 if (cur == (xmlNodePtr) ctxt->context->doc)
8104 return(ctxt->context->node->next);
8109 * xmlXPathNextPrecedingSibling:
8110 * @ctxt: the XPath Parser context
8111 * @cur: the current node in the traversal
8113 * Traversal function for the "preceding-sibling" direction
8114 * The preceding-sibling axis contains the preceding siblings of the context
8115 * node in reverse document order; the first preceding sibling is first on the
8116 * axis; the sibling preceding that node is the second on the axis and so on.
8118 * Returns the next element following that axis
8121 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8122 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8123 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8124 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8126 if (cur == (xmlNodePtr) ctxt->context->doc)
8129 return(ctxt->context->node->prev);
8130 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8133 return(ctxt->context->node->prev);
8139 * xmlXPathNextFollowing:
8140 * @ctxt: the XPath Parser context
8141 * @cur: the current node in the traversal
8143 * Traversal function for the "following" direction
8144 * The following axis contains all nodes in the same document as the context
8145 * node that are after the context node in document order, excluding any
8146 * descendants and excluding attribute nodes and namespace nodes; the nodes
8147 * are ordered in document order
8149 * Returns the next element following that axis
8152 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8153 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8154 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8155 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8156 return(cur->children);
8159 cur = ctxt->context->node;
8160 if (cur->type == XML_NAMESPACE_DECL)
8162 if (cur->type == XML_ATTRIBUTE_NODE)
8165 if (cur == NULL) return(NULL) ; /* ERROR */
8166 if (cur->next != NULL) return(cur->next) ;
8169 if (cur == NULL) break;
8170 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8171 if (cur->next != NULL) return(cur->next);
8172 } while (cur != NULL);
8177 * xmlXPathIsAncestor:
8178 * @ancestor: the ancestor node
8179 * @node: the current node
8181 * Check that @ancestor is a @node's ancestor
8183 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8186 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8187 if ((ancestor == NULL) || (node == NULL)) return(0);
8188 /* nodes need to be in the same document */
8189 if (ancestor->doc != node->doc) return(0);
8190 /* avoid searching if ancestor or node is the root node */
8191 if (ancestor == (xmlNodePtr) node->doc) return(1);
8192 if (node == (xmlNodePtr) ancestor->doc) return(0);
8193 while (node->parent != NULL) {
8194 if (node->parent == ancestor)
8196 node = node->parent;
8202 * xmlXPathNextPreceding:
8203 * @ctxt: the XPath Parser context
8204 * @cur: the current node in the traversal
8206 * Traversal function for the "preceding" direction
8207 * the preceding axis contains all nodes in the same document as the context
8208 * node that are before the context node in document order, excluding any
8209 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8210 * ordered in reverse document order
8212 * Returns the next element following that axis
8215 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8217 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8219 cur = ctxt->context->node;
8220 if (cur->type == XML_NAMESPACE_DECL)
8222 if (cur->type == XML_ATTRIBUTE_NODE)
8223 return(cur->parent);
8227 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8230 if (cur->prev != NULL) {
8231 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8238 if (cur == ctxt->context->doc->children)
8240 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8245 * xmlXPathNextPrecedingInternal:
8246 * @ctxt: the XPath Parser context
8247 * @cur: the current node in the traversal
8249 * Traversal function for the "preceding" direction
8250 * the preceding axis contains all nodes in the same document as the context
8251 * node that are before the context node in document order, excluding any
8252 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8253 * ordered in reverse document order
8254 * This is a faster implementation but internal only since it requires a
8255 * state kept in the parser context: ctxt->ancestor.
8257 * Returns the next element following that axis
8260 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8263 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8265 cur = ctxt->context->node;
8268 if (cur->type == XML_NAMESPACE_DECL)
8270 ctxt->ancestor = cur->parent;
8272 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8274 while (cur->prev == NULL) {
8278 if (cur == ctxt->context->doc->children)
8280 if (cur != ctxt->ancestor)
8282 ctxt->ancestor = cur->parent;
8285 while (cur->last != NULL)
8291 * xmlXPathNextNamespace:
8292 * @ctxt: the XPath Parser context
8293 * @cur: the current attribute in the traversal
8295 * Traversal function for the "namespace" direction
8296 * the namespace axis contains the namespace nodes of the context node;
8297 * the order of nodes on this axis is implementation-defined; the axis will
8298 * be empty unless the context node is an element
8300 * We keep the XML namespace node at the end of the list.
8302 * Returns the next element following that axis
8305 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8306 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8307 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8308 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
8309 if (ctxt->context->tmpNsList != NULL)
8310 xmlFree(ctxt->context->tmpNsList);
8311 ctxt->context->tmpNsList =
8312 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8313 ctxt->context->tmpNsNr = 0;
8314 if (ctxt->context->tmpNsList != NULL) {
8315 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8316 ctxt->context->tmpNsNr++;
8319 return((xmlNodePtr) xmlXPathXMLNamespace);
8321 if (ctxt->context->tmpNsNr > 0) {
8322 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8324 if (ctxt->context->tmpNsList != NULL)
8325 xmlFree(ctxt->context->tmpNsList);
8326 ctxt->context->tmpNsList = NULL;
8332 * xmlXPathNextAttribute:
8333 * @ctxt: the XPath Parser context
8334 * @cur: the current attribute in the traversal
8336 * Traversal function for the "attribute" direction
8337 * TODO: support DTD inherited default attributes
8339 * Returns the next element following that axis
8342 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8343 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8344 if (ctxt->context->node == NULL)
8346 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8349 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8351 return((xmlNodePtr)ctxt->context->node->properties);
8353 return((xmlNodePtr)cur->next);
8356 /************************************************************************
8358 * NodeTest Functions *
8360 ************************************************************************/
8362 #define IS_FUNCTION 200
8365 /************************************************************************
8367 * Implicit tree core function library *
8369 ************************************************************************/
8373 * @ctxt: the XPath Parser context
8375 * Initialize the context to the root of the document
8378 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8379 if ((ctxt == NULL) || (ctxt->context == NULL))
8381 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8382 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8383 ctxt->context->node));
8386 /************************************************************************
8388 * The explicit core function library *
8389 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8391 ************************************************************************/
8395 * xmlXPathLastFunction:
8396 * @ctxt: the XPath Parser context
8397 * @nargs: the number of arguments
8399 * Implement the last() XPath function
8401 * The last function returns the number of nodes in the context node list.
8404 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8406 if (ctxt->context->contextSize >= 0) {
8408 xmlXPathCacheNewFloat(ctxt->context,
8409 (double) ctxt->context->contextSize));
8411 xmlGenericError(xmlGenericErrorContext,
8412 "last() : %d\n", ctxt->context->contextSize);
8415 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8420 * xmlXPathPositionFunction:
8421 * @ctxt: the XPath Parser context
8422 * @nargs: the number of arguments
8424 * Implement the position() XPath function
8426 * The position function returns the position of the context node in the
8427 * context node list. The first position is 1, and so the last position
8428 * will be equal to last().
8431 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8433 if (ctxt->context->proximityPosition >= 0) {
8435 xmlXPathCacheNewFloat(ctxt->context,
8436 (double) ctxt->context->proximityPosition));
8438 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8439 ctxt->context->proximityPosition);
8442 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8447 * xmlXPathCountFunction:
8448 * @ctxt: the XPath Parser context
8449 * @nargs: the number of arguments
8451 * Implement the count() XPath function
8452 * number count(node-set)
8455 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8456 xmlXPathObjectPtr cur;
8459 if ((ctxt->value == NULL) ||
8460 ((ctxt->value->type != XPATH_NODESET) &&
8461 (ctxt->value->type != XPATH_XSLT_TREE)))
8462 XP_ERROR(XPATH_INVALID_TYPE);
8463 cur = valuePop(ctxt);
8465 if ((cur == NULL) || (cur->nodesetval == NULL))
8466 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8467 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8468 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8469 (double) cur->nodesetval->nodeNr));
8471 if ((cur->nodesetval->nodeNr != 1) ||
8472 (cur->nodesetval->nodeTab == NULL)) {
8473 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8478 tmp = cur->nodesetval->nodeTab[0];
8480 tmp = tmp->children;
8481 while (tmp != NULL) {
8486 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8489 xmlXPathReleaseObject(ctxt->context, cur);
8493 * xmlXPathGetElementsByIds:
8494 * @doc: the document
8495 * @ids: a whitespace separated list of IDs
8497 * Selects elements by their unique ID.
8499 * Returns a node-set of selected elements.
8501 static xmlNodeSetPtr
8502 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8504 const xmlChar *cur = ids;
8507 xmlNodePtr elem = NULL;
8509 if (ids == NULL) return(NULL);
8511 ret = xmlXPathNodeSetCreate(NULL);
8515 while (IS_BLANK_CH(*cur)) cur++;
8517 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8520 ID = xmlStrndup(ids, cur - ids);
8523 * We used to check the fact that the value passed
8524 * was an NCName, but this generated much troubles for
8525 * me and Aleksey Sanin, people blatantly violated that
8526 * constaint, like Visa3D spec.
8527 * if (xmlValidateNCName(ID, 1) == 0)
8529 attr = xmlGetID(doc, ID);
8531 if (attr->type == XML_ATTRIBUTE_NODE)
8532 elem = attr->parent;
8533 else if (attr->type == XML_ELEMENT_NODE)
8534 elem = (xmlNodePtr) attr;
8538 xmlXPathNodeSetAdd(ret, elem);
8543 while (IS_BLANK_CH(*cur)) cur++;
8550 * xmlXPathIdFunction:
8551 * @ctxt: the XPath Parser context
8552 * @nargs: the number of arguments
8554 * Implement the id() XPath function
8555 * node-set id(object)
8556 * The id function selects elements by their unique ID
8557 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8558 * then the result is the union of the result of applying id to the
8559 * string value of each of the nodes in the argument node-set. When the
8560 * argument to id is of any other type, the argument is converted to a
8561 * string as if by a call to the string function; the string is split
8562 * into a whitespace-separated list of tokens (whitespace is any sequence
8563 * of characters matching the production S); the result is a node-set
8564 * containing the elements in the same document as the context node that
8565 * have a unique ID equal to any of the tokens in the list.
8568 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8571 xmlXPathObjectPtr obj;
8574 obj = valuePop(ctxt);
8575 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8576 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8580 ret = xmlXPathNodeSetCreate(NULL);
8582 * FIXME -- in an out-of-memory condition this will behave badly.
8583 * The solution is not clear -- we already popped an item from
8584 * ctxt, so the object is in a corrupt state.
8587 if (obj->nodesetval != NULL) {
8588 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8590 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8591 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8592 ret = xmlXPathNodeSetMerge(ret, ns);
8593 xmlXPathFreeNodeSet(ns);
8598 xmlXPathReleaseObject(ctxt->context, obj);
8599 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8602 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8603 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8604 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8605 xmlXPathReleaseObject(ctxt->context, obj);
8610 * xmlXPathLocalNameFunction:
8611 * @ctxt: the XPath Parser context
8612 * @nargs: the number of arguments
8614 * Implement the local-name() XPath function
8615 * string local-name(node-set?)
8616 * The local-name function returns a string containing the local part
8617 * of the name of the node in the argument node-set that is first in
8618 * document order. If the node-set is empty or the first node has no
8619 * name, an empty string is returned. If the argument is omitted it
8620 * defaults to the context node.
8623 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8624 xmlXPathObjectPtr cur;
8626 if (ctxt == NULL) return;
8629 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8630 ctxt->context->node));
8635 if ((ctxt->value == NULL) ||
8636 ((ctxt->value->type != XPATH_NODESET) &&
8637 (ctxt->value->type != XPATH_XSLT_TREE)))
8638 XP_ERROR(XPATH_INVALID_TYPE);
8639 cur = valuePop(ctxt);
8641 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8642 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8644 int i = 0; /* Should be first in document order !!!!! */
8645 switch (cur->nodesetval->nodeTab[i]->type) {
8646 case XML_ELEMENT_NODE:
8647 case XML_ATTRIBUTE_NODE:
8649 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8650 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8653 xmlXPathCacheNewString(ctxt->context,
8654 cur->nodesetval->nodeTab[i]->name));
8656 case XML_NAMESPACE_DECL:
8657 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8658 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8661 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8664 xmlXPathReleaseObject(ctxt->context, cur);
8668 * xmlXPathNamespaceURIFunction:
8669 * @ctxt: the XPath Parser context
8670 * @nargs: the number of arguments
8672 * Implement the namespace-uri() XPath function
8673 * string namespace-uri(node-set?)
8674 * The namespace-uri function returns a string containing the
8675 * namespace URI of the expanded name of the node in the argument
8676 * node-set that is first in document order. If the node-set is empty,
8677 * the first node has no name, or the expanded name has no namespace
8678 * URI, an empty string is returned. If the argument is omitted it
8679 * defaults to the context node.
8682 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8683 xmlXPathObjectPtr cur;
8685 if (ctxt == NULL) return;
8688 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8689 ctxt->context->node));
8693 if ((ctxt->value == NULL) ||
8694 ((ctxt->value->type != XPATH_NODESET) &&
8695 (ctxt->value->type != XPATH_XSLT_TREE)))
8696 XP_ERROR(XPATH_INVALID_TYPE);
8697 cur = valuePop(ctxt);
8699 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8700 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8702 int i = 0; /* Should be first in document order !!!!! */
8703 switch (cur->nodesetval->nodeTab[i]->type) {
8704 case XML_ELEMENT_NODE:
8705 case XML_ATTRIBUTE_NODE:
8706 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8707 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8709 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8710 cur->nodesetval->nodeTab[i]->ns->href));
8713 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8716 xmlXPathReleaseObject(ctxt->context, cur);
8720 * xmlXPathNameFunction:
8721 * @ctxt: the XPath Parser context
8722 * @nargs: the number of arguments
8724 * Implement the name() XPath function
8725 * string name(node-set?)
8726 * The name function returns a string containing a QName representing
8727 * the name of the node in the argument node-set that is first in document
8728 * order. The QName must represent the name with respect to the namespace
8729 * declarations in effect on the node whose name is being represented.
8730 * Typically, this will be the form in which the name occurred in the XML
8731 * source. This need not be the case if there are namespace declarations
8732 * in effect on the node that associate multiple prefixes with the same
8733 * namespace. However, an implementation may include information about
8734 * the original prefix in its representation of nodes; in this case, an
8735 * implementation can ensure that the returned string is always the same
8736 * as the QName used in the XML source. If the argument it omitted it
8737 * defaults to the context node.
8738 * Libxml keep the original prefix so the "real qualified name" used is
8742 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8744 xmlXPathObjectPtr cur;
8747 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8748 ctxt->context->node));
8753 if ((ctxt->value == NULL) ||
8754 ((ctxt->value->type != XPATH_NODESET) &&
8755 (ctxt->value->type != XPATH_XSLT_TREE)))
8756 XP_ERROR(XPATH_INVALID_TYPE);
8757 cur = valuePop(ctxt);
8759 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8760 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8762 int i = 0; /* Should be first in document order !!!!! */
8764 switch (cur->nodesetval->nodeTab[i]->type) {
8765 case XML_ELEMENT_NODE:
8766 case XML_ATTRIBUTE_NODE:
8767 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8769 xmlXPathCacheNewCString(ctxt->context, ""));
8770 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8771 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8773 xmlXPathCacheNewString(ctxt->context,
8774 cur->nodesetval->nodeTab[i]->name));
8778 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8779 cur->nodesetval->nodeTab[i]->ns->prefix,
8781 if (fullname == cur->nodesetval->nodeTab[i]->name)
8782 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8783 if (fullname == NULL) {
8784 XP_ERROR(XPATH_MEMORY_ERROR);
8786 valuePush(ctxt, xmlXPathCacheWrapString(
8787 ctxt->context, fullname));
8791 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8792 cur->nodesetval->nodeTab[i]));
8793 xmlXPathLocalNameFunction(ctxt, 1);
8796 xmlXPathReleaseObject(ctxt->context, cur);
8801 * xmlXPathStringFunction:
8802 * @ctxt: the XPath Parser context
8803 * @nargs: the number of arguments
8805 * Implement the string() XPath function
8806 * string string(object?)
8807 * The string function converts an object to a string as follows:
8808 * - A node-set is converted to a string by returning the value of
8809 * the node in the node-set that is first in document order.
8810 * If the node-set is empty, an empty string is returned.
8811 * - A number is converted to a string as follows
8812 * + NaN is converted to the string NaN
8813 * + positive zero is converted to the string 0
8814 * + negative zero is converted to the string 0
8815 * + positive infinity is converted to the string Infinity
8816 * + negative infinity is converted to the string -Infinity
8817 * + if the number is an integer, the number is represented in
8818 * decimal form as a Number with no decimal point and no leading
8819 * zeros, preceded by a minus sign (-) if the number is negative
8820 * + otherwise, the number is represented in decimal form as a
8821 * Number including a decimal point with at least one digit
8822 * before the decimal point and at least one digit after the
8823 * decimal point, preceded by a minus sign (-) if the number
8824 * is negative; there must be no leading zeros before the decimal
8825 * point apart possibly from the one required digit immediately
8826 * before the decimal point; beyond the one required digit
8827 * after the decimal point there must be as many, but only as
8828 * many, more digits as are needed to uniquely distinguish the
8829 * number from all other IEEE 754 numeric values.
8830 * - The boolean false value is converted to the string false.
8831 * The boolean true value is converted to the string true.
8833 * If the argument is omitted, it defaults to a node-set with the
8834 * context node as its only member.
8837 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8838 xmlXPathObjectPtr cur;
8840 if (ctxt == NULL) return;
8843 xmlXPathCacheWrapString(ctxt->context,
8844 xmlXPathCastNodeToString(ctxt->context->node)));
8849 cur = valuePop(ctxt);
8850 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8851 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8855 * xmlXPathStringLengthFunction:
8856 * @ctxt: the XPath Parser context
8857 * @nargs: the number of arguments
8859 * Implement the string-length() XPath function
8860 * number string-length(string?)
8861 * The string-length returns the number of characters in the string
8862 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8863 * the context node converted to a string, in other words the value
8864 * of the context node.
8867 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8868 xmlXPathObjectPtr cur;
8871 if ((ctxt == NULL) || (ctxt->context == NULL))
8873 if (ctxt->context->node == NULL) {
8874 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8878 content = xmlXPathCastNodeToString(ctxt->context->node);
8879 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8880 xmlUTF8Strlen(content)));
8887 CHECK_TYPE(XPATH_STRING);
8888 cur = valuePop(ctxt);
8889 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8890 xmlUTF8Strlen(cur->stringval)));
8891 xmlXPathReleaseObject(ctxt->context, cur);
8895 * xmlXPathConcatFunction:
8896 * @ctxt: the XPath Parser context
8897 * @nargs: the number of arguments
8899 * Implement the concat() XPath function
8900 * string concat(string, string, string*)
8901 * The concat function returns the concatenation of its arguments.
8904 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8905 xmlXPathObjectPtr cur, newobj;
8908 if (ctxt == NULL) return;
8914 cur = valuePop(ctxt);
8915 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8916 xmlXPathReleaseObject(ctxt->context, cur);
8923 newobj = valuePop(ctxt);
8924 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8925 xmlXPathReleaseObject(ctxt->context, newobj);
8926 xmlXPathReleaseObject(ctxt->context, cur);
8927 XP_ERROR(XPATH_INVALID_TYPE);
8929 tmp = xmlStrcat(newobj->stringval, cur->stringval);
8930 newobj->stringval = cur->stringval;
8931 cur->stringval = tmp;
8932 xmlXPathReleaseObject(ctxt->context, newobj);
8935 valuePush(ctxt, cur);
8939 * xmlXPathContainsFunction:
8940 * @ctxt: the XPath Parser context
8941 * @nargs: the number of arguments
8943 * Implement the contains() XPath function
8944 * boolean contains(string, string)
8945 * The contains function returns true if the first argument string
8946 * contains the second argument string, and otherwise returns false.
8949 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8950 xmlXPathObjectPtr hay, needle;
8954 CHECK_TYPE(XPATH_STRING);
8955 needle = valuePop(ctxt);
8957 hay = valuePop(ctxt);
8959 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8960 xmlXPathReleaseObject(ctxt->context, hay);
8961 xmlXPathReleaseObject(ctxt->context, needle);
8962 XP_ERROR(XPATH_INVALID_TYPE);
8964 if (xmlStrstr(hay->stringval, needle->stringval))
8965 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8967 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8968 xmlXPathReleaseObject(ctxt->context, hay);
8969 xmlXPathReleaseObject(ctxt->context, needle);
8973 * xmlXPathStartsWithFunction:
8974 * @ctxt: the XPath Parser context
8975 * @nargs: the number of arguments
8977 * Implement the starts-with() XPath function
8978 * boolean starts-with(string, string)
8979 * The starts-with function returns true if the first argument string
8980 * starts with the second argument string, and otherwise returns false.
8983 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8984 xmlXPathObjectPtr hay, needle;
8989 CHECK_TYPE(XPATH_STRING);
8990 needle = valuePop(ctxt);
8992 hay = valuePop(ctxt);
8994 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8995 xmlXPathReleaseObject(ctxt->context, hay);
8996 xmlXPathReleaseObject(ctxt->context, needle);
8997 XP_ERROR(XPATH_INVALID_TYPE);
8999 n = xmlStrlen(needle->stringval);
9000 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9001 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9003 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9004 xmlXPathReleaseObject(ctxt->context, hay);
9005 xmlXPathReleaseObject(ctxt->context, needle);
9009 * xmlXPathSubstringFunction:
9010 * @ctxt: the XPath Parser context
9011 * @nargs: the number of arguments
9013 * Implement the substring() XPath function
9014 * string substring(string, number, number?)
9015 * The substring function returns the substring of the first argument
9016 * starting at the position specified in the second argument with
9017 * length specified in the third argument. For example,
9018 * substring("12345",2,3) returns "234". If the third argument is not
9019 * specified, it returns the substring starting at the position specified
9020 * in the second argument and continuing to the end of the string. For
9021 * example, substring("12345",2) returns "2345". More precisely, each
9022 * character in the string (see [3.6 Strings]) is considered to have a
9023 * numeric position: the position of the first character is 1, the position
9024 * of the second character is 2 and so on. The returned substring contains
9025 * those characters for which the position of the character is greater than
9026 * or equal to the second argument and, if the third argument is specified,
9027 * less than the sum of the second and third arguments; the comparisons
9028 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9029 * - substring("12345", 1.5, 2.6) returns "234"
9030 * - substring("12345", 0, 3) returns "12"
9031 * - substring("12345", 0 div 0, 3) returns ""
9032 * - substring("12345", 1, 0 div 0) returns ""
9033 * - substring("12345", -42, 1 div 0) returns "12345"
9034 * - substring("12345", -1 div 0, 1 div 0) returns ""
9037 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9038 xmlXPathObjectPtr str, start, len;
9050 * take care of possible last (position) argument
9054 CHECK_TYPE(XPATH_NUMBER);
9055 len = valuePop(ctxt);
9057 xmlXPathReleaseObject(ctxt->context, len);
9061 CHECK_TYPE(XPATH_NUMBER);
9062 start = valuePop(ctxt);
9063 in = start->floatval;
9064 xmlXPathReleaseObject(ctxt->context, start);
9066 CHECK_TYPE(XPATH_STRING);
9067 str = valuePop(ctxt);
9068 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9071 * If last pos not present, calculate last position
9079 /* Need to check for the special cases where either
9080 * the index is NaN, the length is NaN, or both
9081 * arguments are infinity (relying on Inf + -Inf = NaN)
9083 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9085 * To meet the requirements of the spec, the arguments
9086 * must be converted to integer format before
9087 * initial index calculations are done
9089 * First we go to integer form, rounding up
9090 * and checking for special cases
9093 if (((double)i)+0.5 <= in) i++;
9095 if (xmlXPathIsInf(le) == 1) {
9100 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9104 if (((double)l)+0.5 <= le) l++;
9107 /* Now we normalize inidices */
9115 /* number of chars to copy */
9118 ret = xmlUTF8Strsub(str->stringval, i, l);
9124 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9126 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9129 xmlXPathReleaseObject(ctxt->context, str);
9133 * xmlXPathSubstringBeforeFunction:
9134 * @ctxt: the XPath Parser context
9135 * @nargs: the number of arguments
9137 * Implement the substring-before() XPath function
9138 * string substring-before(string, string)
9139 * The substring-before function returns the substring of the first
9140 * argument string that precedes the first occurrence of the second
9141 * argument string in the first argument string, or the empty string
9142 * if the first argument string does not contain the second argument
9143 * string. For example, substring-before("1999/04/01","/") returns 1999.
9146 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9147 xmlXPathObjectPtr str;
9148 xmlXPathObjectPtr find;
9149 xmlBufferPtr target;
9150 const xmlChar *point;
9155 find = valuePop(ctxt);
9157 str = valuePop(ctxt);
9159 target = xmlBufferCreate();
9161 point = xmlStrstr(str->stringval, find->stringval);
9163 offset = (int)(point - str->stringval);
9164 xmlBufferAdd(target, str->stringval, offset);
9166 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9167 xmlBufferContent(target)));
9168 xmlBufferFree(target);
9170 xmlXPathReleaseObject(ctxt->context, str);
9171 xmlXPathReleaseObject(ctxt->context, find);
9175 * xmlXPathSubstringAfterFunction:
9176 * @ctxt: the XPath Parser context
9177 * @nargs: the number of arguments
9179 * Implement the substring-after() XPath function
9180 * string substring-after(string, string)
9181 * The substring-after function returns the substring of the first
9182 * argument string that follows the first occurrence of the second
9183 * argument string in the first argument string, or the empty stringi
9184 * if the first argument string does not contain the second argument
9185 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9186 * and substring-after("1999/04/01","19") returns 99/04/01.
9189 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9190 xmlXPathObjectPtr str;
9191 xmlXPathObjectPtr find;
9192 xmlBufferPtr target;
9193 const xmlChar *point;
9198 find = valuePop(ctxt);
9200 str = valuePop(ctxt);
9202 target = xmlBufferCreate();
9204 point = xmlStrstr(str->stringval, find->stringval);
9206 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9207 xmlBufferAdd(target, &str->stringval[offset],
9208 xmlStrlen(str->stringval) - offset);
9210 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9211 xmlBufferContent(target)));
9212 xmlBufferFree(target);
9214 xmlXPathReleaseObject(ctxt->context, str);
9215 xmlXPathReleaseObject(ctxt->context, find);
9219 * xmlXPathNormalizeFunction:
9220 * @ctxt: the XPath Parser context
9221 * @nargs: the number of arguments
9223 * Implement the normalize-space() XPath function
9224 * string normalize-space(string?)
9225 * The normalize-space function returns the argument string with white
9226 * space normalized by stripping leading and trailing whitespace
9227 * and replacing sequences of whitespace characters by a single
9228 * space. Whitespace characters are the same allowed by the S production
9229 * in XML. If the argument is omitted, it defaults to the context
9230 * node converted to a string, in other words the value of the context node.
9233 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9234 xmlXPathObjectPtr obj = NULL;
9235 xmlChar *source = NULL;
9236 xmlBufferPtr target;
9239 if (ctxt == NULL) return;
9241 /* Use current context node */
9243 xmlXPathCacheWrapString(ctxt->context,
9244 xmlXPathCastNodeToString(ctxt->context->node)));
9250 CHECK_TYPE(XPATH_STRING);
9251 obj = valuePop(ctxt);
9252 source = obj->stringval;
9254 target = xmlBufferCreate();
9255 if (target && source) {
9257 /* Skip leading whitespaces */
9258 while (IS_BLANK_CH(*source))
9261 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9264 if (IS_BLANK_CH(*source)) {
9268 xmlBufferAdd(target, &blank, 1);
9271 xmlBufferAdd(target, source, 1);
9275 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9276 xmlBufferContent(target)));
9277 xmlBufferFree(target);
9279 xmlXPathReleaseObject(ctxt->context, obj);
9283 * xmlXPathTranslateFunction:
9284 * @ctxt: the XPath Parser context
9285 * @nargs: the number of arguments
9287 * Implement the translate() XPath function
9288 * string translate(string, string, string)
9289 * The translate function returns the first argument string with
9290 * occurrences of characters in the second argument string replaced
9291 * by the character at the corresponding position in the third argument
9292 * string. For example, translate("bar","abc","ABC") returns the string
9293 * BAr. If there is a character in the second argument string with no
9294 * character at a corresponding position in the third argument string
9295 * (because the second argument string is longer than the third argument
9296 * string), then occurrences of that character in the first argument
9297 * string are removed. For example, translate("--aaa--","abc-","ABC")
9298 * returns "AAA". If a character occurs more than once in second
9299 * argument string, then the first occurrence determines the replacement
9300 * character. If the third argument string is longer than the second
9301 * argument string, then excess characters are ignored.
9304 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9305 xmlXPathObjectPtr str;
9306 xmlXPathObjectPtr from;
9307 xmlXPathObjectPtr to;
9308 xmlBufferPtr target;
9311 const xmlChar *point;
9317 to = valuePop(ctxt);
9319 from = valuePop(ctxt);
9321 str = valuePop(ctxt);
9323 target = xmlBufferCreate();
9325 max = xmlUTF8Strlen(to->stringval);
9326 for (cptr = str->stringval; (ch=*cptr); ) {
9327 offset = xmlUTF8Strloc(from->stringval, cptr);
9330 point = xmlUTF8Strpos(to->stringval, offset);
9332 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
9335 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9337 /* Step to next character in input */
9340 /* if not simple ascii, verify proper format */
9341 if ( (ch & 0xc0) != 0xc0 ) {
9342 xmlGenericError(xmlGenericErrorContext,
9343 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9344 /* not asserting an XPath error is probably better */
9347 /* then skip over remaining bytes for this char */
9348 while ( (ch <<= 1) & 0x80 )
9349 if ( (*cptr++ & 0xc0) != 0x80 ) {
9350 xmlGenericError(xmlGenericErrorContext,
9351 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9352 /* not asserting an XPath error is probably better */
9355 if (ch & 0x80) /* must have had error encountered */
9360 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9361 xmlBufferContent(target)));
9362 xmlBufferFree(target);
9363 xmlXPathReleaseObject(ctxt->context, str);
9364 xmlXPathReleaseObject(ctxt->context, from);
9365 xmlXPathReleaseObject(ctxt->context, to);
9369 * xmlXPathBooleanFunction:
9370 * @ctxt: the XPath Parser context
9371 * @nargs: the number of arguments
9373 * Implement the boolean() XPath function
9374 * boolean boolean(object)
9375 * The boolean function converts its argument to a boolean as follows:
9376 * - a number is true if and only if it is neither positive or
9377 * negative zero nor NaN
9378 * - a node-set is true if and only if it is non-empty
9379 * - a string is true if and only if its length is non-zero
9382 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9383 xmlXPathObjectPtr cur;
9386 cur = valuePop(ctxt);
9387 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9388 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9389 valuePush(ctxt, cur);
9393 * xmlXPathNotFunction:
9394 * @ctxt: the XPath Parser context
9395 * @nargs: the number of arguments
9397 * Implement the not() XPath function
9398 * boolean not(boolean)
9399 * The not function returns true if its argument is false,
9400 * and false otherwise.
9403 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9406 CHECK_TYPE(XPATH_BOOLEAN);
9407 ctxt->value->boolval = ! ctxt->value->boolval;
9411 * xmlXPathTrueFunction:
9412 * @ctxt: the XPath Parser context
9413 * @nargs: the number of arguments
9415 * Implement the true() XPath function
9419 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9421 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9425 * xmlXPathFalseFunction:
9426 * @ctxt: the XPath Parser context
9427 * @nargs: the number of arguments
9429 * Implement the false() XPath function
9433 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9435 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9439 * xmlXPathLangFunction:
9440 * @ctxt: the XPath Parser context
9441 * @nargs: the number of arguments
9443 * Implement the lang() XPath function
9444 * boolean lang(string)
9445 * The lang function returns true or false depending on whether the
9446 * language of the context node as specified by xml:lang attributes
9447 * is the same as or is a sublanguage of the language specified by
9448 * the argument string. The language of the context node is determined
9449 * by the value of the xml:lang attribute on the context node, or, if
9450 * the context node has no xml:lang attribute, by the value of the
9451 * xml:lang attribute on the nearest ancestor of the context node that
9452 * has an xml:lang attribute. If there is no such attribute, then lang
9453 * returns false. If there is such an attribute, then lang returns
9454 * true if the attribute value is equal to the argument ignoring case,
9455 * or if there is some suffix starting with - such that the attribute
9456 * value is equal to the argument ignoring that suffix of the attribute
9457 * value and ignoring case.
9460 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9461 xmlXPathObjectPtr val = NULL;
9462 const xmlChar *theLang = NULL;
9463 const xmlChar *lang;
9469 CHECK_TYPE(XPATH_STRING);
9470 val = valuePop(ctxt);
9471 lang = val->stringval;
9472 theLang = xmlNodeGetLang(ctxt->context->node);
9473 if ((theLang != NULL) && (lang != NULL)) {
9474 for (i = 0;lang[i] != 0;i++)
9475 if (toupper(lang[i]) != toupper(theLang[i]))
9477 if ((theLang[i] == 0) || (theLang[i] == '-'))
9481 if (theLang != NULL)
9482 xmlFree((void *)theLang);
9484 xmlXPathReleaseObject(ctxt->context, val);
9485 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9489 * xmlXPathNumberFunction:
9490 * @ctxt: the XPath Parser context
9491 * @nargs: the number of arguments
9493 * Implement the number() XPath function
9494 * number number(object?)
9497 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9498 xmlXPathObjectPtr cur;
9501 if (ctxt == NULL) return;
9503 if (ctxt->context->node == NULL) {
9504 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9506 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9508 res = xmlXPathStringEvalNumber(content);
9509 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9516 cur = valuePop(ctxt);
9517 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9521 * xmlXPathSumFunction:
9522 * @ctxt: the XPath Parser context
9523 * @nargs: the number of arguments
9525 * Implement the sum() XPath function
9526 * number sum(node-set)
9527 * The sum function returns the sum of the values of the nodes in
9528 * the argument node-set.
9531 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9532 xmlXPathObjectPtr cur;
9537 if ((ctxt->value == NULL) ||
9538 ((ctxt->value->type != XPATH_NODESET) &&
9539 (ctxt->value->type != XPATH_XSLT_TREE)))
9540 XP_ERROR(XPATH_INVALID_TYPE);
9541 cur = valuePop(ctxt);
9543 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9544 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9545 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9548 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9549 xmlXPathReleaseObject(ctxt->context, cur);
9553 * To assure working code on multiple platforms, we want to only depend
9554 * upon the characteristic truncation of converting a floating point value
9555 * to an integer. Unfortunately, because of the different storage sizes
9556 * of our internal floating point value (double) and integer (int), we
9557 * can't directly convert (see bug 301162). This macro is a messy
9560 #define XTRUNC(f, v) \
9561 f = fmod((v), INT_MAX); \
9562 f = (v) - (f) + (double)((int)(f));
9565 * xmlXPathFloorFunction:
9566 * @ctxt: the XPath Parser context
9567 * @nargs: the number of arguments
9569 * Implement the floor() XPath function
9570 * number floor(number)
9571 * The floor function returns the largest (closest to positive infinity)
9572 * number that is not greater than the argument and that is an integer.
9575 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9580 CHECK_TYPE(XPATH_NUMBER);
9582 XTRUNC(f, ctxt->value->floatval);
9583 if (f != ctxt->value->floatval) {
9584 if (ctxt->value->floatval > 0)
9585 ctxt->value->floatval = f;
9587 ctxt->value->floatval = f - 1;
9592 * xmlXPathCeilingFunction:
9593 * @ctxt: the XPath Parser context
9594 * @nargs: the number of arguments
9596 * Implement the ceiling() XPath function
9597 * number ceiling(number)
9598 * The ceiling function returns the smallest (closest to negative infinity)
9599 * number that is not less than the argument and that is an integer.
9602 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9607 CHECK_TYPE(XPATH_NUMBER);
9610 ctxt->value->floatval = ceil(ctxt->value->floatval);
9612 XTRUNC(f, ctxt->value->floatval);
9613 if (f != ctxt->value->floatval) {
9614 if (ctxt->value->floatval > 0)
9615 ctxt->value->floatval = f + 1;
9617 if (ctxt->value->floatval < 0 && f == 0)
9618 ctxt->value->floatval = xmlXPathNZERO;
9620 ctxt->value->floatval = f;
9628 * xmlXPathRoundFunction:
9629 * @ctxt: the XPath Parser context
9630 * @nargs: the number of arguments
9632 * Implement the round() XPath function
9633 * number round(number)
9634 * The round function returns the number that is closest to the
9635 * argument and that is an integer. If there are two such numbers,
9636 * then the one that is even is returned.
9639 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9644 CHECK_TYPE(XPATH_NUMBER);
9646 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
9647 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
9648 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
9649 (ctxt->value->floatval == 0.0))
9652 XTRUNC(f, ctxt->value->floatval);
9653 if (ctxt->value->floatval < 0) {
9654 if (ctxt->value->floatval < f - 0.5)
9655 ctxt->value->floatval = f - 1;
9657 ctxt->value->floatval = f;
9658 if (ctxt->value->floatval == 0)
9659 ctxt->value->floatval = xmlXPathNZERO;
9661 if (ctxt->value->floatval < f + 0.5)
9662 ctxt->value->floatval = f;
9664 ctxt->value->floatval = f + 1;
9668 /************************************************************************
9672 ************************************************************************/
9675 * a few forward declarations since we use a recursive call based
9678 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9679 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9680 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9681 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9682 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9686 * xmlXPathCurrentChar:
9687 * @ctxt: the XPath parser context
9688 * @cur: pointer to the beginning of the char
9689 * @len: pointer to the length of the char read
9691 * The current char value, if using UTF-8 this may actually span multiple
9692 * bytes in the input buffer.
9694 * Returns the current char value and its length
9698 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9708 * We are supposed to handle UTF8, check it's valid
9709 * From rfc2044: encoding of the Unicode values on UTF-8:
9711 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9712 * 0000 0000-0000 007F 0xxxxxxx
9713 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9714 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9716 * Check for the 0x110000 limit too
9720 if ((cur[1] & 0xc0) != 0x80)
9721 goto encoding_error;
9722 if ((c & 0xe0) == 0xe0) {
9724 if ((cur[2] & 0xc0) != 0x80)
9725 goto encoding_error;
9726 if ((c & 0xf0) == 0xf0) {
9727 if (((c & 0xf8) != 0xf0) ||
9728 ((cur[3] & 0xc0) != 0x80))
9729 goto encoding_error;
9732 val = (cur[0] & 0x7) << 18;
9733 val |= (cur[1] & 0x3f) << 12;
9734 val |= (cur[2] & 0x3f) << 6;
9735 val |= cur[3] & 0x3f;
9739 val = (cur[0] & 0xf) << 12;
9740 val |= (cur[1] & 0x3f) << 6;
9741 val |= cur[2] & 0x3f;
9746 val = (cur[0] & 0x1f) << 6;
9747 val |= cur[1] & 0x3f;
9749 if (!IS_CHAR(val)) {
9750 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9760 * If we detect an UTF8 error that probably means that the
9761 * input encoding didn't get properly advertised in the
9762 * declaration header. Report the error and switch the encoding
9763 * to ISO-Latin-1 (if you don't like this policy, just declare the
9767 XP_ERROR0(XPATH_ENCODING_ERROR);
9771 * xmlXPathParseNCName:
9772 * @ctxt: the XPath Parser context
9774 * parse an XML namespace non qualified name.
9776 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9778 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9779 * CombiningChar | Extender
9781 * Returns the namespace name or NULL
9785 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9790 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9792 * Accelerator for simple ASCII names
9795 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9796 ((*in >= 0x41) && (*in <= 0x5A)) ||
9799 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9800 ((*in >= 0x41) && (*in <= 0x5A)) ||
9801 ((*in >= 0x30) && (*in <= 0x39)) ||
9802 (*in == '_') || (*in == '.') ||
9805 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9806 (*in == '[') || (*in == ']') || (*in == ':') ||
9807 (*in == '@') || (*in == '*')) {
9808 count = in - ctxt->cur;
9811 ret = xmlStrndup(ctxt->cur, count);
9816 return(xmlXPathParseNameComplex(ctxt, 0));
9821 * xmlXPathParseQName:
9822 * @ctxt: the XPath Parser context
9823 * @prefix: a xmlChar **
9825 * parse an XML qualified name
9827 * [NS 5] QName ::= (Prefix ':')? LocalPart
9829 * [NS 6] Prefix ::= NCName
9831 * [NS 7] LocalPart ::= NCName
9833 * Returns the function returns the local part, and prefix is updated
9834 * to get the Prefix if any.
9838 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9839 xmlChar *ret = NULL;
9842 ret = xmlXPathParseNCName(ctxt);
9843 if (ret && CUR == ':') {
9846 ret = xmlXPathParseNCName(ctxt);
9852 * xmlXPathParseName:
9853 * @ctxt: the XPath Parser context
9857 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9858 * CombiningChar | Extender
9860 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9862 * Returns the namespace name or NULL
9866 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9871 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9873 * Accelerator for simple ASCII names
9876 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9877 ((*in >= 0x41) && (*in <= 0x5A)) ||
9878 (*in == '_') || (*in == ':')) {
9880 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9881 ((*in >= 0x41) && (*in <= 0x5A)) ||
9882 ((*in >= 0x30) && (*in <= 0x39)) ||
9883 (*in == '_') || (*in == '-') ||
9884 (*in == ':') || (*in == '.'))
9886 if ((*in > 0) && (*in < 0x80)) {
9887 count = in - ctxt->cur;
9888 ret = xmlStrndup(ctxt->cur, count);
9893 return(xmlXPathParseNameComplex(ctxt, 1));
9897 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9898 xmlChar buf[XML_MAX_NAMELEN + 5];
9903 * Handler for more complex cases
9906 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9907 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
9908 (c == '*') || /* accelerators */
9909 (!IS_LETTER(c) && (c != '_') &&
9910 ((qualified) && (c != ':')))) {
9914 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9915 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9916 (c == '.') || (c == '-') ||
9917 (c == '_') || ((qualified) && (c == ':')) ||
9918 (IS_COMBINING(c)) ||
9919 (IS_EXTENDER(c)))) {
9920 COPY_BUF(l,buf,len,c);
9923 if (len >= XML_MAX_NAMELEN) {
9925 * Okay someone managed to make a huge name, so he's ready to pay
9926 * for the processing speed.
9931 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
9932 if (buffer == NULL) {
9933 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9935 memcpy(buffer, buf, len);
9936 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9937 (c == '.') || (c == '-') ||
9938 (c == '_') || ((qualified) && (c == ':')) ||
9939 (IS_COMBINING(c)) ||
9941 if (len + 10 > max) {
9943 buffer = (xmlChar *) xmlRealloc(buffer,
9944 max * sizeof(xmlChar));
9945 if (buffer == NULL) {
9946 XP_ERRORNULL(XPATH_MEMORY_ERROR);
9949 COPY_BUF(l,buffer,len,c);
9959 return(xmlStrndup(buf, len));
9965 * These are used as divisors for the fractional part of a number.
9966 * Since the table includes 1.0 (representing '0' fractional digits),
9967 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
9969 static double my_pow10[MAX_FRAC+1] = {
9970 1.0, 10.0, 100.0, 1000.0, 10000.0,
9971 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
9972 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
9974 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
9975 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
9979 * xmlXPathStringEvalNumber:
9980 * @str: A string to scan
9982 * [30a] Float ::= Number ('e' Digits?)?
9984 * [30] Number ::= Digits ('.' Digits?)?
9986 * [31] Digits ::= [0-9]+
9988 * Compile a Number in the string
9989 * In complement of the Number expression, this function also handles
9990 * negative values : '-' Number.
9992 * Returns the double value.
9995 xmlXPathStringEvalNumber(const xmlChar *str) {
9996 const xmlChar *cur = str;
10001 int is_exponent_negative = 0;
10003 unsigned long tmp = 0;
10006 if (cur == NULL) return(0);
10007 while (IS_BLANK_CH(*cur)) cur++;
10008 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10009 return(xmlXPathNAN);
10018 * tmp/temp is a workaround against a gcc compiler bug
10019 * http://veillard.com/gcc.bug
10022 while ((*cur >= '0') && (*cur <= '9')) {
10024 tmp = (*cur - '0');
10027 temp = (double) tmp;
10032 while ((*cur >= '0') && (*cur <= '9')) {
10033 ret = ret * 10 + (*cur - '0');
10041 double fraction = 0;
10044 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10045 return(xmlXPathNAN);
10047 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
10049 fraction = fraction * 10 + v;
10053 fraction /= my_pow10[frac];
10054 ret = ret + fraction;
10055 while ((*cur >= '0') && (*cur <= '9'))
10058 if ((*cur == 'e') || (*cur == 'E')) {
10061 is_exponent_negative = 1;
10063 } else if (*cur == '+') {
10066 while ((*cur >= '0') && (*cur <= '9')) {
10067 exponent = exponent * 10 + (*cur - '0');
10071 while (IS_BLANK_CH(*cur)) cur++;
10072 if (*cur != 0) return(xmlXPathNAN);
10073 if (isneg) ret = -ret;
10074 if (is_exponent_negative) exponent = -exponent;
10075 ret *= pow(10.0, (double)exponent);
10080 * xmlXPathCompNumber:
10081 * @ctxt: the XPath Parser context
10083 * [30] Number ::= Digits ('.' Digits?)?
10085 * [31] Digits ::= [0-9]+
10087 * Compile a Number, then push it on the stack
10091 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10096 int is_exponent_negative = 0;
10098 unsigned long tmp = 0;
10103 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10104 XP_ERROR(XPATH_NUMBER_ERROR);
10108 * tmp/temp is a workaround against a gcc compiler bug
10109 * http://veillard.com/gcc.bug
10112 while ((CUR >= '0') && (CUR <= '9')) {
10117 temp = (double) tmp;
10122 while ((CUR >= '0') && (CUR <= '9')) {
10123 ret = ret * 10 + (CUR - '0');
10130 double fraction = 0;
10133 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10134 XP_ERROR(XPATH_NUMBER_ERROR);
10136 while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
10138 fraction = fraction * 10 + v;
10142 fraction /= my_pow10[frac];
10143 ret = ret + fraction;
10144 while ((CUR >= '0') && (CUR <= '9'))
10147 if ((CUR == 'e') || (CUR == 'E')) {
10150 is_exponent_negative = 1;
10152 } else if (CUR == '+') {
10155 while ((CUR >= '0') && (CUR <= '9')) {
10156 exponent = exponent * 10 + (CUR - '0');
10159 if (is_exponent_negative)
10160 exponent = -exponent;
10161 ret *= pow(10.0, (double) exponent);
10163 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10164 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10168 * xmlXPathParseLiteral:
10169 * @ctxt: the XPath Parser context
10173 * [29] Literal ::= '"' [^"]* '"'
10176 * Returns the value found or NULL in case of error
10179 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10181 xmlChar *ret = NULL;
10186 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10188 if (!IS_CHAR_CH(CUR)) {
10189 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10191 ret = xmlStrndup(q, CUR_PTR - q);
10194 } else if (CUR == '\'') {
10197 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10199 if (!IS_CHAR_CH(CUR)) {
10200 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10202 ret = xmlStrndup(q, CUR_PTR - q);
10206 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10212 * xmlXPathCompLiteral:
10213 * @ctxt: the XPath Parser context
10215 * Parse a Literal and push it on the stack.
10217 * [29] Literal ::= '"' [^"]* '"'
10220 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10223 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10225 xmlChar *ret = NULL;
10230 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10232 if (!IS_CHAR_CH(CUR)) {
10233 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10235 ret = xmlStrndup(q, CUR_PTR - q);
10238 } else if (CUR == '\'') {
10241 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10243 if (!IS_CHAR_CH(CUR)) {
10244 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10246 ret = xmlStrndup(q, CUR_PTR - q);
10250 XP_ERROR(XPATH_START_LITERAL_ERROR);
10252 if (ret == NULL) return;
10253 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10254 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10259 * xmlXPathCompVariableReference:
10260 * @ctxt: the XPath Parser context
10262 * Parse a VariableReference, evaluate it and push it on the stack.
10264 * The variable bindings consist of a mapping from variable names
10265 * to variable values. The value of a variable is an object, which can be
10266 * of any of the types that are possible for the value of an expression,
10267 * and may also be of additional types not specified here.
10269 * Early evaluation is possible since:
10270 * The variable bindings [...] used to evaluate a subexpression are
10271 * always the same as those used to evaluate the containing expression.
10273 * [36] VariableReference ::= '$' QName
10276 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10282 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10285 name = xmlXPathParseQName(ctxt, &prefix);
10286 if (name == NULL) {
10287 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10289 ctxt->comp->last = -1;
10290 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10293 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10294 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
10299 * xmlXPathIsNodeType:
10300 * @name: a name string
10302 * Is the name given a NodeType one.
10304 * [38] NodeType ::= 'comment'
10306 * | 'processing-instruction'
10309 * Returns 1 if true 0 otherwise
10312 xmlXPathIsNodeType(const xmlChar *name) {
10316 if (xmlStrEqual(name, BAD_CAST "node"))
10318 if (xmlStrEqual(name, BAD_CAST "text"))
10320 if (xmlStrEqual(name, BAD_CAST "comment"))
10322 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10328 * xmlXPathCompFunctionCall:
10329 * @ctxt: the XPath Parser context
10331 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10332 * [17] Argument ::= Expr
10334 * Compile a function call, the evaluation of all arguments are
10335 * pushed on the stack
10338 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10344 name = xmlXPathParseQName(ctxt, &prefix);
10345 if (name == NULL) {
10347 XP_ERROR(XPATH_EXPR_ERROR);
10351 if (prefix == NULL)
10352 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10355 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10360 XP_ERROR(XPATH_EXPR_ERROR);
10366 * Optimization for count(): we don't need the node-set to be sorted.
10368 if ((prefix == NULL) && (name[0] == 'c') &&
10369 xmlStrEqual(name, BAD_CAST "count"))
10373 ctxt->comp->last = -1;
10376 int op1 = ctxt->comp->last;
10377 ctxt->comp->last = -1;
10378 xmlXPathCompileExpr(ctxt, sort);
10379 if (ctxt->error != XPATH_EXPRESSION_OK) {
10384 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10386 if (CUR == ')') break;
10388 XP_ERROR(XPATH_EXPR_ERROR);
10394 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10401 * xmlXPathCompPrimaryExpr:
10402 * @ctxt: the XPath Parser context
10404 * [15] PrimaryExpr ::= VariableReference
10410 * Compile a primary expression.
10413 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10415 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10416 else if (CUR == '(') {
10419 xmlXPathCompileExpr(ctxt, 1);
10422 XP_ERROR(XPATH_EXPR_ERROR);
10426 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10427 xmlXPathCompNumber(ctxt);
10428 } else if ((CUR == '\'') || (CUR == '"')) {
10429 xmlXPathCompLiteral(ctxt);
10431 xmlXPathCompFunctionCall(ctxt);
10437 * xmlXPathCompFilterExpr:
10438 * @ctxt: the XPath Parser context
10440 * [20] FilterExpr ::= PrimaryExpr
10441 * | FilterExpr Predicate
10443 * Compile a filter expression.
10444 * Square brackets are used to filter expressions in the same way that
10445 * they are used in location paths. It is an error if the expression to
10446 * be filtered does not evaluate to a node-set. The context node list
10447 * used for evaluating the expression in square brackets is the node-set
10448 * to be filtered listed in document order.
10452 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10453 xmlXPathCompPrimaryExpr(ctxt);
10457 while (CUR == '[') {
10458 xmlXPathCompPredicate(ctxt, 1);
10466 * xmlXPathScanName:
10467 * @ctxt: the XPath Parser context
10469 * Trickery: parse an XML name but without consuming the input flow
10470 * Needed to avoid insanity in the parser state.
10472 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10473 * CombiningChar | Extender
10475 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10477 * [6] Names ::= Name (S Name)*
10479 * Returns the Name parsed or NULL
10483 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10486 const xmlChar *cur;
10492 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10493 (!IS_LETTER(c) && (c != '_') &&
10498 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10499 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10500 (c == '.') || (c == '-') ||
10501 (c == '_') || (c == ':') ||
10502 (IS_COMBINING(c)) ||
10503 (IS_EXTENDER(c)))) {
10508 ret = xmlStrndup(cur, ctxt->cur - cur);
10514 * xmlXPathCompPathExpr:
10515 * @ctxt: the XPath Parser context
10517 * [19] PathExpr ::= LocationPath
10519 * | FilterExpr '/' RelativeLocationPath
10520 * | FilterExpr '//' RelativeLocationPath
10522 * Compile a path expression.
10523 * The / operator and // operators combine an arbitrary expression
10524 * and a relative location path. It is an error if the expression
10525 * does not evaluate to a node-set.
10526 * The / operator does composition in the same way as when / is
10527 * used in a location path. As in location paths, // is short for
10528 * /descendant-or-self::node()/.
10532 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10533 int lc = 1; /* Should we branch to LocationPath ? */
10534 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10537 if ((CUR == '$') || (CUR == '(') ||
10538 (IS_ASCII_DIGIT(CUR)) ||
10539 (CUR == '\'') || (CUR == '"') ||
10540 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10542 } else if (CUR == '*') {
10543 /* relative or absolute location path */
10545 } else if (CUR == '/') {
10546 /* relative or absolute location path */
10548 } else if (CUR == '@') {
10549 /* relative abbreviated attribute location path */
10551 } else if (CUR == '.') {
10552 /* relative abbreviated attribute location path */
10556 * Problem is finding if we have a name here whether it's:
10558 * - a function call in which case it's followed by '('
10559 * - an axis in which case it's followed by ':'
10561 * We do an a priori analysis here rather than having to
10562 * maintain parsed token content through the recursive function
10563 * calls. This looks uglier but makes the code easier to
10564 * read/write/debug.
10567 name = xmlXPathScanName(ctxt);
10568 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10570 xmlGenericError(xmlGenericErrorContext,
10571 "PathExpr: Axis\n");
10575 } else if (name != NULL) {
10576 int len =xmlStrlen(name);
10579 while (NXT(len) != 0) {
10580 if (NXT(len) == '/') {
10583 xmlGenericError(xmlGenericErrorContext,
10584 "PathExpr: AbbrRelLocation\n");
10588 } else if (IS_BLANK_CH(NXT(len))) {
10589 /* ignore blanks */
10591 } else if (NXT(len) == ':') {
10593 xmlGenericError(xmlGenericErrorContext,
10594 "PathExpr: AbbrRelLocation\n");
10598 } else if ((NXT(len) == '(')) {
10599 /* Note Type or Function */
10600 if (xmlXPathIsNodeType(name)) {
10602 xmlGenericError(xmlGenericErrorContext,
10603 "PathExpr: Type search\n");
10608 xmlGenericError(xmlGenericErrorContext,
10609 "PathExpr: function call\n");
10614 } else if ((NXT(len) == '[')) {
10617 xmlGenericError(xmlGenericErrorContext,
10618 "PathExpr: AbbrRelLocation\n");
10622 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10623 (NXT(len) == '=')) {
10632 if (NXT(len) == 0) {
10634 xmlGenericError(xmlGenericErrorContext,
10635 "PathExpr: AbbrRelLocation\n");
10642 /* make sure all cases are covered explicitly */
10643 XP_ERROR(XPATH_EXPR_ERROR);
10649 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10651 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10653 xmlXPathCompLocationPath(ctxt);
10655 xmlXPathCompFilterExpr(ctxt);
10657 if ((CUR == '/') && (NXT(1) == '/')) {
10661 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10662 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10663 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10665 xmlXPathCompRelativeLocationPath(ctxt);
10666 } else if (CUR == '/') {
10667 xmlXPathCompRelativeLocationPath(ctxt);
10674 * xmlXPathCompUnionExpr:
10675 * @ctxt: the XPath Parser context
10677 * [18] UnionExpr ::= PathExpr
10678 * | UnionExpr '|' PathExpr
10680 * Compile an union expression.
10684 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10685 xmlXPathCompPathExpr(ctxt);
10688 while (CUR == '|') {
10689 int op1 = ctxt->comp->last;
10690 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10694 xmlXPathCompPathExpr(ctxt);
10696 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10703 * xmlXPathCompUnaryExpr:
10704 * @ctxt: the XPath Parser context
10706 * [27] UnaryExpr ::= UnionExpr
10709 * Compile an unary expression.
10713 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10718 while (CUR == '-') {
10725 xmlXPathCompUnionExpr(ctxt);
10729 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10731 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10736 * xmlXPathCompMultiplicativeExpr:
10737 * @ctxt: the XPath Parser context
10739 * [26] MultiplicativeExpr ::= UnaryExpr
10740 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10741 * | MultiplicativeExpr 'div' UnaryExpr
10742 * | MultiplicativeExpr 'mod' UnaryExpr
10743 * [34] MultiplyOperator ::= '*'
10745 * Compile an Additive expression.
10749 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10750 xmlXPathCompUnaryExpr(ctxt);
10753 while ((CUR == '*') ||
10754 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10755 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10757 int op1 = ctxt->comp->last;
10762 } else if (CUR == 'd') {
10765 } else if (CUR == 'm') {
10770 xmlXPathCompUnaryExpr(ctxt);
10772 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10778 * xmlXPathCompAdditiveExpr:
10779 * @ctxt: the XPath Parser context
10781 * [25] AdditiveExpr ::= MultiplicativeExpr
10782 * | AdditiveExpr '+' MultiplicativeExpr
10783 * | AdditiveExpr '-' MultiplicativeExpr
10785 * Compile an Additive expression.
10789 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10791 xmlXPathCompMultiplicativeExpr(ctxt);
10794 while ((CUR == '+') || (CUR == '-')) {
10796 int op1 = ctxt->comp->last;
10798 if (CUR == '+') plus = 1;
10802 xmlXPathCompMultiplicativeExpr(ctxt);
10804 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10810 * xmlXPathCompRelationalExpr:
10811 * @ctxt: the XPath Parser context
10813 * [24] RelationalExpr ::= AdditiveExpr
10814 * | RelationalExpr '<' AdditiveExpr
10815 * | RelationalExpr '>' AdditiveExpr
10816 * | RelationalExpr '<=' AdditiveExpr
10817 * | RelationalExpr '>=' AdditiveExpr
10819 * A <= B > C is allowed ? Answer from James, yes with
10820 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10821 * which is basically what got implemented.
10823 * Compile a Relational expression, then push the result
10828 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10829 xmlXPathCompAdditiveExpr(ctxt);
10832 while ((CUR == '<') ||
10834 ((CUR == '<') && (NXT(1) == '=')) ||
10835 ((CUR == '>') && (NXT(1) == '='))) {
10837 int op1 = ctxt->comp->last;
10839 if (CUR == '<') inf = 1;
10841 if (NXT(1) == '=') strict = 0;
10846 xmlXPathCompAdditiveExpr(ctxt);
10848 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10854 * xmlXPathCompEqualityExpr:
10855 * @ctxt: the XPath Parser context
10857 * [23] EqualityExpr ::= RelationalExpr
10858 * | EqualityExpr '=' RelationalExpr
10859 * | EqualityExpr '!=' RelationalExpr
10861 * A != B != C is allowed ? Answer from James, yes with
10862 * (RelationalExpr = RelationalExpr) = RelationalExpr
10863 * (RelationalExpr != RelationalExpr) != RelationalExpr
10864 * which is basically what got implemented.
10866 * Compile an Equality expression.
10870 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10871 xmlXPathCompRelationalExpr(ctxt);
10874 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10876 int op1 = ctxt->comp->last;
10878 if (CUR == '=') eq = 1;
10883 xmlXPathCompRelationalExpr(ctxt);
10885 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10891 * xmlXPathCompAndExpr:
10892 * @ctxt: the XPath Parser context
10894 * [22] AndExpr ::= EqualityExpr
10895 * | AndExpr 'and' EqualityExpr
10897 * Compile an AND expression.
10901 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10902 xmlXPathCompEqualityExpr(ctxt);
10905 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10906 int op1 = ctxt->comp->last;
10909 xmlXPathCompEqualityExpr(ctxt);
10911 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10917 * xmlXPathCompileExpr:
10918 * @ctxt: the XPath Parser context
10920 * [14] Expr ::= OrExpr
10921 * [21] OrExpr ::= AndExpr
10922 * | OrExpr 'or' AndExpr
10924 * Parse and compile an expression
10927 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10928 xmlXPathCompAndExpr(ctxt);
10931 while ((CUR == 'o') && (NXT(1) == 'r')) {
10932 int op1 = ctxt->comp->last;
10935 xmlXPathCompAndExpr(ctxt);
10937 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10940 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10941 /* more ops could be optimized too */
10943 * This is the main place to eliminate sorting for
10944 * operations which don't require a sorted node-set.
10947 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10952 * xmlXPathCompPredicate:
10953 * @ctxt: the XPath Parser context
10954 * @filter: act as a filter
10956 * [8] Predicate ::= '[' PredicateExpr ']'
10957 * [9] PredicateExpr ::= Expr
10959 * Compile a predicate expression
10962 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10963 int op1 = ctxt->comp->last;
10967 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10972 ctxt->comp->last = -1;
10974 * This call to xmlXPathCompileExpr() will deactivate sorting
10975 * of the predicate result.
10976 * TODO: Sorting is still activated for filters, since I'm not
10977 * sure if needed. Normally sorting should not be needed, since
10978 * a filter can only diminish the number of items in a sequence,
10979 * but won't change its order; so if the initial sequence is sorted,
10980 * subsequent sorting is not needed.
10983 xmlXPathCompileExpr(ctxt, 0);
10985 xmlXPathCompileExpr(ctxt, 1);
10989 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10993 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10995 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11002 * xmlXPathCompNodeTest:
11003 * @ctxt: the XPath Parser context
11004 * @test: pointer to a xmlXPathTestVal
11005 * @type: pointer to a xmlXPathTypeVal
11006 * @prefix: placeholder for a possible name prefix
11008 * [7] NodeTest ::= NameTest
11009 * | NodeType '(' ')'
11010 * | 'processing-instruction' '(' Literal ')'
11012 * [37] NameTest ::= '*'
11015 * [38] NodeType ::= 'comment'
11017 * | 'processing-instruction'
11020 * Returns the name found and updates @test, @type and @prefix appropriately
11023 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11024 xmlXPathTypeVal *type, const xmlChar **prefix,
11028 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11032 *type = (xmlXPathTypeVal) 0;
11033 *test = (xmlXPathTestVal) 0;
11037 if ((name == NULL) && (CUR == '*')) {
11042 *test = NODE_TEST_ALL;
11047 name = xmlXPathParseNCName(ctxt);
11048 if (name == NULL) {
11049 XP_ERRORNULL(XPATH_EXPR_ERROR);
11052 blanks = IS_BLANK_CH(CUR);
11057 * NodeType or PI search
11059 if (xmlStrEqual(name, BAD_CAST "comment"))
11060 *type = NODE_TYPE_COMMENT;
11061 else if (xmlStrEqual(name, BAD_CAST "node"))
11062 *type = NODE_TYPE_NODE;
11063 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11064 *type = NODE_TYPE_PI;
11065 else if (xmlStrEqual(name, BAD_CAST "text"))
11066 *type = NODE_TYPE_TEXT;
11070 XP_ERRORNULL(XPATH_EXPR_ERROR);
11073 *test = NODE_TEST_TYPE;
11076 if (*type == NODE_TYPE_PI) {
11078 * Specific case: search a PI by name.
11084 name = xmlXPathParseLiteral(ctxt);
11086 *test = NODE_TEST_PI;
11093 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11098 *test = NODE_TEST_NAME;
11099 if ((!blanks) && (CUR == ':')) {
11103 * Since currently the parser context don't have a
11104 * namespace list associated:
11105 * The namespace name for this prefix can be computed
11106 * only at evaluation time. The compilation is done
11107 * outside of any context.
11110 *prefix = xmlXPathNsLookup(ctxt->context, name);
11113 if (*prefix == NULL) {
11114 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11125 *test = NODE_TEST_ALL;
11129 name = xmlXPathParseNCName(ctxt);
11130 if (name == NULL) {
11131 XP_ERRORNULL(XPATH_EXPR_ERROR);
11138 * xmlXPathIsAxisName:
11139 * @name: a preparsed name token
11141 * [6] AxisName ::= 'ancestor'
11142 * | 'ancestor-or-self'
11146 * | 'descendant-or-self'
11148 * | 'following-sibling'
11152 * | 'preceding-sibling'
11155 * Returns the axis or 0
11157 static xmlXPathAxisVal
11158 xmlXPathIsAxisName(const xmlChar *name) {
11159 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11162 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11163 ret = AXIS_ANCESTOR;
11164 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11165 ret = AXIS_ANCESTOR_OR_SELF;
11166 if (xmlStrEqual(name, BAD_CAST "attribute"))
11167 ret = AXIS_ATTRIBUTE;
11170 if (xmlStrEqual(name, BAD_CAST "child"))
11174 if (xmlStrEqual(name, BAD_CAST "descendant"))
11175 ret = AXIS_DESCENDANT;
11176 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11177 ret = AXIS_DESCENDANT_OR_SELF;
11180 if (xmlStrEqual(name, BAD_CAST "following"))
11181 ret = AXIS_FOLLOWING;
11182 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11183 ret = AXIS_FOLLOWING_SIBLING;
11186 if (xmlStrEqual(name, BAD_CAST "namespace"))
11187 ret = AXIS_NAMESPACE;
11190 if (xmlStrEqual(name, BAD_CAST "parent"))
11192 if (xmlStrEqual(name, BAD_CAST "preceding"))
11193 ret = AXIS_PRECEDING;
11194 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11195 ret = AXIS_PRECEDING_SIBLING;
11198 if (xmlStrEqual(name, BAD_CAST "self"))
11206 * xmlXPathCompStep:
11207 * @ctxt: the XPath Parser context
11209 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11210 * | AbbreviatedStep
11212 * [12] AbbreviatedStep ::= '.' | '..'
11214 * [5] AxisSpecifier ::= AxisName '::'
11215 * | AbbreviatedAxisSpecifier
11217 * [13] AbbreviatedAxisSpecifier ::= '@'?
11219 * Modified for XPtr range support as:
11221 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11222 * | AbbreviatedStep
11223 * | 'range-to' '(' Expr ')' Predicate*
11225 * Compile one step in a Location Path
11226 * A location step of . is short for self::node(). This is
11227 * particularly useful in conjunction with //. For example, the
11228 * location path .//para is short for
11229 * self::node()/descendant-or-self::node()/child::para
11230 * and so will select all para descendant elements of the context
11232 * Similarly, a location step of .. is short for parent::node().
11233 * For example, ../title is short for parent::node()/child::title
11234 * and so will select the title children of the parent of the context
11238 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11239 #ifdef LIBXML_XPTR_ENABLED
11245 if ((CUR == '.') && (NXT(1) == '.')) {
11248 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11249 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11250 } else if (CUR == '.') {
11254 xmlChar *name = NULL;
11255 const xmlChar *prefix = NULL;
11256 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11257 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11258 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11262 * The modification needed for XPointer change to the production
11264 #ifdef LIBXML_XPTR_ENABLED
11266 name = xmlXPathParseNCName(ctxt);
11267 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11268 op2 = ctxt->comp->last;
11272 XP_ERROR(XPATH_EXPR_ERROR);
11277 xmlXPathCompileExpr(ctxt, 1);
11278 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11283 XP_ERROR(XPATH_EXPR_ERROR);
11287 goto eval_predicates;
11295 name = xmlXPathParseNCName(ctxt);
11296 if (name != NULL) {
11297 axis = xmlXPathIsAxisName(name);
11300 if ((CUR == ':') && (NXT(1) == ':')) {
11305 /* an element name can conflict with an axis one :-\ */
11311 } else if (CUR == '@') {
11313 axis = AXIS_ATTRIBUTE;
11319 if (ctxt->error != XPATH_EXPRESSION_OK) {
11324 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11328 if ((prefix != NULL) && (ctxt->context != NULL) &&
11329 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11330 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11331 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11335 xmlGenericError(xmlGenericErrorContext,
11336 "Basis : computing new set\n");
11340 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11341 if (ctxt->value == NULL)
11342 xmlGenericError(xmlGenericErrorContext, "no value\n");
11343 else if (ctxt->value->nodesetval == NULL)
11344 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11346 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11349 #ifdef LIBXML_XPTR_ENABLED
11352 op1 = ctxt->comp->last;
11353 ctxt->comp->last = -1;
11356 while (CUR == '[') {
11357 xmlXPathCompPredicate(ctxt, 0);
11360 #ifdef LIBXML_XPTR_ENABLED
11362 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11365 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11366 test, type, (void *)prefix, (void *)name);
11370 xmlGenericError(xmlGenericErrorContext, "Step : ");
11371 if (ctxt->value == NULL)
11372 xmlGenericError(xmlGenericErrorContext, "no value\n");
11373 else if (ctxt->value->nodesetval == NULL)
11374 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11376 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11377 ctxt->value->nodesetval);
11382 * xmlXPathCompRelativeLocationPath:
11383 * @ctxt: the XPath Parser context
11385 * [3] RelativeLocationPath ::= Step
11386 * | RelativeLocationPath '/' Step
11387 * | AbbreviatedRelativeLocationPath
11388 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11390 * Compile a relative location path.
11393 xmlXPathCompRelativeLocationPath
11394 (xmlXPathParserContextPtr ctxt) {
11396 if ((CUR == '/') && (NXT(1) == '/')) {
11399 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11400 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11401 } else if (CUR == '/') {
11405 xmlXPathCompStep(ctxt);
11408 while (CUR == '/') {
11409 if ((CUR == '/') && (NXT(1) == '/')) {
11412 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11413 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11414 xmlXPathCompStep(ctxt);
11415 } else if (CUR == '/') {
11418 xmlXPathCompStep(ctxt);
11425 * xmlXPathCompLocationPath:
11426 * @ctxt: the XPath Parser context
11428 * [1] LocationPath ::= RelativeLocationPath
11429 * | AbsoluteLocationPath
11430 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11431 * | AbbreviatedAbsoluteLocationPath
11432 * [10] AbbreviatedAbsoluteLocationPath ::=
11433 * '//' RelativeLocationPath
11435 * Compile a location path
11437 * // is short for /descendant-or-self::node()/. For example,
11438 * //para is short for /descendant-or-self::node()/child::para and
11439 * so will select any para element in the document (even a para element
11440 * that is a document element will be selected by //para since the
11441 * document element node is a child of the root node); div//para is
11442 * short for div/descendant-or-self::node()/child::para and so will
11443 * select all para descendants of div children.
11446 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11449 xmlXPathCompRelativeLocationPath(ctxt);
11451 while (CUR == '/') {
11452 if ((CUR == '/') && (NXT(1) == '/')) {
11455 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11456 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11457 xmlXPathCompRelativeLocationPath(ctxt);
11458 } else if (CUR == '/') {
11462 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11463 (CUR == '@') || (CUR == '*')))
11464 xmlXPathCompRelativeLocationPath(ctxt);
11471 /************************************************************************
11473 * XPath precompiled expression evaluation *
11475 ************************************************************************/
11478 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11482 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11485 xmlGenericError(xmlGenericErrorContext, "new step : ");
11486 switch (op->value) {
11487 case AXIS_ANCESTOR:
11488 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11490 case AXIS_ANCESTOR_OR_SELF:
11491 xmlGenericError(xmlGenericErrorContext,
11492 "axis 'ancestors-or-self' ");
11494 case AXIS_ATTRIBUTE:
11495 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11498 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11500 case AXIS_DESCENDANT:
11501 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11503 case AXIS_DESCENDANT_OR_SELF:
11504 xmlGenericError(xmlGenericErrorContext,
11505 "axis 'descendant-or-self' ");
11507 case AXIS_FOLLOWING:
11508 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11510 case AXIS_FOLLOWING_SIBLING:
11511 xmlGenericError(xmlGenericErrorContext,
11512 "axis 'following-siblings' ");
11514 case AXIS_NAMESPACE:
11515 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11518 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11520 case AXIS_PRECEDING:
11521 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11523 case AXIS_PRECEDING_SIBLING:
11524 xmlGenericError(xmlGenericErrorContext,
11525 "axis 'preceding-sibling' ");
11528 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11531 xmlGenericError(xmlGenericErrorContext,
11532 " context contains %d nodes\n", nbNodes);
11533 switch (op->value2) {
11534 case NODE_TEST_NONE:
11535 xmlGenericError(xmlGenericErrorContext,
11536 " searching for none !!!\n");
11538 case NODE_TEST_TYPE:
11539 xmlGenericError(xmlGenericErrorContext,
11540 " searching for type %d\n", op->value3);
11543 xmlGenericError(xmlGenericErrorContext,
11544 " searching for PI !!!\n");
11546 case NODE_TEST_ALL:
11547 xmlGenericError(xmlGenericErrorContext,
11548 " searching for *\n");
11551 xmlGenericError(xmlGenericErrorContext,
11552 " searching for namespace %s\n",
11555 case NODE_TEST_NAME:
11556 xmlGenericError(xmlGenericErrorContext,
11557 " searching for name %s\n", op->value5);
11559 xmlGenericError(xmlGenericErrorContext,
11560 " with namespace %s\n", op->value4);
11563 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11565 #endif /* DEBUG_STEP */
11568 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11569 xmlXPathStepOpPtr op,
11574 if (op->ch1 != -1) {
11575 xmlXPathCompExprPtr comp = ctxt->comp;
11577 * Process inner predicates first.
11579 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11581 * TODO: raise an internal error.
11584 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11585 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11587 if (contextSize <= 0)
11590 if (op->ch2 != -1) {
11591 xmlXPathContextPtr xpctxt = ctxt->context;
11592 xmlNodePtr contextNode, oldContextNode;
11593 xmlDocPtr oldContextDoc;
11594 int i, res, contextPos = 0, newContextSize;
11595 xmlXPathStepOpPtr exprOp;
11596 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11598 #ifdef LIBXML_XPTR_ENABLED
11600 * URGENT TODO: Check the following:
11601 * We don't expect location sets if evaluating prediates, right?
11602 * Only filters should expect location sets, right?
11607 * "For each node in the node-set to be filtered, the
11608 * PredicateExpr is evaluated with that node as the
11609 * context node, with the number of nodes in the
11610 * node-set as the context size, and with the proximity
11611 * position of the node in the node-set with respect to
11612 * the axis as the context position;"
11613 * @oldset is the node-set" to be filtered.
11616 * "only predicates change the context position and
11617 * context size (see [2.4 Predicates])."
11619 * node-set context pos
11623 * After applying predicate [position() > 1] :
11624 * node-set context pos
11628 oldContextNode = xpctxt->node;
11629 oldContextDoc = xpctxt->doc;
11631 * Get the expression of this predicate.
11633 exprOp = &ctxt->comp->steps[op->ch2];
11634 newContextSize = 0;
11635 for (i = 0; i < set->nodeNr; i++) {
11636 if (set->nodeTab[i] == NULL)
11639 contextNode = set->nodeTab[i];
11640 xpctxt->node = contextNode;
11641 xpctxt->contextSize = contextSize;
11642 xpctxt->proximityPosition = ++contextPos;
11645 * Also set the xpath document in case things like
11646 * key() are evaluated in the predicate.
11648 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11649 (contextNode->doc != NULL))
11650 xpctxt->doc = contextNode->doc;
11652 * Evaluate the predicate expression with 1 context node
11653 * at a time; this node is packaged into a node set; this
11654 * node set is handed over to the evaluation mechanism.
11656 if (contextObj == NULL)
11657 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11659 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11662 valuePush(ctxt, contextObj);
11664 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11666 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11667 xmlXPathNodeSetClear(set, hasNsNodes);
11668 newContextSize = 0;
11669 goto evaluation_exit;
11676 * Remove the entry from the initial node set.
11678 set->nodeTab[i] = NULL;
11679 if (contextNode->type == XML_NAMESPACE_DECL)
11680 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11682 if (ctxt->value == contextObj) {
11684 * Don't free the temporary XPath object holding the
11685 * context node, in order to avoid massive recreation
11686 * inside this loop.
11689 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11692 * TODO: The object was lost in the evaluation machinery.
11693 * Can this happen? Maybe in internal-error cases.
11699 if (contextObj != NULL) {
11700 if (ctxt->value == contextObj)
11702 xmlXPathReleaseObject(xpctxt, contextObj);
11705 if (exprRes != NULL)
11706 xmlXPathReleaseObject(ctxt->context, exprRes);
11708 * Reset/invalidate the context.
11710 xpctxt->node = oldContextNode;
11711 xpctxt->doc = oldContextDoc;
11712 xpctxt->contextSize = -1;
11713 xpctxt->proximityPosition = -1;
11714 return(newContextSize);
11716 return(contextSize);
11720 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11721 xmlXPathStepOpPtr op,
11728 if (op->ch1 != -1) {
11729 xmlXPathCompExprPtr comp = ctxt->comp;
11730 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11732 * TODO: raise an internal error.
11735 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11736 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11738 if (contextSize <= 0)
11742 * Check if the node set contains a sufficient number of nodes for
11743 * the requested range.
11745 if (contextSize < minPos) {
11746 xmlXPathNodeSetClear(set, hasNsNodes);
11749 if (op->ch2 == -1) {
11751 * TODO: Can this ever happen?
11753 return (contextSize);
11755 xmlDocPtr oldContextDoc;
11756 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11757 xmlXPathStepOpPtr exprOp;
11758 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11759 xmlNodePtr oldContextNode, contextNode = NULL;
11760 xmlXPathContextPtr xpctxt = ctxt->context;
11763 #ifdef LIBXML_XPTR_ENABLED
11765 * URGENT TODO: Check the following:
11766 * We don't expect location sets if evaluating prediates, right?
11767 * Only filters should expect location sets, right?
11769 #endif /* LIBXML_XPTR_ENABLED */
11772 * Save old context.
11774 oldContextNode = xpctxt->node;
11775 oldContextDoc = xpctxt->doc;
11777 * Get the expression of this predicate.
11779 exprOp = &ctxt->comp->steps[op->ch2];
11780 for (i = 0; i < set->nodeNr; i++) {
11781 xmlXPathObjectPtr tmp;
11783 if (set->nodeTab[i] == NULL)
11786 contextNode = set->nodeTab[i];
11787 xpctxt->node = contextNode;
11788 xpctxt->contextSize = contextSize;
11789 xpctxt->proximityPosition = ++contextPos;
11792 * Initialize the new set.
11793 * Also set the xpath document in case things like
11794 * key() evaluation are attempted on the predicate
11796 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11797 (contextNode->doc != NULL))
11798 xpctxt->doc = contextNode->doc;
11800 * Evaluate the predicate expression with 1 context node
11801 * at a time; this node is packaged into a node set; this
11802 * node set is handed over to the evaluation mechanism.
11804 if (contextObj == NULL)
11805 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11807 xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11810 frame = xmlXPathSetFrame(ctxt);
11811 valuePush(ctxt, contextObj);
11812 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11813 tmp = valuePop(ctxt);
11814 xmlXPathPopFrame(ctxt, frame);
11816 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11817 while (tmp != contextObj) {
11819 * Free up the result
11820 * then pop off contextObj, which will be freed later
11822 xmlXPathReleaseObject(xpctxt, tmp);
11823 tmp = valuePop(ctxt);
11825 goto evaluation_error;
11827 /* push the result back onto the stack */
11828 valuePush(ctxt, tmp);
11833 if (res && (pos >= minPos) && (pos <= maxPos)) {
11835 * Fits in the requested range.
11838 if (minPos == maxPos) {
11840 * Only 1 node was requested.
11842 if (contextNode->type == XML_NAMESPACE_DECL) {
11844 * As always: take care of those nasty
11847 set->nodeTab[i] = NULL;
11849 xmlXPathNodeSetClear(set, hasNsNodes);
11851 set->nodeTab[0] = contextNode;
11852 goto evaluation_exit;
11854 if (pos == maxPos) {
11858 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11859 goto evaluation_exit;
11863 * Remove the entry from the initial node set.
11865 set->nodeTab[i] = NULL;
11866 if (contextNode->type == XML_NAMESPACE_DECL)
11867 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11869 if (exprRes != NULL) {
11870 xmlXPathReleaseObject(ctxt->context, exprRes);
11873 if (ctxt->value == contextObj) {
11875 * Don't free the temporary XPath object holding the
11876 * context node, in order to avoid massive recreation
11877 * inside this loop.
11880 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11883 * The object was lost in the evaluation machinery.
11884 * Can this happen? Maybe in case of internal-errors.
11889 goto evaluation_exit;
11892 xmlXPathNodeSetClear(set, hasNsNodes);
11893 newContextSize = 0;
11896 if (contextObj != NULL) {
11897 if (ctxt->value == contextObj)
11899 xmlXPathReleaseObject(xpctxt, contextObj);
11901 if (exprRes != NULL)
11902 xmlXPathReleaseObject(ctxt->context, exprRes);
11904 * Reset/invalidate the context.
11906 xpctxt->node = oldContextNode;
11907 xpctxt->doc = oldContextDoc;
11908 xpctxt->contextSize = -1;
11909 xpctxt->proximityPosition = -1;
11910 return(newContextSize);
11912 return(contextSize);
11916 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11917 xmlXPathStepOpPtr op,
11921 xmlXPathStepOpPtr exprOp;
11924 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11928 * If not -1, then ch1 will point to:
11929 * 1) For predicates (XPATH_OP_PREDICATE):
11930 * - an inner predicate operator
11931 * 2) For filters (XPATH_OP_FILTER):
11932 * - an inner filter operater OR
11933 * - an expression selecting the node set.
11934 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11936 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11939 if (op->ch2 != -1) {
11940 exprOp = &ctxt->comp->steps[op->ch2];
11944 if ((exprOp != NULL) &&
11945 (exprOp->op == XPATH_OP_VALUE) &&
11946 (exprOp->value4 != NULL) &&
11947 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11950 * We have a "[n]" predicate here.
11951 * TODO: Unfortunately this simplistic test here is not
11952 * able to detect a position() predicate in compound
11953 * expressions like "[@attr = 'a" and position() = 1],
11954 * and even not the usage of position() in
11955 * "[position() = 1]"; thus - obviously - a position-range,
11956 * like it "[position() < 5]", is also not detected.
11957 * Maybe we could rewrite the AST to ease the optimization.
11959 *maxPos = (int) ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11961 if (((xmlXPathObjectPtr) exprOp->value4)->floatval ==
11971 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11972 xmlXPathStepOpPtr op,
11973 xmlNodePtr * first, xmlNodePtr * last,
11977 #define XP_TEST_HIT \
11978 if (hasAxisRange != 0) { \
11979 if (++pos == maxPos) { \
11980 addNode(seq, cur); \
11981 goto axis_range_end; } \
11983 addNode(seq, cur); \
11984 if (breakOnFirstHit) goto first_hit; }
11986 #define XP_TEST_HIT_NS \
11987 if (hasAxisRange != 0) { \
11988 if (++pos == maxPos) { \
11990 xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
11991 goto axis_range_end; } \
11994 xmlXPathNodeSetAddNs(seq, \
11995 xpctxt->node, (xmlNsPtr) cur); \
11996 if (breakOnFirstHit) goto first_hit; }
11998 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11999 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12000 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12001 const xmlChar *prefix = op->value4;
12002 const xmlChar *name = op->value5;
12003 const xmlChar *URI = NULL;
12006 int nbMatches = 0, prevMatches = 0;
12008 int total = 0, hasNsNodes = 0;
12009 /* The popped object holding the context nodes */
12010 xmlXPathObjectPtr obj;
12011 /* The set of context nodes for the node tests */
12012 xmlNodeSetPtr contextSeq;
12014 xmlNodePtr contextNode;
12015 /* The context node for a compound traversal */
12016 xmlNodePtr outerContextNode;
12017 /* The final resulting node set wrt to all context nodes */
12018 xmlNodeSetPtr outSeq;
12020 * The temporary resulting node set wrt 1 context node.
12021 * Used to feed predicate evaluation.
12025 /* First predicate operator */
12026 xmlXPathStepOpPtr predOp;
12027 int maxPos; /* The requested position() (when a "[n]" predicate) */
12028 int hasPredicateRange, hasAxisRange, pos, size, newSize;
12029 int breakOnFirstHit;
12031 xmlXPathTraversalFunction next = NULL;
12032 /* compound axis traversal */
12033 xmlXPathTraversalFunctionExt outerNext = NULL;
12034 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12035 xmlXPathNodeSetMergeFunction mergeAndClear;
12036 xmlNodePtr oldContextNode;
12037 xmlXPathContextPtr xpctxt = ctxt->context;
12040 CHECK_TYPE0(XPATH_NODESET);
12041 obj = valuePop(ctxt);
12043 * Setup namespaces.
12045 if (prefix != NULL) {
12046 URI = xmlXPathNsLookup(xpctxt, prefix);
12048 xmlXPathReleaseObject(xpctxt, obj);
12049 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12055 * MAYBE FUTURE TODO: merging optimizations:
12056 * - If the nodes to be traversed wrt to the initial nodes and
12057 * the current axis cannot overlap, then we could avoid searching
12058 * for duplicates during the merge.
12059 * But the question is how/when to evaluate if they cannot overlap.
12060 * Example: if we know that for two initial nodes, the one is
12061 * not in the ancestor-or-self axis of the other, then we could safely
12062 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12063 * the descendant-or-self axis.
12065 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12067 case AXIS_ANCESTOR:
12069 next = xmlXPathNextAncestor;
12071 case AXIS_ANCESTOR_OR_SELF:
12073 next = xmlXPathNextAncestorOrSelf;
12075 case AXIS_ATTRIBUTE:
12078 next = xmlXPathNextAttribute;
12079 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12083 if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
12085 * This iterator will give us only nodes which can
12086 * hold element nodes.
12088 outerNext = xmlXPathNextDescendantOrSelfElemParent;
12090 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12091 (type == NODE_TYPE_NODE))
12094 * Optimization if an element node type is 'element'.
12096 next = xmlXPathNextChildElement;
12098 next = xmlXPathNextChild;
12099 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12101 case AXIS_DESCENDANT:
12103 next = xmlXPathNextDescendant;
12105 case AXIS_DESCENDANT_OR_SELF:
12107 next = xmlXPathNextDescendantOrSelf;
12109 case AXIS_FOLLOWING:
12111 next = xmlXPathNextFollowing;
12113 case AXIS_FOLLOWING_SIBLING:
12115 next = xmlXPathNextFollowingSibling;
12117 case AXIS_NAMESPACE:
12120 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12121 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12125 next = xmlXPathNextParent;
12127 case AXIS_PRECEDING:
12129 next = xmlXPathNextPrecedingInternal;
12131 case AXIS_PRECEDING_SIBLING:
12133 next = xmlXPathNextPrecedingSibling;
12138 next = xmlXPathNextSelf;
12139 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12144 xmlXPathDebugDumpStepAxis(op,
12145 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12148 if (next == NULL) {
12149 xmlXPathReleaseObject(xpctxt, obj);
12152 contextSeq = obj->nodesetval;
12153 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12154 xmlXPathReleaseObject(xpctxt, obj);
12155 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12159 * Predicate optimization ---------------------------------------------
12160 * If this step has a last predicate, which contains a position(),
12161 * then we'll optimize (although not exactly "position()", but only
12162 * the short-hand form, i.e., "[n]".
12164 * Example - expression "/foo[parent::bar][1]":
12166 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12168 * PREDICATE -- op->ch2 (predOp)
12169 * PREDICATE -- predOp->ch1 = [parent::bar]
12171 * COLLECT 'parent' 'name' 'node' bar
12173 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12178 hasPredicateRange = 0;
12180 if (op->ch2 != -1) {
12182 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12184 predOp = &ctxt->comp->steps[op->ch2];
12185 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12186 if (predOp->ch1 != -1) {
12188 * Use the next inner predicate operator.
12190 predOp = &ctxt->comp->steps[predOp->ch1];
12191 hasPredicateRange = 1;
12194 * There's no other predicate than the [n] predicate.
12201 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12203 * Axis traversal -----------------------------------------------------
12207 * - For the attribute axis, the principal node type is attribute.
12208 * - For the namespace axis, the principal node type is namespace.
12209 * - For other axes, the principal node type is element.
12211 * A node test * is true for any node of the
12212 * principal node type. For example, child::* will
12213 * select all element children of the context node
12215 oldContextNode = xpctxt->node;
12216 addNode = xmlXPathNodeSetAddUnique;
12219 outerContextNode = NULL;
12220 contextNode = NULL;
12224 while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
12225 if (outerNext != NULL) {
12227 * This is a compound traversal.
12229 if (contextNode == NULL) {
12231 * Set the context for the outer traversal.
12233 outerContextNode = contextSeq->nodeTab[contextIdx++];
12234 contextNode = outerNext(NULL, outerContextNode);
12236 contextNode = outerNext(contextNode, outerContextNode);
12237 if (contextNode == NULL)
12240 * Set the context for the main traversal.
12242 xpctxt->node = contextNode;
12244 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12247 seq = xmlXPathNodeSetCreate(NULL);
12254 * Traverse the axis and test the nodes.
12260 cur = next(ctxt, cur);
12265 * QUESTION TODO: What does the "first" and "last" stuff do?
12267 if ((first != NULL) && (*first != NULL)) {
12270 if (((total % 256) == 0) &&
12271 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12272 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12274 (xmlXPathCmpNodes(*first, cur) >= 0))
12280 if ((last != NULL) && (*last != NULL)) {
12283 if (((total % 256) == 0) &&
12284 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12285 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12287 (xmlXPathCmpNodes(cur, *last) >= 0))
12297 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12301 case NODE_TEST_NONE:
12305 case NODE_TEST_TYPE:
12307 * TODO: Don't we need to use
12308 * xmlXPathNodeSetAddNs() for namespace nodes here?
12309 * Surprisingly, some c14n tests fail, if we do this.
12311 if (type == NODE_TYPE_NODE) {
12312 switch (cur->type) {
12313 case XML_DOCUMENT_NODE:
12314 case XML_HTML_DOCUMENT_NODE:
12315 #ifdef LIBXML_DOCB_ENABLED
12316 case XML_DOCB_DOCUMENT_NODE:
12318 case XML_ELEMENT_NODE:
12319 case XML_ATTRIBUTE_NODE:
12321 case XML_COMMENT_NODE:
12322 case XML_CDATA_SECTION_NODE:
12323 case XML_TEXT_NODE:
12324 case XML_NAMESPACE_DECL:
12330 } else if (cur->type == type) {
12331 if (type == XML_NAMESPACE_DECL)
12335 } else if ((type == NODE_TYPE_TEXT) &&
12336 (cur->type == XML_CDATA_SECTION_NODE))
12342 if ((cur->type == XML_PI_NODE) &&
12343 ((name == NULL) || xmlStrEqual(name, cur->name)))
12348 case NODE_TEST_ALL:
12349 if (axis == AXIS_ATTRIBUTE) {
12350 if (cur->type == XML_ATTRIBUTE_NODE)
12354 } else if (axis == AXIS_NAMESPACE) {
12355 if (cur->type == XML_NAMESPACE_DECL)
12360 if (cur->type == XML_ELEMENT_NODE) {
12361 if (prefix == NULL)
12365 } else if ((cur->ns != NULL) &&
12366 (xmlStrEqual(URI, cur->ns->href)))
12373 case NODE_TEST_NS:{
12377 case NODE_TEST_NAME:
12378 if (axis == AXIS_ATTRIBUTE) {
12379 if (cur->type != XML_ATTRIBUTE_NODE)
12381 } else if (axis == AXIS_NAMESPACE) {
12382 if (cur->type != XML_NAMESPACE_DECL)
12385 if (cur->type != XML_ELEMENT_NODE)
12388 switch (cur->type) {
12389 case XML_ELEMENT_NODE:
12390 if (xmlStrEqual(name, cur->name)) {
12391 if (prefix == NULL) {
12392 if (cur->ns == NULL)
12397 if ((cur->ns != NULL) &&
12398 (xmlStrEqual(URI, cur->ns->href)))
12405 case XML_ATTRIBUTE_NODE:{
12406 xmlAttrPtr attr = (xmlAttrPtr) cur;
12408 if (xmlStrEqual(name, attr->name)) {
12409 if (prefix == NULL) {
12410 if ((attr->ns == NULL) ||
12411 (attr->ns->prefix == NULL))
12416 if ((attr->ns != NULL) &&
12426 case XML_NAMESPACE_DECL:
12427 if (cur->type == XML_NAMESPACE_DECL) {
12428 xmlNsPtr ns = (xmlNsPtr) cur;
12430 if ((ns->prefix != NULL) && (name != NULL)
12431 && (xmlStrEqual(ns->prefix, name)))
12441 } /* switch(test) */
12442 } while (cur != NULL);
12444 goto apply_predicates;
12446 axis_range_end: /* ----------------------------------------------------- */
12448 * We have a "/foo[n]", and position() = n was reached.
12449 * Note that we can have as well "/foo/::parent::foo[1]", so
12450 * a duplicate-aware merge is still needed.
12451 * Merge with the result.
12453 if (outSeq == NULL) {
12457 outSeq = mergeAndClear(outSeq, seq, 0);
12459 * Break if only a true/false result was requested.
12465 first_hit: /* ---------------------------------------------------------- */
12467 * Break if only a true/false result was requested and
12468 * no predicates existed and a node test succeeded.
12470 if (outSeq == NULL) {
12474 outSeq = mergeAndClear(outSeq, seq, 0);
12479 nbMatches += seq->nodeNr;
12482 apply_predicates: /* --------------------------------------------------- */
12484 * Apply predicates.
12486 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12488 * E.g. when we have a "/foo[some expression][n]".
12491 * QUESTION TODO: The old predicate evaluation took into
12492 * account location-sets.
12493 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12494 * Do we expect such a set here?
12495 * All what I learned now from the evaluation semantics
12496 * does not indicate that a location-set will be processed
12497 * here, so this looks OK.
12500 * Iterate over all predicates, starting with the outermost
12502 * TODO: Problem: we cannot execute the inner predicates first
12503 * since we cannot go back *up* the operator tree!
12505 * 1) Use of recursive functions (like is it currently done
12506 * via xmlXPathCompOpEval())
12507 * 2) Add a predicate evaluation information stack to the
12509 * 3) Change the way the operators are linked; we need a
12510 * "parent" field on xmlXPathStepOp
12512 * For the moment, I'll try to solve this with a recursive
12513 * function: xmlXPathCompOpEvalPredicate().
12515 size = seq->nodeNr;
12516 if (hasPredicateRange != 0)
12517 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12518 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12520 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12521 predOp, seq, size, hasNsNodes);
12523 if (ctxt->error != XPATH_EXPRESSION_OK) {
12528 * Add the filtered set of nodes to the result node set.
12530 if (newSize == 0) {
12532 * The predicates filtered all nodes out.
12534 xmlXPathNodeSetClear(seq, hasNsNodes);
12535 } else if (seq->nodeNr > 0) {
12537 * Add to result set.
12539 if (outSeq == NULL) {
12540 if (size != newSize) {
12542 * We need to merge and clear here, since
12543 * the sequence will contained NULLed entries.
12545 outSeq = mergeAndClear(NULL, seq, 1);
12551 outSeq = mergeAndClear(outSeq, seq,
12552 (size != newSize) ? 1: 0);
12554 * Break if only a true/false result was requested.
12559 } else if (seq->nodeNr > 0) {
12561 * Add to result set.
12563 if (outSeq == NULL) {
12567 outSeq = mergeAndClear(outSeq, seq, 0);
12573 if ((obj->boolval) && (obj->user != NULL)) {
12575 * QUESTION TODO: What does this do and why?
12576 * TODO: Do we have to do this also for the "error"
12577 * cleanup further down?
12579 ctxt->value->boolval = 1;
12580 ctxt->value->user = obj->user;
12584 xmlXPathReleaseObject(xpctxt, obj);
12587 * Ensure we return at least an emtpy set.
12589 if (outSeq == NULL) {
12590 if ((seq != NULL) && (seq->nodeNr == 0))
12593 outSeq = xmlXPathNodeSetCreate(NULL);
12594 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12596 if ((seq != NULL) && (seq != outSeq)) {
12597 xmlXPathFreeNodeSet(seq);
12600 * Hand over the result. Better to push the set also in
12603 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12605 * Reset the context node.
12607 xpctxt->node = oldContextNode;
12610 xmlGenericError(xmlGenericErrorContext,
12611 "\nExamined %d nodes, found %d nodes at that step\n",
12619 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12620 xmlXPathStepOpPtr op, xmlNodePtr * first);
12623 * xmlXPathCompOpEvalFirst:
12624 * @ctxt: the XPath parser context with the compiled expression
12625 * @op: an XPath compiled operation
12626 * @first: the first elem found so far
12628 * Evaluate the Precompiled XPath operation searching only the first
12629 * element in document order
12631 * Returns the number of examined objects.
12634 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12635 xmlXPathStepOpPtr op, xmlNodePtr * first)
12637 int total = 0, cur;
12638 xmlXPathCompExprPtr comp;
12639 xmlXPathObjectPtr arg1, arg2;
12646 case XPATH_OP_UNION:
12648 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12651 if ((ctxt->value != NULL)
12652 && (ctxt->value->type == XPATH_NODESET)
12653 && (ctxt->value->nodesetval != NULL)
12654 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12656 * limit tree traversing to first node in the result
12659 * OPTIMIZE TODO: This implicitely sorts
12660 * the result, even if not needed. E.g. if the argument
12661 * of the count() function, no sorting is needed.
12662 * OPTIMIZE TODO: How do we know if the node-list wasn't
12665 if (ctxt->value->nodesetval->nodeNr > 1)
12666 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12667 *first = ctxt->value->nodesetval->nodeTab[0];
12670 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12673 CHECK_TYPE0(XPATH_NODESET);
12674 arg2 = valuePop(ctxt);
12676 CHECK_TYPE0(XPATH_NODESET);
12677 arg1 = valuePop(ctxt);
12679 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12681 valuePush(ctxt, arg1);
12682 xmlXPathReleaseObject(ctxt->context, arg2);
12685 xmlXPathCompSwap(op);
12686 return (total + cur);
12687 case XPATH_OP_ROOT:
12688 xmlXPathRoot(ctxt);
12690 case XPATH_OP_NODE:
12692 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12697 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12698 ctxt->context->node));
12700 case XPATH_OP_RESET:
12702 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12705 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12707 ctxt->context->node = NULL;
12709 case XPATH_OP_COLLECT:{
12713 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12716 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12719 case XPATH_OP_VALUE:
12721 xmlXPathCacheObjectCopy(ctxt->context,
12722 (xmlXPathObjectPtr) op->value4));
12724 case XPATH_OP_SORT:
12727 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12730 if ((ctxt->value != NULL)
12731 && (ctxt->value->type == XPATH_NODESET)
12732 && (ctxt->value->nodesetval != NULL)
12733 && (ctxt->value->nodesetval->nodeNr > 1))
12734 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12736 #ifdef XP_OPTIMIZED_FILTER_FIRST
12737 case XPATH_OP_FILTER:
12738 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12742 return (xmlXPathCompOpEval(ctxt, op));
12747 * xmlXPathCompOpEvalLast:
12748 * @ctxt: the XPath parser context with the compiled expression
12749 * @op: an XPath compiled operation
12750 * @last: the last elem found so far
12752 * Evaluate the Precompiled XPath operation searching only the last
12753 * element in document order
12755 * Returns the number of nodes traversed
12758 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12761 int total = 0, cur;
12762 xmlXPathCompExprPtr comp;
12763 xmlXPathObjectPtr arg1, arg2;
12774 case XPATH_OP_UNION:
12775 bakd = ctxt->context->doc;
12776 bak = ctxt->context->node;
12777 pp = ctxt->context->proximityPosition;
12778 cs = ctxt->context->contextSize;
12780 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12782 if ((ctxt->value != NULL)
12783 && (ctxt->value->type == XPATH_NODESET)
12784 && (ctxt->value->nodesetval != NULL)
12785 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12787 * limit tree traversing to first node in the result
12789 if (ctxt->value->nodesetval->nodeNr > 1)
12790 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12792 ctxt->value->nodesetval->nodeTab[ctxt->value->
12793 nodesetval->nodeNr -
12796 ctxt->context->doc = bakd;
12797 ctxt->context->node = bak;
12798 ctxt->context->proximityPosition = pp;
12799 ctxt->context->contextSize = cs;
12801 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12803 if ((ctxt->value != NULL)
12804 && (ctxt->value->type == XPATH_NODESET)
12805 && (ctxt->value->nodesetval != NULL)
12806 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12808 CHECK_TYPE0(XPATH_NODESET);
12809 arg2 = valuePop(ctxt);
12811 CHECK_TYPE0(XPATH_NODESET);
12812 arg1 = valuePop(ctxt);
12814 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12816 valuePush(ctxt, arg1);
12817 xmlXPathReleaseObject(ctxt->context, arg2);
12820 xmlXPathCompSwap(op);
12821 return (total + cur);
12822 case XPATH_OP_ROOT:
12823 xmlXPathRoot(ctxt);
12825 case XPATH_OP_NODE:
12827 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12830 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12832 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12833 ctxt->context->node));
12835 case XPATH_OP_RESET:
12837 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12840 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12842 ctxt->context->node = NULL;
12844 case XPATH_OP_COLLECT:{
12848 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12851 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12854 case XPATH_OP_VALUE:
12856 xmlXPathCacheObjectCopy(ctxt->context,
12857 (xmlXPathObjectPtr) op->value4));
12859 case XPATH_OP_SORT:
12862 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12865 if ((ctxt->value != NULL)
12866 && (ctxt->value->type == XPATH_NODESET)
12867 && (ctxt->value->nodesetval != NULL)
12868 && (ctxt->value->nodesetval->nodeNr > 1))
12869 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12872 return (xmlXPathCompOpEval(ctxt, op));
12876 #ifdef XP_OPTIMIZED_FILTER_FIRST
12878 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12879 xmlXPathStepOpPtr op, xmlNodePtr * first)
12882 xmlXPathCompExprPtr comp;
12883 xmlXPathObjectPtr res;
12884 xmlXPathObjectPtr obj;
12885 xmlNodeSetPtr oldset;
12886 xmlNodePtr oldnode;
12893 * Optimization for ()[last()] selection i.e. the last elem
12895 if ((op->ch1 != -1) && (op->ch2 != -1) &&
12896 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12897 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12898 int f = comp->steps[op->ch2].ch1;
12901 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
12902 (comp->steps[f].value5 == NULL) &&
12903 (comp->steps[f].value == 0) &&
12904 (comp->steps[f].value4 != NULL) &&
12906 (comp->steps[f].value4, BAD_CAST "last"))) {
12907 xmlNodePtr last = NULL;
12910 xmlXPathCompOpEvalLast(ctxt,
12911 &comp->steps[op->ch1],
12915 * The nodeset should be in document order,
12916 * Keep only the last value
12918 if ((ctxt->value != NULL) &&
12919 (ctxt->value->type == XPATH_NODESET) &&
12920 (ctxt->value->nodesetval != NULL) &&
12921 (ctxt->value->nodesetval->nodeTab != NULL) &&
12922 (ctxt->value->nodesetval->nodeNr > 1)) {
12923 ctxt->value->nodesetval->nodeTab[0] =
12924 ctxt->value->nodesetval->nodeTab[ctxt->
12929 ctxt->value->nodesetval->nodeNr = 1;
12930 *first = *(ctxt->value->nodesetval->nodeTab);
12937 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12941 if (ctxt->value == NULL)
12944 #ifdef LIBXML_XPTR_ENABLED
12945 oldnode = ctxt->context->node;
12947 * Hum are we filtering the result of an XPointer expression
12949 if (ctxt->value->type == XPATH_LOCATIONSET) {
12950 xmlXPathObjectPtr tmp = NULL;
12951 xmlLocationSetPtr newlocset = NULL;
12952 xmlLocationSetPtr oldlocset;
12955 * Extract the old locset, and then evaluate the result of the
12956 * expression for all the element in the locset. use it to grow
12959 CHECK_TYPE0(XPATH_LOCATIONSET);
12960 obj = valuePop(ctxt);
12961 oldlocset = obj->user;
12962 ctxt->context->node = NULL;
12964 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
12965 ctxt->context->contextSize = 0;
12966 ctxt->context->proximityPosition = 0;
12968 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12969 res = valuePop(ctxt);
12971 xmlXPathReleaseObject(ctxt->context, res);
12973 valuePush(ctxt, obj);
12977 newlocset = xmlXPtrLocationSetCreate(NULL);
12979 for (i = 0; i < oldlocset->locNr; i++) {
12981 * Run the evaluation with a node list made of a
12982 * single item in the nodelocset.
12984 ctxt->context->node = oldlocset->locTab[i]->user;
12985 ctxt->context->contextSize = oldlocset->locNr;
12986 ctxt->context->proximityPosition = i + 1;
12988 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12989 ctxt->context->node);
12991 xmlXPathNodeSetAddUnique(tmp->nodesetval,
12992 ctxt->context->node);
12994 valuePush(ctxt, tmp);
12996 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12997 if (ctxt->error != XPATH_EXPRESSION_OK) {
12998 xmlXPathFreeObject(obj);
13002 * The result of the evaluation need to be tested to
13003 * decided whether the filter succeeded or not
13005 res = valuePop(ctxt);
13006 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13007 xmlXPtrLocationSetAdd(newlocset,
13008 xmlXPathCacheObjectCopy(ctxt->context,
13009 oldlocset->locTab[i]));
13015 xmlXPathReleaseObject(ctxt->context, res);
13017 if (ctxt->value == tmp) {
13019 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13021 * REVISIT TODO: Don't create a temporary nodeset
13022 * for everly iteration.
13024 /* OLD: xmlXPathFreeObject(res); */
13027 ctxt->context->node = NULL;
13029 * Only put the first node in the result, then leave.
13031 if (newlocset->locNr > 0) {
13032 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13037 xmlXPathReleaseObject(ctxt->context, tmp);
13040 * The result is used as the new evaluation locset.
13042 xmlXPathReleaseObject(ctxt->context, obj);
13043 ctxt->context->node = NULL;
13044 ctxt->context->contextSize = -1;
13045 ctxt->context->proximityPosition = -1;
13046 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13047 ctxt->context->node = oldnode;
13050 #endif /* LIBXML_XPTR_ENABLED */
13053 * Extract the old set, and then evaluate the result of the
13054 * expression for all the element in the set. use it to grow
13057 CHECK_TYPE0(XPATH_NODESET);
13058 obj = valuePop(ctxt);
13059 oldset = obj->nodesetval;
13061 oldnode = ctxt->context->node;
13062 oldDoc = ctxt->context->doc;
13063 ctxt->context->node = NULL;
13065 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13066 ctxt->context->contextSize = 0;
13067 ctxt->context->proximityPosition = 0;
13068 /* QUESTION TODO: Why was this code commented out?
13071 xmlXPathCompOpEval(ctxt,
13072 &comp->steps[op->ch2]);
13074 res = valuePop(ctxt);
13076 xmlXPathFreeObject(res);
13078 valuePush(ctxt, obj);
13079 ctxt->context->node = oldnode;
13082 xmlNodeSetPtr newset;
13083 xmlXPathObjectPtr tmp = NULL;
13085 * Initialize the new set.
13086 * Also set the xpath document in case things like
13087 * key() evaluation are attempted on the predicate
13089 newset = xmlXPathNodeSetCreate(NULL);
13090 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13092 for (i = 0; i < oldset->nodeNr; i++) {
13094 * Run the evaluation with a node list made of
13095 * a single item in the nodeset.
13097 ctxt->context->node = oldset->nodeTab[i];
13098 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13099 (oldset->nodeTab[i]->doc != NULL))
13100 ctxt->context->doc = oldset->nodeTab[i]->doc;
13102 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13103 ctxt->context->node);
13105 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13106 ctxt->context->node);
13108 valuePush(ctxt, tmp);
13109 ctxt->context->contextSize = oldset->nodeNr;
13110 ctxt->context->proximityPosition = i + 1;
13112 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13113 if (ctxt->error != XPATH_EXPRESSION_OK) {
13114 xmlXPathFreeNodeSet(newset);
13115 xmlXPathFreeObject(obj);
13119 * The result of the evaluation needs to be tested to
13120 * decide whether the filter succeeded or not
13122 res = valuePop(ctxt);
13123 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13124 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13130 xmlXPathReleaseObject(ctxt->context, res);
13132 if (ctxt->value == tmp) {
13135 * Don't free the temporary nodeset
13136 * in order to avoid massive recreation inside this
13139 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13142 ctxt->context->node = NULL;
13144 * Only put the first node in the result, then leave.
13146 if (newset->nodeNr > 0) {
13147 *first = *(newset->nodeTab);
13152 xmlXPathReleaseObject(ctxt->context, tmp);
13155 * The result is used as the new evaluation set.
13157 xmlXPathReleaseObject(ctxt->context, obj);
13158 ctxt->context->node = NULL;
13159 ctxt->context->contextSize = -1;
13160 ctxt->context->proximityPosition = -1;
13161 /* may want to move this past the '}' later */
13162 ctxt->context->doc = oldDoc;
13163 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13165 ctxt->context->node = oldnode;
13168 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13171 * xmlXPathCompOpEval:
13172 * @ctxt: the XPath parser context with the compiled expression
13173 * @op: an XPath compiled operation
13175 * Evaluate the Precompiled XPath operation
13176 * Returns the number of nodes traversed
13179 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13183 xmlXPathCompExprPtr comp;
13184 xmlXPathObjectPtr arg1, arg2;
13196 bakd = ctxt->context->doc;
13197 bak = ctxt->context->node;
13198 pp = ctxt->context->proximityPosition;
13199 cs = ctxt->context->contextSize;
13200 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13202 xmlXPathBooleanFunction(ctxt, 1);
13203 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13205 arg2 = valuePop(ctxt);
13206 ctxt->context->doc = bakd;
13207 ctxt->context->node = bak;
13208 ctxt->context->proximityPosition = pp;
13209 ctxt->context->contextSize = cs;
13210 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13212 xmlXPathFreeObject(arg2);
13215 xmlXPathBooleanFunction(ctxt, 1);
13216 arg1 = valuePop(ctxt);
13217 arg1->boolval &= arg2->boolval;
13218 valuePush(ctxt, arg1);
13219 xmlXPathReleaseObject(ctxt->context, arg2);
13222 bakd = ctxt->context->doc;
13223 bak = ctxt->context->node;
13224 pp = ctxt->context->proximityPosition;
13225 cs = ctxt->context->contextSize;
13226 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13228 xmlXPathBooleanFunction(ctxt, 1);
13229 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13231 arg2 = valuePop(ctxt);
13232 ctxt->context->doc = bakd;
13233 ctxt->context->node = bak;
13234 ctxt->context->proximityPosition = pp;
13235 ctxt->context->contextSize = cs;
13236 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13238 xmlXPathFreeObject(arg2);
13241 xmlXPathBooleanFunction(ctxt, 1);
13242 arg1 = valuePop(ctxt);
13243 arg1->boolval |= arg2->boolval;
13244 valuePush(ctxt, arg1);
13245 xmlXPathReleaseObject(ctxt->context, arg2);
13247 case XPATH_OP_EQUAL:
13248 bakd = ctxt->context->doc;
13249 bak = ctxt->context->node;
13250 pp = ctxt->context->proximityPosition;
13251 cs = ctxt->context->contextSize;
13252 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13254 ctxt->context->doc = bakd;
13255 ctxt->context->node = bak;
13256 ctxt->context->proximityPosition = pp;
13257 ctxt->context->contextSize = cs;
13258 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13261 equal = xmlXPathEqualValues(ctxt);
13263 equal = xmlXPathNotEqualValues(ctxt);
13264 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13267 bakd = ctxt->context->doc;
13268 bak = ctxt->context->node;
13269 pp = ctxt->context->proximityPosition;
13270 cs = ctxt->context->contextSize;
13271 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13273 ctxt->context->doc = bakd;
13274 ctxt->context->node = bak;
13275 ctxt->context->proximityPosition = pp;
13276 ctxt->context->contextSize = cs;
13277 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13279 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13280 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13282 case XPATH_OP_PLUS:
13283 bakd = ctxt->context->doc;
13284 bak = ctxt->context->node;
13285 pp = ctxt->context->proximityPosition;
13286 cs = ctxt->context->contextSize;
13287 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13289 if (op->ch2 != -1) {
13290 ctxt->context->doc = bakd;
13291 ctxt->context->node = bak;
13292 ctxt->context->proximityPosition = pp;
13293 ctxt->context->contextSize = cs;
13294 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13297 if (op->value == 0)
13298 xmlXPathSubValues(ctxt);
13299 else if (op->value == 1)
13300 xmlXPathAddValues(ctxt);
13301 else if (op->value == 2)
13302 xmlXPathValueFlipSign(ctxt);
13303 else if (op->value == 3) {
13305 CHECK_TYPE0(XPATH_NUMBER);
13308 case XPATH_OP_MULT:
13309 bakd = ctxt->context->doc;
13310 bak = ctxt->context->node;
13311 pp = ctxt->context->proximityPosition;
13312 cs = ctxt->context->contextSize;
13313 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13315 ctxt->context->doc = bakd;
13316 ctxt->context->node = bak;
13317 ctxt->context->proximityPosition = pp;
13318 ctxt->context->contextSize = cs;
13319 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13321 if (op->value == 0)
13322 xmlXPathMultValues(ctxt);
13323 else if (op->value == 1)
13324 xmlXPathDivValues(ctxt);
13325 else if (op->value == 2)
13326 xmlXPathModValues(ctxt);
13328 case XPATH_OP_UNION:
13329 bakd = ctxt->context->doc;
13330 bak = ctxt->context->node;
13331 pp = ctxt->context->proximityPosition;
13332 cs = ctxt->context->contextSize;
13333 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13335 ctxt->context->doc = bakd;
13336 ctxt->context->node = bak;
13337 ctxt->context->proximityPosition = pp;
13338 ctxt->context->contextSize = cs;
13339 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13341 CHECK_TYPE0(XPATH_NODESET);
13342 arg2 = valuePop(ctxt);
13344 CHECK_TYPE0(XPATH_NODESET);
13345 arg1 = valuePop(ctxt);
13347 if ((arg1->nodesetval == NULL) ||
13348 ((arg2->nodesetval != NULL) &&
13349 (arg2->nodesetval->nodeNr != 0)))
13351 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13355 valuePush(ctxt, arg1);
13356 xmlXPathReleaseObject(ctxt->context, arg2);
13358 case XPATH_OP_ROOT:
13359 xmlXPathRoot(ctxt);
13361 case XPATH_OP_NODE:
13363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13368 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13369 ctxt->context->node));
13371 case XPATH_OP_RESET:
13373 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13376 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13378 ctxt->context->node = NULL;
13380 case XPATH_OP_COLLECT:{
13384 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13387 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13390 case XPATH_OP_VALUE:
13392 xmlXPathCacheObjectCopy(ctxt->context,
13393 (xmlXPathObjectPtr) op->value4));
13395 case XPATH_OP_VARIABLE:{
13396 xmlXPathObjectPtr val;
13400 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13401 if (op->value5 == NULL) {
13402 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13404 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13407 valuePush(ctxt, val);
13409 const xmlChar *URI;
13411 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13413 xmlGenericError(xmlGenericErrorContext,
13414 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13415 (char *) op->value4, (char *)op->value5);
13416 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13419 val = xmlXPathVariableLookupNS(ctxt->context,
13422 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
13425 valuePush(ctxt, val);
13429 case XPATH_OP_FUNCTION:{
13430 xmlXPathFunction func;
13431 const xmlChar *oldFunc, *oldFuncURI;
13435 frame = xmlXPathSetFrame(ctxt);
13438 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13439 if (ctxt->valueNr < op->value) {
13440 xmlGenericError(xmlGenericErrorContext,
13441 "xmlXPathCompOpEval: parameter error\n");
13442 ctxt->error = XPATH_INVALID_OPERAND;
13443 xmlXPathPopFrame(ctxt, frame);
13446 for (i = 0; i < op->value; i++) {
13447 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13448 xmlGenericError(xmlGenericErrorContext,
13449 "xmlXPathCompOpEval: parameter error\n");
13450 ctxt->error = XPATH_INVALID_OPERAND;
13451 xmlXPathPopFrame(ctxt, frame);
13455 if (op->cache != NULL)
13456 XML_CAST_FPTR(func) = op->cache;
13458 const xmlChar *URI = NULL;
13460 if (op->value5 == NULL)
13462 xmlXPathFunctionLookup(ctxt->context,
13465 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13467 xmlGenericError(xmlGenericErrorContext,
13468 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13469 (char *)op->value4, (char *)op->value5);
13470 xmlXPathPopFrame(ctxt, frame);
13471 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13474 func = xmlXPathFunctionLookupNS(ctxt->context,
13477 if (func == NULL) {
13478 xmlGenericError(xmlGenericErrorContext,
13479 "xmlXPathCompOpEval: function %s not found\n",
13480 (char *)op->value4);
13481 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13483 op->cache = XML_CAST_FPTR(func);
13484 op->cacheURI = (void *) URI;
13486 oldFunc = ctxt->context->function;
13487 oldFuncURI = ctxt->context->functionURI;
13488 ctxt->context->function = op->value4;
13489 ctxt->context->functionURI = op->cacheURI;
13490 func(ctxt, op->value);
13491 ctxt->context->function = oldFunc;
13492 ctxt->context->functionURI = oldFuncURI;
13493 xmlXPathPopFrame(ctxt, frame);
13497 bakd = ctxt->context->doc;
13498 bak = ctxt->context->node;
13499 pp = ctxt->context->proximityPosition;
13500 cs = ctxt->context->contextSize;
13502 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13503 ctxt->context->contextSize = cs;
13504 ctxt->context->proximityPosition = pp;
13505 ctxt->context->node = bak;
13506 ctxt->context->doc = bakd;
13508 if (op->ch2 != -1) {
13509 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13510 ctxt->context->doc = bakd;
13511 ctxt->context->node = bak;
13515 case XPATH_OP_PREDICATE:
13516 case XPATH_OP_FILTER:{
13517 xmlXPathObjectPtr res;
13518 xmlXPathObjectPtr obj, tmp;
13519 xmlNodeSetPtr newset = NULL;
13520 xmlNodeSetPtr oldset;
13521 xmlNodePtr oldnode;
13526 * Optimization for ()[1] selection i.e. the first elem
13528 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13529 #ifdef XP_OPTIMIZED_FILTER_FIRST
13531 * FILTER TODO: Can we assume that the inner processing
13532 * will result in an ordered list if we have an
13534 * What about an additional field or flag on
13535 * xmlXPathObject like @sorted ? This way we wouln'd need
13536 * to assume anything, so it would be more robust and
13537 * easier to optimize.
13539 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13540 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13542 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13544 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13545 xmlXPathObjectPtr val;
13547 val = comp->steps[op->ch2].value4;
13548 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13549 (val->floatval == 1.0)) {
13550 xmlNodePtr first = NULL;
13553 xmlXPathCompOpEvalFirst(ctxt,
13554 &comp->steps[op->ch1],
13558 * The nodeset should be in document order,
13559 * Keep only the first value
13561 if ((ctxt->value != NULL) &&
13562 (ctxt->value->type == XPATH_NODESET) &&
13563 (ctxt->value->nodesetval != NULL) &&
13564 (ctxt->value->nodesetval->nodeNr > 1))
13565 ctxt->value->nodesetval->nodeNr = 1;
13570 * Optimization for ()[last()] selection i.e. the last elem
13572 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13573 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13574 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13575 int f = comp->steps[op->ch2].ch1;
13578 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13579 (comp->steps[f].value5 == NULL) &&
13580 (comp->steps[f].value == 0) &&
13581 (comp->steps[f].value4 != NULL) &&
13583 (comp->steps[f].value4, BAD_CAST "last"))) {
13584 xmlNodePtr last = NULL;
13587 xmlXPathCompOpEvalLast(ctxt,
13588 &comp->steps[op->ch1],
13592 * The nodeset should be in document order,
13593 * Keep only the last value
13595 if ((ctxt->value != NULL) &&
13596 (ctxt->value->type == XPATH_NODESET) &&
13597 (ctxt->value->nodesetval != NULL) &&
13598 (ctxt->value->nodesetval->nodeTab != NULL) &&
13599 (ctxt->value->nodesetval->nodeNr > 1)) {
13600 ctxt->value->nodesetval->nodeTab[0] =
13601 ctxt->value->nodesetval->nodeTab[ctxt->
13606 ctxt->value->nodesetval->nodeNr = 1;
13612 * Process inner predicates first.
13613 * Example "index[parent::book][1]":
13615 * PREDICATE <-- we are here "[1]"
13616 * PREDICATE <-- process "[parent::book]" first
13618 * COLLECT 'parent' 'name' 'node' book
13620 * ELEM Object is a number : 1
13624 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13628 if (ctxt->value == NULL)
13631 oldnode = ctxt->context->node;
13633 #ifdef LIBXML_XPTR_ENABLED
13635 * Hum are we filtering the result of an XPointer expression
13637 if (ctxt->value->type == XPATH_LOCATIONSET) {
13638 xmlLocationSetPtr newlocset = NULL;
13639 xmlLocationSetPtr oldlocset;
13642 * Extract the old locset, and then evaluate the result of the
13643 * expression for all the element in the locset. use it to grow
13646 CHECK_TYPE0(XPATH_LOCATIONSET);
13647 obj = valuePop(ctxt);
13648 oldlocset = obj->user;
13649 ctxt->context->node = NULL;
13651 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13652 ctxt->context->contextSize = 0;
13653 ctxt->context->proximityPosition = 0;
13656 xmlXPathCompOpEval(ctxt,
13657 &comp->steps[op->ch2]);
13658 res = valuePop(ctxt);
13660 xmlXPathReleaseObject(ctxt->context, res);
13662 valuePush(ctxt, obj);
13666 newlocset = xmlXPtrLocationSetCreate(NULL);
13668 for (i = 0; i < oldlocset->locNr; i++) {
13670 * Run the evaluation with a node list made of a
13671 * single item in the nodelocset.
13673 ctxt->context->node = oldlocset->locTab[i]->user;
13674 ctxt->context->contextSize = oldlocset->locNr;
13675 ctxt->context->proximityPosition = i + 1;
13676 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13677 ctxt->context->node);
13678 valuePush(ctxt, tmp);
13682 xmlXPathCompOpEval(ctxt,
13683 &comp->steps[op->ch2]);
13684 if (ctxt->error != XPATH_EXPRESSION_OK) {
13685 xmlXPathFreeObject(obj);
13690 * The result of the evaluation need to be tested to
13691 * decided whether the filter succeeded or not
13693 res = valuePop(ctxt);
13694 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13695 xmlXPtrLocationSetAdd(newlocset,
13697 (oldlocset->locTab[i]));
13704 xmlXPathReleaseObject(ctxt->context, res);
13706 if (ctxt->value == tmp) {
13707 res = valuePop(ctxt);
13708 xmlXPathReleaseObject(ctxt->context, res);
13711 ctxt->context->node = NULL;
13715 * The result is used as the new evaluation locset.
13717 xmlXPathReleaseObject(ctxt->context, obj);
13718 ctxt->context->node = NULL;
13719 ctxt->context->contextSize = -1;
13720 ctxt->context->proximityPosition = -1;
13721 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13722 ctxt->context->node = oldnode;
13725 #endif /* LIBXML_XPTR_ENABLED */
13728 * Extract the old set, and then evaluate the result of the
13729 * expression for all the element in the set. use it to grow
13732 CHECK_TYPE0(XPATH_NODESET);
13733 obj = valuePop(ctxt);
13734 oldset = obj->nodesetval;
13736 oldnode = ctxt->context->node;
13737 oldDoc = ctxt->context->doc;
13738 ctxt->context->node = NULL;
13740 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13741 ctxt->context->contextSize = 0;
13742 ctxt->context->proximityPosition = 0;
13746 xmlXPathCompOpEval(ctxt,
13747 &comp->steps[op->ch2]);
13749 res = valuePop(ctxt);
13751 xmlXPathFreeObject(res);
13753 valuePush(ctxt, obj);
13754 ctxt->context->node = oldnode;
13759 * Initialize the new set.
13760 * Also set the xpath document in case things like
13761 * key() evaluation are attempted on the predicate
13763 newset = xmlXPathNodeSetCreate(NULL);
13766 * "For each node in the node-set to be filtered, the
13767 * PredicateExpr is evaluated with that node as the
13768 * context node, with the number of nodes in the
13769 * node-set as the context size, and with the proximity
13770 * position of the node in the node-set with respect to
13771 * the axis as the context position;"
13772 * @oldset is the node-set" to be filtered.
13775 * "only predicates change the context position and
13776 * context size (see [2.4 Predicates])."
13778 * node-set context pos
13782 * After applying predicate [position() > 1] :
13783 * node-set context pos
13787 * removed the first node in the node-set, then
13788 * the context position of the
13790 for (i = 0; i < oldset->nodeNr; i++) {
13792 * Run the evaluation with a node list made of
13793 * a single item in the nodeset.
13795 ctxt->context->node = oldset->nodeTab[i];
13796 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13797 (oldset->nodeTab[i]->doc != NULL))
13798 ctxt->context->doc = oldset->nodeTab[i]->doc;
13800 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13801 ctxt->context->node);
13803 xmlXPathNodeSetAddUnique(tmp->nodesetval,
13804 ctxt->context->node);
13806 valuePush(ctxt, tmp);
13807 ctxt->context->contextSize = oldset->nodeNr;
13808 ctxt->context->proximityPosition = i + 1;
13810 * Evaluate the predicate against the context node.
13811 * Can/should we optimize position() predicates
13812 * here (e.g. "[1]")?
13816 xmlXPathCompOpEval(ctxt,
13817 &comp->steps[op->ch2]);
13818 if (ctxt->error != XPATH_EXPRESSION_OK) {
13819 xmlXPathFreeNodeSet(newset);
13820 xmlXPathFreeObject(obj);
13825 * The result of the evaluation needs to be tested to
13826 * decide whether the filter succeeded or not
13829 * OPTIMIZE TODO: Can we use
13830 * xmlXPathNodeSetAdd*Unique()* instead?
13832 res = valuePop(ctxt);
13833 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13834 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
13841 xmlXPathReleaseObject(ctxt->context, res);
13843 if (ctxt->value == tmp) {
13845 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13847 * Don't free the temporary nodeset
13848 * in order to avoid massive recreation inside this
13853 ctxt->context->node = NULL;
13856 xmlXPathReleaseObject(ctxt->context, tmp);
13858 * The result is used as the new evaluation set.
13860 xmlXPathReleaseObject(ctxt->context, obj);
13861 ctxt->context->node = NULL;
13862 ctxt->context->contextSize = -1;
13863 ctxt->context->proximityPosition = -1;
13864 /* may want to move this past the '}' later */
13865 ctxt->context->doc = oldDoc;
13867 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13869 ctxt->context->node = oldnode;
13872 case XPATH_OP_SORT:
13874 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13876 if ((ctxt->value != NULL) &&
13877 (ctxt->value->type == XPATH_NODESET) &&
13878 (ctxt->value->nodesetval != NULL) &&
13879 (ctxt->value->nodesetval->nodeNr > 1))
13881 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13884 #ifdef LIBXML_XPTR_ENABLED
13885 case XPATH_OP_RANGETO:{
13886 xmlXPathObjectPtr range;
13887 xmlXPathObjectPtr res, obj;
13888 xmlXPathObjectPtr tmp;
13889 xmlLocationSetPtr newlocset = NULL;
13890 xmlLocationSetPtr oldlocset;
13891 xmlNodeSetPtr oldset;
13896 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13900 if (ctxt->value->type == XPATH_LOCATIONSET) {
13902 * Extract the old locset, and then evaluate the result of the
13903 * expression for all the element in the locset. use it to grow
13906 CHECK_TYPE0(XPATH_LOCATIONSET);
13907 obj = valuePop(ctxt);
13908 oldlocset = obj->user;
13910 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13911 ctxt->context->node = NULL;
13912 ctxt->context->contextSize = 0;
13913 ctxt->context->proximityPosition = 0;
13914 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
13915 res = valuePop(ctxt);
13917 xmlXPathReleaseObject(ctxt->context, res);
13919 valuePush(ctxt, obj);
13923 newlocset = xmlXPtrLocationSetCreate(NULL);
13925 for (i = 0; i < oldlocset->locNr; i++) {
13927 * Run the evaluation with a node list made of a
13928 * single item in the nodelocset.
13930 ctxt->context->node = oldlocset->locTab[i]->user;
13931 ctxt->context->contextSize = oldlocset->locNr;
13932 ctxt->context->proximityPosition = i + 1;
13933 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13934 ctxt->context->node);
13935 valuePush(ctxt, tmp);
13939 xmlXPathCompOpEval(ctxt,
13940 &comp->steps[op->ch2]);
13941 if (ctxt->error != XPATH_EXPRESSION_OK) {
13942 xmlXPathFreeObject(obj);
13946 res = valuePop(ctxt);
13947 if (res->type == XPATH_LOCATIONSET) {
13948 xmlLocationSetPtr rloc =
13949 (xmlLocationSetPtr)res->user;
13950 for (j=0; j<rloc->locNr; j++) {
13951 range = xmlXPtrNewRange(
13952 oldlocset->locTab[i]->user,
13953 oldlocset->locTab[i]->index,
13954 rloc->locTab[j]->user2,
13955 rloc->locTab[j]->index2);
13956 if (range != NULL) {
13957 xmlXPtrLocationSetAdd(newlocset, range);
13961 range = xmlXPtrNewRangeNodeObject(
13962 (xmlNodePtr)oldlocset->locTab[i]->user, res);
13963 if (range != NULL) {
13964 xmlXPtrLocationSetAdd(newlocset,range);
13972 xmlXPathReleaseObject(ctxt->context, res);
13974 if (ctxt->value == tmp) {
13975 res = valuePop(ctxt);
13976 xmlXPathReleaseObject(ctxt->context, res);
13979 ctxt->context->node = NULL;
13981 } else { /* Not a location set */
13982 CHECK_TYPE0(XPATH_NODESET);
13983 obj = valuePop(ctxt);
13984 oldset = obj->nodesetval;
13985 ctxt->context->node = NULL;
13987 newlocset = xmlXPtrLocationSetCreate(NULL);
13989 if (oldset != NULL) {
13990 for (i = 0; i < oldset->nodeNr; i++) {
13992 * Run the evaluation with a node list made of a single item
13995 ctxt->context->node = oldset->nodeTab[i];
13997 * OPTIMIZE TODO: Avoid recreation for every iteration.
13999 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14000 ctxt->context->node);
14001 valuePush(ctxt, tmp);
14005 xmlXPathCompOpEval(ctxt,
14006 &comp->steps[op->ch2]);
14007 if (ctxt->error != XPATH_EXPRESSION_OK) {
14008 xmlXPathFreeObject(obj);
14012 res = valuePop(ctxt);
14014 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14016 if (range != NULL) {
14017 xmlXPtrLocationSetAdd(newlocset, range);
14024 xmlXPathReleaseObject(ctxt->context, res);
14026 if (ctxt->value == tmp) {
14027 res = valuePop(ctxt);
14028 xmlXPathReleaseObject(ctxt->context, res);
14031 ctxt->context->node = NULL;
14037 * The result is used as the new evaluation set.
14039 xmlXPathReleaseObject(ctxt->context, obj);
14040 ctxt->context->node = NULL;
14041 ctxt->context->contextSize = -1;
14042 ctxt->context->proximityPosition = -1;
14043 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14046 #endif /* LIBXML_XPTR_ENABLED */
14048 xmlGenericError(xmlGenericErrorContext,
14049 "XPath: unknown precompiled operation %d\n", op->op);
14050 ctxt->error = XPATH_INVALID_OPERAND;
14055 * xmlXPathCompOpEvalToBoolean:
14056 * @ctxt: the XPath parser context
14058 * Evaluates if the expression evaluates to true.
14060 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14063 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14064 xmlXPathStepOpPtr op,
14067 xmlXPathObjectPtr resObj = NULL;
14070 /* comp = ctxt->comp; */
14074 case XPATH_OP_VALUE:
14075 resObj = (xmlXPathObjectPtr) op->value4;
14077 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14078 return(xmlXPathCastToBoolean(resObj));
14079 case XPATH_OP_SORT:
14081 * We don't need sorting for boolean results. Skip this one.
14083 if (op->ch1 != -1) {
14084 op = &ctxt->comp->steps[op->ch1];
14088 case XPATH_OP_COLLECT:
14092 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14093 if (ctxt->error != XPATH_EXPRESSION_OK)
14096 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14097 if (ctxt->error != XPATH_EXPRESSION_OK)
14100 resObj = valuePop(ctxt);
14101 if (resObj == NULL)
14106 * Fallback to call xmlXPathCompOpEval().
14108 xmlXPathCompOpEval(ctxt, op);
14109 if (ctxt->error != XPATH_EXPRESSION_OK)
14112 resObj = valuePop(ctxt);
14113 if (resObj == NULL)
14121 if (resObj->type == XPATH_BOOLEAN) {
14122 res = resObj->boolval;
14123 } else if (isPredicate) {
14125 * For predicates a result of type "number" is handled
14128 * "If the result is a number, the result will be converted
14129 * to true if the number is equal to the context position
14130 * and will be converted to false otherwise;"
14132 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14134 res = xmlXPathCastToBoolean(resObj);
14136 xmlXPathReleaseObject(ctxt->context, resObj);
14143 #ifdef XPATH_STREAMING
14145 * xmlXPathRunStreamEval:
14146 * @ctxt: the XPath parser context with the compiled expression
14148 * Evaluate the Precompiled Streamable XPath expression in the given context.
14151 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14152 xmlXPathObjectPtr *resultSeq, int toBool)
14154 int max_depth, min_depth;
14157 int eval_all_nodes;
14158 xmlNodePtr cur = NULL, limit = NULL;
14159 xmlStreamCtxtPtr patstream = NULL;
14163 if ((ctxt == NULL) || (comp == NULL))
14165 max_depth = xmlPatternMaxDepth(comp);
14166 if (max_depth == -1)
14168 if (max_depth == -2)
14170 min_depth = xmlPatternMinDepth(comp);
14171 if (min_depth == -1)
14173 from_root = xmlPatternFromRoot(comp);
14177 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14181 if (resultSeq == NULL)
14183 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14184 if (*resultSeq == NULL)
14189 * handle the special cases of "/" amd "." being matched
14191 if (min_depth == 0) {
14196 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14197 (xmlNodePtr) ctxt->doc);
14199 /* Select "self::node()" */
14202 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14205 if (max_depth == 0) {
14210 cur = (xmlNodePtr)ctxt->doc;
14211 } else if (ctxt->node != NULL) {
14212 switch (ctxt->node->type) {
14213 case XML_ELEMENT_NODE:
14214 case XML_DOCUMENT_NODE:
14215 case XML_DOCUMENT_FRAG_NODE:
14216 case XML_HTML_DOCUMENT_NODE:
14217 #ifdef LIBXML_DOCB_ENABLED
14218 case XML_DOCB_DOCUMENT_NODE:
14222 case XML_ATTRIBUTE_NODE:
14223 case XML_TEXT_NODE:
14224 case XML_CDATA_SECTION_NODE:
14225 case XML_ENTITY_REF_NODE:
14226 case XML_ENTITY_NODE:
14228 case XML_COMMENT_NODE:
14229 case XML_NOTATION_NODE:
14231 case XML_DOCUMENT_TYPE_NODE:
14232 case XML_ELEMENT_DECL:
14233 case XML_ATTRIBUTE_DECL:
14234 case XML_ENTITY_DECL:
14235 case XML_NAMESPACE_DECL:
14236 case XML_XINCLUDE_START:
14237 case XML_XINCLUDE_END:
14246 patstream = xmlPatternGetStreamCtxt(comp);
14247 if (patstream == NULL) {
14249 * QUESTION TODO: Is this an error?
14254 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14257 ret = xmlStreamPush(patstream, NULL, NULL);
14259 } else if (ret == 1) {
14262 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14266 goto scan_children;
14271 switch (cur->type) {
14272 case XML_ELEMENT_NODE:
14273 case XML_TEXT_NODE:
14274 case XML_CDATA_SECTION_NODE:
14275 case XML_COMMENT_NODE:
14277 if (cur->type == XML_ELEMENT_NODE) {
14278 ret = xmlStreamPush(patstream, cur->name,
14279 (cur->ns ? cur->ns->href : NULL));
14280 } else if (eval_all_nodes)
14281 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14287 } else if (ret == 1) {
14290 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14292 if ((cur->children == NULL) || (depth >= max_depth)) {
14293 ret = xmlStreamPop(patstream);
14294 while (cur->next != NULL) {
14296 if ((cur->type != XML_ENTITY_DECL) &&
14297 (cur->type != XML_DTD_NODE))
14306 if ((cur->children != NULL) && (depth < max_depth)) {
14308 * Do not descend on entities declarations
14310 if (cur->children->type != XML_ENTITY_DECL) {
14311 cur = cur->children;
14316 if (cur->type != XML_DTD_NODE)
14324 while (cur->next != NULL) {
14326 if ((cur->type != XML_ENTITY_DECL) &&
14327 (cur->type != XML_DTD_NODE))
14334 if ((cur == NULL) || (cur == limit))
14336 if (cur->type == XML_ELEMENT_NODE) {
14337 ret = xmlStreamPop(patstream);
14338 } else if ((eval_all_nodes) &&
14339 ((cur->type == XML_TEXT_NODE) ||
14340 (cur->type == XML_CDATA_SECTION_NODE) ||
14341 (cur->type == XML_COMMENT_NODE) ||
14342 (cur->type == XML_PI_NODE)))
14344 ret = xmlStreamPop(patstream);
14346 if (cur->next != NULL) {
14350 } while (cur != NULL);
14352 } while ((cur != NULL) && (depth >= 0));
14357 printf("stream eval: checked %d nodes selected %d\n",
14358 nb_nodes, retObj->nodesetval->nodeNr);
14362 xmlFreeStreamCtxt(patstream);
14367 xmlFreeStreamCtxt(patstream);
14370 #endif /* XPATH_STREAMING */
14374 * @ctxt: the XPath parser context with the compiled expression
14375 * @toBool: evaluate to a boolean result
14377 * Evaluate the Precompiled XPath expression in the given context.
14380 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14382 xmlXPathCompExprPtr comp;
14384 if ((ctxt == NULL) || (ctxt->comp == NULL))
14387 if (ctxt->valueTab == NULL) {
14388 /* Allocate the value stack */
14389 ctxt->valueTab = (xmlXPathObjectPtr *)
14390 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14391 if (ctxt->valueTab == NULL) {
14392 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14396 ctxt->valueMax = 10;
14397 ctxt->value = NULL;
14398 ctxt->valueFrame = 0;
14400 #ifdef XPATH_STREAMING
14401 if (ctxt->comp->stream) {
14406 * Evaluation to boolean result.
14408 res = xmlXPathRunStreamEval(ctxt->context,
14409 ctxt->comp->stream, NULL, 1);
14413 xmlXPathObjectPtr resObj = NULL;
14416 * Evaluation to a sequence.
14418 res = xmlXPathRunStreamEval(ctxt->context,
14419 ctxt->comp->stream, &resObj, 0);
14421 if ((res != -1) && (resObj != NULL)) {
14422 valuePush(ctxt, resObj);
14425 if (resObj != NULL)
14426 xmlXPathReleaseObject(ctxt->context, resObj);
14429 * QUESTION TODO: This falls back to normal XPath evaluation
14430 * if res == -1. Is this intended?
14435 if (comp->last < 0) {
14436 xmlGenericError(xmlGenericErrorContext,
14437 "xmlXPathRunEval: last is less than zero\n");
14441 return(xmlXPathCompOpEvalToBoolean(ctxt,
14442 &comp->steps[comp->last], 0));
14444 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14449 /************************************************************************
14451 * Public interfaces *
14453 ************************************************************************/
14456 * xmlXPathEvalPredicate:
14457 * @ctxt: the XPath context
14458 * @res: the Predicate Expression evaluation result
14460 * Evaluate a predicate result for the current node.
14461 * A PredicateExpr is evaluated by evaluating the Expr and converting
14462 * the result to a boolean. If the result is a number, the result will
14463 * be converted to true if the number is equal to the position of the
14464 * context node in the context node list (as returned by the position
14465 * function) and will be converted to false otherwise; if the result
14466 * is not a number, then the result will be converted as if by a call
14467 * to the boolean function.
14469 * Returns 1 if predicate is true, 0 otherwise
14472 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14473 if ((ctxt == NULL) || (res == NULL)) return(0);
14474 switch (res->type) {
14475 case XPATH_BOOLEAN:
14476 return(res->boolval);
14478 return(res->floatval == ctxt->proximityPosition);
14479 case XPATH_NODESET:
14480 case XPATH_XSLT_TREE:
14481 if (res->nodesetval == NULL)
14483 return(res->nodesetval->nodeNr != 0);
14485 return((res->stringval != NULL) &&
14486 (xmlStrlen(res->stringval) != 0));
14494 * xmlXPathEvaluatePredicateResult:
14495 * @ctxt: the XPath Parser context
14496 * @res: the Predicate Expression evaluation result
14498 * Evaluate a predicate result for the current node.
14499 * A PredicateExpr is evaluated by evaluating the Expr and converting
14500 * the result to a boolean. If the result is a number, the result will
14501 * be converted to true if the number is equal to the position of the
14502 * context node in the context node list (as returned by the position
14503 * function) and will be converted to false otherwise; if the result
14504 * is not a number, then the result will be converted as if by a call
14505 * to the boolean function.
14507 * Returns 1 if predicate is true, 0 otherwise
14510 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14511 xmlXPathObjectPtr res) {
14512 if ((ctxt == NULL) || (res == NULL)) return(0);
14513 switch (res->type) {
14514 case XPATH_BOOLEAN:
14515 return(res->boolval);
14517 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14518 return((res->floatval == ctxt->context->proximityPosition) &&
14519 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14521 return(res->floatval == ctxt->context->proximityPosition);
14523 case XPATH_NODESET:
14524 case XPATH_XSLT_TREE:
14525 if (res->nodesetval == NULL)
14527 return(res->nodesetval->nodeNr != 0);
14529 return((res->stringval != NULL) && (res->stringval[0] != 0));
14530 #ifdef LIBXML_XPTR_ENABLED
14531 case XPATH_LOCATIONSET:{
14532 xmlLocationSetPtr ptr = res->user;
14535 return (ptr->locNr != 0);
14544 #ifdef XPATH_STREAMING
14546 * xmlXPathTryStreamCompile:
14547 * @ctxt: an XPath context
14548 * @str: the XPath expression
14550 * Try to compile the XPath expression as a streamable subset.
14552 * Returns the compiled expression or NULL if failed to compile.
14554 static xmlXPathCompExprPtr
14555 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14557 * Optimization: use streaming patterns when the XPath expression can
14558 * be compiled to a stream lookup
14560 xmlPatternPtr stream;
14561 xmlXPathCompExprPtr comp;
14562 xmlDictPtr dict = NULL;
14563 const xmlChar **namespaces = NULL;
14567 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14568 (!xmlStrchr(str, '@'))) {
14569 const xmlChar *tmp;
14572 * We don't try to handle expressions using the verbose axis
14573 * specifiers ("::"), just the simplied form at this point.
14574 * Additionally, if there is no list of namespaces available and
14575 * there's a ":" in the expression, indicating a prefixed QName,
14576 * then we won't try to compile either. xmlPatterncompile() needs
14577 * to have a list of namespaces at compilation time in order to
14578 * compile prefixed name tests.
14580 tmp = xmlStrchr(str, ':');
14581 if ((tmp != NULL) &&
14582 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14585 if (ctxt != NULL) {
14587 if (ctxt->nsNr > 0) {
14588 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14589 if (namespaces == NULL) {
14590 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14593 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14594 ns = ctxt->namespaces[j];
14595 namespaces[i++] = ns->href;
14596 namespaces[i++] = ns->prefix;
14598 namespaces[i++] = NULL;
14599 namespaces[i] = NULL;
14603 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14605 if (namespaces != NULL) {
14606 xmlFree((xmlChar **)namespaces);
14608 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14609 comp = xmlXPathNewCompExpr();
14610 if (comp == NULL) {
14611 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14614 comp->stream = stream;
14617 xmlDictReference(comp->dict);
14620 xmlFreePattern(stream);
14624 #endif /* XPATH_STREAMING */
14627 xmlXPathCanRewriteDosExpression(xmlChar *expr)
14632 if ((*expr == '/') && (*(++expr) == '/'))
14638 xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14641 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14642 * internal representation.
14644 if (op->ch1 != -1) {
14645 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14646 ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
14647 ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
14648 ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
14651 * This is a "child::foo"
14653 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14655 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14656 (prevop->ch1 != -1) &&
14657 ((xmlXPathAxisVal) prevop->value ==
14658 AXIS_DESCENDANT_OR_SELF) &&
14659 (prevop->ch2 == -1) &&
14660 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14661 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
14662 (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
14665 * This is a "/descendant-or-self::node()" without predicates.
14668 op->ch1 = prevop->ch1;
14669 op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
14673 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
14676 xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
14680 * xmlXPathCtxtCompile:
14681 * @ctxt: an XPath context
14682 * @str: the XPath expression
14684 * Compile an XPath expression
14686 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687 * the caller has to free the object.
14689 xmlXPathCompExprPtr
14690 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14691 xmlXPathParserContextPtr pctxt;
14692 xmlXPathCompExprPtr comp;
14694 #ifdef XPATH_STREAMING
14695 comp = xmlXPathTryStreamCompile(ctxt, str);
14702 pctxt = xmlXPathNewParserContext(str, ctxt);
14705 xmlXPathCompileExpr(pctxt, 1);
14707 if( pctxt->error != XPATH_EXPRESSION_OK )
14709 xmlXPathFreeParserContext(pctxt);
14713 if (*pctxt->cur != 0) {
14715 * aleksey: in some cases this line prints *second* error message
14716 * (see bug #78858) and probably this should be fixed.
14717 * However, we are not sure that all error messages are printed
14718 * out in other places. It's not critical so we leave it as-is for now
14720 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14723 comp = pctxt->comp;
14724 pctxt->comp = NULL;
14726 xmlXPathFreeParserContext(pctxt);
14728 if (comp != NULL) {
14729 comp->expr = xmlStrdup(str);
14730 #ifdef DEBUG_EVAL_COUNTS
14731 comp->string = xmlStrdup(str);
14734 if ((comp->expr != NULL) &&
14735 (comp->nbStep > 2) &&
14736 (comp->last >= 0) &&
14737 (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
14739 xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
14747 * @str: the XPath expression
14749 * Compile an XPath expression
14751 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14752 * the caller has to free the object.
14754 xmlXPathCompExprPtr
14755 xmlXPathCompile(const xmlChar *str) {
14756 return(xmlXPathCtxtCompile(NULL, str));
14760 * xmlXPathCompiledEvalInternal:
14761 * @comp: the compiled XPath expression
14762 * @ctxt: the XPath context
14763 * @resObj: the resulting XPath object or NULL
14764 * @toBool: 1 if only a boolean result is requested
14766 * Evaluate the Precompiled XPath expression in the given context.
14767 * The caller has to free @resObj.
14769 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14770 * the caller has to free the object.
14773 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14774 xmlXPathContextPtr ctxt,
14775 xmlXPathObjectPtr *resObj,
14778 xmlXPathParserContextPtr pctxt;
14779 #ifndef LIBXML_THREAD_ENABLED
14780 static int reentance = 0;
14784 CHECK_CTXT_NEG(ctxt)
14790 #ifndef LIBXML_THREAD_ENABLED
14793 xmlXPathDisableOptimizer = 1;
14796 #ifdef DEBUG_EVAL_COUNTS
14798 if ((comp->string != NULL) && (comp->nb > 100)) {
14799 fprintf(stderr, "100 x %s\n", comp->string);
14803 pctxt = xmlXPathCompParserContext(comp, ctxt);
14804 res = xmlXPathRunEval(pctxt, toBool);
14807 if (pctxt->value == NULL) {
14808 xmlGenericError(xmlGenericErrorContext,
14809 "xmlXPathCompiledEval: evaluation failed\n");
14812 *resObj = valuePop(pctxt);
14817 * Pop all remaining objects from the stack.
14819 if (pctxt->valueNr > 0) {
14820 xmlXPathObjectPtr tmp;
14824 tmp = valuePop(pctxt);
14827 xmlXPathReleaseObject(ctxt, tmp);
14829 } while (tmp != NULL);
14830 if ((stack != 0) &&
14831 ((toBool) || ((resObj) && (*resObj))))
14833 xmlGenericError(xmlGenericErrorContext,
14834 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14839 if ((pctxt->error != XPATH_EXPRESSION_OK) && (resObj) && (*resObj)) {
14840 xmlXPathFreeObject(*resObj);
14843 pctxt->comp = NULL;
14844 xmlXPathFreeParserContext(pctxt);
14845 #ifndef LIBXML_THREAD_ENABLED
14853 * xmlXPathCompiledEval:
14854 * @comp: the compiled XPath expression
14855 * @ctx: the XPath context
14857 * Evaluate the Precompiled XPath expression in the given context.
14859 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860 * the caller has to free the object.
14863 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14865 xmlXPathObjectPtr res = NULL;
14867 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
14872 * xmlXPathCompiledEvalToBoolean:
14873 * @comp: the compiled XPath expression
14874 * @ctxt: the XPath context
14876 * Applies the XPath boolean() function on the result of the given
14877 * compiled expression.
14879 * Returns 1 if the expression evaluated to true, 0 if to false and
14880 * -1 in API and internal errors.
14883 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
14884 xmlXPathContextPtr ctxt)
14886 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
14890 * xmlXPathEvalExpr:
14891 * @ctxt: the XPath Parser context
14893 * Parse and evaluate an XPath expression in the given context,
14894 * then push the result on the context stack
14897 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
14898 #ifdef XPATH_STREAMING
14899 xmlXPathCompExprPtr comp;
14902 if (ctxt == NULL) return;
14904 #ifdef XPATH_STREAMING
14905 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
14906 if (comp != NULL) {
14907 if (ctxt->comp != NULL)
14908 xmlXPathFreeCompExpr(ctxt->comp);
14910 if (ctxt->cur != NULL)
14911 while (*ctxt->cur != 0) ctxt->cur++;
14915 xmlXPathCompileExpr(ctxt, 1);
14917 * In this scenario the expression string will sit in ctxt->base.
14919 if ((ctxt->error == XPATH_EXPRESSION_OK) &&
14920 (ctxt->comp != NULL) &&
14921 (ctxt->base != NULL) &&
14922 (ctxt->comp->nbStep > 2) &&
14923 (ctxt->comp->last >= 0) &&
14924 (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
14926 xmlXPathRewriteDOSExpression(ctxt->comp,
14927 &ctxt->comp->steps[ctxt->comp->last]);
14931 xmlXPathRunEval(ctxt, 0);
14936 * @str: the XPath expression
14937 * @ctx: the XPath context
14939 * Evaluate the XPath Location Path in the given context.
14941 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14942 * the caller has to free the object.
14945 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
14946 xmlXPathParserContextPtr ctxt;
14947 xmlXPathObjectPtr res, tmp, init = NULL;
14954 ctxt = xmlXPathNewParserContext(str, ctx);
14957 xmlXPathEvalExpr(ctxt);
14959 if (ctxt->value == NULL) {
14960 xmlGenericError(xmlGenericErrorContext,
14961 "xmlXPathEval: evaluation failed\n");
14963 } else if ((*ctxt->cur != 0) && (ctxt->comp != NULL)
14964 #ifdef XPATH_STREAMING
14965 && (ctxt->comp->stream == NULL)
14968 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14971 res = valuePop(ctxt);
14975 tmp = valuePop(ctxt);
14979 xmlXPathReleaseObject(ctx, tmp);
14981 } while (tmp != NULL);
14982 if ((stack != 0) && (res != NULL)) {
14983 xmlGenericError(xmlGenericErrorContext,
14984 "xmlXPathEval: %d object left on the stack\n",
14987 if (ctxt->error != XPATH_EXPRESSION_OK) {
14988 xmlXPathFreeObject(res);
14992 xmlXPathFreeParserContext(ctxt);
14997 * xmlXPathEvalExpression:
14998 * @str: the XPath expression
14999 * @ctxt: the XPath context
15001 * Evaluate the XPath expression in the given context.
15003 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15004 * the caller has to free the object.
15007 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15008 xmlXPathParserContextPtr pctxt;
15009 xmlXPathObjectPtr res, tmp;
15016 pctxt = xmlXPathNewParserContext(str, ctxt);
15019 xmlXPathEvalExpr(pctxt);
15021 if ((*pctxt->cur != 0) || (pctxt->error != XPATH_EXPRESSION_OK)) {
15022 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
15025 res = valuePop(pctxt);
15028 tmp = valuePop(pctxt);
15030 xmlXPathReleaseObject(ctxt, tmp);
15033 } while (tmp != NULL);
15034 if ((stack != 0) && (res != NULL)) {
15035 xmlGenericError(xmlGenericErrorContext,
15036 "xmlXPathEvalExpression: %d object left on the stack\n",
15039 xmlXPathFreeParserContext(pctxt);
15043 /************************************************************************
15045 * Extra functions not pertaining to the XPath spec *
15047 ************************************************************************/
15049 * xmlXPathEscapeUriFunction:
15050 * @ctxt: the XPath Parser context
15051 * @nargs: the number of arguments
15053 * Implement the escape-uri() XPath function
15054 * string escape-uri(string $str, bool $escape-reserved)
15056 * This function applies the URI escaping rules defined in section 2 of [RFC
15057 * 2396] to the string supplied as $uri-part, which typically represents all
15058 * or part of a URI. The effect of the function is to replace any special
15059 * character in the string by an escape sequence of the form %xx%yy...,
15060 * where xxyy... is the hexadecimal representation of the octets used to
15061 * represent the character in UTF-8.
15063 * The set of characters that are escaped depends on the setting of the
15064 * boolean argument $escape-reserved.
15066 * If $escape-reserved is true, all characters are escaped other than lower
15067 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15068 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15069 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15070 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15073 * If $escape-reserved is false, the behavior differs in that characters
15074 * referred to in [RFC 2396] as reserved characters are not escaped. These
15075 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15077 * [RFC 2396] does not define whether escaped URIs should use lower case or
15078 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15079 * compared using string comparison functions, this function must always use
15080 * the upper-case letters A-F.
15082 * Generally, $escape-reserved should be set to true when escaping a string
15083 * that is to form a single part of a URI, and to false when escaping an
15084 * entire URI or URI reference.
15086 * In the case of non-ascii characters, the string is encoded according to
15087 * utf-8 and then converted according to RFC 2396.
15090 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15091 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15092 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15093 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15097 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15098 xmlXPathObjectPtr str;
15099 int escape_reserved;
15100 xmlBufferPtr target;
15106 escape_reserved = xmlXPathPopBoolean(ctxt);
15109 str = valuePop(ctxt);
15111 target = xmlBufferCreate();
15117 for (cptr = str->stringval; *cptr; cptr++) {
15118 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15119 (*cptr >= 'a' && *cptr <= 'z') ||
15120 (*cptr >= '0' && *cptr <= '9') ||
15121 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15122 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15123 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15125 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15126 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15127 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15128 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15129 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15130 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15131 (!escape_reserved &&
15132 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15133 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15134 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15136 xmlBufferAdd(target, cptr, 1);
15138 if ((*cptr >> 4) < 10)
15139 escape[1] = '0' + (*cptr >> 4);
15141 escape[1] = 'A' - 10 + (*cptr >> 4);
15142 if ((*cptr & 0xF) < 10)
15143 escape[2] = '0' + (*cptr & 0xF);
15145 escape[2] = 'A' - 10 + (*cptr & 0xF);
15147 xmlBufferAdd(target, &escape[0], 3);
15151 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15152 xmlBufferContent(target)));
15153 xmlBufferFree(target);
15154 xmlXPathReleaseObject(ctxt->context, str);
15158 * xmlXPathRegisterAllFunctions:
15159 * @ctxt: the XPath context
15161 * Registers all default XPath functions in this context
15164 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15166 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15167 xmlXPathBooleanFunction);
15168 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15169 xmlXPathCeilingFunction);
15170 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15171 xmlXPathCountFunction);
15172 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15173 xmlXPathConcatFunction);
15174 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15175 xmlXPathContainsFunction);
15176 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15177 xmlXPathIdFunction);
15178 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15179 xmlXPathFalseFunction);
15180 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15181 xmlXPathFloorFunction);
15182 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15183 xmlXPathLastFunction);
15184 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15185 xmlXPathLangFunction);
15186 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15187 xmlXPathLocalNameFunction);
15188 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15189 xmlXPathNotFunction);
15190 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15191 xmlXPathNameFunction);
15192 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15193 xmlXPathNamespaceURIFunction);
15194 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15195 xmlXPathNormalizeFunction);
15196 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15197 xmlXPathNumberFunction);
15198 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15199 xmlXPathPositionFunction);
15200 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15201 xmlXPathRoundFunction);
15202 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15203 xmlXPathStringFunction);
15204 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15205 xmlXPathStringLengthFunction);
15206 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15207 xmlXPathStartsWithFunction);
15208 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15209 xmlXPathSubstringFunction);
15210 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15211 xmlXPathSubstringBeforeFunction);
15212 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15213 xmlXPathSubstringAfterFunction);
15214 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15215 xmlXPathSumFunction);
15216 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15217 xmlXPathTrueFunction);
15218 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15219 xmlXPathTranslateFunction);
15221 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15222 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15223 xmlXPathEscapeUriFunction);
15226 #endif /* LIBXML_XPATH_ENABLED */
15227 #define bottom_xpath
15228 #include "elfgcchack.h"