2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
9 * http://www.w3.org/TR/xpath
11 * See Copyright for the status of this software
13 * Author: daniel@veillard.com
17 /* To avoid EBCDIC trouble when parsing on zOS */
19 #pragma convert("ISO8859-1")
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
72 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
101 #define XP_OPTIMIZED_FILTER_FIRST
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
108 /* #define XP_DEBUG_OBJ_USAGE */
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
117 #define XPATH_MAX_STEPS 1000000
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
126 #define XPATH_MAX_STACK_DEPTH 1000000
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
136 #define XPATH_MAX_NODESET_LENGTH 10000000
139 * XPATH_MAX_RECRUSION_DEPTH:
140 * Maximum amount of nested functions calls when parsing or evaluating
143 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
144 #define XPATH_MAX_RECURSION_DEPTH 500
146 #define XPATH_MAX_RECURSION_DEPTH 5000
151 * There are a few spots where some tests are done which depend upon ascii
152 * data. These should be enhanced for full UTF8 support (see particularly
153 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
156 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
158 * xmlXPathCmpNodesExt:
159 * @node1: the first node
160 * @node2: the second node
162 * Compare two nodes w.r.t document order.
163 * This one is optimized for handling of non-element nodes.
165 * Returns -2 in case of error 1 if first point < second point, 0 if
166 * it's the same node, -1 otherwise
169 xmlXPathCmpNodesExt(xmlNodePtr node1
, xmlNodePtr node2
) {
171 int misc
= 0, precedence1
= 0, precedence2
= 0;
172 xmlNodePtr miscNode1
= NULL
, miscNode2
= NULL
;
173 xmlNodePtr cur
, root
;
176 if ((node1
== NULL
) || (node2
== NULL
))
183 * a couple of optimizations which will avoid computations in most cases
185 switch (node1
->type
) {
186 case XML_ELEMENT_NODE
:
187 if (node2
->type
== XML_ELEMENT_NODE
) {
188 if ((0 > (ptrdiff_t) node1
->content
) &&
189 (0 > (ptrdiff_t) node2
->content
) &&
190 (node1
->doc
== node2
->doc
))
192 l1
= -((ptrdiff_t) node1
->content
);
193 l2
= -((ptrdiff_t) node2
->content
);
199 goto turtle_comparison
;
202 case XML_ATTRIBUTE_NODE
:
203 precedence1
= 1; /* element is owner */
205 node1
= node1
->parent
;
209 case XML_CDATA_SECTION_NODE
:
210 case XML_COMMENT_NODE
:
214 * Find nearest element node.
216 if (node1
->prev
!= NULL
) {
219 if (node1
->type
== XML_ELEMENT_NODE
) {
220 precedence1
= 3; /* element in prev-sibl axis */
223 if (node1
->prev
== NULL
) {
224 precedence1
= 2; /* element is parent */
226 * URGENT TODO: Are there any cases, where the
227 * parent of such a node is not an element node?
229 node1
= node1
->parent
;
234 precedence1
= 2; /* element is parent */
235 node1
= node1
->parent
;
237 if ((node1
== NULL
) || (node1
->type
!= XML_ELEMENT_NODE
) ||
238 (0 <= (ptrdiff_t) node1
->content
)) {
240 * Fallback for whatever case.
248 case XML_NAMESPACE_DECL
:
250 * TODO: why do we return 1 for namespace nodes?
256 switch (node2
->type
) {
257 case XML_ELEMENT_NODE
:
259 case XML_ATTRIBUTE_NODE
:
260 precedence2
= 1; /* element is owner */
262 node2
= node2
->parent
;
266 case XML_CDATA_SECTION_NODE
:
267 case XML_COMMENT_NODE
:
270 if (node2
->prev
!= NULL
) {
273 if (node2
->type
== XML_ELEMENT_NODE
) {
274 precedence2
= 3; /* element in prev-sibl axis */
277 if (node2
->prev
== NULL
) {
278 precedence2
= 2; /* element is parent */
279 node2
= node2
->parent
;
284 precedence2
= 2; /* element is parent */
285 node2
= node2
->parent
;
287 if ((node2
== NULL
) || (node2
->type
!= XML_ELEMENT_NODE
) ||
288 (0 <= (ptrdiff_t) node2
->content
))
296 case XML_NAMESPACE_DECL
:
302 if (node1
== node2
) {
303 if (precedence1
== precedence2
) {
305 * The ugly case; but normally there aren't many
306 * adjacent non-element nodes around.
308 cur
= miscNode2
->prev
;
309 while (cur
!= NULL
) {
310 if (cur
== miscNode1
)
312 if (cur
->type
== XML_ELEMENT_NODE
)
319 * Evaluate based on higher precedence wrt to the element.
320 * TODO: This assumes attributes are sorted before content.
321 * Is this 100% correct?
323 if (precedence1
< precedence2
)
330 * Special case: One of the helper-elements is contained by the other.
333 * <node1>Text-1(precedence1 == 2)</node1>
335 * Text-6(precedence2 == 3)
338 if ((precedence2
== 3) && (precedence1
> 1)) {
346 if ((precedence1
== 3) && (precedence2
> 1)) {
357 * Speedup using document order if available.
359 if ((node1
->type
== XML_ELEMENT_NODE
) &&
360 (node2
->type
== XML_ELEMENT_NODE
) &&
361 (0 > (ptrdiff_t) node1
->content
) &&
362 (0 > (ptrdiff_t) node2
->content
) &&
363 (node1
->doc
== node2
->doc
)) {
365 l1
= -((ptrdiff_t) node1
->content
);
366 l2
= -((ptrdiff_t) node2
->content
);
375 if (node1
== node2
->prev
)
377 if (node1
== node2
->next
)
380 * compute depth to root
382 for (depth2
= 0, cur
= node2
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
383 if (cur
->parent
== node1
)
388 for (depth1
= 0, cur
= node1
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
389 if (cur
->parent
== node2
)
394 * Distinct document (or distinct entities :-( ) case.
400 * get the nearest common ancestor.
402 while (depth1
> depth2
) {
404 node1
= node1
->parent
;
406 while (depth2
> depth1
) {
408 node2
= node2
->parent
;
410 while (node1
->parent
!= node2
->parent
) {
411 node1
= node1
->parent
;
412 node2
= node2
->parent
;
413 /* should not happen but just in case ... */
414 if ((node1
== NULL
) || (node2
== NULL
))
420 if (node1
== node2
->prev
)
422 if (node1
== node2
->next
)
425 * Speedup using document order if available.
427 if ((node1
->type
== XML_ELEMENT_NODE
) &&
428 (node2
->type
== XML_ELEMENT_NODE
) &&
429 (0 > (ptrdiff_t) node1
->content
) &&
430 (0 > (ptrdiff_t) node2
->content
) &&
431 (node1
->doc
== node2
->doc
)) {
433 l1
= -((ptrdiff_t) node1
->content
);
434 l2
= -((ptrdiff_t) node2
->content
);
441 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
444 return(-1); /* assume there is no sibling list corruption */
446 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
449 * Wrapper for the Timsort algorithm from timsort.h
452 #define SORT_NAME libxml_domnode
453 #define SORT_TYPE xmlNodePtr
459 * Comparison function for the Timsort implementation
461 * Returns -2 in case of error -1 if first point < second point, 0 if
462 * it's the same node, +1 otherwise
465 int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
);
466 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
467 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
469 int res
= xmlXPathCmpNodesExt(x
, y
);
470 return res
== -2 ? res
: -res
;
473 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
475 int res
= xmlXPathCmpNodes(x
, y
);
476 return res
== -2 ? res
: -res
;
479 #define SORT_CMP(x, y) (wrap_cmp(x, y))
481 #endif /* WITH_TIM_SORT */
483 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
485 /************************************************************************
487 * Floating point stuff *
489 ************************************************************************/
498 * Initialize the XPath environment
502 /* Use MSVC definitions */
504 xmlXPathPINF
= INFINITY
;
505 xmlXPathNINF
= -INFINITY
;
510 * @val: a double value
512 * Returns 1 if the value is a NaN, 0 otherwise
515 xmlXPathIsNaN(double val
) {
519 return !(val
== val
);
525 * @val: a double value
527 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
530 xmlXPathIsInf(double val
) {
532 return isinf(val
) ? (val
> 0 ? 1 : -1) : 0;
534 if (val
>= xmlXPathPINF
)
536 if (val
<= -xmlXPathPINF
)
542 #endif /* SCHEMAS or XPATH */
544 #ifdef LIBXML_XPATH_ENABLED
547 * TODO: when compatibility allows remove all "fake node libxslt" strings
548 * the test should just be name[0] = ' '
550 #ifdef DEBUG_XPATH_EXPRESSION
553 #define DEBUG_EVAL_COUNTS
556 static xmlNs xmlXPathXMLNamespaceStruct
= {
564 static xmlNsPtr xmlXPathXMLNamespace
= &xmlXPathXMLNamespaceStruct
;
565 #ifndef LIBXML_THREAD_ENABLED
567 * Optimizer is disabled only when threaded apps are detected while
568 * the library ain't compiled for thread safety.
570 static int xmlXPathDisableOptimizer
= 0;
573 /************************************************************************
575 * Error handling routines *
577 ************************************************************************/
583 * Macro to raise an XPath error and return NULL.
585 #define XP_ERRORNULL(X) \
586 { xmlXPathErr(ctxt, X); return(NULL); }
589 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
591 static const char *xmlXPathErrorMessages
[] = {
594 "Unfinished literal\n",
595 "Start of literal\n",
596 "Expected $ for variable reference\n",
597 "Undefined variable\n",
598 "Invalid predicate\n",
599 "Invalid expression\n",
600 "Missing closing curly brace\n",
601 "Unregistered function\n",
604 "Invalid number of arguments\n",
605 "Invalid context size\n",
606 "Invalid context position\n",
607 "Memory allocation error\n",
610 "Sub resource error\n",
611 "Undefined namespace prefix\n",
613 "Char out of XML range\n",
614 "Invalid or incomplete context\n",
615 "Stack usage error\n",
616 "Forbidden variable\n",
617 "Operation limit exceeded\n",
618 "Recursion limit exceeded\n",
619 "?? Unknown error ??\n" /* Must be last in the list! */
621 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
622 sizeof(xmlXPathErrorMessages[0])) - 1)
625 * @ctxt: an XPath context
626 * @extra: extra information
628 * Handle a redefinition of attribute error
631 xmlXPathErrMemory(xmlXPathContextPtr ctxt
, const char *extra
)
634 xmlResetError(&ctxt
->lastError
);
638 xmlStrPrintf(buf
, 200,
639 "Memory allocation failed : %s\n",
641 ctxt
->lastError
.message
= (char *) xmlStrdup(buf
);
643 ctxt
->lastError
.message
= (char *)
644 xmlStrdup(BAD_CAST
"Memory allocation failed\n");
646 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
647 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
648 if (ctxt
->error
!= NULL
)
649 ctxt
->error(ctxt
->userData
, &ctxt
->lastError
);
652 __xmlRaiseError(NULL
, NULL
, NULL
,
653 NULL
, NULL
, XML_FROM_XPATH
,
654 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
655 extra
, NULL
, NULL
, 0, 0,
656 "Memory allocation failed : %s\n", extra
);
658 __xmlRaiseError(NULL
, NULL
, NULL
,
659 NULL
, NULL
, XML_FROM_XPATH
,
660 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
661 NULL
, NULL
, NULL
, 0, 0,
662 "Memory allocation failed\n");
667 * xmlXPathPErrMemory:
668 * @ctxt: an XPath parser context
669 * @extra: extra information
671 * Handle a redefinition of attribute error
674 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt
, const char *extra
)
677 xmlXPathErrMemory(NULL
, extra
);
679 ctxt
->error
= XPATH_MEMORY_ERROR
;
680 xmlXPathErrMemory(ctxt
->context
, extra
);
686 * @ctxt: a XPath parser context
687 * @error: the error code
689 * Handle an XPath error
692 xmlXPathErr(xmlXPathParserContextPtr ctxt
, int error
)
694 if ((error
< 0) || (error
> MAXERRNO
))
697 __xmlRaiseError(NULL
, NULL
, NULL
,
698 NULL
, NULL
, XML_FROM_XPATH
,
699 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
700 XML_ERR_ERROR
, NULL
, 0,
701 NULL
, NULL
, NULL
, 0, 0,
702 "%s", xmlXPathErrorMessages
[error
]);
706 if (ctxt
->context
== NULL
) {
707 __xmlRaiseError(NULL
, NULL
, NULL
,
708 NULL
, NULL
, XML_FROM_XPATH
,
709 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
710 XML_ERR_ERROR
, NULL
, 0,
711 (const char *) ctxt
->base
, NULL
, NULL
,
712 ctxt
->cur
- ctxt
->base
, 0,
713 "%s", xmlXPathErrorMessages
[error
]);
717 /* cleanup current last error */
718 xmlResetError(&ctxt
->context
->lastError
);
720 ctxt
->context
->lastError
.domain
= XML_FROM_XPATH
;
721 ctxt
->context
->lastError
.code
= error
+ XML_XPATH_EXPRESSION_OK
-
723 ctxt
->context
->lastError
.level
= XML_ERR_ERROR
;
724 ctxt
->context
->lastError
.str1
= (char *) xmlStrdup(ctxt
->base
);
725 ctxt
->context
->lastError
.int1
= ctxt
->cur
- ctxt
->base
;
726 ctxt
->context
->lastError
.node
= ctxt
->context
->debugNode
;
727 if (ctxt
->context
->error
!= NULL
) {
728 ctxt
->context
->error(ctxt
->context
->userData
,
729 &ctxt
->context
->lastError
);
731 __xmlRaiseError(NULL
, NULL
, NULL
,
732 NULL
, ctxt
->context
->debugNode
, XML_FROM_XPATH
,
733 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
734 XML_ERR_ERROR
, NULL
, 0,
735 (const char *) ctxt
->base
, NULL
, NULL
,
736 ctxt
->cur
- ctxt
->base
, 0,
737 "%s", xmlXPathErrorMessages
[error
]);
744 * @ctxt: the XPath Parser context
745 * @file: the file name
746 * @line: the line number
747 * @no: the error number
749 * Formats an error message.
752 xmlXPatherror(xmlXPathParserContextPtr ctxt
, const char *file ATTRIBUTE_UNUSED
,
753 int line ATTRIBUTE_UNUSED
, int no
) {
754 xmlXPathErr(ctxt
, no
);
758 * xmlXPathCheckOpLimit:
759 * @ctxt: the XPath Parser context
760 * @opCount: the number of operations to be added
762 * Adds opCount to the running total of operations and returns -1 if the
763 * operation limit is exceeded. Returns 0 otherwise.
766 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt
, unsigned long opCount
) {
767 xmlXPathContextPtr xpctxt
= ctxt
->context
;
769 if ((opCount
> xpctxt
->opLimit
) ||
770 (xpctxt
->opCount
> xpctxt
->opLimit
- opCount
)) {
771 xpctxt
->opCount
= xpctxt
->opLimit
;
772 xmlXPathErr(ctxt
, XPATH_OP_LIMIT_EXCEEDED
);
776 xpctxt
->opCount
+= opCount
;
780 #define OP_LIMIT_EXCEEDED(ctxt, n) \
781 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
783 /************************************************************************
787 ************************************************************************/
792 * Pointer-list for various purposes.
794 typedef struct _xmlPointerList xmlPointerList
;
795 typedef xmlPointerList
*xmlPointerListPtr
;
796 struct _xmlPointerList
{
802 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
803 * and here, we should make the functions public.
806 xmlPointerListAddSize(xmlPointerListPtr list
,
810 if (list
->items
== NULL
) {
811 if (initialSize
<= 0)
813 list
->items
= (void **) xmlMalloc(initialSize
* sizeof(void *));
814 if (list
->items
== NULL
) {
815 xmlXPathErrMemory(NULL
,
816 "xmlPointerListCreate: allocating item\n");
820 list
->size
= initialSize
;
821 } else if (list
->size
<= list
->number
) {
822 if (list
->size
> 50000000) {
823 xmlXPathErrMemory(NULL
,
824 "xmlPointerListAddSize: re-allocating item\n");
828 list
->items
= (void **) xmlRealloc(list
->items
,
829 list
->size
* sizeof(void *));
830 if (list
->items
== NULL
) {
831 xmlXPathErrMemory(NULL
,
832 "xmlPointerListAddSize: re-allocating item\n");
837 list
->items
[list
->number
++] = item
;
842 * xsltPointerListCreate:
844 * Creates an xsltPointerList structure.
846 * Returns a xsltPointerList structure or NULL in case of an error.
848 static xmlPointerListPtr
849 xmlPointerListCreate(int initialSize
)
851 xmlPointerListPtr ret
;
853 ret
= xmlMalloc(sizeof(xmlPointerList
));
855 xmlXPathErrMemory(NULL
,
856 "xmlPointerListCreate: allocating item\n");
859 memset(ret
, 0, sizeof(xmlPointerList
));
860 if (initialSize
> 0) {
861 xmlPointerListAddSize(ret
, NULL
, initialSize
);
868 * xsltPointerListFree:
870 * Frees the xsltPointerList structure. This does not free
871 * the content of the list.
874 xmlPointerListFree(xmlPointerListPtr list
)
878 if (list
->items
!= NULL
)
879 xmlFree(list
->items
);
883 /************************************************************************
887 ************************************************************************/
905 XPATH_OP_VALUE
, /* 11 */
910 XPATH_OP_FILTER
, /* 16 */
911 XPATH_OP_SORT
/* 17 */
912 #ifdef LIBXML_XPTR_ENABLED
919 AXIS_ANCESTOR_OR_SELF
,
923 AXIS_DESCENDANT_OR_SELF
,
925 AXIS_FOLLOWING_SIBLING
,
929 AXIS_PRECEDING_SIBLING
,
944 NODE_TYPE_COMMENT
= XML_COMMENT_NODE
,
945 NODE_TYPE_TEXT
= XML_TEXT_NODE
,
946 NODE_TYPE_PI
= XML_PI_NODE
949 typedef struct _xmlXPathStepOp xmlXPathStepOp
;
950 typedef xmlXPathStepOp
*xmlXPathStepOpPtr
;
951 struct _xmlXPathStepOp
{
952 xmlXPathOp op
; /* The identifier of the operation */
953 int ch1
; /* First child */
954 int ch2
; /* Second child */
960 xmlXPathFunction cache
;
964 struct _xmlXPathCompExpr
{
965 int nbStep
; /* Number of steps in this expression */
966 int maxStep
; /* Maximum number of steps allocated */
967 xmlXPathStepOp
*steps
; /* ops for computation of this expression */
968 int last
; /* index of last step in expression */
969 xmlChar
*expr
; /* the expression being computed */
970 xmlDictPtr dict
; /* the dictionary to use if any */
971 #ifdef DEBUG_EVAL_COUNTS
975 #ifdef XPATH_STREAMING
976 xmlPatternPtr stream
;
980 /************************************************************************
982 * Forward declarations *
984 ************************************************************************/
986 xmlXPathFreeValueTree(xmlNodeSetPtr obj
);
988 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
);
990 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
991 xmlXPathStepOpPtr op
, xmlNodePtr
*first
);
993 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
994 xmlXPathStepOpPtr op
,
997 xmlXPathFreeObjectEntry(void *obj
, const xmlChar
*name
);
999 /************************************************************************
1001 * Parser Type functions *
1003 ************************************************************************/
1006 * xmlXPathNewCompExpr:
1008 * Create a new Xpath component
1010 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1012 static xmlXPathCompExprPtr
1013 xmlXPathNewCompExpr(void) {
1014 xmlXPathCompExprPtr cur
;
1016 cur
= (xmlXPathCompExprPtr
) xmlMalloc(sizeof(xmlXPathCompExpr
));
1018 xmlXPathErrMemory(NULL
, "allocating component\n");
1021 memset(cur
, 0, sizeof(xmlXPathCompExpr
));
1024 cur
->steps
= (xmlXPathStepOp
*) xmlMalloc(cur
->maxStep
*
1025 sizeof(xmlXPathStepOp
));
1026 if (cur
->steps
== NULL
) {
1027 xmlXPathErrMemory(NULL
, "allocating steps\n");
1031 memset(cur
->steps
, 0, cur
->maxStep
* sizeof(xmlXPathStepOp
));
1033 #ifdef DEBUG_EVAL_COUNTS
1040 * xmlXPathFreeCompExpr:
1041 * @comp: an XPATH comp
1043 * Free up the memory allocated by @comp
1046 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp
)
1048 xmlXPathStepOpPtr op
;
1053 if (comp
->dict
== NULL
) {
1054 for (i
= 0; i
< comp
->nbStep
; i
++) {
1055 op
= &comp
->steps
[i
];
1056 if (op
->value4
!= NULL
) {
1057 if (op
->op
== XPATH_OP_VALUE
)
1058 xmlXPathFreeObject(op
->value4
);
1060 xmlFree(op
->value4
);
1062 if (op
->value5
!= NULL
)
1063 xmlFree(op
->value5
);
1066 for (i
= 0; i
< comp
->nbStep
; i
++) {
1067 op
= &comp
->steps
[i
];
1068 if (op
->value4
!= NULL
) {
1069 if (op
->op
== XPATH_OP_VALUE
)
1070 xmlXPathFreeObject(op
->value4
);
1073 xmlDictFree(comp
->dict
);
1075 if (comp
->steps
!= NULL
) {
1076 xmlFree(comp
->steps
);
1078 #ifdef DEBUG_EVAL_COUNTS
1079 if (comp
->string
!= NULL
) {
1080 xmlFree(comp
->string
);
1083 #ifdef XPATH_STREAMING
1084 if (comp
->stream
!= NULL
) {
1085 xmlFreePatternList(comp
->stream
);
1088 if (comp
->expr
!= NULL
) {
1089 xmlFree(comp
->expr
);
1096 * xmlXPathCompExprAdd:
1097 * @comp: the compiled expression
1098 * @ch1: first child index
1099 * @ch2: second child index
1101 * @value: the first int value
1102 * @value2: the second int value
1103 * @value3: the third int value
1104 * @value4: the first string value
1105 * @value5: the second string value
1107 * Add a step to an XPath Compiled Expression
1109 * Returns -1 in case of failure, the index otherwise
1112 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt
, int ch1
, int ch2
,
1113 xmlXPathOp op
, int value
,
1114 int value2
, int value3
, void *value4
, void *value5
) {
1115 xmlXPathCompExprPtr comp
= ctxt
->comp
;
1116 if (comp
->nbStep
>= comp
->maxStep
) {
1117 xmlXPathStepOp
*real
;
1119 if (comp
->maxStep
>= XPATH_MAX_STEPS
) {
1120 xmlXPathPErrMemory(ctxt
, "adding step\n");
1124 real
= (xmlXPathStepOp
*) xmlRealloc(comp
->steps
,
1125 comp
->maxStep
* sizeof(xmlXPathStepOp
));
1128 xmlXPathPErrMemory(ctxt
, "adding step\n");
1133 comp
->last
= comp
->nbStep
;
1134 comp
->steps
[comp
->nbStep
].ch1
= ch1
;
1135 comp
->steps
[comp
->nbStep
].ch2
= ch2
;
1136 comp
->steps
[comp
->nbStep
].op
= op
;
1137 comp
->steps
[comp
->nbStep
].value
= value
;
1138 comp
->steps
[comp
->nbStep
].value2
= value2
;
1139 comp
->steps
[comp
->nbStep
].value3
= value3
;
1140 if ((comp
->dict
!= NULL
) &&
1141 ((op
== XPATH_OP_FUNCTION
) || (op
== XPATH_OP_VARIABLE
) ||
1142 (op
== XPATH_OP_COLLECT
))) {
1143 if (value4
!= NULL
) {
1144 comp
->steps
[comp
->nbStep
].value4
= (xmlChar
*)
1145 (void *)xmlDictLookup(comp
->dict
, value4
, -1);
1148 comp
->steps
[comp
->nbStep
].value4
= NULL
;
1149 if (value5
!= NULL
) {
1150 comp
->steps
[comp
->nbStep
].value5
= (xmlChar
*)
1151 (void *)xmlDictLookup(comp
->dict
, value5
, -1);
1154 comp
->steps
[comp
->nbStep
].value5
= NULL
;
1156 comp
->steps
[comp
->nbStep
].value4
= value4
;
1157 comp
->steps
[comp
->nbStep
].value5
= value5
;
1159 comp
->steps
[comp
->nbStep
].cache
= NULL
;
1160 return(comp
->nbStep
++);
1165 * @comp: the compiled expression
1166 * @op: operation index
1168 * Swaps 2 operations in the compiled expression
1171 xmlXPathCompSwap(xmlXPathStepOpPtr op
) {
1174 #ifndef LIBXML_THREAD_ENABLED
1176 * Since this manipulates possibly shared variables, this is
1177 * disabled if one detects that the library is used in a multithreaded
1180 if (xmlXPathDisableOptimizer
)
1189 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1190 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1191 (op), (val), (val2), (val3), (val4), (val5))
1192 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1193 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1194 (op), (val), (val2), (val3), (val4), (val5))
1196 #define PUSH_LEAVE_EXPR(op, val, val2) \
1197 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1199 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1200 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1202 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1203 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1204 (val), (val2), 0 ,NULL ,NULL)
1206 /************************************************************************
1208 * XPath object cache structures *
1210 ************************************************************************/
1212 /* #define XP_DEFAULT_CACHE_ON */
1214 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1216 typedef struct _xmlXPathContextCache xmlXPathContextCache
;
1217 typedef xmlXPathContextCache
*xmlXPathContextCachePtr
;
1218 struct _xmlXPathContextCache
{
1219 xmlPointerListPtr nodesetObjs
; /* contains xmlXPathObjectPtr */
1220 xmlPointerListPtr stringObjs
; /* contains xmlXPathObjectPtr */
1221 xmlPointerListPtr booleanObjs
; /* contains xmlXPathObjectPtr */
1222 xmlPointerListPtr numberObjs
; /* contains xmlXPathObjectPtr */
1223 xmlPointerListPtr miscObjs
; /* contains xmlXPathObjectPtr */
1229 #ifdef XP_DEBUG_OBJ_USAGE
1231 int dbgCachedNodeset
;
1232 int dbgCachedString
;
1234 int dbgCachedNumber
;
1237 int dbgCachedLocset
;
1239 int dbgCachedXSLTTree
;
1240 int dbgCachedUndefined
;
1244 int dbgReusedNodeset
;
1245 int dbgReusedString
;
1247 int dbgReusedNumber
;
1250 int dbgReusedLocset
;
1252 int dbgReusedXSLTTree
;
1253 int dbgReusedUndefined
;
1258 /************************************************************************
1260 * Debugging related functions *
1262 ************************************************************************/
1265 xmlGenericError(xmlGenericErrorContext, \
1266 "Internal error at %s:%d\n", \
1267 __FILE__, __LINE__);
1269 #ifdef LIBXML_DEBUG_ENABLED
1271 xmlXPathDebugDumpNode(FILE *output
, xmlNodePtr cur
, int depth
) {
1275 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1276 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1277 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1279 fprintf(output
, "%s", shift
);
1280 fprintf(output
, "Node is NULL !\n");
1285 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
1286 (cur
->type
== XML_HTML_DOCUMENT_NODE
)) {
1287 fprintf(output
, "%s", shift
);
1288 fprintf(output
, " /\n");
1289 } else if (cur
->type
== XML_ATTRIBUTE_NODE
)
1290 xmlDebugDumpAttr(output
, (xmlAttrPtr
)cur
, depth
);
1292 xmlDebugDumpOneNode(output
, cur
, depth
);
1295 xmlXPathDebugDumpNodeList(FILE *output
, xmlNodePtr cur
, int depth
) {
1300 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1301 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1302 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1304 fprintf(output
, "%s", shift
);
1305 fprintf(output
, "Node is NULL !\n");
1310 while (cur
!= NULL
) {
1313 xmlDebugDumpOneNode(output
, tmp
, depth
);
1318 xmlXPathDebugDumpNodeSet(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1322 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1323 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1324 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1327 fprintf(output
, "%s", shift
);
1328 fprintf(output
, "NodeSet is NULL !\n");
1334 fprintf(output
, "Set contains %d nodes:\n", cur
->nodeNr
);
1335 for (i
= 0;i
< cur
->nodeNr
;i
++) {
1336 fprintf(output
, "%s", shift
);
1337 fprintf(output
, "%d", i
+ 1);
1338 xmlXPathDebugDumpNode(output
, cur
->nodeTab
[i
], depth
+ 1);
1344 xmlXPathDebugDumpValueTree(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1348 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1349 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1350 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1352 if ((cur
== NULL
) || (cur
->nodeNr
== 0) || (cur
->nodeTab
[0] == NULL
)) {
1353 fprintf(output
, "%s", shift
);
1354 fprintf(output
, "Value Tree is NULL !\n");
1359 fprintf(output
, "%s", shift
);
1360 fprintf(output
, "%d", i
+ 1);
1361 xmlXPathDebugDumpNodeList(output
, cur
->nodeTab
[0]->children
, depth
+ 1);
1363 #if defined(LIBXML_XPTR_ENABLED)
1365 xmlXPathDebugDumpLocationSet(FILE *output
, xmlLocationSetPtr cur
, int depth
) {
1369 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1370 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1371 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1374 fprintf(output
, "%s", shift
);
1375 fprintf(output
, "LocationSet is NULL !\n");
1380 for (i
= 0;i
< cur
->locNr
;i
++) {
1381 fprintf(output
, "%s", shift
);
1382 fprintf(output
, "%d : ", i
+ 1);
1383 xmlXPathDebugDumpObject(output
, cur
->locTab
[i
], depth
+ 1);
1386 #endif /* LIBXML_XPTR_ENABLED */
1389 * xmlXPathDebugDumpObject:
1390 * @output: the FILE * to dump the output
1391 * @cur: the object to inspect
1392 * @depth: indentation level
1394 * Dump the content of the object for debugging purposes
1397 xmlXPathDebugDumpObject(FILE *output
, xmlXPathObjectPtr cur
, int depth
) {
1401 if (output
== NULL
) return;
1403 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1404 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1405 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1408 fprintf(output
, "%s", shift
);
1411 fprintf(output
, "Object is empty (NULL)\n");
1415 case XPATH_UNDEFINED
:
1416 fprintf(output
, "Object is uninitialized\n");
1419 fprintf(output
, "Object is a Node Set :\n");
1420 xmlXPathDebugDumpNodeSet(output
, cur
->nodesetval
, depth
);
1422 case XPATH_XSLT_TREE
:
1423 fprintf(output
, "Object is an XSLT value tree :\n");
1424 xmlXPathDebugDumpValueTree(output
, cur
->nodesetval
, depth
);
1427 fprintf(output
, "Object is a Boolean : ");
1428 if (cur
->boolval
) fprintf(output
, "true\n");
1429 else fprintf(output
, "false\n");
1432 switch (xmlXPathIsInf(cur
->floatval
)) {
1434 fprintf(output
, "Object is a number : Infinity\n");
1437 fprintf(output
, "Object is a number : -Infinity\n");
1440 if (xmlXPathIsNaN(cur
->floatval
)) {
1441 fprintf(output
, "Object is a number : NaN\n");
1442 } else if (cur
->floatval
== 0) {
1443 /* Omit sign for negative zero. */
1444 fprintf(output
, "Object is a number : 0\n");
1446 fprintf(output
, "Object is a number : %0g\n", cur
->floatval
);
1451 fprintf(output
, "Object is a string : ");
1452 xmlDebugDumpString(output
, cur
->stringval
);
1453 fprintf(output
, "\n");
1456 fprintf(output
, "Object is a point : index %d in node", cur
->index
);
1457 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
, depth
+ 1);
1458 fprintf(output
, "\n");
1461 if ((cur
->user2
== NULL
) ||
1462 ((cur
->user2
== cur
->user
) && (cur
->index
== cur
->index2
))) {
1463 fprintf(output
, "Object is a collapsed range :\n");
1464 fprintf(output
, "%s", shift
);
1465 if (cur
->index
>= 0)
1466 fprintf(output
, "index %d in ", cur
->index
);
1467 fprintf(output
, "node\n");
1468 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1471 fprintf(output
, "Object is a range :\n");
1472 fprintf(output
, "%s", shift
);
1473 fprintf(output
, "From ");
1474 if (cur
->index
>= 0)
1475 fprintf(output
, "index %d in ", cur
->index
);
1476 fprintf(output
, "node\n");
1477 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1479 fprintf(output
, "%s", shift
);
1480 fprintf(output
, "To ");
1481 if (cur
->index2
>= 0)
1482 fprintf(output
, "index %d in ", cur
->index2
);
1483 fprintf(output
, "node\n");
1484 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user2
,
1486 fprintf(output
, "\n");
1489 case XPATH_LOCATIONSET
:
1490 #if defined(LIBXML_XPTR_ENABLED)
1491 fprintf(output
, "Object is a Location Set:\n");
1492 xmlXPathDebugDumpLocationSet(output
,
1493 (xmlLocationSetPtr
) cur
->user
, depth
);
1497 fprintf(output
, "Object is user defined\n");
1503 xmlXPathDebugDumpStepOp(FILE *output
, xmlXPathCompExprPtr comp
,
1504 xmlXPathStepOpPtr op
, int depth
) {
1508 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1509 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1510 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1512 fprintf(output
, "%s", shift
);
1514 fprintf(output
, "Step is NULL\n");
1519 fprintf(output
, "END"); break;
1521 fprintf(output
, "AND"); break;
1523 fprintf(output
, "OR"); break;
1524 case XPATH_OP_EQUAL
:
1526 fprintf(output
, "EQUAL =");
1528 fprintf(output
, "EQUAL !=");
1532 fprintf(output
, "CMP <");
1534 fprintf(output
, "CMP >");
1536 fprintf(output
, "=");
1540 fprintf(output
, "PLUS -");
1541 else if (op
->value
== 1)
1542 fprintf(output
, "PLUS +");
1543 else if (op
->value
== 2)
1544 fprintf(output
, "PLUS unary -");
1545 else if (op
->value
== 3)
1546 fprintf(output
, "PLUS unary - -");
1550 fprintf(output
, "MULT *");
1551 else if (op
->value
== 1)
1552 fprintf(output
, "MULT div");
1554 fprintf(output
, "MULT mod");
1556 case XPATH_OP_UNION
:
1557 fprintf(output
, "UNION"); break;
1559 fprintf(output
, "ROOT"); break;
1561 fprintf(output
, "NODE"); break;
1563 fprintf(output
, "SORT"); break;
1564 case XPATH_OP_COLLECT
: {
1565 xmlXPathAxisVal axis
= (xmlXPathAxisVal
)op
->value
;
1566 xmlXPathTestVal test
= (xmlXPathTestVal
)op
->value2
;
1567 xmlXPathTypeVal type
= (xmlXPathTypeVal
)op
->value3
;
1568 const xmlChar
*prefix
= op
->value4
;
1569 const xmlChar
*name
= op
->value5
;
1571 fprintf(output
, "COLLECT ");
1574 fprintf(output
, " 'ancestors' "); break;
1575 case AXIS_ANCESTOR_OR_SELF
:
1576 fprintf(output
, " 'ancestors-or-self' "); break;
1577 case AXIS_ATTRIBUTE
:
1578 fprintf(output
, " 'attributes' "); break;
1580 fprintf(output
, " 'child' "); break;
1581 case AXIS_DESCENDANT
:
1582 fprintf(output
, " 'descendant' "); break;
1583 case AXIS_DESCENDANT_OR_SELF
:
1584 fprintf(output
, " 'descendant-or-self' "); break;
1585 case AXIS_FOLLOWING
:
1586 fprintf(output
, " 'following' "); break;
1587 case AXIS_FOLLOWING_SIBLING
:
1588 fprintf(output
, " 'following-siblings' "); break;
1589 case AXIS_NAMESPACE
:
1590 fprintf(output
, " 'namespace' "); break;
1592 fprintf(output
, " 'parent' "); break;
1593 case AXIS_PRECEDING
:
1594 fprintf(output
, " 'preceding' "); break;
1595 case AXIS_PRECEDING_SIBLING
:
1596 fprintf(output
, " 'preceding-sibling' "); break;
1598 fprintf(output
, " 'self' "); break;
1601 case NODE_TEST_NONE
:
1602 fprintf(output
, "'none' "); break;
1603 case NODE_TEST_TYPE
:
1604 fprintf(output
, "'type' "); break;
1606 fprintf(output
, "'PI' "); break;
1608 fprintf(output
, "'all' "); break;
1610 fprintf(output
, "'namespace' "); break;
1611 case NODE_TEST_NAME
:
1612 fprintf(output
, "'name' "); break;
1615 case NODE_TYPE_NODE
:
1616 fprintf(output
, "'node' "); break;
1617 case NODE_TYPE_COMMENT
:
1618 fprintf(output
, "'comment' "); break;
1619 case NODE_TYPE_TEXT
:
1620 fprintf(output
, "'text' "); break;
1622 fprintf(output
, "'PI' "); break;
1625 fprintf(output
, "%s:", prefix
);
1627 fprintf(output
, "%s", (const char *) name
);
1631 case XPATH_OP_VALUE
: {
1632 xmlXPathObjectPtr object
= (xmlXPathObjectPtr
) op
->value4
;
1634 fprintf(output
, "ELEM ");
1635 xmlXPathDebugDumpObject(output
, object
, 0);
1638 case XPATH_OP_VARIABLE
: {
1639 const xmlChar
*prefix
= op
->value5
;
1640 const xmlChar
*name
= op
->value4
;
1643 fprintf(output
, "VARIABLE %s:%s", prefix
, name
);
1645 fprintf(output
, "VARIABLE %s", name
);
1648 case XPATH_OP_FUNCTION
: {
1649 int nbargs
= op
->value
;
1650 const xmlChar
*prefix
= op
->value5
;
1651 const xmlChar
*name
= op
->value4
;
1654 fprintf(output
, "FUNCTION %s:%s(%d args)",
1655 prefix
, name
, nbargs
);
1657 fprintf(output
, "FUNCTION %s(%d args)", name
, nbargs
);
1660 case XPATH_OP_ARG
: fprintf(output
, "ARG"); break;
1661 case XPATH_OP_PREDICATE
: fprintf(output
, "PREDICATE"); break;
1662 case XPATH_OP_FILTER
: fprintf(output
, "FILTER"); break;
1663 #ifdef LIBXML_XPTR_ENABLED
1664 case XPATH_OP_RANGETO
: fprintf(output
, "RANGETO"); break;
1667 fprintf(output
, "UNKNOWN %d\n", op
->op
); return;
1669 fprintf(output
, "\n");
1672 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch1
], depth
+ 1);
1674 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch2
], depth
+ 1);
1678 * xmlXPathDebugDumpCompExpr:
1679 * @output: the FILE * for the output
1680 * @comp: the precompiled XPath expression
1681 * @depth: the indentation level.
1683 * Dumps the tree of the compiled XPath expression.
1686 xmlXPathDebugDumpCompExpr(FILE *output
, xmlXPathCompExprPtr comp
,
1691 if ((output
== NULL
) || (comp
== NULL
)) return;
1693 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1694 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1695 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1697 fprintf(output
, "%s", shift
);
1699 #ifdef XPATH_STREAMING
1701 fprintf(output
, "Streaming Expression\n");
1705 fprintf(output
, "Compiled Expression : %d elements\n",
1708 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[i
], depth
+ 1);
1712 #ifdef XP_DEBUG_OBJ_USAGE
1715 * XPath object usage related debugging variables.
1717 static int xmlXPathDebugObjCounterUndefined
= 0;
1718 static int xmlXPathDebugObjCounterNodeset
= 0;
1719 static int xmlXPathDebugObjCounterBool
= 0;
1720 static int xmlXPathDebugObjCounterNumber
= 0;
1721 static int xmlXPathDebugObjCounterString
= 0;
1722 static int xmlXPathDebugObjCounterPoint
= 0;
1723 static int xmlXPathDebugObjCounterRange
= 0;
1724 static int xmlXPathDebugObjCounterLocset
= 0;
1725 static int xmlXPathDebugObjCounterUsers
= 0;
1726 static int xmlXPathDebugObjCounterXSLTTree
= 0;
1727 static int xmlXPathDebugObjCounterAll
= 0;
1729 static int xmlXPathDebugObjTotalUndefined
= 0;
1730 static int xmlXPathDebugObjTotalNodeset
= 0;
1731 static int xmlXPathDebugObjTotalBool
= 0;
1732 static int xmlXPathDebugObjTotalNumber
= 0;
1733 static int xmlXPathDebugObjTotalString
= 0;
1734 static int xmlXPathDebugObjTotalPoint
= 0;
1735 static int xmlXPathDebugObjTotalRange
= 0;
1736 static int xmlXPathDebugObjTotalLocset
= 0;
1737 static int xmlXPathDebugObjTotalUsers
= 0;
1738 static int xmlXPathDebugObjTotalXSLTTree
= 0;
1739 static int xmlXPathDebugObjTotalAll
= 0;
1741 static int xmlXPathDebugObjMaxUndefined
= 0;
1742 static int xmlXPathDebugObjMaxNodeset
= 0;
1743 static int xmlXPathDebugObjMaxBool
= 0;
1744 static int xmlXPathDebugObjMaxNumber
= 0;
1745 static int xmlXPathDebugObjMaxString
= 0;
1746 static int xmlXPathDebugObjMaxPoint
= 0;
1747 static int xmlXPathDebugObjMaxRange
= 0;
1748 static int xmlXPathDebugObjMaxLocset
= 0;
1749 static int xmlXPathDebugObjMaxUsers
= 0;
1750 static int xmlXPathDebugObjMaxXSLTTree
= 0;
1751 static int xmlXPathDebugObjMaxAll
= 0;
1754 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt
)
1757 if (ctxt
->cache
!= NULL
) {
1758 xmlXPathContextCachePtr cache
=
1759 (xmlXPathContextCachePtr
) ctxt
->cache
;
1761 cache
->dbgCachedAll
= 0;
1762 cache
->dbgCachedNodeset
= 0;
1763 cache
->dbgCachedString
= 0;
1764 cache
->dbgCachedBool
= 0;
1765 cache
->dbgCachedNumber
= 0;
1766 cache
->dbgCachedPoint
= 0;
1767 cache
->dbgCachedRange
= 0;
1768 cache
->dbgCachedLocset
= 0;
1769 cache
->dbgCachedUsers
= 0;
1770 cache
->dbgCachedXSLTTree
= 0;
1771 cache
->dbgCachedUndefined
= 0;
1773 cache
->dbgReusedAll
= 0;
1774 cache
->dbgReusedNodeset
= 0;
1775 cache
->dbgReusedString
= 0;
1776 cache
->dbgReusedBool
= 0;
1777 cache
->dbgReusedNumber
= 0;
1778 cache
->dbgReusedPoint
= 0;
1779 cache
->dbgReusedRange
= 0;
1780 cache
->dbgReusedLocset
= 0;
1781 cache
->dbgReusedUsers
= 0;
1782 cache
->dbgReusedXSLTTree
= 0;
1783 cache
->dbgReusedUndefined
= 0;
1787 xmlXPathDebugObjCounterUndefined
= 0;
1788 xmlXPathDebugObjCounterNodeset
= 0;
1789 xmlXPathDebugObjCounterBool
= 0;
1790 xmlXPathDebugObjCounterNumber
= 0;
1791 xmlXPathDebugObjCounterString
= 0;
1792 xmlXPathDebugObjCounterPoint
= 0;
1793 xmlXPathDebugObjCounterRange
= 0;
1794 xmlXPathDebugObjCounterLocset
= 0;
1795 xmlXPathDebugObjCounterUsers
= 0;
1796 xmlXPathDebugObjCounterXSLTTree
= 0;
1797 xmlXPathDebugObjCounterAll
= 0;
1799 xmlXPathDebugObjTotalUndefined
= 0;
1800 xmlXPathDebugObjTotalNodeset
= 0;
1801 xmlXPathDebugObjTotalBool
= 0;
1802 xmlXPathDebugObjTotalNumber
= 0;
1803 xmlXPathDebugObjTotalString
= 0;
1804 xmlXPathDebugObjTotalPoint
= 0;
1805 xmlXPathDebugObjTotalRange
= 0;
1806 xmlXPathDebugObjTotalLocset
= 0;
1807 xmlXPathDebugObjTotalUsers
= 0;
1808 xmlXPathDebugObjTotalXSLTTree
= 0;
1809 xmlXPathDebugObjTotalAll
= 0;
1811 xmlXPathDebugObjMaxUndefined
= 0;
1812 xmlXPathDebugObjMaxNodeset
= 0;
1813 xmlXPathDebugObjMaxBool
= 0;
1814 xmlXPathDebugObjMaxNumber
= 0;
1815 xmlXPathDebugObjMaxString
= 0;
1816 xmlXPathDebugObjMaxPoint
= 0;
1817 xmlXPathDebugObjMaxRange
= 0;
1818 xmlXPathDebugObjMaxLocset
= 0;
1819 xmlXPathDebugObjMaxUsers
= 0;
1820 xmlXPathDebugObjMaxXSLTTree
= 0;
1821 xmlXPathDebugObjMaxAll
= 0;
1826 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt
,
1827 xmlXPathObjectType objType
)
1832 if (ctxt
->cache
!= NULL
) {
1833 xmlXPathContextCachePtr cache
=
1834 (xmlXPathContextCachePtr
) ctxt
->cache
;
1838 cache
->dbgReusedAll
++;
1840 case XPATH_UNDEFINED
:
1841 cache
->dbgReusedUndefined
++;
1844 cache
->dbgReusedNodeset
++;
1847 cache
->dbgReusedBool
++;
1850 cache
->dbgReusedNumber
++;
1853 cache
->dbgReusedString
++;
1856 cache
->dbgReusedPoint
++;
1859 cache
->dbgReusedRange
++;
1861 case XPATH_LOCATIONSET
:
1862 cache
->dbgReusedLocset
++;
1865 cache
->dbgReusedUsers
++;
1867 case XPATH_XSLT_TREE
:
1868 cache
->dbgReusedXSLTTree
++;
1877 case XPATH_UNDEFINED
:
1879 xmlXPathDebugObjTotalUndefined
++;
1880 xmlXPathDebugObjCounterUndefined
++;
1881 if (xmlXPathDebugObjCounterUndefined
>
1882 xmlXPathDebugObjMaxUndefined
)
1883 xmlXPathDebugObjMaxUndefined
=
1884 xmlXPathDebugObjCounterUndefined
;
1888 xmlXPathDebugObjTotalNodeset
++;
1889 xmlXPathDebugObjCounterNodeset
++;
1890 if (xmlXPathDebugObjCounterNodeset
>
1891 xmlXPathDebugObjMaxNodeset
)
1892 xmlXPathDebugObjMaxNodeset
=
1893 xmlXPathDebugObjCounterNodeset
;
1897 xmlXPathDebugObjTotalBool
++;
1898 xmlXPathDebugObjCounterBool
++;
1899 if (xmlXPathDebugObjCounterBool
>
1900 xmlXPathDebugObjMaxBool
)
1901 xmlXPathDebugObjMaxBool
=
1902 xmlXPathDebugObjCounterBool
;
1906 xmlXPathDebugObjTotalNumber
++;
1907 xmlXPathDebugObjCounterNumber
++;
1908 if (xmlXPathDebugObjCounterNumber
>
1909 xmlXPathDebugObjMaxNumber
)
1910 xmlXPathDebugObjMaxNumber
=
1911 xmlXPathDebugObjCounterNumber
;
1915 xmlXPathDebugObjTotalString
++;
1916 xmlXPathDebugObjCounterString
++;
1917 if (xmlXPathDebugObjCounterString
>
1918 xmlXPathDebugObjMaxString
)
1919 xmlXPathDebugObjMaxString
=
1920 xmlXPathDebugObjCounterString
;
1924 xmlXPathDebugObjTotalPoint
++;
1925 xmlXPathDebugObjCounterPoint
++;
1926 if (xmlXPathDebugObjCounterPoint
>
1927 xmlXPathDebugObjMaxPoint
)
1928 xmlXPathDebugObjMaxPoint
=
1929 xmlXPathDebugObjCounterPoint
;
1933 xmlXPathDebugObjTotalRange
++;
1934 xmlXPathDebugObjCounterRange
++;
1935 if (xmlXPathDebugObjCounterRange
>
1936 xmlXPathDebugObjMaxRange
)
1937 xmlXPathDebugObjMaxRange
=
1938 xmlXPathDebugObjCounterRange
;
1940 case XPATH_LOCATIONSET
:
1942 xmlXPathDebugObjTotalLocset
++;
1943 xmlXPathDebugObjCounterLocset
++;
1944 if (xmlXPathDebugObjCounterLocset
>
1945 xmlXPathDebugObjMaxLocset
)
1946 xmlXPathDebugObjMaxLocset
=
1947 xmlXPathDebugObjCounterLocset
;
1951 xmlXPathDebugObjTotalUsers
++;
1952 xmlXPathDebugObjCounterUsers
++;
1953 if (xmlXPathDebugObjCounterUsers
>
1954 xmlXPathDebugObjMaxUsers
)
1955 xmlXPathDebugObjMaxUsers
=
1956 xmlXPathDebugObjCounterUsers
;
1958 case XPATH_XSLT_TREE
:
1960 xmlXPathDebugObjTotalXSLTTree
++;
1961 xmlXPathDebugObjCounterXSLTTree
++;
1962 if (xmlXPathDebugObjCounterXSLTTree
>
1963 xmlXPathDebugObjMaxXSLTTree
)
1964 xmlXPathDebugObjMaxXSLTTree
=
1965 xmlXPathDebugObjCounterXSLTTree
;
1971 xmlXPathDebugObjTotalAll
++;
1972 xmlXPathDebugObjCounterAll
++;
1973 if (xmlXPathDebugObjCounterAll
>
1974 xmlXPathDebugObjMaxAll
)
1975 xmlXPathDebugObjMaxAll
=
1976 xmlXPathDebugObjCounterAll
;
1980 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt
,
1981 xmlXPathObjectType objType
)
1986 if (ctxt
->cache
!= NULL
) {
1987 xmlXPathContextCachePtr cache
=
1988 (xmlXPathContextCachePtr
) ctxt
->cache
;
1992 cache
->dbgCachedAll
++;
1994 case XPATH_UNDEFINED
:
1995 cache
->dbgCachedUndefined
++;
1998 cache
->dbgCachedNodeset
++;
2001 cache
->dbgCachedBool
++;
2004 cache
->dbgCachedNumber
++;
2007 cache
->dbgCachedString
++;
2010 cache
->dbgCachedPoint
++;
2013 cache
->dbgCachedRange
++;
2015 case XPATH_LOCATIONSET
:
2016 cache
->dbgCachedLocset
++;
2019 cache
->dbgCachedUsers
++;
2021 case XPATH_XSLT_TREE
:
2022 cache
->dbgCachedXSLTTree
++;
2031 case XPATH_UNDEFINED
:
2032 xmlXPathDebugObjCounterUndefined
--;
2035 xmlXPathDebugObjCounterNodeset
--;
2038 xmlXPathDebugObjCounterBool
--;
2041 xmlXPathDebugObjCounterNumber
--;
2044 xmlXPathDebugObjCounterString
--;
2047 xmlXPathDebugObjCounterPoint
--;
2050 xmlXPathDebugObjCounterRange
--;
2052 case XPATH_LOCATIONSET
:
2053 xmlXPathDebugObjCounterLocset
--;
2056 xmlXPathDebugObjCounterUsers
--;
2058 case XPATH_XSLT_TREE
:
2059 xmlXPathDebugObjCounterXSLTTree
--;
2064 xmlXPathDebugObjCounterAll
--;
2068 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt
)
2070 int reqAll
, reqNodeset
, reqString
, reqBool
, reqNumber
,
2071 reqXSLTTree
, reqUndefined
;
2072 int caAll
= 0, caNodeset
= 0, caString
= 0, caBool
= 0,
2073 caNumber
= 0, caXSLTTree
= 0, caUndefined
= 0;
2074 int reAll
= 0, reNodeset
= 0, reString
= 0, reBool
= 0,
2075 reNumber
= 0, reXSLTTree
= 0, reUndefined
= 0;
2076 int leftObjs
= xmlXPathDebugObjCounterAll
;
2078 reqAll
= xmlXPathDebugObjTotalAll
;
2079 reqNodeset
= xmlXPathDebugObjTotalNodeset
;
2080 reqString
= xmlXPathDebugObjTotalString
;
2081 reqBool
= xmlXPathDebugObjTotalBool
;
2082 reqNumber
= xmlXPathDebugObjTotalNumber
;
2083 reqXSLTTree
= xmlXPathDebugObjTotalXSLTTree
;
2084 reqUndefined
= xmlXPathDebugObjTotalUndefined
;
2086 printf("# XPath object usage:\n");
2089 if (ctxt
->cache
!= NULL
) {
2090 xmlXPathContextCachePtr cache
=
2091 (xmlXPathContextCachePtr
) ctxt
->cache
;
2093 reAll
= cache
->dbgReusedAll
;
2095 reNodeset
= cache
->dbgReusedNodeset
;
2096 reqNodeset
+= reNodeset
;
2097 reString
= cache
->dbgReusedString
;
2098 reqString
+= reString
;
2099 reBool
= cache
->dbgReusedBool
;
2101 reNumber
= cache
->dbgReusedNumber
;
2102 reqNumber
+= reNumber
;
2103 reXSLTTree
= cache
->dbgReusedXSLTTree
;
2104 reqXSLTTree
+= reXSLTTree
;
2105 reUndefined
= cache
->dbgReusedUndefined
;
2106 reqUndefined
+= reUndefined
;
2108 caAll
= cache
->dbgCachedAll
;
2109 caBool
= cache
->dbgCachedBool
;
2110 caNodeset
= cache
->dbgCachedNodeset
;
2111 caString
= cache
->dbgCachedString
;
2112 caNumber
= cache
->dbgCachedNumber
;
2113 caXSLTTree
= cache
->dbgCachedXSLTTree
;
2114 caUndefined
= cache
->dbgCachedUndefined
;
2116 if (cache
->nodesetObjs
)
2117 leftObjs
-= cache
->nodesetObjs
->number
;
2118 if (cache
->stringObjs
)
2119 leftObjs
-= cache
->stringObjs
->number
;
2120 if (cache
->booleanObjs
)
2121 leftObjs
-= cache
->booleanObjs
->number
;
2122 if (cache
->numberObjs
)
2123 leftObjs
-= cache
->numberObjs
->number
;
2124 if (cache
->miscObjs
)
2125 leftObjs
-= cache
->miscObjs
->number
;
2130 printf("# total : %d\n", reqAll
);
2131 printf("# left : %d\n", leftObjs
);
2132 printf("# created: %d\n", xmlXPathDebugObjTotalAll
);
2133 printf("# reused : %d\n", reAll
);
2134 printf("# max : %d\n", xmlXPathDebugObjMaxAll
);
2136 printf("# node-sets\n");
2137 printf("# total : %d\n", reqNodeset
);
2138 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset
);
2139 printf("# reused : %d\n", reNodeset
);
2140 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset
);
2142 printf("# strings\n");
2143 printf("# total : %d\n", reqString
);
2144 printf("# created: %d\n", xmlXPathDebugObjTotalString
);
2145 printf("# reused : %d\n", reString
);
2146 printf("# max : %d\n", xmlXPathDebugObjMaxString
);
2148 printf("# booleans\n");
2149 printf("# total : %d\n", reqBool
);
2150 printf("# created: %d\n", xmlXPathDebugObjTotalBool
);
2151 printf("# reused : %d\n", reBool
);
2152 printf("# max : %d\n", xmlXPathDebugObjMaxBool
);
2154 printf("# numbers\n");
2155 printf("# total : %d\n", reqNumber
);
2156 printf("# created: %d\n", xmlXPathDebugObjTotalNumber
);
2157 printf("# reused : %d\n", reNumber
);
2158 printf("# max : %d\n", xmlXPathDebugObjMaxNumber
);
2160 printf("# XSLT result tree fragments\n");
2161 printf("# total : %d\n", reqXSLTTree
);
2162 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree
);
2163 printf("# reused : %d\n", reXSLTTree
);
2164 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree
);
2166 printf("# undefined\n");
2167 printf("# total : %d\n", reqUndefined
);
2168 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined
);
2169 printf("# reused : %d\n", reUndefined
);
2170 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined
);
2174 #endif /* XP_DEBUG_OBJ_USAGE */
2176 #endif /* LIBXML_DEBUG_ENABLED */
2178 /************************************************************************
2180 * XPath object caching *
2182 ************************************************************************/
2187 * Create a new object cache
2189 * Returns the xmlXPathCache just allocated.
2191 static xmlXPathContextCachePtr
2192 xmlXPathNewCache(void)
2194 xmlXPathContextCachePtr ret
;
2196 ret
= (xmlXPathContextCachePtr
) xmlMalloc(sizeof(xmlXPathContextCache
));
2198 xmlXPathErrMemory(NULL
, "creating object cache\n");
2201 memset(ret
, 0 , (size_t) sizeof(xmlXPathContextCache
));
2202 ret
->maxNodeset
= 100;
2203 ret
->maxString
= 100;
2204 ret
->maxBoolean
= 100;
2205 ret
->maxNumber
= 100;
2211 xmlXPathCacheFreeObjectList(xmlPointerListPtr list
)
2214 xmlXPathObjectPtr obj
;
2219 for (i
= 0; i
< list
->number
; i
++) {
2220 obj
= list
->items
[i
];
2222 * Note that it is already assured that we don't need to
2223 * look out for namespace nodes in the node-set.
2225 if (obj
->nodesetval
!= NULL
) {
2226 if (obj
->nodesetval
->nodeTab
!= NULL
)
2227 xmlFree(obj
->nodesetval
->nodeTab
);
2228 xmlFree(obj
->nodesetval
);
2231 #ifdef XP_DEBUG_OBJ_USAGE
2232 xmlXPathDebugObjCounterAll
--;
2235 xmlPointerListFree(list
);
2239 xmlXPathFreeCache(xmlXPathContextCachePtr cache
)
2243 if (cache
->nodesetObjs
)
2244 xmlXPathCacheFreeObjectList(cache
->nodesetObjs
);
2245 if (cache
->stringObjs
)
2246 xmlXPathCacheFreeObjectList(cache
->stringObjs
);
2247 if (cache
->booleanObjs
)
2248 xmlXPathCacheFreeObjectList(cache
->booleanObjs
);
2249 if (cache
->numberObjs
)
2250 xmlXPathCacheFreeObjectList(cache
->numberObjs
);
2251 if (cache
->miscObjs
)
2252 xmlXPathCacheFreeObjectList(cache
->miscObjs
);
2257 * xmlXPathContextSetCache:
2259 * @ctxt: the XPath context
2260 * @active: enables/disables (creates/frees) the cache
2261 * @value: a value with semantics dependent on @options
2262 * @options: options (currently only the value 0 is used)
2264 * Creates/frees an object cache on the XPath context.
2265 * If activates XPath objects (xmlXPathObject) will be cached internally
2268 * 0: This will set the XPath object caching:
2270 * This will set the maximum number of XPath objects
2271 * to be cached per slot
2272 * There are 5 slots for: node-set, string, number, boolean, and
2273 * misc objects. Use <0 for the default number (100).
2274 * Other values for @options have currently no effect.
2276 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2279 xmlXPathContextSetCache(xmlXPathContextPtr ctxt
,
2287 xmlXPathContextCachePtr cache
;
2289 if (ctxt
->cache
== NULL
) {
2290 ctxt
->cache
= xmlXPathNewCache();
2291 if (ctxt
->cache
== NULL
)
2294 cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2298 cache
->maxNodeset
= value
;
2299 cache
->maxString
= value
;
2300 cache
->maxNumber
= value
;
2301 cache
->maxBoolean
= value
;
2302 cache
->maxMisc
= value
;
2304 } else if (ctxt
->cache
!= NULL
) {
2305 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
2312 * xmlXPathCacheWrapNodeSet:
2313 * @ctxt: the XPath context
2314 * @val: the NodePtr value
2316 * This is the cached version of xmlXPathWrapNodeSet().
2317 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2319 * Returns the created or reused object.
2321 static xmlXPathObjectPtr
2322 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt
, xmlNodeSetPtr val
)
2324 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2325 xmlXPathContextCachePtr cache
=
2326 (xmlXPathContextCachePtr
) ctxt
->cache
;
2328 if ((cache
->miscObjs
!= NULL
) &&
2329 (cache
->miscObjs
->number
!= 0))
2331 xmlXPathObjectPtr ret
;
2333 ret
= (xmlXPathObjectPtr
)
2334 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2335 ret
->type
= XPATH_NODESET
;
2336 ret
->nodesetval
= val
;
2337 #ifdef XP_DEBUG_OBJ_USAGE
2338 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2344 return(xmlXPathWrapNodeSet(val
));
2349 * xmlXPathCacheWrapString:
2350 * @ctxt: the XPath context
2351 * @val: the xmlChar * value
2353 * This is the cached version of xmlXPathWrapString().
2354 * Wraps the @val string into an XPath object.
2356 * Returns the created or reused object.
2358 static xmlXPathObjectPtr
2359 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt
, xmlChar
*val
)
2361 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2362 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2364 if ((cache
->stringObjs
!= NULL
) &&
2365 (cache
->stringObjs
->number
!= 0))
2368 xmlXPathObjectPtr ret
;
2370 ret
= (xmlXPathObjectPtr
)
2371 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2372 ret
->type
= XPATH_STRING
;
2373 ret
->stringval
= val
;
2374 #ifdef XP_DEBUG_OBJ_USAGE
2375 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2378 } else if ((cache
->miscObjs
!= NULL
) &&
2379 (cache
->miscObjs
->number
!= 0))
2381 xmlXPathObjectPtr ret
;
2383 * Fallback to misc-cache.
2385 ret
= (xmlXPathObjectPtr
)
2386 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2388 ret
->type
= XPATH_STRING
;
2389 ret
->stringval
= val
;
2390 #ifdef XP_DEBUG_OBJ_USAGE
2391 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2396 return(xmlXPathWrapString(val
));
2400 * xmlXPathCacheNewNodeSet:
2401 * @ctxt: the XPath context
2402 * @val: the NodePtr value
2404 * This is the cached version of xmlXPathNewNodeSet().
2405 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2406 * it with the single Node @val
2408 * Returns the created or reused object.
2410 static xmlXPathObjectPtr
2411 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt
, xmlNodePtr val
)
2413 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2414 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2416 if ((cache
->nodesetObjs
!= NULL
) &&
2417 (cache
->nodesetObjs
->number
!= 0))
2419 xmlXPathObjectPtr ret
;
2421 * Use the nodeset-cache.
2423 ret
= (xmlXPathObjectPtr
)
2424 cache
->nodesetObjs
->items
[--cache
->nodesetObjs
->number
];
2425 ret
->type
= XPATH_NODESET
;
2428 if ((ret
->nodesetval
->nodeMax
== 0) ||
2429 (val
->type
== XML_NAMESPACE_DECL
))
2431 /* TODO: Check memory error. */
2432 xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
);
2434 ret
->nodesetval
->nodeTab
[0] = val
;
2435 ret
->nodesetval
->nodeNr
= 1;
2438 #ifdef XP_DEBUG_OBJ_USAGE
2439 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2442 } else if ((cache
->miscObjs
!= NULL
) &&
2443 (cache
->miscObjs
->number
!= 0))
2445 xmlXPathObjectPtr ret
;
2447 * Fallback to misc-cache.
2450 ret
= (xmlXPathObjectPtr
)
2451 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2453 ret
->type
= XPATH_NODESET
;
2455 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
2456 if (ret
->nodesetval
== NULL
) {
2457 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
2458 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
2461 #ifdef XP_DEBUG_OBJ_USAGE
2462 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2467 return(xmlXPathNewNodeSet(val
));
2471 * xmlXPathCacheNewCString:
2472 * @ctxt: the XPath context
2473 * @val: the char * value
2475 * This is the cached version of xmlXPathNewCString().
2476 * Acquire an xmlXPathObjectPtr of type string and of value @val
2478 * Returns the created or reused object.
2480 static xmlXPathObjectPtr
2481 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt
, const char *val
)
2483 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2484 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2486 if ((cache
->stringObjs
!= NULL
) &&
2487 (cache
->stringObjs
->number
!= 0))
2489 xmlXPathObjectPtr ret
;
2491 ret
= (xmlXPathObjectPtr
)
2492 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2494 ret
->type
= XPATH_STRING
;
2495 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2496 #ifdef XP_DEBUG_OBJ_USAGE
2497 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2500 } else if ((cache
->miscObjs
!= NULL
) &&
2501 (cache
->miscObjs
->number
!= 0))
2503 xmlXPathObjectPtr ret
;
2505 ret
= (xmlXPathObjectPtr
)
2506 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2508 ret
->type
= XPATH_STRING
;
2509 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2510 #ifdef XP_DEBUG_OBJ_USAGE
2511 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2516 return(xmlXPathNewCString(val
));
2520 * xmlXPathCacheNewString:
2521 * @ctxt: the XPath context
2522 * @val: the xmlChar * value
2524 * This is the cached version of xmlXPathNewString().
2525 * Acquire an xmlXPathObjectPtr of type string and of value @val
2527 * Returns the created or reused object.
2529 static xmlXPathObjectPtr
2530 xmlXPathCacheNewString(xmlXPathContextPtr ctxt
, const xmlChar
*val
)
2532 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2533 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2535 if ((cache
->stringObjs
!= NULL
) &&
2536 (cache
->stringObjs
->number
!= 0))
2538 xmlXPathObjectPtr ret
;
2540 ret
= (xmlXPathObjectPtr
)
2541 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2542 ret
->type
= XPATH_STRING
;
2544 ret
->stringval
= xmlStrdup(val
);
2546 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2547 #ifdef XP_DEBUG_OBJ_USAGE
2548 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2551 } else if ((cache
->miscObjs
!= NULL
) &&
2552 (cache
->miscObjs
->number
!= 0))
2554 xmlXPathObjectPtr ret
;
2556 ret
= (xmlXPathObjectPtr
)
2557 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2559 ret
->type
= XPATH_STRING
;
2561 ret
->stringval
= xmlStrdup(val
);
2563 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2564 #ifdef XP_DEBUG_OBJ_USAGE
2565 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2570 return(xmlXPathNewString(val
));
2574 * xmlXPathCacheNewBoolean:
2575 * @ctxt: the XPath context
2576 * @val: the boolean value
2578 * This is the cached version of xmlXPathNewBoolean().
2579 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2581 * Returns the created or reused object.
2583 static xmlXPathObjectPtr
2584 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt
, int val
)
2586 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2587 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2589 if ((cache
->booleanObjs
!= NULL
) &&
2590 (cache
->booleanObjs
->number
!= 0))
2592 xmlXPathObjectPtr ret
;
2594 ret
= (xmlXPathObjectPtr
)
2595 cache
->booleanObjs
->items
[--cache
->booleanObjs
->number
];
2596 ret
->type
= XPATH_BOOLEAN
;
2597 ret
->boolval
= (val
!= 0);
2598 #ifdef XP_DEBUG_OBJ_USAGE
2599 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2602 } else if ((cache
->miscObjs
!= NULL
) &&
2603 (cache
->miscObjs
->number
!= 0))
2605 xmlXPathObjectPtr ret
;
2607 ret
= (xmlXPathObjectPtr
)
2608 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2610 ret
->type
= XPATH_BOOLEAN
;
2611 ret
->boolval
= (val
!= 0);
2612 #ifdef XP_DEBUG_OBJ_USAGE
2613 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2618 return(xmlXPathNewBoolean(val
));
2622 * xmlXPathCacheNewFloat:
2623 * @ctxt: the XPath context
2624 * @val: the double value
2626 * This is the cached version of xmlXPathNewFloat().
2627 * Acquires an xmlXPathObjectPtr of type double and of value @val
2629 * Returns the created or reused object.
2631 static xmlXPathObjectPtr
2632 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt
, double val
)
2634 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2635 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2637 if ((cache
->numberObjs
!= NULL
) &&
2638 (cache
->numberObjs
->number
!= 0))
2640 xmlXPathObjectPtr ret
;
2642 ret
= (xmlXPathObjectPtr
)
2643 cache
->numberObjs
->items
[--cache
->numberObjs
->number
];
2644 ret
->type
= XPATH_NUMBER
;
2645 ret
->floatval
= val
;
2646 #ifdef XP_DEBUG_OBJ_USAGE
2647 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2650 } else if ((cache
->miscObjs
!= NULL
) &&
2651 (cache
->miscObjs
->number
!= 0))
2653 xmlXPathObjectPtr ret
;
2655 ret
= (xmlXPathObjectPtr
)
2656 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2658 ret
->type
= XPATH_NUMBER
;
2659 ret
->floatval
= val
;
2660 #ifdef XP_DEBUG_OBJ_USAGE
2661 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2666 return(xmlXPathNewFloat(val
));
2670 * xmlXPathCacheConvertString:
2671 * @ctxt: the XPath context
2672 * @val: an XPath object
2674 * This is the cached version of xmlXPathConvertString().
2675 * Converts an existing object to its string() equivalent
2677 * Returns a created or reused object, the old one is freed (cached)
2678 * (or the operation is done directly on @val)
2681 static xmlXPathObjectPtr
2682 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2683 xmlChar
*res
= NULL
;
2686 return(xmlXPathCacheNewCString(ctxt
, ""));
2688 switch (val
->type
) {
2689 case XPATH_UNDEFINED
:
2691 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
2695 case XPATH_XSLT_TREE
:
2696 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
2701 res
= xmlXPathCastBooleanToString(val
->boolval
);
2704 res
= xmlXPathCastNumberToString(val
->floatval
);
2709 case XPATH_LOCATIONSET
:
2713 xmlXPathReleaseObject(ctxt
, val
);
2715 return(xmlXPathCacheNewCString(ctxt
, ""));
2716 return(xmlXPathCacheWrapString(ctxt
, res
));
2720 * xmlXPathCacheObjectCopy:
2721 * @ctxt: the XPath context
2722 * @val: the original object
2724 * This is the cached version of xmlXPathObjectCopy().
2725 * Acquire a copy of a given object
2727 * Returns a created or reused created object.
2729 static xmlXPathObjectPtr
2730 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
)
2735 if (XP_HAS_CACHE(ctxt
)) {
2736 switch (val
->type
) {
2738 return(xmlXPathCacheWrapNodeSet(ctxt
,
2739 xmlXPathNodeSetMerge(NULL
, val
->nodesetval
)));
2741 return(xmlXPathCacheNewString(ctxt
, val
->stringval
));
2743 return(xmlXPathCacheNewBoolean(ctxt
, val
->boolval
));
2745 return(xmlXPathCacheNewFloat(ctxt
, val
->floatval
));
2750 return(xmlXPathObjectCopy(val
));
2754 * xmlXPathCacheConvertBoolean:
2755 * @ctxt: the XPath context
2756 * @val: an XPath object
2758 * This is the cached version of xmlXPathConvertBoolean().
2759 * Converts an existing object to its boolean() equivalent
2761 * Returns a created or reused object, the old one is freed (or the operation
2762 * is done directly on @val)
2764 static xmlXPathObjectPtr
2765 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2766 xmlXPathObjectPtr ret
;
2769 return(xmlXPathCacheNewBoolean(ctxt
, 0));
2770 if (val
->type
== XPATH_BOOLEAN
)
2772 ret
= xmlXPathCacheNewBoolean(ctxt
, xmlXPathCastToBoolean(val
));
2773 xmlXPathReleaseObject(ctxt
, val
);
2778 * xmlXPathCacheConvertNumber:
2779 * @ctxt: the XPath context
2780 * @val: an XPath object
2782 * This is the cached version of xmlXPathConvertNumber().
2783 * Converts an existing object to its number() equivalent
2785 * Returns a created or reused object, the old one is freed (or the operation
2786 * is done directly on @val)
2788 static xmlXPathObjectPtr
2789 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2790 xmlXPathObjectPtr ret
;
2793 return(xmlXPathCacheNewFloat(ctxt
, 0.0));
2794 if (val
->type
== XPATH_NUMBER
)
2796 ret
= xmlXPathCacheNewFloat(ctxt
, xmlXPathCastToNumber(val
));
2797 xmlXPathReleaseObject(ctxt
, val
);
2801 /************************************************************************
2803 * Parser stacks related functions and macros *
2805 ************************************************************************/
2809 * @ctxt: an XPath parser context
2811 * Set the callee evaluation frame
2813 * Returns the previous frame value to be restored once done
2816 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt
) {
2821 ret
= ctxt
->valueFrame
;
2822 ctxt
->valueFrame
= ctxt
->valueNr
;
2828 * @ctxt: an XPath parser context
2829 * @frame: the previous frame value
2831 * Remove the callee evaluation frame
2834 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt
, int frame
) {
2837 if (ctxt
->valueNr
< ctxt
->valueFrame
) {
2838 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2840 ctxt
->valueFrame
= frame
;
2845 * @ctxt: an XPath evaluation context
2847 * Pops the top XPath object from the value stack
2849 * Returns the XPath object just removed
2852 valuePop(xmlXPathParserContextPtr ctxt
)
2854 xmlXPathObjectPtr ret
;
2856 if ((ctxt
== NULL
) || (ctxt
->valueNr
<= 0))
2859 if (ctxt
->valueNr
<= ctxt
->valueFrame
) {
2860 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2865 if (ctxt
->valueNr
> 0)
2866 ctxt
->value
= ctxt
->valueTab
[ctxt
->valueNr
- 1];
2869 ret
= ctxt
->valueTab
[ctxt
->valueNr
];
2870 ctxt
->valueTab
[ctxt
->valueNr
] = NULL
;
2875 * @ctxt: an XPath evaluation context
2876 * @value: the XPath object
2878 * Pushes a new XPath object on top of the value stack. If value is NULL,
2879 * a memory error is recorded in the parser context.
2881 * Returns the number of items on the value stack, or -1 in case of error.
2884 valuePush(xmlXPathParserContextPtr ctxt
, xmlXPathObjectPtr value
)
2886 if (ctxt
== NULL
) return(-1);
2887 if (value
== NULL
) {
2889 * A NULL value typically indicates that a memory allocation failed,
2890 * so we set ctxt->error here to propagate the error.
2892 ctxt
->error
= XPATH_MEMORY_ERROR
;
2895 if (ctxt
->valueNr
>= ctxt
->valueMax
) {
2896 xmlXPathObjectPtr
*tmp
;
2898 if (ctxt
->valueMax
>= XPATH_MAX_STACK_DEPTH
) {
2899 xmlXPathPErrMemory(ctxt
, "XPath stack depth limit reached\n");
2902 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(ctxt
->valueTab
,
2903 2 * ctxt
->valueMax
*
2904 sizeof(ctxt
->valueTab
[0]));
2906 xmlXPathPErrMemory(ctxt
, "pushing value\n");
2909 ctxt
->valueMax
*= 2;
2910 ctxt
->valueTab
= tmp
;
2912 ctxt
->valueTab
[ctxt
->valueNr
] = value
;
2913 ctxt
->value
= value
;
2914 return (ctxt
->valueNr
++);
2918 * xmlXPathPopBoolean:
2919 * @ctxt: an XPath parser context
2921 * Pops a boolean from the stack, handling conversion if needed.
2922 * Check error with #xmlXPathCheckError.
2924 * Returns the boolean
2927 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt
) {
2928 xmlXPathObjectPtr obj
;
2931 obj
= valuePop(ctxt
);
2933 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2936 if (obj
->type
!= XPATH_BOOLEAN
)
2937 ret
= xmlXPathCastToBoolean(obj
);
2940 xmlXPathReleaseObject(ctxt
->context
, obj
);
2945 * xmlXPathPopNumber:
2946 * @ctxt: an XPath parser context
2948 * Pops a number from the stack, handling conversion if needed.
2949 * Check error with #xmlXPathCheckError.
2951 * Returns the number
2954 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt
) {
2955 xmlXPathObjectPtr obj
;
2958 obj
= valuePop(ctxt
);
2960 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2963 if (obj
->type
!= XPATH_NUMBER
)
2964 ret
= xmlXPathCastToNumber(obj
);
2966 ret
= obj
->floatval
;
2967 xmlXPathReleaseObject(ctxt
->context
, obj
);
2972 * xmlXPathPopString:
2973 * @ctxt: an XPath parser context
2975 * Pops a string from the stack, handling conversion if needed.
2976 * Check error with #xmlXPathCheckError.
2978 * Returns the string
2981 xmlXPathPopString (xmlXPathParserContextPtr ctxt
) {
2982 xmlXPathObjectPtr obj
;
2985 obj
= valuePop(ctxt
);
2987 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2990 ret
= xmlXPathCastToString(obj
); /* this does required strdup */
2991 /* TODO: needs refactoring somewhere else */
2992 if (obj
->stringval
== ret
)
2993 obj
->stringval
= NULL
;
2994 xmlXPathReleaseObject(ctxt
->context
, obj
);
2999 * xmlXPathPopNodeSet:
3000 * @ctxt: an XPath parser context
3002 * Pops a node-set from the stack, handling conversion if needed.
3003 * Check error with #xmlXPathCheckError.
3005 * Returns the node-set
3008 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt
) {
3009 xmlXPathObjectPtr obj
;
3012 if (ctxt
== NULL
) return(NULL
);
3013 if (ctxt
->value
== NULL
) {
3014 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
3017 if (!xmlXPathStackIsNodeSet(ctxt
)) {
3018 xmlXPathSetTypeError(ctxt
);
3021 obj
= valuePop(ctxt
);
3022 ret
= obj
->nodesetval
;
3024 /* to fix memory leak of not clearing obj->user */
3025 if (obj
->boolval
&& obj
->user
!= NULL
)
3026 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
3028 obj
->nodesetval
= NULL
;
3029 xmlXPathReleaseObject(ctxt
->context
, obj
);
3034 * xmlXPathPopExternal:
3035 * @ctxt: an XPath parser context
3037 * Pops an external object from the stack, handling conversion if needed.
3038 * Check error with #xmlXPathCheckError.
3040 * Returns the object
3043 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt
) {
3044 xmlXPathObjectPtr obj
;
3047 if ((ctxt
== NULL
) || (ctxt
->value
== NULL
)) {
3048 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
3051 if (ctxt
->value
->type
!= XPATH_USERS
) {
3052 xmlXPathSetTypeError(ctxt
);
3055 obj
= valuePop(ctxt
);
3058 xmlXPathReleaseObject(ctxt
->context
, obj
);
3063 * Macros for accessing the content. Those should be used only by the parser,
3066 * Dirty macros, i.e. one need to make assumption on the context to use them
3068 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3069 * CUR returns the current xmlChar value, i.e. a 8 bit value
3070 * in ISO-Latin or UTF-8.
3071 * This should be used internally by the parser
3072 * only to compare to ASCII values otherwise it would break when
3073 * running with UTF-8 encoding.
3074 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3075 * to compare on ASCII based substring.
3076 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3077 * strings within the parser.
3078 * CURRENT Returns the current char value, with the full decoding of
3079 * UTF-8 if we are using this mode. It returns an int.
3080 * NEXT Skip to the next character, this does the proper decoding
3081 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3082 * It returns the pointer to the current xmlChar.
3085 #define CUR (*ctxt->cur)
3086 #define SKIP(val) ctxt->cur += (val)
3087 #define NXT(val) ctxt->cur[(val)]
3088 #define CUR_PTR ctxt->cur
3089 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3091 #define COPY_BUF(l,b,i,v) \
3092 if (l == 1) b[i++] = (xmlChar) v; \
3093 else i += xmlCopyChar(l,&b[i],v)
3095 #define NEXTL(l) ctxt->cur += l
3097 #define SKIP_BLANKS \
3098 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3100 #define CURRENT (*ctxt->cur)
3101 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3108 #define DBL_EPSILON 1E-9
3111 #define UPPER_DOUBLE 1E9
3112 #define LOWER_DOUBLE 1E-5
3113 #define LOWER_DOUBLE_EXP 5
3115 #define INTEGER_DIGITS DBL_DIG
3116 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3117 #define EXPONENT_DIGITS (3 + 2)
3120 * xmlXPathFormatNumber:
3121 * @number: number to format
3122 * @buffer: output buffer
3123 * @buffersize: size of output buffer
3125 * Convert the number into a string representation.
3128 xmlXPathFormatNumber(double number
, char buffer
[], int buffersize
)
3130 switch (xmlXPathIsInf(number
)) {
3132 if (buffersize
> (int)sizeof("Infinity"))
3133 snprintf(buffer
, buffersize
, "Infinity");
3136 if (buffersize
> (int)sizeof("-Infinity"))
3137 snprintf(buffer
, buffersize
, "-Infinity");
3140 if (xmlXPathIsNaN(number
)) {
3141 if (buffersize
> (int)sizeof("NaN"))
3142 snprintf(buffer
, buffersize
, "NaN");
3143 } else if (number
== 0) {
3144 /* Omit sign for negative zero. */
3145 snprintf(buffer
, buffersize
, "0");
3146 } else if ((number
> INT_MIN
) && (number
< INT_MAX
) &&
3147 (number
== (int) number
)) {
3150 int value
= (int) number
;
3156 snprintf(work
, 29, "%d", value
);
3158 while ((*cur
) && (ptr
- buffer
< buffersize
)) {
3162 if (ptr
- buffer
< buffersize
) {
3164 } else if (buffersize
> 0) {
3170 For the dimension of work,
3171 DBL_DIG is number of significant digits
3172 EXPONENT is only needed for "scientific notation"
3173 3 is sign, decimal point, and terminating zero
3174 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3175 Note that this dimension is slightly (a few characters)
3176 larger than actually necessary.
3178 char work
[DBL_DIG
+ EXPONENT_DIGITS
+ 3 + LOWER_DOUBLE_EXP
];
3179 int integer_place
, fraction_place
;
3181 char *after_fraction
;
3182 double absolute_value
;
3185 absolute_value
= fabs(number
);
3188 * First choose format - scientific or regular floating point.
3189 * In either case, result is in work, and after_fraction points
3190 * just past the fractional part.
3192 if ( ((absolute_value
> UPPER_DOUBLE
) ||
3193 (absolute_value
< LOWER_DOUBLE
)) &&
3194 (absolute_value
!= 0.0) ) {
3195 /* Use scientific notation */
3196 integer_place
= DBL_DIG
+ EXPONENT_DIGITS
+ 1;
3197 fraction_place
= DBL_DIG
- 1;
3198 size
= snprintf(work
, sizeof(work
),"%*.*e",
3199 integer_place
, fraction_place
, number
);
3200 while ((size
> 0) && (work
[size
] != 'e')) size
--;
3204 /* Use regular notation */
3205 if (absolute_value
> 0.0) {
3206 integer_place
= (int)log10(absolute_value
);
3207 if (integer_place
> 0)
3208 fraction_place
= DBL_DIG
- integer_place
- 1;
3210 fraction_place
= DBL_DIG
- integer_place
;
3214 size
= snprintf(work
, sizeof(work
), "%0.*f",
3215 fraction_place
, number
);
3218 /* Remove leading spaces sometimes inserted by snprintf */
3219 while (work
[0] == ' ') {
3220 for (ptr
= &work
[0];(ptr
[0] = ptr
[1]);ptr
++);
3224 /* Remove fractional trailing zeroes */
3225 after_fraction
= work
+ size
;
3226 ptr
= after_fraction
;
3227 while (*(--ptr
) == '0')
3231 while ((*ptr
++ = *after_fraction
++) != 0);
3233 /* Finally copy result back to caller */
3234 size
= strlen(work
) + 1;
3235 if (size
> buffersize
) {
3236 work
[buffersize
- 1] = 0;
3239 memmove(buffer
, work
, size
);
3246 /************************************************************************
3248 * Routines to handle NodeSets *
3250 ************************************************************************/
3253 * xmlXPathOrderDocElems:
3254 * @doc: an input document
3256 * Call this routine to speed up XPath computation on static documents.
3257 * This stamps all the element nodes with the document order
3258 * Like for line information, the order is kept in the element->content
3259 * field, the value stored is actually - the node number (starting at -1)
3260 * to be able to differentiate from line numbers.
3262 * Returns the number of elements found in the document or -1 in case
3266 xmlXPathOrderDocElems(xmlDocPtr doc
) {
3267 ptrdiff_t count
= 0;
3272 cur
= doc
->children
;
3273 while (cur
!= NULL
) {
3274 if (cur
->type
== XML_ELEMENT_NODE
) {
3275 cur
->content
= (void *) (-(++count
));
3276 if (cur
->children
!= NULL
) {
3277 cur
= cur
->children
;
3281 if (cur
->next
!= NULL
) {
3289 if (cur
== (xmlNodePtr
) doc
) {
3293 if (cur
->next
!= NULL
) {
3297 } while (cur
!= NULL
);
3299 return((long) count
);
3304 * @node1: the first node
3305 * @node2: the second node
3307 * Compare two nodes w.r.t document order
3309 * Returns -2 in case of error 1 if first point < second point, 0 if
3310 * it's the same node, -1 otherwise
3313 xmlXPathCmpNodes(xmlNodePtr node1
, xmlNodePtr node2
) {
3315 int attr1
= 0, attr2
= 0;
3316 xmlNodePtr attrNode1
= NULL
, attrNode2
= NULL
;
3317 xmlNodePtr cur
, root
;
3319 if ((node1
== NULL
) || (node2
== NULL
))
3322 * a couple of optimizations which will avoid computations in most cases
3324 if (node1
== node2
) /* trivial case */
3326 if (node1
->type
== XML_ATTRIBUTE_NODE
) {
3329 node1
= node1
->parent
;
3331 if (node2
->type
== XML_ATTRIBUTE_NODE
) {
3334 node2
= node2
->parent
;
3336 if (node1
== node2
) {
3337 if (attr1
== attr2
) {
3338 /* not required, but we keep attributes in order */
3340 cur
= attrNode2
->prev
;
3341 while (cur
!= NULL
) {
3342 if (cur
== attrNode1
)
3354 if ((node1
->type
== XML_NAMESPACE_DECL
) ||
3355 (node2
->type
== XML_NAMESPACE_DECL
))
3357 if (node1
== node2
->prev
)
3359 if (node1
== node2
->next
)
3363 * Speedup using document order if available.
3365 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3366 (node2
->type
== XML_ELEMENT_NODE
) &&
3367 (0 > (ptrdiff_t) node1
->content
) &&
3368 (0 > (ptrdiff_t) node2
->content
) &&
3369 (node1
->doc
== node2
->doc
)) {
3372 l1
= -((ptrdiff_t) node1
->content
);
3373 l2
= -((ptrdiff_t) node2
->content
);
3381 * compute depth to root
3383 for (depth2
= 0, cur
= node2
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3384 if (cur
->parent
== node1
)
3389 for (depth1
= 0, cur
= node1
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3390 if (cur
->parent
== node2
)
3395 * Distinct document (or distinct entities :-( ) case.
3401 * get the nearest common ancestor.
3403 while (depth1
> depth2
) {
3405 node1
= node1
->parent
;
3407 while (depth2
> depth1
) {
3409 node2
= node2
->parent
;
3411 while (node1
->parent
!= node2
->parent
) {
3412 node1
= node1
->parent
;
3413 node2
= node2
->parent
;
3414 /* should not happen but just in case ... */
3415 if ((node1
== NULL
) || (node2
== NULL
))
3421 if (node1
== node2
->prev
)
3423 if (node1
== node2
->next
)
3426 * Speedup using document order if available.
3428 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3429 (node2
->type
== XML_ELEMENT_NODE
) &&
3430 (0 > (ptrdiff_t) node1
->content
) &&
3431 (0 > (ptrdiff_t) node2
->content
) &&
3432 (node1
->doc
== node2
->doc
)) {
3435 l1
= -((ptrdiff_t) node1
->content
);
3436 l2
= -((ptrdiff_t) node2
->content
);
3443 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
3446 return(-1); /* assume there is no sibling list corruption */
3450 * xmlXPathNodeSetSort:
3451 * @set: the node set
3453 * Sort the node set in document order
3456 xmlXPathNodeSetSort(xmlNodeSetPtr set
) {
3457 #ifndef WITH_TIM_SORT
3458 int i
, j
, incr
, len
;
3465 #ifndef WITH_TIM_SORT
3467 * Use the old Shell's sort implementation to sort the node-set
3468 * Timsort ought to be quite faster
3471 for (incr
= len
/ 2; incr
> 0; incr
/= 2) {
3472 for (i
= incr
; i
< len
; i
++) {
3475 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3476 if (xmlXPathCmpNodesExt(set
->nodeTab
[j
],
3477 set
->nodeTab
[j
+ incr
]) == -1)
3479 if (xmlXPathCmpNodes(set
->nodeTab
[j
],
3480 set
->nodeTab
[j
+ incr
]) == -1)
3483 tmp
= set
->nodeTab
[j
];
3484 set
->nodeTab
[j
] = set
->nodeTab
[j
+ incr
];
3485 set
->nodeTab
[j
+ incr
] = tmp
;
3492 #else /* WITH_TIM_SORT */
3493 libxml_domnode_tim_sort(set
->nodeTab
, set
->nodeNr
);
3494 #endif /* WITH_TIM_SORT */
3497 #define XML_NODESET_DEFAULT 10
3499 * xmlXPathNodeSetDupNs:
3500 * @node: the parent node of the namespace XPath node
3501 * @ns: the libxml namespace declaration node.
3503 * Namespace node in libxml don't match the XPath semantic. In a node set
3504 * the namespace nodes are duplicated and the next pointer is set to the
3505 * parent node in the XPath semantic.
3507 * Returns the newly created object.
3510 xmlXPathNodeSetDupNs(xmlNodePtr node
, xmlNsPtr ns
) {
3513 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3515 if ((node
== NULL
) || (node
->type
== XML_NAMESPACE_DECL
))
3516 return((xmlNodePtr
) ns
);
3519 * Allocate a new Namespace and fill the fields.
3521 cur
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
3523 xmlXPathErrMemory(NULL
, "duplicating namespace\n");
3526 memset(cur
, 0, sizeof(xmlNs
));
3527 cur
->type
= XML_NAMESPACE_DECL
;
3528 if (ns
->href
!= NULL
)
3529 cur
->href
= xmlStrdup(ns
->href
);
3530 if (ns
->prefix
!= NULL
)
3531 cur
->prefix
= xmlStrdup(ns
->prefix
);
3532 cur
->next
= (xmlNsPtr
) node
;
3533 return((xmlNodePtr
) cur
);
3537 * xmlXPathNodeSetFreeNs:
3538 * @ns: the XPath namespace node found in a nodeset.
3540 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3541 * the namespace nodes are duplicated and the next pointer is set to the
3542 * parent node in the XPath semantic. Check if such a node needs to be freed
3545 xmlXPathNodeSetFreeNs(xmlNsPtr ns
) {
3546 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3549 if ((ns
->next
!= NULL
) && (ns
->next
->type
!= XML_NAMESPACE_DECL
)) {
3550 if (ns
->href
!= NULL
)
3551 xmlFree((xmlChar
*)ns
->href
);
3552 if (ns
->prefix
!= NULL
)
3553 xmlFree((xmlChar
*)ns
->prefix
);
3559 * xmlXPathNodeSetCreate:
3560 * @val: an initial xmlNodePtr, or NULL
3562 * Create a new xmlNodeSetPtr of type double and of value @val
3564 * Returns the newly created object.
3567 xmlXPathNodeSetCreate(xmlNodePtr val
) {
3570 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3572 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3575 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3577 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3578 sizeof(xmlNodePtr
));
3579 if (ret
->nodeTab
== NULL
) {
3580 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3584 memset(ret
->nodeTab
, 0 ,
3585 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3586 ret
->nodeMax
= XML_NODESET_DEFAULT
;
3587 if (val
->type
== XML_NAMESPACE_DECL
) {
3588 xmlNsPtr ns
= (xmlNsPtr
) val
;
3590 /* TODO: Check memory error. */
3591 ret
->nodeTab
[ret
->nodeNr
++] =
3592 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3594 ret
->nodeTab
[ret
->nodeNr
++] = val
;
3600 * xmlXPathNodeSetContains:
3601 * @cur: the node-set
3604 * checks whether @cur contains @val
3606 * Returns true (1) if @cur contains @val, false (0) otherwise
3609 xmlXPathNodeSetContains (xmlNodeSetPtr cur
, xmlNodePtr val
) {
3612 if ((cur
== NULL
) || (val
== NULL
)) return(0);
3613 if (val
->type
== XML_NAMESPACE_DECL
) {
3614 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3615 if (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
3618 ns1
= (xmlNsPtr
) val
;
3619 ns2
= (xmlNsPtr
) cur
->nodeTab
[i
];
3622 if ((ns1
->next
!= NULL
) && (ns2
->next
== ns1
->next
) &&
3623 (xmlStrEqual(ns1
->prefix
, ns2
->prefix
)))
3628 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3629 if (cur
->nodeTab
[i
] == val
)
3637 * xmlXPathNodeSetAddNs:
3638 * @cur: the initial node set
3639 * @node: the hosting node
3640 * @ns: a the namespace node
3642 * add a new namespace node to an existing NodeSet
3644 * Returns 0 in case of success and -1 in case of error
3647 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur
, xmlNodePtr node
, xmlNsPtr ns
) {
3651 if ((cur
== NULL
) || (ns
== NULL
) || (node
== NULL
) ||
3652 (ns
->type
!= XML_NAMESPACE_DECL
) ||
3653 (node
->type
!= XML_ELEMENT_NODE
))
3656 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3658 * prevent duplicates
3660 for (i
= 0;i
< cur
->nodeNr
;i
++) {
3661 if ((cur
->nodeTab
[i
] != NULL
) &&
3662 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) &&
3663 (((xmlNsPtr
)cur
->nodeTab
[i
])->next
== (xmlNsPtr
) node
) &&
3664 (xmlStrEqual(ns
->prefix
, ((xmlNsPtr
)cur
->nodeTab
[i
])->prefix
)))
3669 * grow the nodeTab if needed
3671 if (cur
->nodeMax
== 0) {
3672 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3673 sizeof(xmlNodePtr
));
3674 if (cur
->nodeTab
== NULL
) {
3675 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3678 memset(cur
->nodeTab
, 0 ,
3679 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3680 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3681 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3684 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3685 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3688 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3689 sizeof(xmlNodePtr
));
3691 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3695 cur
->nodeTab
= temp
;
3697 /* TODO: Check memory error. */
3698 cur
->nodeTab
[cur
->nodeNr
++] = xmlXPathNodeSetDupNs(node
, ns
);
3703 * xmlXPathNodeSetAdd:
3704 * @cur: the initial node set
3705 * @val: a new xmlNodePtr
3707 * add a new xmlNodePtr to an existing NodeSet
3709 * Returns 0 in case of success, and -1 in case of error
3712 xmlXPathNodeSetAdd(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3715 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3717 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3719 * prevent duplicates
3721 for (i
= 0;i
< cur
->nodeNr
;i
++)
3722 if (cur
->nodeTab
[i
] == val
) return(0);
3725 * grow the nodeTab if needed
3727 if (cur
->nodeMax
== 0) {
3728 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3729 sizeof(xmlNodePtr
));
3730 if (cur
->nodeTab
== NULL
) {
3731 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3734 memset(cur
->nodeTab
, 0 ,
3735 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3736 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3737 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3740 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3741 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3744 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3745 sizeof(xmlNodePtr
));
3747 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3751 cur
->nodeTab
= temp
;
3753 if (val
->type
== XML_NAMESPACE_DECL
) {
3754 xmlNsPtr ns
= (xmlNsPtr
) val
;
3756 /* TODO: Check memory error. */
3757 cur
->nodeTab
[cur
->nodeNr
++] =
3758 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3760 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3765 * xmlXPathNodeSetAddUnique:
3766 * @cur: the initial node set
3767 * @val: a new xmlNodePtr
3769 * add a new xmlNodePtr to an existing NodeSet, optimized version
3770 * when we are sure the node is not already in the set.
3772 * Returns 0 in case of success and -1 in case of failure
3775 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3776 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3778 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3780 * grow the nodeTab if needed
3782 if (cur
->nodeMax
== 0) {
3783 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3784 sizeof(xmlNodePtr
));
3785 if (cur
->nodeTab
== NULL
) {
3786 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3789 memset(cur
->nodeTab
, 0 ,
3790 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3791 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3792 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3795 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3796 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3799 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3800 sizeof(xmlNodePtr
));
3802 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3805 cur
->nodeTab
= temp
;
3808 if (val
->type
== XML_NAMESPACE_DECL
) {
3809 xmlNsPtr ns
= (xmlNsPtr
) val
;
3811 /* TODO: Check memory error. */
3812 cur
->nodeTab
[cur
->nodeNr
++] =
3813 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3815 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3820 * xmlXPathNodeSetMerge:
3821 * @val1: the first NodeSet or NULL
3822 * @val2: the second NodeSet
3824 * Merges two nodesets, all nodes from @val2 are added to @val1
3825 * if @val1 is NULL, a new set is created and copied from @val2
3827 * Returns @val1 once extended or NULL in case of error.
3830 xmlXPathNodeSetMerge(xmlNodeSetPtr val1
, xmlNodeSetPtr val2
) {
3831 int i
, j
, initNr
, skip
;
3834 if (val2
== NULL
) return(val1
);
3836 val1
= xmlXPathNodeSetCreate(NULL
);
3841 * TODO: The optimization won't work in every case, since
3842 * those nasty namespace nodes need to be added with
3843 * xmlXPathNodeSetDupNs() to the set; thus a pure
3844 * memcpy is not possible.
3845 * If there was a flag on the nodesetval, indicating that
3846 * some temporary nodes are in, that would be helpful.
3849 * Optimization: Create an equally sized node-set
3850 * and memcpy the content.
3852 val1
= xmlXPathNodeSetCreateSize(val2
->nodeNr
);
3855 if (val2
->nodeNr
!= 0) {
3856 if (val2
->nodeNr
== 1)
3857 *(val1
->nodeTab
) = *(val2
->nodeTab
);
3859 memcpy(val1
->nodeTab
, val2
->nodeTab
,
3860 val2
->nodeNr
* sizeof(xmlNodePtr
));
3862 val1
->nodeNr
= val2
->nodeNr
;
3868 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3869 initNr
= val1
->nodeNr
;
3871 for (i
= 0;i
< val2
->nodeNr
;i
++) {
3872 n2
= val2
->nodeTab
[i
];
3874 * check against duplicates
3877 for (j
= 0; j
< initNr
; j
++) {
3878 n1
= val1
->nodeTab
[j
];
3882 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3883 (n2
->type
== XML_NAMESPACE_DECL
)) {
3884 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3885 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3886 ((xmlNsPtr
) n2
)->prefix
)))
3897 * grow the nodeTab if needed
3899 if (val1
->nodeMax
== 0) {
3900 val1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3901 sizeof(xmlNodePtr
));
3902 if (val1
->nodeTab
== NULL
) {
3903 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3906 memset(val1
->nodeTab
, 0 ,
3907 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3908 val1
->nodeMax
= XML_NODESET_DEFAULT
;
3909 } else if (val1
->nodeNr
== val1
->nodeMax
) {
3912 if (val1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3913 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
3916 temp
= (xmlNodePtr
*) xmlRealloc(val1
->nodeTab
, val1
->nodeMax
* 2 *
3917 sizeof(xmlNodePtr
));
3919 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3922 val1
->nodeTab
= temp
;
3925 if (n2
->type
== XML_NAMESPACE_DECL
) {
3926 xmlNsPtr ns
= (xmlNsPtr
) n2
;
3928 /* TODO: Check memory error. */
3929 val1
->nodeTab
[val1
->nodeNr
++] =
3930 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3932 val1
->nodeTab
[val1
->nodeNr
++] = n2
;
3940 * xmlXPathNodeSetMergeAndClear:
3941 * @set1: the first NodeSet or NULL
3942 * @set2: the second NodeSet
3944 * Merges two nodesets, all nodes from @set2 are added to @set1.
3945 * Checks for duplicate nodes. Clears set2.
3947 * Returns @set1 once extended or NULL in case of error.
3949 static xmlNodeSetPtr
3950 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
)
3953 int i
, j
, initNbSet1
;
3956 initNbSet1
= set1
->nodeNr
;
3957 for (i
= 0;i
< set2
->nodeNr
;i
++) {
3958 n2
= set2
->nodeTab
[i
];
3962 for (j
= 0; j
< initNbSet1
; j
++) {
3963 n1
= set1
->nodeTab
[j
];
3966 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3967 (n2
->type
== XML_NAMESPACE_DECL
))
3969 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3970 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3971 ((xmlNsPtr
) n2
)->prefix
)))
3974 * Free the namespace node.
3976 set2
->nodeTab
[i
] = NULL
;
3977 xmlXPathNodeSetFreeNs((xmlNsPtr
) n2
);
3983 * grow the nodeTab if needed
3985 if (set1
->nodeMax
== 0) {
3986 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
3987 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3988 if (set1
->nodeTab
== NULL
) {
3989 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3992 memset(set1
->nodeTab
, 0,
3993 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3994 set1
->nodeMax
= XML_NODESET_DEFAULT
;
3995 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
3998 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3999 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4002 temp
= (xmlNodePtr
*) xmlRealloc(
4003 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4005 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4008 set1
->nodeTab
= temp
;
4011 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4021 * xmlXPathNodeSetMergeAndClearNoDupls:
4022 * @set1: the first NodeSet or NULL
4023 * @set2: the second NodeSet
4025 * Merges two nodesets, all nodes from @set2 are added to @set1.
4026 * Doesn't check for duplicate nodes. Clears set2.
4028 * Returns @set1 once extended or NULL in case of error.
4030 static xmlNodeSetPtr
4031 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
)
4037 for (i
= 0;i
< set2
->nodeNr
;i
++) {
4038 n2
= set2
->nodeTab
[i
];
4039 if (set1
->nodeMax
== 0) {
4040 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
4041 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4042 if (set1
->nodeTab
== NULL
) {
4043 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4046 memset(set1
->nodeTab
, 0,
4047 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4048 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4049 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4052 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4053 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4056 temp
= (xmlNodePtr
*) xmlRealloc(
4057 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4059 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4062 set1
->nodeTab
= temp
;
4065 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4073 * xmlXPathNodeSetDel:
4074 * @cur: the initial node set
4075 * @val: an xmlNodePtr
4077 * Removes an xmlNodePtr from an existing NodeSet
4080 xmlXPathNodeSetDel(xmlNodeSetPtr cur
, xmlNodePtr val
) {
4083 if (cur
== NULL
) return;
4084 if (val
== NULL
) return;
4087 * find node in nodeTab
4089 for (i
= 0;i
< cur
->nodeNr
;i
++)
4090 if (cur
->nodeTab
[i
] == val
) break;
4092 if (i
>= cur
->nodeNr
) { /* not found */
4094 xmlGenericError(xmlGenericErrorContext
,
4095 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4100 if ((cur
->nodeTab
[i
] != NULL
) &&
4101 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4102 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[i
]);
4104 for (;i
< cur
->nodeNr
;i
++)
4105 cur
->nodeTab
[i
] = cur
->nodeTab
[i
+ 1];
4106 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4110 * xmlXPathNodeSetRemove:
4111 * @cur: the initial node set
4112 * @val: the index to remove
4114 * Removes an entry from an existing NodeSet list.
4117 xmlXPathNodeSetRemove(xmlNodeSetPtr cur
, int val
) {
4118 if (cur
== NULL
) return;
4119 if (val
>= cur
->nodeNr
) return;
4120 if ((cur
->nodeTab
[val
] != NULL
) &&
4121 (cur
->nodeTab
[val
]->type
== XML_NAMESPACE_DECL
))
4122 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[val
]);
4124 for (;val
< cur
->nodeNr
;val
++)
4125 cur
->nodeTab
[val
] = cur
->nodeTab
[val
+ 1];
4126 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4130 * xmlXPathFreeNodeSet:
4131 * @obj: the xmlNodeSetPtr to free
4133 * Free the NodeSet compound (not the actual nodes !).
4136 xmlXPathFreeNodeSet(xmlNodeSetPtr obj
) {
4137 if (obj
== NULL
) return;
4138 if (obj
->nodeTab
!= NULL
) {
4141 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4142 for (i
= 0;i
< obj
->nodeNr
;i
++)
4143 if ((obj
->nodeTab
[i
] != NULL
) &&
4144 (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4145 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4146 xmlFree(obj
->nodeTab
);
4152 * xmlXPathNodeSetClearFromPos:
4153 * @set: the node set to be cleared
4154 * @pos: the start position to clear from
4156 * Clears the list from temporary XPath objects (e.g. namespace nodes
4157 * are feed) starting with the entry at @pos, but does *not* free the list
4158 * itself. Sets the length of the list to @pos.
4161 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set
, int pos
, int hasNsNodes
)
4163 if ((set
== NULL
) || (pos
>= set
->nodeNr
))
4165 else if ((hasNsNodes
)) {
4169 for (i
= pos
; i
< set
->nodeNr
; i
++) {
4170 node
= set
->nodeTab
[i
];
4171 if ((node
!= NULL
) &&
4172 (node
->type
== XML_NAMESPACE_DECL
))
4173 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4180 * xmlXPathNodeSetClear:
4181 * @set: the node set to clear
4183 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4184 * are feed), but does *not* free the list itself. Sets the length of the
4188 xmlXPathNodeSetClear(xmlNodeSetPtr set
, int hasNsNodes
)
4190 xmlXPathNodeSetClearFromPos(set
, 0, hasNsNodes
);
4194 * xmlXPathNodeSetKeepLast:
4195 * @set: the node set to be cleared
4197 * Move the last node to the first position and clear temporary XPath objects
4198 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4202 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set
)
4207 if ((set
== NULL
) || (set
->nodeNr
<= 1))
4209 for (i
= 0; i
< set
->nodeNr
- 1; i
++) {
4210 node
= set
->nodeTab
[i
];
4211 if ((node
!= NULL
) &&
4212 (node
->type
== XML_NAMESPACE_DECL
))
4213 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4215 set
->nodeTab
[0] = set
->nodeTab
[set
->nodeNr
-1];
4220 * xmlXPathFreeValueTree:
4221 * @obj: the xmlNodeSetPtr to free
4223 * Free the NodeSet compound and the actual tree, this is different
4224 * from xmlXPathFreeNodeSet()
4227 xmlXPathFreeValueTree(xmlNodeSetPtr obj
) {
4230 if (obj
== NULL
) return;
4232 if (obj
->nodeTab
!= NULL
) {
4233 for (i
= 0;i
< obj
->nodeNr
;i
++) {
4234 if (obj
->nodeTab
[i
] != NULL
) {
4235 if (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
4236 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4238 xmlFreeNodeList(obj
->nodeTab
[i
]);
4242 xmlFree(obj
->nodeTab
);
4247 #if defined(DEBUG) || defined(DEBUG_STEP)
4249 * xmlGenericErrorContextNodeSet:
4250 * @output: a FILE * for the output
4251 * @obj: the xmlNodeSetPtr to display
4253 * Quick display of a NodeSet
4256 xmlGenericErrorContextNodeSet(FILE *output
, xmlNodeSetPtr obj
) {
4259 if (output
== NULL
) output
= xmlGenericErrorContext
;
4261 fprintf(output
, "NodeSet == NULL !\n");
4264 if (obj
->nodeNr
== 0) {
4265 fprintf(output
, "NodeSet is empty\n");
4268 if (obj
->nodeTab
== NULL
) {
4269 fprintf(output
, " nodeTab == NULL !\n");
4272 for (i
= 0; i
< obj
->nodeNr
; i
++) {
4273 if (obj
->nodeTab
[i
] == NULL
) {
4274 fprintf(output
, " NULL !\n");
4277 if ((obj
->nodeTab
[i
]->type
== XML_DOCUMENT_NODE
) ||
4278 (obj
->nodeTab
[i
]->type
== XML_HTML_DOCUMENT_NODE
))
4279 fprintf(output
, " /");
4280 else if (obj
->nodeTab
[i
]->name
== NULL
)
4281 fprintf(output
, " noname!");
4282 else fprintf(output
, " %s", obj
->nodeTab
[i
]->name
);
4284 fprintf(output
, "\n");
4289 * xmlXPathNewNodeSet:
4290 * @val: the NodePtr value
4292 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4293 * it with the single Node @val
4295 * Returns the newly created object.
4298 xmlXPathNewNodeSet(xmlNodePtr val
) {
4299 xmlXPathObjectPtr ret
;
4301 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4303 xmlXPathErrMemory(NULL
, "creating nodeset\n");
4306 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4307 ret
->type
= XPATH_NODESET
;
4309 /* TODO: Check memory error. */
4310 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4311 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4312 #ifdef XP_DEBUG_OBJ_USAGE
4313 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4319 * xmlXPathNewValueTree:
4320 * @val: the NodePtr value
4322 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4323 * it with the tree root @val
4325 * Returns the newly created object.
4328 xmlXPathNewValueTree(xmlNodePtr val
) {
4329 xmlXPathObjectPtr ret
;
4331 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4333 xmlXPathErrMemory(NULL
, "creating result value tree\n");
4336 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4337 ret
->type
= XPATH_XSLT_TREE
;
4339 ret
->user
= (void *) val
;
4340 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4341 #ifdef XP_DEBUG_OBJ_USAGE
4342 xmlXPathDebugObjUsageRequested(NULL
, XPATH_XSLT_TREE
);
4348 * xmlXPathNewNodeSetList:
4349 * @val: an existing NodeSet
4351 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4352 * it with the Nodeset @val
4354 * Returns the newly created object.
4357 xmlXPathNewNodeSetList(xmlNodeSetPtr val
)
4359 xmlXPathObjectPtr ret
;
4364 else if (val
->nodeTab
== NULL
)
4365 ret
= xmlXPathNewNodeSet(NULL
);
4367 ret
= xmlXPathNewNodeSet(val
->nodeTab
[0]);
4369 for (i
= 1; i
< val
->nodeNr
; ++i
) {
4370 /* TODO: Propagate memory error. */
4371 if (xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
->nodeTab
[i
])
4381 * xmlXPathWrapNodeSet:
4382 * @val: the NodePtr value
4384 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4386 * Returns the newly created object.
4389 xmlXPathWrapNodeSet(xmlNodeSetPtr val
) {
4390 xmlXPathObjectPtr ret
;
4392 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4394 xmlXPathErrMemory(NULL
, "creating node set object\n");
4397 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4398 ret
->type
= XPATH_NODESET
;
4399 ret
->nodesetval
= val
;
4400 #ifdef XP_DEBUG_OBJ_USAGE
4401 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4407 * xmlXPathFreeNodeSetList:
4408 * @obj: an existing NodeSetList object
4410 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4411 * the list contrary to xmlXPathFreeObject().
4414 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj
) {
4415 if (obj
== NULL
) return;
4416 #ifdef XP_DEBUG_OBJ_USAGE
4417 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
4423 * xmlXPathDifference:
4424 * @nodes1: a node-set
4425 * @nodes2: a node-set
4427 * Implements the EXSLT - Sets difference() function:
4428 * node-set set:difference (node-set, node-set)
4430 * Returns the difference between the two node sets, or nodes1 if
4434 xmlXPathDifference (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4439 if (xmlXPathNodeSetIsEmpty(nodes2
))
4442 /* TODO: Check memory error. */
4443 ret
= xmlXPathNodeSetCreate(NULL
);
4444 if (xmlXPathNodeSetIsEmpty(nodes1
))
4447 l1
= xmlXPathNodeSetGetLength(nodes1
);
4449 for (i
= 0; i
< l1
; i
++) {
4450 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4451 if (!xmlXPathNodeSetContains(nodes2
, cur
)) {
4452 /* TODO: Propagate memory error. */
4453 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4461 * xmlXPathIntersection:
4462 * @nodes1: a node-set
4463 * @nodes2: a node-set
4465 * Implements the EXSLT - Sets intersection() function:
4466 * node-set set:intersection (node-set, node-set)
4468 * Returns a node set comprising the nodes that are within both the
4469 * node sets passed as arguments
4472 xmlXPathIntersection (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4473 xmlNodeSetPtr ret
= xmlXPathNodeSetCreate(NULL
);
4479 if (xmlXPathNodeSetIsEmpty(nodes1
))
4481 if (xmlXPathNodeSetIsEmpty(nodes2
))
4484 l1
= xmlXPathNodeSetGetLength(nodes1
);
4486 for (i
= 0; i
< l1
; i
++) {
4487 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4488 if (xmlXPathNodeSetContains(nodes2
, cur
)) {
4489 /* TODO: Propagate memory error. */
4490 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4498 * xmlXPathDistinctSorted:
4499 * @nodes: a node-set, sorted by document order
4501 * Implements the EXSLT - Sets distinct() function:
4502 * node-set set:distinct (node-set)
4504 * Returns a subset of the nodes contained in @nodes, or @nodes if
4508 xmlXPathDistinctSorted (xmlNodeSetPtr nodes
) {
4510 xmlHashTablePtr hash
;
4515 if (xmlXPathNodeSetIsEmpty(nodes
))
4518 ret
= xmlXPathNodeSetCreate(NULL
);
4521 l
= xmlXPathNodeSetGetLength(nodes
);
4522 hash
= xmlHashCreate (l
);
4523 for (i
= 0; i
< l
; i
++) {
4524 cur
= xmlXPathNodeSetItem(nodes
, i
);
4525 strval
= xmlXPathCastNodeToString(cur
);
4526 if (xmlHashLookup(hash
, strval
) == NULL
) {
4527 xmlHashAddEntry(hash
, strval
, strval
);
4528 /* TODO: Propagate memory error. */
4529 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4535 xmlHashFree(hash
, xmlHashDefaultDeallocator
);
4541 * @nodes: a node-set
4543 * Implements the EXSLT - Sets distinct() function:
4544 * node-set set:distinct (node-set)
4545 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4546 * is called with the sorted node-set
4548 * Returns a subset of the nodes contained in @nodes, or @nodes if
4552 xmlXPathDistinct (xmlNodeSetPtr nodes
) {
4553 if (xmlXPathNodeSetIsEmpty(nodes
))
4556 xmlXPathNodeSetSort(nodes
);
4557 return(xmlXPathDistinctSorted(nodes
));
4561 * xmlXPathHasSameNodes:
4562 * @nodes1: a node-set
4563 * @nodes2: a node-set
4565 * Implements the EXSLT - Sets has-same-nodes function:
4566 * boolean set:has-same-node(node-set, node-set)
4568 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4572 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4576 if (xmlXPathNodeSetIsEmpty(nodes1
) ||
4577 xmlXPathNodeSetIsEmpty(nodes2
))
4580 l
= xmlXPathNodeSetGetLength(nodes1
);
4581 for (i
= 0; i
< l
; i
++) {
4582 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4583 if (xmlXPathNodeSetContains(nodes2
, cur
))
4590 * xmlXPathNodeLeadingSorted:
4591 * @nodes: a node-set, sorted by document order
4594 * Implements the EXSLT - Sets leading() function:
4595 * node-set set:leading (node-set, node-set)
4597 * Returns the nodes in @nodes that precede @node in document order,
4598 * @nodes if @node is NULL or an empty node-set if @nodes
4599 * doesn't contain @node
4602 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4610 ret
= xmlXPathNodeSetCreate(NULL
);
4613 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4614 (!xmlXPathNodeSetContains(nodes
, node
)))
4617 l
= xmlXPathNodeSetGetLength(nodes
);
4618 for (i
= 0; i
< l
; i
++) {
4619 cur
= xmlXPathNodeSetItem(nodes
, i
);
4622 /* TODO: Propagate memory error. */
4623 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4630 * xmlXPathNodeLeading:
4631 * @nodes: a node-set
4634 * Implements the EXSLT - Sets leading() function:
4635 * node-set set:leading (node-set, node-set)
4636 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4639 * Returns the nodes in @nodes that precede @node in document order,
4640 * @nodes if @node is NULL or an empty node-set if @nodes
4641 * doesn't contain @node
4644 xmlXPathNodeLeading (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4645 xmlXPathNodeSetSort(nodes
);
4646 return(xmlXPathNodeLeadingSorted(nodes
, node
));
4650 * xmlXPathLeadingSorted:
4651 * @nodes1: a node-set, sorted by document order
4652 * @nodes2: a node-set, sorted by document order
4654 * Implements the EXSLT - Sets leading() function:
4655 * node-set set:leading (node-set, node-set)
4657 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4658 * in document order, @nodes1 if @nodes2 is NULL or empty or
4659 * an empty node-set if @nodes1 doesn't contain @nodes2
4662 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4663 if (xmlXPathNodeSetIsEmpty(nodes2
))
4665 return(xmlXPathNodeLeadingSorted(nodes1
,
4666 xmlXPathNodeSetItem(nodes2
, 1)));
4671 * @nodes1: a node-set
4672 * @nodes2: a node-set
4674 * Implements the EXSLT - Sets leading() function:
4675 * node-set set:leading (node-set, node-set)
4676 * @nodes1 and @nodes2 are sorted by document order, then
4677 * #exslSetsLeadingSorted is called.
4679 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4680 * in document order, @nodes1 if @nodes2 is NULL or empty or
4681 * an empty node-set if @nodes1 doesn't contain @nodes2
4684 xmlXPathLeading (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4685 if (xmlXPathNodeSetIsEmpty(nodes2
))
4687 if (xmlXPathNodeSetIsEmpty(nodes1
))
4688 return(xmlXPathNodeSetCreate(NULL
));
4689 xmlXPathNodeSetSort(nodes1
);
4690 xmlXPathNodeSetSort(nodes2
);
4691 return(xmlXPathNodeLeadingSorted(nodes1
,
4692 xmlXPathNodeSetItem(nodes2
, 1)));
4696 * xmlXPathNodeTrailingSorted:
4697 * @nodes: a node-set, sorted by document order
4700 * Implements the EXSLT - Sets trailing() function:
4701 * node-set set:trailing (node-set, node-set)
4703 * Returns the nodes in @nodes that follow @node in document order,
4704 * @nodes if @node is NULL or an empty node-set if @nodes
4705 * doesn't contain @node
4708 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4716 ret
= xmlXPathNodeSetCreate(NULL
);
4719 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4720 (!xmlXPathNodeSetContains(nodes
, node
)))
4723 l
= xmlXPathNodeSetGetLength(nodes
);
4724 for (i
= l
- 1; i
>= 0; i
--) {
4725 cur
= xmlXPathNodeSetItem(nodes
, i
);
4728 /* TODO: Propagate memory error. */
4729 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4732 xmlXPathNodeSetSort(ret
); /* bug 413451 */
4737 * xmlXPathNodeTrailing:
4738 * @nodes: a node-set
4741 * Implements the EXSLT - Sets trailing() function:
4742 * node-set set:trailing (node-set, node-set)
4743 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4746 * Returns the nodes in @nodes that follow @node in document order,
4747 * @nodes if @node is NULL or an empty node-set if @nodes
4748 * doesn't contain @node
4751 xmlXPathNodeTrailing (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4752 xmlXPathNodeSetSort(nodes
);
4753 return(xmlXPathNodeTrailingSorted(nodes
, node
));
4757 * xmlXPathTrailingSorted:
4758 * @nodes1: a node-set, sorted by document order
4759 * @nodes2: a node-set, sorted by document order
4761 * Implements the EXSLT - Sets trailing() function:
4762 * node-set set:trailing (node-set, node-set)
4764 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4765 * in document order, @nodes1 if @nodes2 is NULL or empty or
4766 * an empty node-set if @nodes1 doesn't contain @nodes2
4769 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4770 if (xmlXPathNodeSetIsEmpty(nodes2
))
4772 return(xmlXPathNodeTrailingSorted(nodes1
,
4773 xmlXPathNodeSetItem(nodes2
, 0)));
4778 * @nodes1: a node-set
4779 * @nodes2: a node-set
4781 * Implements the EXSLT - Sets trailing() function:
4782 * node-set set:trailing (node-set, node-set)
4783 * @nodes1 and @nodes2 are sorted by document order, then
4784 * #xmlXPathTrailingSorted is called.
4786 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4787 * in document order, @nodes1 if @nodes2 is NULL or empty or
4788 * an empty node-set if @nodes1 doesn't contain @nodes2
4791 xmlXPathTrailing (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4792 if (xmlXPathNodeSetIsEmpty(nodes2
))
4794 if (xmlXPathNodeSetIsEmpty(nodes1
))
4795 return(xmlXPathNodeSetCreate(NULL
));
4796 xmlXPathNodeSetSort(nodes1
);
4797 xmlXPathNodeSetSort(nodes2
);
4798 return(xmlXPathNodeTrailingSorted(nodes1
,
4799 xmlXPathNodeSetItem(nodes2
, 0)));
4802 /************************************************************************
4804 * Routines to handle extra functions *
4806 ************************************************************************/
4809 * xmlXPathRegisterFunc:
4810 * @ctxt: the XPath context
4811 * @name: the function name
4812 * @f: the function implementation or NULL
4814 * Register a new function. If @f is NULL it unregisters the function
4816 * Returns 0 in case of success, -1 in case of error
4819 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4820 xmlXPathFunction f
) {
4821 return(xmlXPathRegisterFuncNS(ctxt
, name
, NULL
, f
));
4825 * xmlXPathRegisterFuncNS:
4826 * @ctxt: the XPath context
4827 * @name: the function name
4828 * @ns_uri: the function namespace URI
4829 * @f: the function implementation or NULL
4831 * Register a new function. If @f is NULL it unregisters the function
4833 * Returns 0 in case of success, -1 in case of error
4836 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4837 const xmlChar
*ns_uri
, xmlXPathFunction f
) {
4843 if (ctxt
->funcHash
== NULL
)
4844 ctxt
->funcHash
= xmlHashCreate(0);
4845 if (ctxt
->funcHash
== NULL
)
4848 return(xmlHashRemoveEntry2(ctxt
->funcHash
, name
, ns_uri
, NULL
));
4849 XML_IGNORE_PEDANTIC_WARNINGS
4850 return(xmlHashAddEntry2(ctxt
->funcHash
, name
, ns_uri
, (void *) f
));
4855 * xmlXPathRegisterFuncLookup:
4856 * @ctxt: the XPath context
4857 * @f: the lookup function
4858 * @funcCtxt: the lookup data
4860 * Registers an external mechanism to do function lookup.
4863 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt
,
4864 xmlXPathFuncLookupFunc f
,
4868 ctxt
->funcLookupFunc
= f
;
4869 ctxt
->funcLookupData
= funcCtxt
;
4873 * xmlXPathFunctionLookup:
4874 * @ctxt: the XPath context
4875 * @name: the function name
4877 * Search in the Function array of the context for the given
4880 * Returns the xmlXPathFunction or NULL if not found
4883 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
4887 if (ctxt
->funcLookupFunc
!= NULL
) {
4888 xmlXPathFunction ret
;
4889 xmlXPathFuncLookupFunc f
;
4891 f
= ctxt
->funcLookupFunc
;
4892 ret
= f(ctxt
->funcLookupData
, name
, NULL
);
4896 return(xmlXPathFunctionLookupNS(ctxt
, name
, NULL
));
4900 * xmlXPathFunctionLookupNS:
4901 * @ctxt: the XPath context
4902 * @name: the function name
4903 * @ns_uri: the function namespace URI
4905 * Search in the Function array of the context for the given
4908 * Returns the xmlXPathFunction or NULL if not found
4911 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4912 const xmlChar
*ns_uri
) {
4913 xmlXPathFunction ret
;
4920 if (ctxt
->funcLookupFunc
!= NULL
) {
4921 xmlXPathFuncLookupFunc f
;
4923 f
= ctxt
->funcLookupFunc
;
4924 ret
= f(ctxt
->funcLookupData
, name
, ns_uri
);
4929 if (ctxt
->funcHash
== NULL
)
4932 XML_IGNORE_PEDANTIC_WARNINGS
4933 ret
= (xmlXPathFunction
) xmlHashLookup2(ctxt
->funcHash
, name
, ns_uri
);
4939 * xmlXPathRegisteredFuncsCleanup:
4940 * @ctxt: the XPath context
4942 * Cleanup the XPath context data associated to registered functions
4945 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt
) {
4949 xmlHashFree(ctxt
->funcHash
, NULL
);
4950 ctxt
->funcHash
= NULL
;
4953 /************************************************************************
4955 * Routines to handle Variables *
4957 ************************************************************************/
4960 * xmlXPathRegisterVariable:
4961 * @ctxt: the XPath context
4962 * @name: the variable name
4963 * @value: the variable value or NULL
4965 * Register a new variable value. If @value is NULL it unregisters
4968 * Returns 0 in case of success, -1 in case of error
4971 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4972 xmlXPathObjectPtr value
) {
4973 return(xmlXPathRegisterVariableNS(ctxt
, name
, NULL
, value
));
4977 * xmlXPathRegisterVariableNS:
4978 * @ctxt: the XPath context
4979 * @name: the variable name
4980 * @ns_uri: the variable namespace URI
4981 * @value: the variable value or NULL
4983 * Register a new variable value. If @value is NULL it unregisters
4986 * Returns 0 in case of success, -1 in case of error
4989 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4990 const xmlChar
*ns_uri
,
4991 xmlXPathObjectPtr value
) {
4997 if (ctxt
->varHash
== NULL
)
4998 ctxt
->varHash
= xmlHashCreate(0);
4999 if (ctxt
->varHash
== NULL
)
5002 return(xmlHashRemoveEntry2(ctxt
->varHash
, name
, ns_uri
,
5003 xmlXPathFreeObjectEntry
));
5004 return(xmlHashUpdateEntry2(ctxt
->varHash
, name
, ns_uri
,
5005 (void *) value
, xmlXPathFreeObjectEntry
));
5009 * xmlXPathRegisterVariableLookup:
5010 * @ctxt: the XPath context
5011 * @f: the lookup function
5012 * @data: the lookup data
5014 * register an external mechanism to do variable lookup
5017 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt
,
5018 xmlXPathVariableLookupFunc f
, void *data
) {
5021 ctxt
->varLookupFunc
= f
;
5022 ctxt
->varLookupData
= data
;
5026 * xmlXPathVariableLookup:
5027 * @ctxt: the XPath context
5028 * @name: the variable name
5030 * Search in the Variable array of the context for the given
5033 * Returns a copy of the value or NULL if not found
5036 xmlXPathVariableLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
5040 if (ctxt
->varLookupFunc
!= NULL
) {
5041 xmlXPathObjectPtr ret
;
5043 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5044 (ctxt
->varLookupData
, name
, NULL
);
5047 return(xmlXPathVariableLookupNS(ctxt
, name
, NULL
));
5051 * xmlXPathVariableLookupNS:
5052 * @ctxt: the XPath context
5053 * @name: the variable name
5054 * @ns_uri: the variable namespace URI
5056 * Search in the Variable array of the context for the given
5059 * Returns the a copy of the value or NULL if not found
5062 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5063 const xmlChar
*ns_uri
) {
5067 if (ctxt
->varLookupFunc
!= NULL
) {
5068 xmlXPathObjectPtr ret
;
5070 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5071 (ctxt
->varLookupData
, name
, ns_uri
);
5072 if (ret
!= NULL
) return(ret
);
5075 if (ctxt
->varHash
== NULL
)
5080 return(xmlXPathCacheObjectCopy(ctxt
, (xmlXPathObjectPtr
)
5081 xmlHashLookup2(ctxt
->varHash
, name
, ns_uri
)));
5085 * xmlXPathRegisteredVariablesCleanup:
5086 * @ctxt: the XPath context
5088 * Cleanup the XPath context data associated to registered variables
5091 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt
) {
5095 xmlHashFree(ctxt
->varHash
, xmlXPathFreeObjectEntry
);
5096 ctxt
->varHash
= NULL
;
5100 * xmlXPathRegisterNs:
5101 * @ctxt: the XPath context
5102 * @prefix: the namespace prefix cannot be NULL or empty string
5103 * @ns_uri: the namespace name
5105 * Register a new namespace. If @ns_uri is NULL it unregisters
5108 * Returns 0 in case of success, -1 in case of error
5111 xmlXPathRegisterNs(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
,
5112 const xmlChar
*ns_uri
) {
5120 if (ctxt
->nsHash
== NULL
)
5121 ctxt
->nsHash
= xmlHashCreate(10);
5122 if (ctxt
->nsHash
== NULL
)
5125 return(xmlHashRemoveEntry(ctxt
->nsHash
, prefix
,
5126 xmlHashDefaultDeallocator
));
5127 return(xmlHashUpdateEntry(ctxt
->nsHash
, prefix
, (void *) xmlStrdup(ns_uri
),
5128 xmlHashDefaultDeallocator
));
5133 * @ctxt: the XPath context
5134 * @prefix: the namespace prefix value
5136 * Search in the namespace declaration array of the context for the given
5137 * namespace name associated to the given prefix
5139 * Returns the value or NULL if not found
5142 xmlXPathNsLookup(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
) {
5148 #ifdef XML_XML_NAMESPACE
5149 if (xmlStrEqual(prefix
, (const xmlChar
*) "xml"))
5150 return(XML_XML_NAMESPACE
);
5153 if (ctxt
->namespaces
!= NULL
) {
5156 for (i
= 0;i
< ctxt
->nsNr
;i
++) {
5157 if ((ctxt
->namespaces
[i
] != NULL
) &&
5158 (xmlStrEqual(ctxt
->namespaces
[i
]->prefix
, prefix
)))
5159 return(ctxt
->namespaces
[i
]->href
);
5163 return((const xmlChar
*) xmlHashLookup(ctxt
->nsHash
, prefix
));
5167 * xmlXPathRegisteredNsCleanup:
5168 * @ctxt: the XPath context
5170 * Cleanup the XPath context data associated to registered variables
5173 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt
) {
5177 xmlHashFree(ctxt
->nsHash
, xmlHashDefaultDeallocator
);
5178 ctxt
->nsHash
= NULL
;
5181 /************************************************************************
5183 * Routines to handle Values *
5185 ************************************************************************/
5187 /* Allocations are terrible, one needs to optimize all this !!! */
5191 * @val: the double value
5193 * Create a new xmlXPathObjectPtr of type double and of value @val
5195 * Returns the newly created object.
5198 xmlXPathNewFloat(double val
) {
5199 xmlXPathObjectPtr ret
;
5201 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5203 xmlXPathErrMemory(NULL
, "creating float object\n");
5206 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5207 ret
->type
= XPATH_NUMBER
;
5208 ret
->floatval
= val
;
5209 #ifdef XP_DEBUG_OBJ_USAGE
5210 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NUMBER
);
5216 * xmlXPathNewBoolean:
5217 * @val: the boolean value
5219 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5221 * Returns the newly created object.
5224 xmlXPathNewBoolean(int val
) {
5225 xmlXPathObjectPtr ret
;
5227 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5229 xmlXPathErrMemory(NULL
, "creating boolean object\n");
5232 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5233 ret
->type
= XPATH_BOOLEAN
;
5234 ret
->boolval
= (val
!= 0);
5235 #ifdef XP_DEBUG_OBJ_USAGE
5236 xmlXPathDebugObjUsageRequested(NULL
, XPATH_BOOLEAN
);
5242 * xmlXPathNewString:
5243 * @val: the xmlChar * value
5245 * Create a new xmlXPathObjectPtr of type string and of value @val
5247 * Returns the newly created object.
5250 xmlXPathNewString(const xmlChar
*val
) {
5251 xmlXPathObjectPtr ret
;
5253 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5255 xmlXPathErrMemory(NULL
, "creating string object\n");
5258 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5259 ret
->type
= XPATH_STRING
;
5261 ret
->stringval
= xmlStrdup(val
);
5263 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
5264 #ifdef XP_DEBUG_OBJ_USAGE
5265 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5271 * xmlXPathWrapString:
5272 * @val: the xmlChar * value
5274 * Wraps the @val string into an XPath object.
5276 * Returns the newly created object.
5279 xmlXPathWrapString (xmlChar
*val
) {
5280 xmlXPathObjectPtr ret
;
5282 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5284 xmlXPathErrMemory(NULL
, "creating string object\n");
5287 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5288 ret
->type
= XPATH_STRING
;
5289 ret
->stringval
= val
;
5290 #ifdef XP_DEBUG_OBJ_USAGE
5291 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5297 * xmlXPathNewCString:
5298 * @val: the char * value
5300 * Create a new xmlXPathObjectPtr of type string and of value @val
5302 * Returns the newly created object.
5305 xmlXPathNewCString(const char *val
) {
5306 xmlXPathObjectPtr ret
;
5308 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5310 xmlXPathErrMemory(NULL
, "creating string object\n");
5313 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5314 ret
->type
= XPATH_STRING
;
5315 ret
->stringval
= xmlStrdup(BAD_CAST val
);
5316 #ifdef XP_DEBUG_OBJ_USAGE
5317 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5323 * xmlXPathWrapCString:
5324 * @val: the char * value
5326 * Wraps a string into an XPath object.
5328 * Returns the newly created object.
5331 xmlXPathWrapCString (char * val
) {
5332 return(xmlXPathWrapString((xmlChar
*)(val
)));
5336 * xmlXPathWrapExternal:
5337 * @val: the user data
5339 * Wraps the @val data into an XPath object.
5341 * Returns the newly created object.
5344 xmlXPathWrapExternal (void *val
) {
5345 xmlXPathObjectPtr ret
;
5347 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5349 xmlXPathErrMemory(NULL
, "creating user object\n");
5352 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5353 ret
->type
= XPATH_USERS
;
5355 #ifdef XP_DEBUG_OBJ_USAGE
5356 xmlXPathDebugObjUsageRequested(NULL
, XPATH_USERS
);
5362 * xmlXPathObjectCopy:
5363 * @val: the original object
5365 * allocate a new copy of a given object
5367 * Returns the newly created object.
5370 xmlXPathObjectCopy(xmlXPathObjectPtr val
) {
5371 xmlXPathObjectPtr ret
;
5376 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5378 xmlXPathErrMemory(NULL
, "copying object\n");
5381 memcpy(ret
, val
, (size_t) sizeof(xmlXPathObject
));
5382 #ifdef XP_DEBUG_OBJ_USAGE
5383 xmlXPathDebugObjUsageRequested(NULL
, val
->type
);
5385 switch (val
->type
) {
5392 ret
->stringval
= xmlStrdup(val
->stringval
);
5394 case XPATH_XSLT_TREE
:
5397 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5398 this previous handling is no longer correct, and can cause some serious
5399 problems (ref. bug 145547)
5401 if ((val
->nodesetval
!= NULL
) &&
5402 (val
->nodesetval
->nodeTab
!= NULL
)) {
5403 xmlNodePtr cur
, tmp
;
5407 top
= xmlNewDoc(NULL
);
5408 top
->name
= (char *)
5409 xmlStrdup(val
->nodesetval
->nodeTab
[0]->name
);
5413 cur
= val
->nodesetval
->nodeTab
[0]->children
;
5414 while (cur
!= NULL
) {
5415 tmp
= xmlDocCopyNode(cur
, top
, 1);
5416 xmlAddChild((xmlNodePtr
) top
, tmp
);
5421 ret
->nodesetval
= xmlXPathNodeSetCreate((xmlNodePtr
) top
);
5423 ret
->nodesetval
= xmlXPathNodeSetCreate(NULL
);
5424 /* Deallocate the copied tree value */
5428 /* TODO: Check memory error. */
5429 ret
->nodesetval
= xmlXPathNodeSetMerge(NULL
, val
->nodesetval
);
5430 /* Do not deallocate the copied tree value */
5433 case XPATH_LOCATIONSET
:
5434 #ifdef LIBXML_XPTR_ENABLED
5436 xmlLocationSetPtr loc
= val
->user
;
5437 ret
->user
= (void *) xmlXPtrLocationSetMerge(NULL
, loc
);
5442 ret
->user
= val
->user
;
5444 case XPATH_UNDEFINED
:
5445 xmlGenericError(xmlGenericErrorContext
,
5446 "xmlXPathObjectCopy: unsupported type %d\n",
5454 * xmlXPathFreeObject:
5455 * @obj: the object to free
5457 * Free up an xmlXPathObjectPtr object.
5460 xmlXPathFreeObject(xmlXPathObjectPtr obj
) {
5461 if (obj
== NULL
) return;
5462 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
5465 if (obj
->user
!= NULL
) {
5466 xmlXPathFreeNodeSet(obj
->nodesetval
);
5467 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
5470 obj
->type
= XPATH_XSLT_TREE
; /* TODO: Just for debugging. */
5471 if (obj
->nodesetval
!= NULL
)
5472 xmlXPathFreeValueTree(obj
->nodesetval
);
5474 if (obj
->nodesetval
!= NULL
)
5475 xmlXPathFreeNodeSet(obj
->nodesetval
);
5477 #ifdef LIBXML_XPTR_ENABLED
5478 } else if (obj
->type
== XPATH_LOCATIONSET
) {
5479 if (obj
->user
!= NULL
)
5480 xmlXPtrFreeLocationSet(obj
->user
);
5482 } else if (obj
->type
== XPATH_STRING
) {
5483 if (obj
->stringval
!= NULL
)
5484 xmlFree(obj
->stringval
);
5486 #ifdef XP_DEBUG_OBJ_USAGE
5487 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5493 xmlXPathFreeObjectEntry(void *obj
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
5494 xmlXPathFreeObject((xmlXPathObjectPtr
) obj
);
5498 * xmlXPathReleaseObject:
5499 * @obj: the xmlXPathObjectPtr to free or to cache
5501 * Depending on the state of the cache this frees the given
5502 * XPath object or stores it in the cache.
5505 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
)
5507 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5508 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5509 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5511 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5515 if ((ctxt
== NULL
) || (ctxt
->cache
== NULL
)) {
5516 xmlXPathFreeObject(obj
);
5518 xmlXPathContextCachePtr cache
=
5519 (xmlXPathContextCachePtr
) ctxt
->cache
;
5521 switch (obj
->type
) {
5523 case XPATH_XSLT_TREE
:
5524 if (obj
->nodesetval
!= NULL
) {
5527 * It looks like the @boolval is used for
5528 * evaluation if this an XSLT Result Tree Fragment.
5529 * TODO: Check if this assumption is correct.
5531 obj
->type
= XPATH_XSLT_TREE
; /* just for debugging */
5532 xmlXPathFreeValueTree(obj
->nodesetval
);
5533 obj
->nodesetval
= NULL
;
5534 } else if ((obj
->nodesetval
->nodeMax
<= 40) &&
5535 (XP_CACHE_WANTS(cache
->nodesetObjs
,
5536 cache
->maxNodeset
)))
5538 XP_CACHE_ADD(cache
->nodesetObjs
, obj
);
5541 xmlXPathFreeNodeSet(obj
->nodesetval
);
5542 obj
->nodesetval
= NULL
;
5547 if (obj
->stringval
!= NULL
)
5548 xmlFree(obj
->stringval
);
5550 if (XP_CACHE_WANTS(cache
->stringObjs
, cache
->maxString
)) {
5551 XP_CACHE_ADD(cache
->stringObjs
, obj
);
5556 if (XP_CACHE_WANTS(cache
->booleanObjs
, cache
->maxBoolean
)) {
5557 XP_CACHE_ADD(cache
->booleanObjs
, obj
);
5562 if (XP_CACHE_WANTS(cache
->numberObjs
, cache
->maxNumber
)) {
5563 XP_CACHE_ADD(cache
->numberObjs
, obj
);
5567 #ifdef LIBXML_XPTR_ENABLED
5568 case XPATH_LOCATIONSET
:
5569 if (obj
->user
!= NULL
) {
5570 xmlXPtrFreeLocationSet(obj
->user
);
5579 * Fallback to adding to the misc-objects slot.
5581 if (XP_CACHE_WANTS(cache
->miscObjs
, cache
->maxMisc
)) {
5582 XP_CACHE_ADD(cache
->miscObjs
, obj
);
5588 #ifdef XP_DEBUG_OBJ_USAGE
5589 xmlXPathDebugObjUsageReleased(ctxt
, obj
->type
);
5592 if (obj
->nodesetval
!= NULL
) {
5593 xmlNodeSetPtr tmpset
= obj
->nodesetval
;
5596 * TODO: Due to those nasty ns-nodes, we need to traverse
5597 * the list and free the ns-nodes.
5598 * URGENT TODO: Check if it's actually slowing things down.
5599 * Maybe we shouldn't try to preserve the list.
5601 if (tmpset
->nodeNr
> 1) {
5605 for (i
= 0; i
< tmpset
->nodeNr
; i
++) {
5606 node
= tmpset
->nodeTab
[i
];
5607 if ((node
!= NULL
) &&
5608 (node
->type
== XML_NAMESPACE_DECL
))
5610 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
5613 } else if (tmpset
->nodeNr
== 1) {
5614 if ((tmpset
->nodeTab
[0] != NULL
) &&
5615 (tmpset
->nodeTab
[0]->type
== XML_NAMESPACE_DECL
))
5616 xmlXPathNodeSetFreeNs((xmlNsPtr
) tmpset
->nodeTab
[0]);
5619 memset(obj
, 0, sizeof(xmlXPathObject
));
5620 obj
->nodesetval
= tmpset
;
5622 memset(obj
, 0, sizeof(xmlXPathObject
));
5628 * Cache is full; free the object.
5630 if (obj
->nodesetval
!= NULL
)
5631 xmlXPathFreeNodeSet(obj
->nodesetval
);
5632 #ifdef XP_DEBUG_OBJ_USAGE
5633 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5641 /************************************************************************
5643 * Type Casting Routines *
5645 ************************************************************************/
5648 * xmlXPathCastBooleanToString:
5651 * Converts a boolean to its string value.
5653 * Returns a newly allocated string.
5656 xmlXPathCastBooleanToString (int val
) {
5659 ret
= xmlStrdup((const xmlChar
*) "true");
5661 ret
= xmlStrdup((const xmlChar
*) "false");
5666 * xmlXPathCastNumberToString:
5669 * Converts a number to its string value.
5671 * Returns a newly allocated string.
5674 xmlXPathCastNumberToString (double val
) {
5676 switch (xmlXPathIsInf(val
)) {
5678 ret
= xmlStrdup((const xmlChar
*) "Infinity");
5681 ret
= xmlStrdup((const xmlChar
*) "-Infinity");
5684 if (xmlXPathIsNaN(val
)) {
5685 ret
= xmlStrdup((const xmlChar
*) "NaN");
5686 } else if (val
== 0) {
5687 /* Omit sign for negative zero. */
5688 ret
= xmlStrdup((const xmlChar
*) "0");
5690 /* could be improved */
5692 xmlXPathFormatNumber(val
, buf
, 99);
5694 ret
= xmlStrdup((const xmlChar
*) buf
);
5701 * xmlXPathCastNodeToString:
5704 * Converts a node to its string value.
5706 * Returns a newly allocated string.
5709 xmlXPathCastNodeToString (xmlNodePtr node
) {
5711 if ((ret
= xmlNodeGetContent(node
)) == NULL
)
5712 ret
= xmlStrdup((const xmlChar
*) "");
5717 * xmlXPathCastNodeSetToString:
5720 * Converts a node-set to its string value.
5722 * Returns a newly allocated string.
5725 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns
) {
5726 if ((ns
== NULL
) || (ns
->nodeNr
== 0) || (ns
->nodeTab
== NULL
))
5727 return(xmlStrdup((const xmlChar
*) ""));
5730 xmlXPathNodeSetSort(ns
);
5731 return(xmlXPathCastNodeToString(ns
->nodeTab
[0]));
5735 * xmlXPathCastToString:
5736 * @val: an XPath object
5738 * Converts an existing object to its string() equivalent
5740 * Returns the allocated string value of the object, NULL in case of error.
5741 * It's up to the caller to free the string memory with xmlFree().
5744 xmlXPathCastToString(xmlXPathObjectPtr val
) {
5745 xmlChar
*ret
= NULL
;
5748 return(xmlStrdup((const xmlChar
*) ""));
5749 switch (val
->type
) {
5750 case XPATH_UNDEFINED
:
5752 xmlGenericError(xmlGenericErrorContext
, "String: undefined\n");
5754 ret
= xmlStrdup((const xmlChar
*) "");
5757 case XPATH_XSLT_TREE
:
5758 ret
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5761 return(xmlStrdup(val
->stringval
));
5763 ret
= xmlXPathCastBooleanToString(val
->boolval
);
5765 case XPATH_NUMBER
: {
5766 ret
= xmlXPathCastNumberToString(val
->floatval
);
5772 case XPATH_LOCATIONSET
:
5774 ret
= xmlStrdup((const xmlChar
*) "");
5781 * xmlXPathConvertString:
5782 * @val: an XPath object
5784 * Converts an existing object to its string() equivalent
5786 * Returns the new object, the old one is freed (or the operation
5787 * is done directly on @val)
5790 xmlXPathConvertString(xmlXPathObjectPtr val
) {
5791 xmlChar
*res
= NULL
;
5794 return(xmlXPathNewCString(""));
5796 switch (val
->type
) {
5797 case XPATH_UNDEFINED
:
5799 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
5803 case XPATH_XSLT_TREE
:
5804 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5809 res
= xmlXPathCastBooleanToString(val
->boolval
);
5812 res
= xmlXPathCastNumberToString(val
->floatval
);
5817 case XPATH_LOCATIONSET
:
5821 xmlXPathFreeObject(val
);
5823 return(xmlXPathNewCString(""));
5824 return(xmlXPathWrapString(res
));
5828 * xmlXPathCastBooleanToNumber:
5831 * Converts a boolean to its number value
5833 * Returns the number value
5836 xmlXPathCastBooleanToNumber(int val
) {
5843 * xmlXPathCastStringToNumber:
5846 * Converts a string to its number value
5848 * Returns the number value
5851 xmlXPathCastStringToNumber(const xmlChar
* val
) {
5852 return(xmlXPathStringEvalNumber(val
));
5856 * xmlXPathCastNodeToNumber:
5859 * Converts a node to its number value
5861 * Returns the number value
5864 xmlXPathCastNodeToNumber (xmlNodePtr node
) {
5869 return(xmlXPathNAN
);
5870 strval
= xmlXPathCastNodeToString(node
);
5872 return(xmlXPathNAN
);
5873 ret
= xmlXPathCastStringToNumber(strval
);
5880 * xmlXPathCastNodeSetToNumber:
5883 * Converts a node-set to its number value
5885 * Returns the number value
5888 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns
) {
5893 return(xmlXPathNAN
);
5894 str
= xmlXPathCastNodeSetToString(ns
);
5895 ret
= xmlXPathCastStringToNumber(str
);
5901 * xmlXPathCastToNumber:
5902 * @val: an XPath object
5904 * Converts an XPath object to its number value
5906 * Returns the number value
5909 xmlXPathCastToNumber(xmlXPathObjectPtr val
) {
5913 return(xmlXPathNAN
);
5914 switch (val
->type
) {
5915 case XPATH_UNDEFINED
:
5917 xmlGenericError(xmlGenericErrorContext
, "NUMBER: undefined\n");
5922 case XPATH_XSLT_TREE
:
5923 ret
= xmlXPathCastNodeSetToNumber(val
->nodesetval
);
5926 ret
= xmlXPathCastStringToNumber(val
->stringval
);
5929 ret
= val
->floatval
;
5932 ret
= xmlXPathCastBooleanToNumber(val
->boolval
);
5937 case XPATH_LOCATIONSET
:
5946 * xmlXPathConvertNumber:
5947 * @val: an XPath object
5949 * Converts an existing object to its number() equivalent
5951 * Returns the new object, the old one is freed (or the operation
5952 * is done directly on @val)
5955 xmlXPathConvertNumber(xmlXPathObjectPtr val
) {
5956 xmlXPathObjectPtr ret
;
5959 return(xmlXPathNewFloat(0.0));
5960 if (val
->type
== XPATH_NUMBER
)
5962 ret
= xmlXPathNewFloat(xmlXPathCastToNumber(val
));
5963 xmlXPathFreeObject(val
);
5968 * xmlXPathCastNumberToBoolean:
5971 * Converts a number to its boolean value
5973 * Returns the boolean value
5976 xmlXPathCastNumberToBoolean (double val
) {
5977 if (xmlXPathIsNaN(val
) || (val
== 0.0))
5983 * xmlXPathCastStringToBoolean:
5986 * Converts a string to its boolean value
5988 * Returns the boolean value
5991 xmlXPathCastStringToBoolean (const xmlChar
*val
) {
5992 if ((val
== NULL
) || (xmlStrlen(val
) == 0))
5998 * xmlXPathCastNodeSetToBoolean:
6001 * Converts a node-set to its boolean value
6003 * Returns the boolean value
6006 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns
) {
6007 if ((ns
== NULL
) || (ns
->nodeNr
== 0))
6013 * xmlXPathCastToBoolean:
6014 * @val: an XPath object
6016 * Converts an XPath object to its boolean value
6018 * Returns the boolean value
6021 xmlXPathCastToBoolean (xmlXPathObjectPtr val
) {
6026 switch (val
->type
) {
6027 case XPATH_UNDEFINED
:
6029 xmlGenericError(xmlGenericErrorContext
, "BOOLEAN: undefined\n");
6034 case XPATH_XSLT_TREE
:
6035 ret
= xmlXPathCastNodeSetToBoolean(val
->nodesetval
);
6038 ret
= xmlXPathCastStringToBoolean(val
->stringval
);
6041 ret
= xmlXPathCastNumberToBoolean(val
->floatval
);
6049 case XPATH_LOCATIONSET
:
6059 * xmlXPathConvertBoolean:
6060 * @val: an XPath object
6062 * Converts an existing object to its boolean() equivalent
6064 * Returns the new object, the old one is freed (or the operation
6065 * is done directly on @val)
6068 xmlXPathConvertBoolean(xmlXPathObjectPtr val
) {
6069 xmlXPathObjectPtr ret
;
6072 return(xmlXPathNewBoolean(0));
6073 if (val
->type
== XPATH_BOOLEAN
)
6075 ret
= xmlXPathNewBoolean(xmlXPathCastToBoolean(val
));
6076 xmlXPathFreeObject(val
);
6080 /************************************************************************
6082 * Routines to handle XPath contexts *
6084 ************************************************************************/
6087 * xmlXPathNewContext:
6088 * @doc: the XML document
6090 * Create a new xmlXPathContext
6092 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6095 xmlXPathNewContext(xmlDocPtr doc
) {
6096 xmlXPathContextPtr ret
;
6098 ret
= (xmlXPathContextPtr
) xmlMalloc(sizeof(xmlXPathContext
));
6100 xmlXPathErrMemory(NULL
, "creating context\n");
6103 memset(ret
, 0 , (size_t) sizeof(xmlXPathContext
));
6107 ret
->varHash
= NULL
;
6113 ret
->funcHash
= xmlHashCreate(0);
6122 ret
->contextSize
= -1;
6123 ret
->proximityPosition
= -1;
6125 #ifdef XP_DEFAULT_CACHE_ON
6126 if (xmlXPathContextSetCache(ret
, 1, -1, 0) == -1) {
6127 xmlXPathFreeContext(ret
);
6132 xmlXPathRegisterAllFunctions(ret
);
6138 * xmlXPathFreeContext:
6139 * @ctxt: the context to free
6141 * Free up an xmlXPathContext
6144 xmlXPathFreeContext(xmlXPathContextPtr ctxt
) {
6145 if (ctxt
== NULL
) return;
6147 if (ctxt
->cache
!= NULL
)
6148 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
6149 xmlXPathRegisteredNsCleanup(ctxt
);
6150 xmlXPathRegisteredFuncsCleanup(ctxt
);
6151 xmlXPathRegisteredVariablesCleanup(ctxt
);
6152 xmlResetError(&ctxt
->lastError
);
6156 /************************************************************************
6158 * Routines to handle XPath parser contexts *
6160 ************************************************************************/
6162 #define CHECK_CTXT(ctxt) \
6163 if (ctxt == NULL) { \
6164 __xmlRaiseError(NULL, NULL, NULL, \
6165 NULL, NULL, XML_FROM_XPATH, \
6166 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6167 __FILE__, __LINE__, \
6168 NULL, NULL, NULL, 0, 0, \
6169 "NULL context pointer\n"); \
6173 #define CHECK_CTXT_NEG(ctxt) \
6174 if (ctxt == NULL) { \
6175 __xmlRaiseError(NULL, NULL, NULL, \
6176 NULL, NULL, XML_FROM_XPATH, \
6177 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6178 __FILE__, __LINE__, \
6179 NULL, NULL, NULL, 0, 0, \
6180 "NULL context pointer\n"); \
6185 #define CHECK_CONTEXT(ctxt) \
6186 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6187 (ctxt->doc->children == NULL)) { \
6188 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6194 * xmlXPathNewParserContext:
6195 * @str: the XPath expression
6196 * @ctxt: the XPath context
6198 * Create a new xmlXPathParserContext
6200 * Returns the xmlXPathParserContext just allocated.
6202 xmlXPathParserContextPtr
6203 xmlXPathNewParserContext(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
6204 xmlXPathParserContextPtr ret
;
6206 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6208 xmlXPathErrMemory(ctxt
, "creating parser context\n");
6211 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6212 ret
->cur
= ret
->base
= str
;
6213 ret
->context
= ctxt
;
6215 ret
->comp
= xmlXPathNewCompExpr();
6216 if (ret
->comp
== NULL
) {
6217 xmlFree(ret
->valueTab
);
6221 if ((ctxt
!= NULL
) && (ctxt
->dict
!= NULL
)) {
6222 ret
->comp
->dict
= ctxt
->dict
;
6223 xmlDictReference(ret
->comp
->dict
);
6230 * xmlXPathCompParserContext:
6231 * @comp: the XPath compiled expression
6232 * @ctxt: the XPath context
6234 * Create a new xmlXPathParserContext when processing a compiled expression
6236 * Returns the xmlXPathParserContext just allocated.
6238 static xmlXPathParserContextPtr
6239 xmlXPathCompParserContext(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctxt
) {
6240 xmlXPathParserContextPtr ret
;
6242 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6244 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6247 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6249 /* Allocate the value stack */
6250 ret
->valueTab
= (xmlXPathObjectPtr
*)
6251 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
6252 if (ret
->valueTab
== NULL
) {
6254 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6260 ret
->valueFrame
= 0;
6262 ret
->context
= ctxt
;
6269 * xmlXPathFreeParserContext:
6270 * @ctxt: the context to free
6272 * Free up an xmlXPathParserContext
6275 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt
) {
6278 if (ctxt
->valueTab
!= NULL
) {
6279 for (i
= 0; i
< ctxt
->valueNr
; i
++) {
6281 xmlXPathReleaseObject(ctxt
->context
, ctxt
->valueTab
[i
]);
6283 xmlXPathFreeObject(ctxt
->valueTab
[i
]);
6285 xmlFree(ctxt
->valueTab
);
6287 if (ctxt
->comp
!= NULL
) {
6288 #ifdef XPATH_STREAMING
6289 if (ctxt
->comp
->stream
!= NULL
) {
6290 xmlFreePatternList(ctxt
->comp
->stream
);
6291 ctxt
->comp
->stream
= NULL
;
6294 xmlXPathFreeCompExpr(ctxt
->comp
);
6299 /************************************************************************
6301 * The implicit core function library *
6303 ************************************************************************/
6306 * xmlXPathNodeValHash:
6307 * @node: a node pointer
6309 * Function computing the beginning of the string value of the node,
6310 * used to speed up comparisons
6312 * Returns an int usable as a hash
6315 xmlXPathNodeValHash(xmlNodePtr node
) {
6317 const xmlChar
* string
= NULL
;
6318 xmlNodePtr tmp
= NULL
;
6319 unsigned int ret
= 0;
6324 if (node
->type
== XML_DOCUMENT_NODE
) {
6325 tmp
= xmlDocGetRootElement((xmlDocPtr
) node
);
6327 node
= node
->children
;
6335 switch (node
->type
) {
6336 case XML_COMMENT_NODE
:
6338 case XML_CDATA_SECTION_NODE
:
6340 string
= node
->content
;
6345 return(((unsigned int) string
[0]) +
6346 (((unsigned int) string
[1]) << 8));
6347 case XML_NAMESPACE_DECL
:
6348 string
= ((xmlNsPtr
)node
)->href
;
6353 return(((unsigned int) string
[0]) +
6354 (((unsigned int) string
[1]) << 8));
6355 case XML_ATTRIBUTE_NODE
:
6356 tmp
= ((xmlAttrPtr
) node
)->children
;
6358 case XML_ELEMENT_NODE
:
6359 tmp
= node
->children
;
6364 while (tmp
!= NULL
) {
6365 switch (tmp
->type
) {
6366 case XML_CDATA_SECTION_NODE
:
6368 string
= tmp
->content
;
6374 if ((string
!= NULL
) && (string
[0] != 0)) {
6376 return(ret
+ (((unsigned int) string
[0]) << 8));
6378 if (string
[1] == 0) {
6380 ret
= (unsigned int) string
[0];
6382 return(((unsigned int) string
[0]) +
6383 (((unsigned int) string
[1]) << 8));
6389 if ((tmp
->children
!= NULL
) && (tmp
->type
!= XML_DTD_NODE
)) {
6390 if (tmp
->children
->type
!= XML_ENTITY_DECL
) {
6391 tmp
= tmp
->children
;
6398 if (tmp
->next
!= NULL
) {
6411 if (tmp
->next
!= NULL
) {
6415 } while (tmp
!= NULL
);
6421 * xmlXPathStringHash:
6424 * Function computing the beginning of the string value of the node,
6425 * used to speed up comparisons
6427 * Returns an int usable as a hash
6430 xmlXPathStringHash(const xmlChar
* string
) {
6432 return((unsigned int) 0);
6435 return(((unsigned int) string
[0]) +
6436 (((unsigned int) string
[1]) << 8));
6440 * xmlXPathCompareNodeSetFloat:
6441 * @ctxt: the XPath Parser context
6442 * @inf: less than (1) or greater than (0)
6443 * @strict: is the comparison strict
6444 * @arg: the node set
6447 * Implement the compare operation between a nodeset and a number
6448 * @ns < @val (1, 1, ...
6449 * @ns <= @val (1, 0, ...
6450 * @ns > @val (0, 1, ...
6451 * @ns >= @val (0, 0, ...
6453 * If one object to be compared is a node-set and the other is a number,
6454 * then the comparison will be true if and only if there is a node in the
6455 * node-set such that the result of performing the comparison on the number
6456 * to be compared and on the result of converting the string-value of that
6457 * node to a number using the number function is true.
6459 * Returns 0 or 1 depending on the results of the test.
6462 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6463 xmlXPathObjectPtr arg
, xmlXPathObjectPtr f
) {
6468 if ((f
== NULL
) || (arg
== NULL
) ||
6469 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6470 xmlXPathReleaseObject(ctxt
->context
, arg
);
6471 xmlXPathReleaseObject(ctxt
->context
, f
);
6474 ns
= arg
->nodesetval
;
6476 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6477 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6480 xmlXPathCacheNewString(ctxt
->context
, str2
));
6482 xmlXPathNumberFunction(ctxt
, 1);
6483 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, f
));
6484 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6490 xmlXPathReleaseObject(ctxt
->context
, arg
);
6491 xmlXPathReleaseObject(ctxt
->context
, f
);
6496 * xmlXPathCompareNodeSetString:
6497 * @ctxt: the XPath Parser context
6498 * @inf: less than (1) or greater than (0)
6499 * @strict: is the comparison strict
6500 * @arg: the node set
6503 * Implement the compare operation between a nodeset and a string
6504 * @ns < @val (1, 1, ...
6505 * @ns <= @val (1, 0, ...
6506 * @ns > @val (0, 1, ...
6507 * @ns >= @val (0, 0, ...
6509 * If one object to be compared is a node-set and the other is a string,
6510 * then the comparison will be true if and only if there is a node in
6511 * the node-set such that the result of performing the comparison on the
6512 * string-value of the node and the other string is true.
6514 * Returns 0 or 1 depending on the results of the test.
6517 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6518 xmlXPathObjectPtr arg
, xmlXPathObjectPtr s
) {
6523 if ((s
== NULL
) || (arg
== NULL
) ||
6524 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6525 xmlXPathReleaseObject(ctxt
->context
, arg
);
6526 xmlXPathReleaseObject(ctxt
->context
, s
);
6529 ns
= arg
->nodesetval
;
6531 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6532 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6535 xmlXPathCacheNewString(ctxt
->context
, str2
));
6537 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, s
));
6538 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6544 xmlXPathReleaseObject(ctxt
->context
, arg
);
6545 xmlXPathReleaseObject(ctxt
->context
, s
);
6550 * xmlXPathCompareNodeSets:
6551 * @inf: less than (1) or greater than (0)
6552 * @strict: is the comparison strict
6553 * @arg1: the first node set object
6554 * @arg2: the second node set object
6556 * Implement the compare operation on nodesets:
6558 * If both objects to be compared are node-sets, then the comparison
6559 * will be true if and only if there is a node in the first node-set
6560 * and a node in the second node-set such that the result of performing
6561 * the comparison on the string-values of the two nodes is true.
6563 * When neither object to be compared is a node-set and the operator
6564 * is <=, <, >= or >, then the objects are compared by converting both
6565 * objects to numbers and comparing the numbers according to IEEE 754.
6567 * The number function converts its argument to a number as follows:
6568 * - a string that consists of optional whitespace followed by an
6569 * optional minus sign followed by a Number followed by whitespace
6570 * is converted to the IEEE 754 number that is nearest (according
6571 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6572 * represented by the string; any other string is converted to NaN
6574 * Conclusion all nodes need to be converted first to their string value
6575 * and then the comparison must be done when possible
6578 xmlXPathCompareNodeSets(int inf
, int strict
,
6579 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6587 if ((arg1
== NULL
) ||
6588 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
))) {
6589 xmlXPathFreeObject(arg2
);
6592 if ((arg2
== NULL
) ||
6593 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
))) {
6594 xmlXPathFreeObject(arg1
);
6595 xmlXPathFreeObject(arg2
);
6599 ns1
= arg1
->nodesetval
;
6600 ns2
= arg2
->nodesetval
;
6602 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0)) {
6603 xmlXPathFreeObject(arg1
);
6604 xmlXPathFreeObject(arg2
);
6607 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0)) {
6608 xmlXPathFreeObject(arg1
);
6609 xmlXPathFreeObject(arg2
);
6613 values2
= (double *) xmlMalloc(ns2
->nodeNr
* sizeof(double));
6614 if (values2
== NULL
) {
6615 /* TODO: Propagate memory error. */
6616 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6617 xmlXPathFreeObject(arg1
);
6618 xmlXPathFreeObject(arg2
);
6621 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6622 val1
= xmlXPathCastNodeToNumber(ns1
->nodeTab
[i
]);
6623 if (xmlXPathIsNaN(val1
))
6625 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6627 values2
[j
] = xmlXPathCastNodeToNumber(ns2
->nodeTab
[j
]);
6629 if (xmlXPathIsNaN(values2
[j
]))
6632 ret
= (val1
< values2
[j
]);
6633 else if (inf
&& !strict
)
6634 ret
= (val1
<= values2
[j
]);
6635 else if (!inf
&& strict
)
6636 ret
= (val1
> values2
[j
]);
6637 else if (!inf
&& !strict
)
6638 ret
= (val1
>= values2
[j
]);
6647 xmlXPathFreeObject(arg1
);
6648 xmlXPathFreeObject(arg2
);
6653 * xmlXPathCompareNodeSetValue:
6654 * @ctxt: the XPath Parser context
6655 * @inf: less than (1) or greater than (0)
6656 * @strict: is the comparison strict
6657 * @arg: the node set
6660 * Implement the compare operation between a nodeset and a value
6661 * @ns < @val (1, 1, ...
6662 * @ns <= @val (1, 0, ...
6663 * @ns > @val (0, 1, ...
6664 * @ns >= @val (0, 0, ...
6666 * If one object to be compared is a node-set and the other is a boolean,
6667 * then the comparison will be true if and only if the result of performing
6668 * the comparison on the boolean and on the result of converting
6669 * the node-set to a boolean using the boolean function is true.
6671 * Returns 0 or 1 depending on the results of the test.
6674 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6675 xmlXPathObjectPtr arg
, xmlXPathObjectPtr val
) {
6676 if ((val
== NULL
) || (arg
== NULL
) ||
6677 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6682 return(xmlXPathCompareNodeSetFloat(ctxt
, inf
, strict
, arg
, val
));
6684 case XPATH_XSLT_TREE
:
6685 return(xmlXPathCompareNodeSets(inf
, strict
, arg
, val
));
6687 return(xmlXPathCompareNodeSetString(ctxt
, inf
, strict
, arg
, val
));
6689 valuePush(ctxt
, arg
);
6690 xmlXPathBooleanFunction(ctxt
, 1);
6691 valuePush(ctxt
, val
);
6692 return(xmlXPathCompareValues(ctxt
, inf
, strict
));
6694 xmlGenericError(xmlGenericErrorContext
,
6695 "xmlXPathCompareNodeSetValue: Can't compare node set "
6696 "and object of type %d\n",
6698 xmlXPathReleaseObject(ctxt
->context
, arg
);
6699 xmlXPathReleaseObject(ctxt
->context
, val
);
6700 XP_ERROR0(XPATH_INVALID_TYPE
);
6706 * xmlXPathEqualNodeSetString:
6707 * @arg: the nodeset object argument
6708 * @str: the string to compare to.
6709 * @neq: flag to show whether for '=' (0) or '!=' (1)
6711 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6712 * If one object to be compared is a node-set and the other is a string,
6713 * then the comparison will be true if and only if there is a node in
6714 * the node-set such that the result of performing the comparison on the
6715 * string-value of the node and the other string is true.
6717 * Returns 0 or 1 depending on the results of the test.
6720 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg
, const xmlChar
* str
, int neq
)
6727 if ((str
== NULL
) || (arg
== NULL
) ||
6728 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6730 ns
= arg
->nodesetval
;
6732 * A NULL nodeset compared with a string is always false
6733 * (since there is no node equal, and no node not equal)
6735 if ((ns
== NULL
) || (ns
->nodeNr
<= 0) )
6737 hash
= xmlXPathStringHash(str
);
6738 for (i
= 0; i
< ns
->nodeNr
; i
++) {
6739 if (xmlXPathNodeValHash(ns
->nodeTab
[i
]) == hash
) {
6740 str2
= xmlNodeGetContent(ns
->nodeTab
[i
]);
6741 if ((str2
!= NULL
) && (xmlStrEqual(str
, str2
))) {
6746 } else if ((str2
== NULL
) && (xmlStrEqual(str
, BAD_CAST
""))) {
6764 * xmlXPathEqualNodeSetFloat:
6765 * @arg: the nodeset object argument
6766 * @f: the float to compare to
6767 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6769 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6770 * If one object to be compared is a node-set and the other is a number,
6771 * then the comparison will be true if and only if there is a node in
6772 * the node-set such that the result of performing the comparison on the
6773 * number to be compared and on the result of converting the string-value
6774 * of that node to a number using the number function is true.
6776 * Returns 0 or 1 depending on the results of the test.
6779 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt
,
6780 xmlXPathObjectPtr arg
, double f
, int neq
) {
6784 xmlXPathObjectPtr val
;
6787 if ((arg
== NULL
) ||
6788 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6791 ns
= arg
->nodesetval
;
6793 for (i
=0;i
<ns
->nodeNr
;i
++) {
6794 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6796 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, str2
));
6798 xmlXPathNumberFunction(ctxt
, 1);
6799 val
= valuePop(ctxt
);
6801 xmlXPathReleaseObject(ctxt
->context
, val
);
6802 if (!xmlXPathIsNaN(v
)) {
6803 if ((!neq
) && (v
==f
)) {
6806 } else if ((neq
) && (v
!=f
)) {
6810 } else { /* NaN is unequal to any value */
6823 * xmlXPathEqualNodeSets:
6824 * @arg1: first nodeset object argument
6825 * @arg2: second nodeset object argument
6826 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6828 * Implement the equal / not equal operation on XPath nodesets:
6829 * @arg1 == @arg2 or @arg1 != @arg2
6830 * If both objects to be compared are node-sets, then the comparison
6831 * will be true if and only if there is a node in the first node-set and
6832 * a node in the second node-set such that the result of performing the
6833 * comparison on the string-values of the two nodes is true.
6835 * (needless to say, this is a costly operation)
6837 * Returns 0 or 1 depending on the results of the test.
6840 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
, int neq
) {
6842 unsigned int *hashs1
;
6843 unsigned int *hashs2
;
6850 if ((arg1
== NULL
) ||
6851 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)))
6853 if ((arg2
== NULL
) ||
6854 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
)))
6857 ns1
= arg1
->nodesetval
;
6858 ns2
= arg2
->nodesetval
;
6860 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0))
6862 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0))
6866 * for equal, check if there is a node pertaining to both sets
6869 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6870 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6871 if (ns1
->nodeTab
[i
] == ns2
->nodeTab
[j
])
6874 values1
= (xmlChar
**) xmlMalloc(ns1
->nodeNr
* sizeof(xmlChar
*));
6875 if (values1
== NULL
) {
6876 /* TODO: Propagate memory error. */
6877 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6880 hashs1
= (unsigned int *) xmlMalloc(ns1
->nodeNr
* sizeof(unsigned int));
6881 if (hashs1
== NULL
) {
6882 /* TODO: Propagate memory error. */
6883 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6887 memset(values1
, 0, ns1
->nodeNr
* sizeof(xmlChar
*));
6888 values2
= (xmlChar
**) xmlMalloc(ns2
->nodeNr
* sizeof(xmlChar
*));
6889 if (values2
== NULL
) {
6890 /* TODO: Propagate memory error. */
6891 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6896 hashs2
= (unsigned int *) xmlMalloc(ns2
->nodeNr
* sizeof(unsigned int));
6897 if (hashs2
== NULL
) {
6898 /* TODO: Propagate memory error. */
6899 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6905 memset(values2
, 0, ns2
->nodeNr
* sizeof(xmlChar
*));
6906 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6907 hashs1
[i
] = xmlXPathNodeValHash(ns1
->nodeTab
[i
]);
6908 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6910 hashs2
[j
] = xmlXPathNodeValHash(ns2
->nodeTab
[j
]);
6911 if (hashs1
[i
] != hashs2
[j
]) {
6918 if (values1
[i
] == NULL
)
6919 values1
[i
] = xmlNodeGetContent(ns1
->nodeTab
[i
]);
6920 if (values2
[j
] == NULL
)
6921 values2
[j
] = xmlNodeGetContent(ns2
->nodeTab
[j
]);
6922 ret
= xmlStrEqual(values1
[i
], values2
[j
]) ^ neq
;
6930 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6931 if (values1
[i
] != NULL
)
6932 xmlFree(values1
[i
]);
6933 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6934 if (values2
[j
] != NULL
)
6935 xmlFree(values2
[j
]);
6944 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt
,
6945 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6948 *At this point we are assured neither arg1 nor arg2
6949 *is a nodeset, so we can just pick the appropriate routine.
6951 switch (arg1
->type
) {
6952 case XPATH_UNDEFINED
:
6954 xmlGenericError(xmlGenericErrorContext
,
6955 "Equal: undefined\n");
6959 switch (arg2
->type
) {
6960 case XPATH_UNDEFINED
:
6962 xmlGenericError(xmlGenericErrorContext
,
6963 "Equal: undefined\n");
6968 xmlGenericError(xmlGenericErrorContext
,
6969 "Equal: %d boolean %d \n",
6970 arg1
->boolval
, arg2
->boolval
);
6972 ret
= (arg1
->boolval
== arg2
->boolval
);
6975 ret
= (arg1
->boolval
==
6976 xmlXPathCastNumberToBoolean(arg2
->floatval
));
6979 if ((arg2
->stringval
== NULL
) ||
6980 (arg2
->stringval
[0] == 0)) ret
= 0;
6983 ret
= (arg1
->boolval
== ret
);
6988 case XPATH_LOCATIONSET
:
6992 case XPATH_XSLT_TREE
:
6997 switch (arg2
->type
) {
6998 case XPATH_UNDEFINED
:
7000 xmlGenericError(xmlGenericErrorContext
,
7001 "Equal: undefined\n");
7005 ret
= (arg2
->boolval
==
7006 xmlXPathCastNumberToBoolean(arg1
->floatval
));
7009 valuePush(ctxt
, arg2
);
7010 xmlXPathNumberFunction(ctxt
, 1);
7011 arg2
= valuePop(ctxt
);
7012 /* Falls through. */
7014 /* Hand check NaN and Infinity equalities */
7015 if (xmlXPathIsNaN(arg1
->floatval
) ||
7016 xmlXPathIsNaN(arg2
->floatval
)) {
7018 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7019 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7023 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7024 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7028 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7029 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7033 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7034 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7039 ret
= (arg1
->floatval
== arg2
->floatval
);
7045 case XPATH_LOCATIONSET
:
7049 case XPATH_XSLT_TREE
:
7054 switch (arg2
->type
) {
7055 case XPATH_UNDEFINED
:
7057 xmlGenericError(xmlGenericErrorContext
,
7058 "Equal: undefined\n");
7062 if ((arg1
->stringval
== NULL
) ||
7063 (arg1
->stringval
[0] == 0)) ret
= 0;
7066 ret
= (arg2
->boolval
== ret
);
7069 ret
= xmlStrEqual(arg1
->stringval
, arg2
->stringval
);
7072 valuePush(ctxt
, arg1
);
7073 xmlXPathNumberFunction(ctxt
, 1);
7074 arg1
= valuePop(ctxt
);
7075 /* Hand check NaN and Infinity equalities */
7076 if (xmlXPathIsNaN(arg1
->floatval
) ||
7077 xmlXPathIsNaN(arg2
->floatval
)) {
7079 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7080 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7084 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7085 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7089 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7090 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7094 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7095 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7100 ret
= (arg1
->floatval
== arg2
->floatval
);
7106 case XPATH_LOCATIONSET
:
7110 case XPATH_XSLT_TREE
:
7117 case XPATH_LOCATIONSET
:
7121 case XPATH_XSLT_TREE
:
7124 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7125 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7130 * xmlXPathEqualValues:
7131 * @ctxt: the XPath Parser context
7133 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7135 * Returns 0 or 1 depending on the results of the test.
7138 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt
) {
7139 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7142 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7143 arg2
= valuePop(ctxt
);
7144 arg1
= valuePop(ctxt
);
7145 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7147 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7149 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7150 XP_ERROR0(XPATH_INVALID_OPERAND
);
7155 xmlGenericError(xmlGenericErrorContext
,
7156 "Equal: by pointer\n");
7158 xmlXPathFreeObject(arg1
);
7163 *If either argument is a nodeset, it's a 'special case'
7165 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7166 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7168 *Hack it to assure arg1 is the nodeset
7170 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7175 switch (arg2
->type
) {
7176 case XPATH_UNDEFINED
:
7178 xmlGenericError(xmlGenericErrorContext
,
7179 "Equal: undefined\n");
7183 case XPATH_XSLT_TREE
:
7184 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 0);
7187 if ((arg1
->nodesetval
== NULL
) ||
7188 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7191 ret
= (ret
== arg2
->boolval
);
7194 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 0);
7197 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
, 0);
7202 case XPATH_LOCATIONSET
:
7206 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7207 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7211 return (xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7215 * xmlXPathNotEqualValues:
7216 * @ctxt: the XPath Parser context
7218 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7220 * Returns 0 or 1 depending on the results of the test.
7223 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt
) {
7224 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7227 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7228 arg2
= valuePop(ctxt
);
7229 arg1
= valuePop(ctxt
);
7230 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7232 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7234 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7235 XP_ERROR0(XPATH_INVALID_OPERAND
);
7240 xmlGenericError(xmlGenericErrorContext
,
7241 "NotEqual: by pointer\n");
7243 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7248 *If either argument is a nodeset, it's a 'special case'
7250 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7251 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7253 *Hack it to assure arg1 is the nodeset
7255 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7260 switch (arg2
->type
) {
7261 case XPATH_UNDEFINED
:
7263 xmlGenericError(xmlGenericErrorContext
,
7264 "NotEqual: undefined\n");
7268 case XPATH_XSLT_TREE
:
7269 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 1);
7272 if ((arg1
->nodesetval
== NULL
) ||
7273 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7276 ret
= (ret
!= arg2
->boolval
);
7279 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 1);
7282 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
,1);
7287 case XPATH_LOCATIONSET
:
7291 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7292 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7296 return (!xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7300 * xmlXPathCompareValues:
7301 * @ctxt: the XPath Parser context
7302 * @inf: less than (1) or greater than (0)
7303 * @strict: is the comparison strict
7305 * Implement the compare operation on XPath objects:
7306 * @arg1 < @arg2 (1, 1, ...
7307 * @arg1 <= @arg2 (1, 0, ...
7308 * @arg1 > @arg2 (0, 1, ...
7309 * @arg1 >= @arg2 (0, 0, ...
7311 * When neither object to be compared is a node-set and the operator is
7312 * <=, <, >=, >, then the objects are compared by converted both objects
7313 * to numbers and comparing the numbers according to IEEE 754. The <
7314 * comparison will be true if and only if the first number is less than the
7315 * second number. The <= comparison will be true if and only if the first
7316 * number is less than or equal to the second number. The > comparison
7317 * will be true if and only if the first number is greater than the second
7318 * number. The >= comparison will be true if and only if the first number
7319 * is greater than or equal to the second number.
7321 * Returns 1 if the comparison succeeded, 0 if it failed
7324 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt
, int inf
, int strict
) {
7325 int ret
= 0, arg1i
= 0, arg2i
= 0;
7326 xmlXPathObjectPtr arg1
, arg2
;
7328 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7329 arg2
= valuePop(ctxt
);
7330 arg1
= valuePop(ctxt
);
7331 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7333 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7335 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7336 XP_ERROR0(XPATH_INVALID_OPERAND
);
7339 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7340 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7342 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7343 * are not freed from within this routine; they will be freed from the
7344 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7346 if (((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
)) &&
7347 ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
))){
7348 ret
= xmlXPathCompareNodeSets(inf
, strict
, arg1
, arg2
);
7350 if ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7351 ret
= xmlXPathCompareNodeSetValue(ctxt
, inf
, strict
,
7354 ret
= xmlXPathCompareNodeSetValue(ctxt
, !inf
, strict
,
7361 if (arg1
->type
!= XPATH_NUMBER
) {
7362 valuePush(ctxt
, arg1
);
7363 xmlXPathNumberFunction(ctxt
, 1);
7364 arg1
= valuePop(ctxt
);
7366 if (arg1
->type
!= XPATH_NUMBER
) {
7367 xmlXPathFreeObject(arg1
);
7368 xmlXPathFreeObject(arg2
);
7369 XP_ERROR0(XPATH_INVALID_OPERAND
);
7371 if (arg2
->type
!= XPATH_NUMBER
) {
7372 valuePush(ctxt
, arg2
);
7373 xmlXPathNumberFunction(ctxt
, 1);
7374 arg2
= valuePop(ctxt
);
7376 if (arg2
->type
!= XPATH_NUMBER
) {
7377 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7378 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7379 XP_ERROR0(XPATH_INVALID_OPERAND
);
7382 * Add tests for infinity and nan
7383 * => feedback on 3.4 for Inf and NaN
7385 /* Hand check NaN and Infinity comparisons */
7386 if (xmlXPathIsNaN(arg1
->floatval
) || xmlXPathIsNaN(arg2
->floatval
)) {
7389 arg1i
=xmlXPathIsInf(arg1
->floatval
);
7390 arg2i
=xmlXPathIsInf(arg2
->floatval
);
7391 if (inf
&& strict
) {
7392 if ((arg1i
== -1 && arg2i
!= -1) ||
7393 (arg2i
== 1 && arg1i
!= 1)) {
7395 } else if (arg1i
== 0 && arg2i
== 0) {
7396 ret
= (arg1
->floatval
< arg2
->floatval
);
7401 else if (inf
&& !strict
) {
7402 if (arg1i
== -1 || arg2i
== 1) {
7404 } else if (arg1i
== 0 && arg2i
== 0) {
7405 ret
= (arg1
->floatval
<= arg2
->floatval
);
7410 else if (!inf
&& strict
) {
7411 if ((arg1i
== 1 && arg2i
!= 1) ||
7412 (arg2i
== -1 && arg1i
!= -1)) {
7414 } else if (arg1i
== 0 && arg2i
== 0) {
7415 ret
= (arg1
->floatval
> arg2
->floatval
);
7420 else if (!inf
&& !strict
) {
7421 if (arg1i
== 1 || arg2i
== -1) {
7423 } else if (arg1i
== 0 && arg2i
== 0) {
7424 ret
= (arg1
->floatval
>= arg2
->floatval
);
7430 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7431 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7436 * xmlXPathValueFlipSign:
7437 * @ctxt: the XPath Parser context
7439 * Implement the unary - operation on an XPath object
7440 * The numeric operators convert their operands to numbers as if
7441 * by calling the number function.
7444 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt
) {
7445 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return;
7447 CHECK_TYPE(XPATH_NUMBER
);
7448 ctxt
->value
->floatval
= -ctxt
->value
->floatval
;
7452 * xmlXPathAddValues:
7453 * @ctxt: the XPath Parser context
7455 * Implement the add operation on XPath objects:
7456 * The numeric operators convert their operands to numbers as if
7457 * by calling the number function.
7460 xmlXPathAddValues(xmlXPathParserContextPtr ctxt
) {
7461 xmlXPathObjectPtr arg
;
7464 arg
= valuePop(ctxt
);
7466 XP_ERROR(XPATH_INVALID_OPERAND
);
7467 val
= xmlXPathCastToNumber(arg
);
7468 xmlXPathReleaseObject(ctxt
->context
, arg
);
7470 CHECK_TYPE(XPATH_NUMBER
);
7471 ctxt
->value
->floatval
+= val
;
7475 * xmlXPathSubValues:
7476 * @ctxt: the XPath Parser context
7478 * Implement the subtraction operation on XPath objects:
7479 * The numeric operators convert their operands to numbers as if
7480 * by calling the number function.
7483 xmlXPathSubValues(xmlXPathParserContextPtr ctxt
) {
7484 xmlXPathObjectPtr arg
;
7487 arg
= valuePop(ctxt
);
7489 XP_ERROR(XPATH_INVALID_OPERAND
);
7490 val
= xmlXPathCastToNumber(arg
);
7491 xmlXPathReleaseObject(ctxt
->context
, arg
);
7493 CHECK_TYPE(XPATH_NUMBER
);
7494 ctxt
->value
->floatval
-= val
;
7498 * xmlXPathMultValues:
7499 * @ctxt: the XPath Parser context
7501 * Implement the multiply operation on XPath objects:
7502 * The numeric operators convert their operands to numbers as if
7503 * by calling the number function.
7506 xmlXPathMultValues(xmlXPathParserContextPtr ctxt
) {
7507 xmlXPathObjectPtr arg
;
7510 arg
= valuePop(ctxt
);
7512 XP_ERROR(XPATH_INVALID_OPERAND
);
7513 val
= xmlXPathCastToNumber(arg
);
7514 xmlXPathReleaseObject(ctxt
->context
, arg
);
7516 CHECK_TYPE(XPATH_NUMBER
);
7517 ctxt
->value
->floatval
*= val
;
7521 * xmlXPathDivValues:
7522 * @ctxt: the XPath Parser context
7524 * Implement the div operation on XPath objects @arg1 / @arg2:
7525 * The numeric operators convert their operands to numbers as if
7526 * by calling the number function.
7528 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7530 xmlXPathDivValues(xmlXPathParserContextPtr ctxt
) {
7531 xmlXPathObjectPtr arg
;
7534 arg
= valuePop(ctxt
);
7536 XP_ERROR(XPATH_INVALID_OPERAND
);
7537 val
= xmlXPathCastToNumber(arg
);
7538 xmlXPathReleaseObject(ctxt
->context
, arg
);
7540 CHECK_TYPE(XPATH_NUMBER
);
7541 ctxt
->value
->floatval
/= val
;
7545 * xmlXPathModValues:
7546 * @ctxt: the XPath Parser context
7548 * Implement the mod operation on XPath objects: @arg1 / @arg2
7549 * The numeric operators convert their operands to numbers as if
7550 * by calling the number function.
7553 xmlXPathModValues(xmlXPathParserContextPtr ctxt
) {
7554 xmlXPathObjectPtr arg
;
7557 arg
= valuePop(ctxt
);
7559 XP_ERROR(XPATH_INVALID_OPERAND
);
7560 arg2
= xmlXPathCastToNumber(arg
);
7561 xmlXPathReleaseObject(ctxt
->context
, arg
);
7563 CHECK_TYPE(XPATH_NUMBER
);
7564 arg1
= ctxt
->value
->floatval
;
7566 ctxt
->value
->floatval
= xmlXPathNAN
;
7568 ctxt
->value
->floatval
= fmod(arg1
, arg2
);
7572 /************************************************************************
7574 * The traversal functions *
7576 ************************************************************************/
7579 * A traversal function enumerates nodes along an axis.
7580 * Initially it must be called with NULL, and it indicates
7581 * termination on the axis by returning NULL.
7583 typedef xmlNodePtr (*xmlXPathTraversalFunction
)
7584 (xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
);
7587 * xmlXPathTraversalFunctionExt:
7588 * A traversal function enumerates nodes along an axis.
7589 * Initially it must be called with NULL, and it indicates
7590 * termination on the axis by returning NULL.
7591 * The context node of the traversal is specified via @contextNode.
7593 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt
)
7594 (xmlNodePtr cur
, xmlNodePtr contextNode
);
7597 * xmlXPathNodeSetMergeFunction:
7598 * Used for merging node sets in xmlXPathCollectAndTest().
7600 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction
)
7601 (xmlNodeSetPtr
, xmlNodeSetPtr
);
7606 * @ctxt: the XPath Parser context
7607 * @cur: the current node in the traversal
7609 * Traversal function for the "self" direction
7610 * The self axis contains just the context node itself
7612 * Returns the next element following that axis
7615 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7616 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7618 return(ctxt
->context
->node
);
7623 * xmlXPathNextChild:
7624 * @ctxt: the XPath Parser context
7625 * @cur: the current node in the traversal
7627 * Traversal function for the "child" direction
7628 * The child axis contains the children of the context node in document order.
7630 * Returns the next element following that axis
7633 xmlXPathNextChild(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7634 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7636 if (ctxt
->context
->node
== NULL
) return(NULL
);
7637 switch (ctxt
->context
->node
->type
) {
7638 case XML_ELEMENT_NODE
:
7640 case XML_CDATA_SECTION_NODE
:
7641 case XML_ENTITY_REF_NODE
:
7642 case XML_ENTITY_NODE
:
7644 case XML_COMMENT_NODE
:
7645 case XML_NOTATION_NODE
:
7647 return(ctxt
->context
->node
->children
);
7648 case XML_DOCUMENT_NODE
:
7649 case XML_DOCUMENT_TYPE_NODE
:
7650 case XML_DOCUMENT_FRAG_NODE
:
7651 case XML_HTML_DOCUMENT_NODE
:
7652 #ifdef LIBXML_DOCB_ENABLED
7653 case XML_DOCB_DOCUMENT_NODE
:
7655 return(((xmlDocPtr
) ctxt
->context
->node
)->children
);
7656 case XML_ELEMENT_DECL
:
7657 case XML_ATTRIBUTE_DECL
:
7658 case XML_ENTITY_DECL
:
7659 case XML_ATTRIBUTE_NODE
:
7660 case XML_NAMESPACE_DECL
:
7661 case XML_XINCLUDE_START
:
7662 case XML_XINCLUDE_END
:
7667 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
7668 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
7674 * xmlXPathNextChildElement:
7675 * @ctxt: the XPath Parser context
7676 * @cur: the current node in the traversal
7678 * Traversal function for the "child" direction and nodes of type element.
7679 * The child axis contains the children of the context node in document order.
7681 * Returns the next element following that axis
7684 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7685 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7687 cur
= ctxt
->context
->node
;
7688 if (cur
== NULL
) return(NULL
);
7690 * Get the first element child.
7692 switch (cur
->type
) {
7693 case XML_ELEMENT_NODE
:
7694 case XML_DOCUMENT_FRAG_NODE
:
7695 case XML_ENTITY_REF_NODE
: /* URGENT TODO: entify-refs as well? */
7696 case XML_ENTITY_NODE
:
7697 cur
= cur
->children
;
7699 if (cur
->type
== XML_ELEMENT_NODE
)
7703 } while ((cur
!= NULL
) &&
7704 (cur
->type
!= XML_ELEMENT_NODE
));
7708 case XML_DOCUMENT_NODE
:
7709 case XML_HTML_DOCUMENT_NODE
:
7710 #ifdef LIBXML_DOCB_ENABLED
7711 case XML_DOCB_DOCUMENT_NODE
:
7713 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7720 * Get the next sibling element node.
7722 switch (cur
->type
) {
7723 case XML_ELEMENT_NODE
:
7725 case XML_ENTITY_REF_NODE
:
7726 case XML_ENTITY_NODE
:
7727 case XML_CDATA_SECTION_NODE
:
7729 case XML_COMMENT_NODE
:
7730 case XML_XINCLUDE_END
:
7732 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7736 if (cur
->next
!= NULL
) {
7737 if (cur
->next
->type
== XML_ELEMENT_NODE
)
7742 } while ((cur
!= NULL
) && (cur
->type
!= XML_ELEMENT_NODE
));
7750 * xmlXPathNextDescendantOrSelfElemParent:
7751 * @ctxt: the XPath Parser context
7752 * @cur: the current node in the traversal
7754 * Traversal function for the "descendant-or-self" axis.
7755 * Additionally it returns only nodes which can be parents of
7759 * Returns the next element following that axis
7762 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur
,
7763 xmlNodePtr contextNode
)
7766 if (contextNode
== NULL
)
7768 switch (contextNode
->type
) {
7769 case XML_ELEMENT_NODE
:
7770 case XML_XINCLUDE_START
:
7771 case XML_DOCUMENT_FRAG_NODE
:
7772 case XML_DOCUMENT_NODE
:
7773 #ifdef LIBXML_DOCB_ENABLED
7774 case XML_DOCB_DOCUMENT_NODE
:
7776 case XML_HTML_DOCUMENT_NODE
:
7777 return(contextNode
);
7783 xmlNodePtr start
= cur
;
7785 while (cur
!= NULL
) {
7786 switch (cur
->type
) {
7787 case XML_ELEMENT_NODE
:
7788 /* TODO: OK to have XInclude here? */
7789 case XML_XINCLUDE_START
:
7790 case XML_DOCUMENT_FRAG_NODE
:
7793 if (cur
->children
!= NULL
) {
7794 cur
= cur
->children
;
7798 /* Not sure if we need those here. */
7799 case XML_DOCUMENT_NODE
:
7800 #ifdef LIBXML_DOCB_ENABLED
7801 case XML_DOCB_DOCUMENT_NODE
:
7803 case XML_HTML_DOCUMENT_NODE
:
7806 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7812 if ((cur
== NULL
) || (cur
== contextNode
))
7814 if (cur
->next
!= NULL
) {
7827 * xmlXPathNextDescendant:
7828 * @ctxt: the XPath Parser context
7829 * @cur: the current node in the traversal
7831 * Traversal function for the "descendant" direction
7832 * the descendant axis contains the descendants of the context node in document
7833 * order; a descendant is a child or a child of a child and so on.
7835 * Returns the next element following that axis
7838 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7839 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7841 if (ctxt
->context
->node
== NULL
)
7843 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7844 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7847 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
7848 return(ctxt
->context
->doc
->children
);
7849 return(ctxt
->context
->node
->children
);
7852 if (cur
->type
== XML_NAMESPACE_DECL
)
7854 if (cur
->children
!= NULL
) {
7856 * Do not descend on entities declarations
7858 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
7859 cur
= cur
->children
;
7863 if (cur
->type
!= XML_DTD_NODE
)
7868 if (cur
== ctxt
->context
->node
) return(NULL
);
7870 while (cur
->next
!= NULL
) {
7872 if ((cur
->type
!= XML_ENTITY_DECL
) &&
7873 (cur
->type
!= XML_DTD_NODE
))
7879 if (cur
== NULL
) break;
7880 if (cur
== ctxt
->context
->node
) return(NULL
);
7881 if (cur
->next
!= NULL
) {
7885 } while (cur
!= NULL
);
7890 * xmlXPathNextDescendantOrSelf:
7891 * @ctxt: the XPath Parser context
7892 * @cur: the current node in the traversal
7894 * Traversal function for the "descendant-or-self" direction
7895 * the descendant-or-self axis contains the context node and the descendants
7896 * of the context node in document order; thus the context node is the first
7897 * node on the axis, and the first child of the context node is the second node
7900 * Returns the next element following that axis
7903 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7904 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7906 return(ctxt
->context
->node
);
7908 if (ctxt
->context
->node
== NULL
)
7910 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7911 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7914 return(xmlXPathNextDescendant(ctxt
, cur
));
7918 * xmlXPathNextParent:
7919 * @ctxt: the XPath Parser context
7920 * @cur: the current node in the traversal
7922 * Traversal function for the "parent" direction
7923 * The parent axis contains the parent of the context node, if there is one.
7925 * Returns the next element following that axis
7928 xmlXPathNextParent(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7929 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7931 * the parent of an attribute or namespace node is the element
7932 * to which the attribute or namespace node is attached
7933 * Namespace handling !!!
7936 if (ctxt
->context
->node
== NULL
) return(NULL
);
7937 switch (ctxt
->context
->node
->type
) {
7938 case XML_ELEMENT_NODE
:
7940 case XML_CDATA_SECTION_NODE
:
7941 case XML_ENTITY_REF_NODE
:
7942 case XML_ENTITY_NODE
:
7944 case XML_COMMENT_NODE
:
7945 case XML_NOTATION_NODE
:
7947 case XML_ELEMENT_DECL
:
7948 case XML_ATTRIBUTE_DECL
:
7949 case XML_XINCLUDE_START
:
7950 case XML_XINCLUDE_END
:
7951 case XML_ENTITY_DECL
:
7952 if (ctxt
->context
->node
->parent
== NULL
)
7953 return((xmlNodePtr
) ctxt
->context
->doc
);
7954 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
7955 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
7956 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
7957 BAD_CAST
"fake node libxslt"))))
7959 return(ctxt
->context
->node
->parent
);
7960 case XML_ATTRIBUTE_NODE
: {
7961 xmlAttrPtr att
= (xmlAttrPtr
) ctxt
->context
->node
;
7963 return(att
->parent
);
7965 case XML_DOCUMENT_NODE
:
7966 case XML_DOCUMENT_TYPE_NODE
:
7967 case XML_DOCUMENT_FRAG_NODE
:
7968 case XML_HTML_DOCUMENT_NODE
:
7969 #ifdef LIBXML_DOCB_ENABLED
7970 case XML_DOCB_DOCUMENT_NODE
:
7973 case XML_NAMESPACE_DECL
: {
7974 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
7976 if ((ns
->next
!= NULL
) &&
7977 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
7978 return((xmlNodePtr
) ns
->next
);
7987 * xmlXPathNextAncestor:
7988 * @ctxt: the XPath Parser context
7989 * @cur: the current node in the traversal
7991 * Traversal function for the "ancestor" direction
7992 * the ancestor axis contains the ancestors of the context node; the ancestors
7993 * of the context node consist of the parent of context node and the parent's
7994 * parent and so on; the nodes are ordered in reverse document order; thus the
7995 * parent is the first node on the axis, and the parent's parent is the second
7998 * Returns the next element following that axis
8001 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8002 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8004 * the parent of an attribute or namespace node is the element
8005 * to which the attribute or namespace node is attached
8009 if (ctxt
->context
->node
== NULL
) return(NULL
);
8010 switch (ctxt
->context
->node
->type
) {
8011 case XML_ELEMENT_NODE
:
8013 case XML_CDATA_SECTION_NODE
:
8014 case XML_ENTITY_REF_NODE
:
8015 case XML_ENTITY_NODE
:
8017 case XML_COMMENT_NODE
:
8019 case XML_ELEMENT_DECL
:
8020 case XML_ATTRIBUTE_DECL
:
8021 case XML_ENTITY_DECL
:
8022 case XML_NOTATION_NODE
:
8023 case XML_XINCLUDE_START
:
8024 case XML_XINCLUDE_END
:
8025 if (ctxt
->context
->node
->parent
== NULL
)
8026 return((xmlNodePtr
) ctxt
->context
->doc
);
8027 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
8028 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
8029 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
8030 BAD_CAST
"fake node libxslt"))))
8032 return(ctxt
->context
->node
->parent
);
8033 case XML_ATTRIBUTE_NODE
: {
8034 xmlAttrPtr tmp
= (xmlAttrPtr
) ctxt
->context
->node
;
8036 return(tmp
->parent
);
8038 case XML_DOCUMENT_NODE
:
8039 case XML_DOCUMENT_TYPE_NODE
:
8040 case XML_DOCUMENT_FRAG_NODE
:
8041 case XML_HTML_DOCUMENT_NODE
:
8042 #ifdef LIBXML_DOCB_ENABLED
8043 case XML_DOCB_DOCUMENT_NODE
:
8046 case XML_NAMESPACE_DECL
: {
8047 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8049 if ((ns
->next
!= NULL
) &&
8050 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8051 return((xmlNodePtr
) ns
->next
);
8052 /* Bad, how did that namespace end up here ? */
8058 if (cur
== ctxt
->context
->doc
->children
)
8059 return((xmlNodePtr
) ctxt
->context
->doc
);
8060 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8062 switch (cur
->type
) {
8063 case XML_ELEMENT_NODE
:
8065 case XML_CDATA_SECTION_NODE
:
8066 case XML_ENTITY_REF_NODE
:
8067 case XML_ENTITY_NODE
:
8069 case XML_COMMENT_NODE
:
8070 case XML_NOTATION_NODE
:
8072 case XML_ELEMENT_DECL
:
8073 case XML_ATTRIBUTE_DECL
:
8074 case XML_ENTITY_DECL
:
8075 case XML_XINCLUDE_START
:
8076 case XML_XINCLUDE_END
:
8077 if (cur
->parent
== NULL
)
8079 if ((cur
->parent
->type
== XML_ELEMENT_NODE
) &&
8080 ((cur
->parent
->name
[0] == ' ') ||
8081 (xmlStrEqual(cur
->parent
->name
,
8082 BAD_CAST
"fake node libxslt"))))
8084 return(cur
->parent
);
8085 case XML_ATTRIBUTE_NODE
: {
8086 xmlAttrPtr att
= (xmlAttrPtr
) cur
;
8088 return(att
->parent
);
8090 case XML_NAMESPACE_DECL
: {
8091 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8093 if ((ns
->next
!= NULL
) &&
8094 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8095 return((xmlNodePtr
) ns
->next
);
8096 /* Bad, how did that namespace end up here ? */
8099 case XML_DOCUMENT_NODE
:
8100 case XML_DOCUMENT_TYPE_NODE
:
8101 case XML_DOCUMENT_FRAG_NODE
:
8102 case XML_HTML_DOCUMENT_NODE
:
8103 #ifdef LIBXML_DOCB_ENABLED
8104 case XML_DOCB_DOCUMENT_NODE
:
8112 * xmlXPathNextAncestorOrSelf:
8113 * @ctxt: the XPath Parser context
8114 * @cur: the current node in the traversal
8116 * Traversal function for the "ancestor-or-self" direction
8117 * he ancestor-or-self axis contains the context node and ancestors of
8118 * the context node in reverse document order; thus the context node is
8119 * the first node on the axis, and the context node's parent the second;
8120 * parent here is defined the same as with the parent axis.
8122 * Returns the next element following that axis
8125 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8126 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8128 return(ctxt
->context
->node
);
8129 return(xmlXPathNextAncestor(ctxt
, cur
));
8133 * xmlXPathNextFollowingSibling:
8134 * @ctxt: the XPath Parser context
8135 * @cur: the current node in the traversal
8137 * Traversal function for the "following-sibling" direction
8138 * The following-sibling axis contains the following siblings of the context
8139 * node in document order.
8141 * Returns the next element following that axis
8144 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8145 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8146 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8147 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8149 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8152 return(ctxt
->context
->node
->next
);
8157 * xmlXPathNextPrecedingSibling:
8158 * @ctxt: the XPath Parser context
8159 * @cur: the current node in the traversal
8161 * Traversal function for the "preceding-sibling" direction
8162 * The preceding-sibling axis contains the preceding siblings of the context
8163 * node in reverse document order; the first preceding sibling is first on the
8164 * axis; the sibling preceding that node is the second on the axis and so on.
8166 * Returns the next element following that axis
8169 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8170 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8171 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8172 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8174 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8177 return(ctxt
->context
->node
->prev
);
8178 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
)) {
8181 return(ctxt
->context
->node
->prev
);
8187 * xmlXPathNextFollowing:
8188 * @ctxt: the XPath Parser context
8189 * @cur: the current node in the traversal
8191 * Traversal function for the "following" direction
8192 * The following axis contains all nodes in the same document as the context
8193 * node that are after the context node in document order, excluding any
8194 * descendants and excluding attribute nodes and namespace nodes; the nodes
8195 * are ordered in document order
8197 * Returns the next element following that axis
8200 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8201 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8202 if ((cur
!= NULL
) && (cur
->type
!= XML_ATTRIBUTE_NODE
) &&
8203 (cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->children
!= NULL
))
8204 return(cur
->children
);
8207 cur
= ctxt
->context
->node
;
8208 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8210 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8211 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8213 if ((ns
->next
== NULL
) ||
8214 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8216 cur
= (xmlNodePtr
) ns
->next
;
8219 if (cur
== NULL
) return(NULL
) ; /* ERROR */
8220 if (cur
->next
!= NULL
) return(cur
->next
) ;
8223 if (cur
== NULL
) break;
8224 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
) return(NULL
);
8225 if (cur
->next
!= NULL
) return(cur
->next
);
8226 } while (cur
!= NULL
);
8231 * xmlXPathIsAncestor:
8232 * @ancestor: the ancestor node
8233 * @node: the current node
8235 * Check that @ancestor is a @node's ancestor
8237 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8240 xmlXPathIsAncestor(xmlNodePtr ancestor
, xmlNodePtr node
) {
8241 if ((ancestor
== NULL
) || (node
== NULL
)) return(0);
8242 if (node
->type
== XML_NAMESPACE_DECL
)
8244 if (ancestor
->type
== XML_NAMESPACE_DECL
)
8246 /* nodes need to be in the same document */
8247 if (ancestor
->doc
!= node
->doc
) return(0);
8248 /* avoid searching if ancestor or node is the root node */
8249 if (ancestor
== (xmlNodePtr
) node
->doc
) return(1);
8250 if (node
== (xmlNodePtr
) ancestor
->doc
) return(0);
8251 while (node
->parent
!= NULL
) {
8252 if (node
->parent
== ancestor
)
8254 node
= node
->parent
;
8260 * xmlXPathNextPreceding:
8261 * @ctxt: the XPath Parser context
8262 * @cur: the current node in the traversal
8264 * Traversal function for the "preceding" direction
8265 * the preceding axis contains all nodes in the same document as the context
8266 * node that are before the context node in document order, excluding any
8267 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8268 * ordered in reverse document order
8270 * Returns the next element following that axis
8273 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
)
8275 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8277 cur
= ctxt
->context
->node
;
8278 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8280 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8281 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8283 if ((ns
->next
== NULL
) ||
8284 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8286 cur
= (xmlNodePtr
) ns
->next
;
8289 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
8291 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8294 if (cur
->prev
!= NULL
) {
8295 for (cur
= cur
->prev
; cur
->last
!= NULL
; cur
= cur
->last
) ;
8302 if (cur
== ctxt
->context
->doc
->children
)
8304 } while (xmlXPathIsAncestor(cur
, ctxt
->context
->node
));
8309 * xmlXPathNextPrecedingInternal:
8310 * @ctxt: the XPath Parser context
8311 * @cur: the current node in the traversal
8313 * Traversal function for the "preceding" direction
8314 * the preceding axis contains all nodes in the same document as the context
8315 * node that are before the context node in document order, excluding any
8316 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8317 * ordered in reverse document order
8318 * This is a faster implementation but internal only since it requires a
8319 * state kept in the parser context: ctxt->ancestor.
8321 * Returns the next element following that axis
8324 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt
,
8327 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8329 cur
= ctxt
->context
->node
;
8332 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8334 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8335 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8337 if ((ns
->next
== NULL
) ||
8338 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8340 cur
= (xmlNodePtr
) ns
->next
;
8342 ctxt
->ancestor
= cur
->parent
;
8344 if (cur
->type
== XML_NAMESPACE_DECL
)
8346 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8348 while (cur
->prev
== NULL
) {
8352 if (cur
== ctxt
->context
->doc
->children
)
8354 if (cur
!= ctxt
->ancestor
)
8356 ctxt
->ancestor
= cur
->parent
;
8359 while (cur
->last
!= NULL
)
8365 * xmlXPathNextNamespace:
8366 * @ctxt: the XPath Parser context
8367 * @cur: the current attribute in the traversal
8369 * Traversal function for the "namespace" direction
8370 * the namespace axis contains the namespace nodes of the context node;
8371 * the order of nodes on this axis is implementation-defined; the axis will
8372 * be empty unless the context node is an element
8374 * We keep the XML namespace node at the end of the list.
8376 * Returns the next element following that axis
8379 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8380 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8381 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
) return(NULL
);
8383 if (ctxt
->context
->tmpNsList
!= NULL
)
8384 xmlFree(ctxt
->context
->tmpNsList
);
8385 ctxt
->context
->tmpNsList
=
8386 xmlGetNsList(ctxt
->context
->doc
, ctxt
->context
->node
);
8387 ctxt
->context
->tmpNsNr
= 0;
8388 if (ctxt
->context
->tmpNsList
!= NULL
) {
8389 while (ctxt
->context
->tmpNsList
[ctxt
->context
->tmpNsNr
] != NULL
) {
8390 ctxt
->context
->tmpNsNr
++;
8393 return((xmlNodePtr
) xmlXPathXMLNamespace
);
8395 if (ctxt
->context
->tmpNsNr
> 0) {
8396 return (xmlNodePtr
)ctxt
->context
->tmpNsList
[--ctxt
->context
->tmpNsNr
];
8398 if (ctxt
->context
->tmpNsList
!= NULL
)
8399 xmlFree(ctxt
->context
->tmpNsList
);
8400 ctxt
->context
->tmpNsList
= NULL
;
8406 * xmlXPathNextAttribute:
8407 * @ctxt: the XPath Parser context
8408 * @cur: the current attribute in the traversal
8410 * Traversal function for the "attribute" direction
8411 * TODO: support DTD inherited default attributes
8413 * Returns the next element following that axis
8416 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8417 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8418 if (ctxt
->context
->node
== NULL
)
8420 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
)
8423 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
8425 return((xmlNodePtr
)ctxt
->context
->node
->properties
);
8427 return((xmlNodePtr
)cur
->next
);
8430 /************************************************************************
8432 * NodeTest Functions *
8434 ************************************************************************/
8436 #define IS_FUNCTION 200
8439 /************************************************************************
8441 * Implicit tree core function library *
8443 ************************************************************************/
8447 * @ctxt: the XPath Parser context
8449 * Initialize the context to the root of the document
8452 xmlXPathRoot(xmlXPathParserContextPtr ctxt
) {
8453 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8455 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8456 (xmlNodePtr
) ctxt
->context
->doc
));
8459 /************************************************************************
8461 * The explicit core function library *
8462 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8464 ************************************************************************/
8468 * xmlXPathLastFunction:
8469 * @ctxt: the XPath Parser context
8470 * @nargs: the number of arguments
8472 * Implement the last() XPath function
8474 * The last function returns the number of nodes in the context node list.
8477 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8479 if (ctxt
->context
->contextSize
>= 0) {
8481 xmlXPathCacheNewFloat(ctxt
->context
,
8482 (double) ctxt
->context
->contextSize
));
8484 xmlGenericError(xmlGenericErrorContext
,
8485 "last() : %d\n", ctxt
->context
->contextSize
);
8488 XP_ERROR(XPATH_INVALID_CTXT_SIZE
);
8493 * xmlXPathPositionFunction:
8494 * @ctxt: the XPath Parser context
8495 * @nargs: the number of arguments
8497 * Implement the position() XPath function
8499 * The position function returns the position of the context node in the
8500 * context node list. The first position is 1, and so the last position
8501 * will be equal to last().
8504 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8506 if (ctxt
->context
->proximityPosition
>= 0) {
8508 xmlXPathCacheNewFloat(ctxt
->context
,
8509 (double) ctxt
->context
->proximityPosition
));
8511 xmlGenericError(xmlGenericErrorContext
, "position() : %d\n",
8512 ctxt
->context
->proximityPosition
);
8515 XP_ERROR(XPATH_INVALID_CTXT_POSITION
);
8520 * xmlXPathCountFunction:
8521 * @ctxt: the XPath Parser context
8522 * @nargs: the number of arguments
8524 * Implement the count() XPath function
8525 * number count(node-set)
8528 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8529 xmlXPathObjectPtr cur
;
8532 if ((ctxt
->value
== NULL
) ||
8533 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8534 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8535 XP_ERROR(XPATH_INVALID_TYPE
);
8536 cur
= valuePop(ctxt
);
8538 if ((cur
== NULL
) || (cur
->nodesetval
== NULL
))
8539 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8541 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8542 (double) cur
->nodesetval
->nodeNr
));
8543 xmlXPathReleaseObject(ctxt
->context
, cur
);
8547 * xmlXPathGetElementsByIds:
8548 * @doc: the document
8549 * @ids: a whitespace separated list of IDs
8551 * Selects elements by their unique ID.
8553 * Returns a node-set of selected elements.
8555 static xmlNodeSetPtr
8556 xmlXPathGetElementsByIds (xmlDocPtr doc
, const xmlChar
*ids
) {
8558 const xmlChar
*cur
= ids
;
8561 xmlNodePtr elem
= NULL
;
8563 if (ids
== NULL
) return(NULL
);
8565 ret
= xmlXPathNodeSetCreate(NULL
);
8569 while (IS_BLANK_CH(*cur
)) cur
++;
8571 while ((!IS_BLANK_CH(*cur
)) && (*cur
!= 0))
8574 ID
= xmlStrndup(ids
, cur
- ids
);
8577 * We used to check the fact that the value passed
8578 * was an NCName, but this generated much troubles for
8579 * me and Aleksey Sanin, people blatantly violated that
8580 * constraint, like Visa3D spec.
8581 * if (xmlValidateNCName(ID, 1) == 0)
8583 attr
= xmlGetID(doc
, ID
);
8585 if (attr
->type
== XML_ATTRIBUTE_NODE
)
8586 elem
= attr
->parent
;
8587 else if (attr
->type
== XML_ELEMENT_NODE
)
8588 elem
= (xmlNodePtr
) attr
;
8591 /* TODO: Check memory error. */
8593 xmlXPathNodeSetAdd(ret
, elem
);
8598 while (IS_BLANK_CH(*cur
)) cur
++;
8605 * xmlXPathIdFunction:
8606 * @ctxt: the XPath Parser context
8607 * @nargs: the number of arguments
8609 * Implement the id() XPath function
8610 * node-set id(object)
8611 * The id function selects elements by their unique ID
8612 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8613 * then the result is the union of the result of applying id to the
8614 * string value of each of the nodes in the argument node-set. When the
8615 * argument to id is of any other type, the argument is converted to a
8616 * string as if by a call to the string function; the string is split
8617 * into a whitespace-separated list of tokens (whitespace is any sequence
8618 * of characters matching the production S); the result is a node-set
8619 * containing the elements in the same document as the context node that
8620 * have a unique ID equal to any of the tokens in the list.
8623 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8626 xmlXPathObjectPtr obj
;
8629 obj
= valuePop(ctxt
);
8630 if (obj
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8631 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
8635 /* TODO: Check memory error. */
8636 ret
= xmlXPathNodeSetCreate(NULL
);
8638 if (obj
->nodesetval
!= NULL
) {
8639 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
8641 xmlXPathCastNodeToString(obj
->nodesetval
->nodeTab
[i
]);
8642 ns
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, tokens
);
8643 /* TODO: Check memory error. */
8644 ret
= xmlXPathNodeSetMerge(ret
, ns
);
8645 xmlXPathFreeNodeSet(ns
);
8650 xmlXPathReleaseObject(ctxt
->context
, obj
);
8651 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8654 obj
= xmlXPathCacheConvertString(ctxt
->context
, obj
);
8655 if (obj
== NULL
) return;
8656 ret
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, obj
->stringval
);
8657 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8658 xmlXPathReleaseObject(ctxt
->context
, obj
);
8663 * xmlXPathLocalNameFunction:
8664 * @ctxt: the XPath Parser context
8665 * @nargs: the number of arguments
8667 * Implement the local-name() XPath function
8668 * string local-name(node-set?)
8669 * The local-name function returns a string containing the local part
8670 * of the name of the node in the argument node-set that is first in
8671 * document order. If the node-set is empty or the first node has no
8672 * name, an empty string is returned. If the argument is omitted it
8673 * defaults to the context node.
8676 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8677 xmlXPathObjectPtr cur
;
8679 if (ctxt
== NULL
) return;
8682 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8683 ctxt
->context
->node
));
8688 if ((ctxt
->value
== NULL
) ||
8689 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8690 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8691 XP_ERROR(XPATH_INVALID_TYPE
);
8692 cur
= valuePop(ctxt
);
8694 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8695 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8697 int i
= 0; /* Should be first in document order !!!!! */
8698 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8699 case XML_ELEMENT_NODE
:
8700 case XML_ATTRIBUTE_NODE
:
8702 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8703 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8706 xmlXPathCacheNewString(ctxt
->context
,
8707 cur
->nodesetval
->nodeTab
[i
]->name
));
8709 case XML_NAMESPACE_DECL
:
8710 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8711 ((xmlNsPtr
)cur
->nodesetval
->nodeTab
[i
])->prefix
));
8714 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8717 xmlXPathReleaseObject(ctxt
->context
, cur
);
8721 * xmlXPathNamespaceURIFunction:
8722 * @ctxt: the XPath Parser context
8723 * @nargs: the number of arguments
8725 * Implement the namespace-uri() XPath function
8726 * string namespace-uri(node-set?)
8727 * The namespace-uri function returns a string containing the
8728 * namespace URI of the expanded name of the node in the argument
8729 * node-set that is first in document order. If the node-set is empty,
8730 * the first node has no name, or the expanded name has no namespace
8731 * URI, an empty string is returned. If the argument is omitted it
8732 * defaults to the context node.
8735 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8736 xmlXPathObjectPtr cur
;
8738 if (ctxt
== NULL
) return;
8741 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8742 ctxt
->context
->node
));
8746 if ((ctxt
->value
== NULL
) ||
8747 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8748 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8749 XP_ERROR(XPATH_INVALID_TYPE
);
8750 cur
= valuePop(ctxt
);
8752 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8753 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8755 int i
= 0; /* Should be first in document order !!!!! */
8756 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8757 case XML_ELEMENT_NODE
:
8758 case XML_ATTRIBUTE_NODE
:
8759 if (cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
)
8760 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8762 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8763 cur
->nodesetval
->nodeTab
[i
]->ns
->href
));
8766 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8769 xmlXPathReleaseObject(ctxt
->context
, cur
);
8773 * xmlXPathNameFunction:
8774 * @ctxt: the XPath Parser context
8775 * @nargs: the number of arguments
8777 * Implement the name() XPath function
8778 * string name(node-set?)
8779 * The name function returns a string containing a QName representing
8780 * the name of the node in the argument node-set that is first in document
8781 * order. The QName must represent the name with respect to the namespace
8782 * declarations in effect on the node whose name is being represented.
8783 * Typically, this will be the form in which the name occurred in the XML
8784 * source. This need not be the case if there are namespace declarations
8785 * in effect on the node that associate multiple prefixes with the same
8786 * namespace. However, an implementation may include information about
8787 * the original prefix in its representation of nodes; in this case, an
8788 * implementation can ensure that the returned string is always the same
8789 * as the QName used in the XML source. If the argument it omitted it
8790 * defaults to the context node.
8791 * Libxml keep the original prefix so the "real qualified name" used is
8795 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
8797 xmlXPathObjectPtr cur
;
8800 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8801 ctxt
->context
->node
));
8806 if ((ctxt
->value
== NULL
) ||
8807 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8808 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8809 XP_ERROR(XPATH_INVALID_TYPE
);
8810 cur
= valuePop(ctxt
);
8812 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8813 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8815 int i
= 0; /* Should be first in document order !!!!! */
8817 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8818 case XML_ELEMENT_NODE
:
8819 case XML_ATTRIBUTE_NODE
:
8820 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8822 xmlXPathCacheNewCString(ctxt
->context
, ""));
8823 else if ((cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
) ||
8824 (cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
== NULL
)) {
8826 xmlXPathCacheNewString(ctxt
->context
,
8827 cur
->nodesetval
->nodeTab
[i
]->name
));
8831 fullname
= xmlBuildQName(cur
->nodesetval
->nodeTab
[i
]->name
,
8832 cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
,
8834 if (fullname
== cur
->nodesetval
->nodeTab
[i
]->name
)
8835 fullname
= xmlStrdup(cur
->nodesetval
->nodeTab
[i
]->name
);
8836 if (fullname
== NULL
) {
8837 XP_ERROR(XPATH_MEMORY_ERROR
);
8839 valuePush(ctxt
, xmlXPathCacheWrapString(
8840 ctxt
->context
, fullname
));
8844 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8845 cur
->nodesetval
->nodeTab
[i
]));
8846 xmlXPathLocalNameFunction(ctxt
, 1);
8849 xmlXPathReleaseObject(ctxt
->context
, cur
);
8854 * xmlXPathStringFunction:
8855 * @ctxt: the XPath Parser context
8856 * @nargs: the number of arguments
8858 * Implement the string() XPath function
8859 * string string(object?)
8860 * The string function converts an object to a string as follows:
8861 * - A node-set is converted to a string by returning the value of
8862 * the node in the node-set that is first in document order.
8863 * If the node-set is empty, an empty string is returned.
8864 * - A number is converted to a string as follows
8865 * + NaN is converted to the string NaN
8866 * + positive zero is converted to the string 0
8867 * + negative zero is converted to the string 0
8868 * + positive infinity is converted to the string Infinity
8869 * + negative infinity is converted to the string -Infinity
8870 * + if the number is an integer, the number is represented in
8871 * decimal form as a Number with no decimal point and no leading
8872 * zeros, preceded by a minus sign (-) if the number is negative
8873 * + otherwise, the number is represented in decimal form as a
8874 * Number including a decimal point with at least one digit
8875 * before the decimal point and at least one digit after the
8876 * decimal point, preceded by a minus sign (-) if the number
8877 * is negative; there must be no leading zeros before the decimal
8878 * point apart possibly from the one required digit immediately
8879 * before the decimal point; beyond the one required digit
8880 * after the decimal point there must be as many, but only as
8881 * many, more digits as are needed to uniquely distinguish the
8882 * number from all other IEEE 754 numeric values.
8883 * - The boolean false value is converted to the string false.
8884 * The boolean true value is converted to the string true.
8886 * If the argument is omitted, it defaults to a node-set with the
8887 * context node as its only member.
8890 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8891 xmlXPathObjectPtr cur
;
8893 if (ctxt
== NULL
) return;
8896 xmlXPathCacheWrapString(ctxt
->context
,
8897 xmlXPathCastNodeToString(ctxt
->context
->node
)));
8902 cur
= valuePop(ctxt
);
8903 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8904 valuePush(ctxt
, xmlXPathCacheConvertString(ctxt
->context
, cur
));
8908 * xmlXPathStringLengthFunction:
8909 * @ctxt: the XPath Parser context
8910 * @nargs: the number of arguments
8912 * Implement the string-length() XPath function
8913 * number string-length(string?)
8914 * The string-length returns the number of characters in the string
8915 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8916 * the context node converted to a string, in other words the value
8917 * of the context node.
8920 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8921 xmlXPathObjectPtr cur
;
8924 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8926 if (ctxt
->context
->node
== NULL
) {
8927 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0));
8931 content
= xmlXPathCastNodeToString(ctxt
->context
->node
);
8932 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8933 xmlUTF8Strlen(content
)));
8940 CHECK_TYPE(XPATH_STRING
);
8941 cur
= valuePop(ctxt
);
8942 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8943 xmlUTF8Strlen(cur
->stringval
)));
8944 xmlXPathReleaseObject(ctxt
->context
, cur
);
8948 * xmlXPathConcatFunction:
8949 * @ctxt: the XPath Parser context
8950 * @nargs: the number of arguments
8952 * Implement the concat() XPath function
8953 * string concat(string, string, string*)
8954 * The concat function returns the concatenation of its arguments.
8957 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8958 xmlXPathObjectPtr cur
, newobj
;
8961 if (ctxt
== NULL
) return;
8967 cur
= valuePop(ctxt
);
8968 if ((cur
== NULL
) || (cur
->type
!= XPATH_STRING
)) {
8969 xmlXPathReleaseObject(ctxt
->context
, cur
);
8976 newobj
= valuePop(ctxt
);
8977 if ((newobj
== NULL
) || (newobj
->type
!= XPATH_STRING
)) {
8978 xmlXPathReleaseObject(ctxt
->context
, newobj
);
8979 xmlXPathReleaseObject(ctxt
->context
, cur
);
8980 XP_ERROR(XPATH_INVALID_TYPE
);
8982 tmp
= xmlStrcat(newobj
->stringval
, cur
->stringval
);
8983 newobj
->stringval
= cur
->stringval
;
8984 cur
->stringval
= tmp
;
8985 xmlXPathReleaseObject(ctxt
->context
, newobj
);
8988 valuePush(ctxt
, cur
);
8992 * xmlXPathContainsFunction:
8993 * @ctxt: the XPath Parser context
8994 * @nargs: the number of arguments
8996 * Implement the contains() XPath function
8997 * boolean contains(string, string)
8998 * The contains function returns true if the first argument string
8999 * contains the second argument string, and otherwise returns false.
9002 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9003 xmlXPathObjectPtr hay
, needle
;
9007 CHECK_TYPE(XPATH_STRING
);
9008 needle
= valuePop(ctxt
);
9010 hay
= valuePop(ctxt
);
9012 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9013 xmlXPathReleaseObject(ctxt
->context
, hay
);
9014 xmlXPathReleaseObject(ctxt
->context
, needle
);
9015 XP_ERROR(XPATH_INVALID_TYPE
);
9017 if (xmlStrstr(hay
->stringval
, needle
->stringval
))
9018 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9020 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9021 xmlXPathReleaseObject(ctxt
->context
, hay
);
9022 xmlXPathReleaseObject(ctxt
->context
, needle
);
9026 * xmlXPathStartsWithFunction:
9027 * @ctxt: the XPath Parser context
9028 * @nargs: the number of arguments
9030 * Implement the starts-with() XPath function
9031 * boolean starts-with(string, string)
9032 * The starts-with function returns true if the first argument string
9033 * starts with the second argument string, and otherwise returns false.
9036 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9037 xmlXPathObjectPtr hay
, needle
;
9042 CHECK_TYPE(XPATH_STRING
);
9043 needle
= valuePop(ctxt
);
9045 hay
= valuePop(ctxt
);
9047 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9048 xmlXPathReleaseObject(ctxt
->context
, hay
);
9049 xmlXPathReleaseObject(ctxt
->context
, needle
);
9050 XP_ERROR(XPATH_INVALID_TYPE
);
9052 n
= xmlStrlen(needle
->stringval
);
9053 if (xmlStrncmp(hay
->stringval
, needle
->stringval
, n
))
9054 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9056 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9057 xmlXPathReleaseObject(ctxt
->context
, hay
);
9058 xmlXPathReleaseObject(ctxt
->context
, needle
);
9062 * xmlXPathSubstringFunction:
9063 * @ctxt: the XPath Parser context
9064 * @nargs: the number of arguments
9066 * Implement the substring() XPath function
9067 * string substring(string, number, number?)
9068 * The substring function returns the substring of the first argument
9069 * starting at the position specified in the second argument with
9070 * length specified in the third argument. For example,
9071 * substring("12345",2,3) returns "234". If the third argument is not
9072 * specified, it returns the substring starting at the position specified
9073 * in the second argument and continuing to the end of the string. For
9074 * example, substring("12345",2) returns "2345". More precisely, each
9075 * character in the string (see [3.6 Strings]) is considered to have a
9076 * numeric position: the position of the first character is 1, the position
9077 * of the second character is 2 and so on. The returned substring contains
9078 * those characters for which the position of the character is greater than
9079 * or equal to the second argument and, if the third argument is specified,
9080 * less than the sum of the second and third arguments; the comparisons
9081 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9082 * - substring("12345", 1.5, 2.6) returns "234"
9083 * - substring("12345", 0, 3) returns "12"
9084 * - substring("12345", 0 div 0, 3) returns ""
9085 * - substring("12345", 1, 0 div 0) returns ""
9086 * - substring("12345", -42, 1 div 0) returns "12345"
9087 * - substring("12345", -1 div 0, 1 div 0) returns ""
9090 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9091 xmlXPathObjectPtr str
, start
, len
;
9093 int i
= 1, j
= INT_MAX
;
9102 * take care of possible last (position) argument
9106 CHECK_TYPE(XPATH_NUMBER
);
9107 len
= valuePop(ctxt
);
9109 xmlXPathReleaseObject(ctxt
->context
, len
);
9113 CHECK_TYPE(XPATH_NUMBER
);
9114 start
= valuePop(ctxt
);
9115 in
= start
->floatval
;
9116 xmlXPathReleaseObject(ctxt
->context
, start
);
9118 CHECK_TYPE(XPATH_STRING
);
9119 str
= valuePop(ctxt
);
9121 if (!(in
< INT_MAX
)) { /* Logical NOT to handle NaNs */
9123 } else if (in
>= 1.0) {
9125 if (in
- floor(in
) >= 0.5)
9130 double rin
, rle
, end
;
9133 if (in
- rin
>= 0.5)
9137 if (le
- rle
>= 0.5)
9141 if (!(end
>= 1.0)) { /* Logical NOT to handle NaNs */
9143 } else if (end
< INT_MAX
) {
9149 xmlChar
*ret
= xmlUTF8Strsub(str
->stringval
, i
- 1, j
- i
);
9150 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, ret
));
9153 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
9156 xmlXPathReleaseObject(ctxt
->context
, str
);
9160 * xmlXPathSubstringBeforeFunction:
9161 * @ctxt: the XPath Parser context
9162 * @nargs: the number of arguments
9164 * Implement the substring-before() XPath function
9165 * string substring-before(string, string)
9166 * The substring-before function returns the substring of the first
9167 * argument string that precedes the first occurrence of the second
9168 * argument string in the first argument string, or the empty string
9169 * if the first argument string does not contain the second argument
9170 * string. For example, substring-before("1999/04/01","/") returns 1999.
9173 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9174 xmlXPathObjectPtr str
;
9175 xmlXPathObjectPtr find
;
9177 const xmlChar
*point
;
9182 find
= valuePop(ctxt
);
9184 str
= valuePop(ctxt
);
9186 target
= xmlBufCreate();
9188 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9190 offset
= (int)(point
- str
->stringval
);
9191 xmlBufAdd(target
, str
->stringval
, offset
);
9193 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9194 xmlBufContent(target
)));
9197 xmlXPathReleaseObject(ctxt
->context
, str
);
9198 xmlXPathReleaseObject(ctxt
->context
, find
);
9202 * xmlXPathSubstringAfterFunction:
9203 * @ctxt: the XPath Parser context
9204 * @nargs: the number of arguments
9206 * Implement the substring-after() XPath function
9207 * string substring-after(string, string)
9208 * The substring-after function returns the substring of the first
9209 * argument string that follows the first occurrence of the second
9210 * argument string in the first argument string, or the empty stringi
9211 * if the first argument string does not contain the second argument
9212 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9213 * and substring-after("1999/04/01","19") returns 99/04/01.
9216 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9217 xmlXPathObjectPtr str
;
9218 xmlXPathObjectPtr find
;
9220 const xmlChar
*point
;
9225 find
= valuePop(ctxt
);
9227 str
= valuePop(ctxt
);
9229 target
= xmlBufCreate();
9231 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9233 offset
= (int)(point
- str
->stringval
) + xmlStrlen(find
->stringval
);
9234 xmlBufAdd(target
, &str
->stringval
[offset
],
9235 xmlStrlen(str
->stringval
) - offset
);
9237 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9238 xmlBufContent(target
)));
9241 xmlXPathReleaseObject(ctxt
->context
, str
);
9242 xmlXPathReleaseObject(ctxt
->context
, find
);
9246 * xmlXPathNormalizeFunction:
9247 * @ctxt: the XPath Parser context
9248 * @nargs: the number of arguments
9250 * Implement the normalize-space() XPath function
9251 * string normalize-space(string?)
9252 * The normalize-space function returns the argument string with white
9253 * space normalized by stripping leading and trailing whitespace
9254 * and replacing sequences of whitespace characters by a single
9255 * space. Whitespace characters are the same allowed by the S production
9256 * in XML. If the argument is omitted, it defaults to the context
9257 * node converted to a string, in other words the value of the context node.
9260 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9261 xmlXPathObjectPtr obj
= NULL
;
9262 xmlChar
*source
= NULL
;
9266 if (ctxt
== NULL
) return;
9268 /* Use current context node */
9270 xmlXPathCacheWrapString(ctxt
->context
,
9271 xmlXPathCastNodeToString(ctxt
->context
->node
)));
9277 CHECK_TYPE(XPATH_STRING
);
9278 obj
= valuePop(ctxt
);
9279 source
= obj
->stringval
;
9281 target
= xmlBufCreate();
9282 if (target
&& source
) {
9284 /* Skip leading whitespaces */
9285 while (IS_BLANK_CH(*source
))
9288 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9291 if (IS_BLANK_CH(*source
)) {
9295 xmlBufAdd(target
, &blank
, 1);
9298 xmlBufAdd(target
, source
, 1);
9302 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9303 xmlBufContent(target
)));
9306 xmlXPathReleaseObject(ctxt
->context
, obj
);
9310 * xmlXPathTranslateFunction:
9311 * @ctxt: the XPath Parser context
9312 * @nargs: the number of arguments
9314 * Implement the translate() XPath function
9315 * string translate(string, string, string)
9316 * The translate function returns the first argument string with
9317 * occurrences of characters in the second argument string replaced
9318 * by the character at the corresponding position in the third argument
9319 * string. For example, translate("bar","abc","ABC") returns the string
9320 * BAr. If there is a character in the second argument string with no
9321 * character at a corresponding position in the third argument string
9322 * (because the second argument string is longer than the third argument
9323 * string), then occurrences of that character in the first argument
9324 * string are removed. For example, translate("--aaa--","abc-","ABC")
9325 * returns "AAA". If a character occurs more than once in second
9326 * argument string, then the first occurrence determines the replacement
9327 * character. If the third argument string is longer than the second
9328 * argument string, then excess characters are ignored.
9331 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9332 xmlXPathObjectPtr str
;
9333 xmlXPathObjectPtr from
;
9334 xmlXPathObjectPtr to
;
9338 const xmlChar
*point
;
9344 to
= valuePop(ctxt
);
9346 from
= valuePop(ctxt
);
9348 str
= valuePop(ctxt
);
9350 target
= xmlBufCreate();
9352 max
= xmlUTF8Strlen(to
->stringval
);
9353 for (cptr
= str
->stringval
; (ch
=*cptr
); ) {
9354 offset
= xmlUTF8Strloc(from
->stringval
, cptr
);
9357 point
= xmlUTF8Strpos(to
->stringval
, offset
);
9359 xmlBufAdd(target
, point
, xmlUTF8Strsize(point
, 1));
9362 xmlBufAdd(target
, cptr
, xmlUTF8Strsize(cptr
, 1));
9364 /* Step to next character in input */
9367 /* if not simple ascii, verify proper format */
9368 if ( (ch
& 0xc0) != 0xc0 ) {
9369 xmlGenericError(xmlGenericErrorContext
,
9370 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9371 /* not asserting an XPath error is probably better */
9374 /* then skip over remaining bytes for this char */
9375 while ( (ch
<<= 1) & 0x80 )
9376 if ( (*cptr
++ & 0xc0) != 0x80 ) {
9377 xmlGenericError(xmlGenericErrorContext
,
9378 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9379 /* not asserting an XPath error is probably better */
9382 if (ch
& 0x80) /* must have had error encountered */
9387 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9388 xmlBufContent(target
)));
9390 xmlXPathReleaseObject(ctxt
->context
, str
);
9391 xmlXPathReleaseObject(ctxt
->context
, from
);
9392 xmlXPathReleaseObject(ctxt
->context
, to
);
9396 * xmlXPathBooleanFunction:
9397 * @ctxt: the XPath Parser context
9398 * @nargs: the number of arguments
9400 * Implement the boolean() XPath function
9401 * boolean boolean(object)
9402 * The boolean function converts its argument to a boolean as follows:
9403 * - a number is true if and only if it is neither positive or
9404 * negative zero nor NaN
9405 * - a node-set is true if and only if it is non-empty
9406 * - a string is true if and only if its length is non-zero
9409 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9410 xmlXPathObjectPtr cur
;
9413 cur
= valuePop(ctxt
);
9414 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
9415 cur
= xmlXPathCacheConvertBoolean(ctxt
->context
, cur
);
9416 valuePush(ctxt
, cur
);
9420 * xmlXPathNotFunction:
9421 * @ctxt: the XPath Parser context
9422 * @nargs: the number of arguments
9424 * Implement the not() XPath function
9425 * boolean not(boolean)
9426 * The not function returns true if its argument is false,
9427 * and false otherwise.
9430 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9433 CHECK_TYPE(XPATH_BOOLEAN
);
9434 ctxt
->value
->boolval
= ! ctxt
->value
->boolval
;
9438 * xmlXPathTrueFunction:
9439 * @ctxt: the XPath Parser context
9440 * @nargs: the number of arguments
9442 * Implement the true() XPath function
9446 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9448 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9452 * xmlXPathFalseFunction:
9453 * @ctxt: the XPath Parser context
9454 * @nargs: the number of arguments
9456 * Implement the false() XPath function
9460 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9462 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9466 * xmlXPathLangFunction:
9467 * @ctxt: the XPath Parser context
9468 * @nargs: the number of arguments
9470 * Implement the lang() XPath function
9471 * boolean lang(string)
9472 * The lang function returns true or false depending on whether the
9473 * language of the context node as specified by xml:lang attributes
9474 * is the same as or is a sublanguage of the language specified by
9475 * the argument string. The language of the context node is determined
9476 * by the value of the xml:lang attribute on the context node, or, if
9477 * the context node has no xml:lang attribute, by the value of the
9478 * xml:lang attribute on the nearest ancestor of the context node that
9479 * has an xml:lang attribute. If there is no such attribute, then lang
9480 * returns false. If there is such an attribute, then lang returns
9481 * true if the attribute value is equal to the argument ignoring case,
9482 * or if there is some suffix starting with - such that the attribute
9483 * value is equal to the argument ignoring that suffix of the attribute
9484 * value and ignoring case.
9487 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9488 xmlXPathObjectPtr val
= NULL
;
9489 const xmlChar
*theLang
= NULL
;
9490 const xmlChar
*lang
;
9496 CHECK_TYPE(XPATH_STRING
);
9497 val
= valuePop(ctxt
);
9498 lang
= val
->stringval
;
9499 theLang
= xmlNodeGetLang(ctxt
->context
->node
);
9500 if ((theLang
!= NULL
) && (lang
!= NULL
)) {
9501 for (i
= 0;lang
[i
] != 0;i
++)
9502 if (toupper(lang
[i
]) != toupper(theLang
[i
]))
9504 if ((theLang
[i
] == 0) || (theLang
[i
] == '-'))
9508 if (theLang
!= NULL
)
9509 xmlFree((void *)theLang
);
9511 xmlXPathReleaseObject(ctxt
->context
, val
);
9512 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
9516 * xmlXPathNumberFunction:
9517 * @ctxt: the XPath Parser context
9518 * @nargs: the number of arguments
9520 * Implement the number() XPath function
9521 * number number(object?)
9524 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9525 xmlXPathObjectPtr cur
;
9528 if (ctxt
== NULL
) return;
9530 if (ctxt
->context
->node
== NULL
) {
9531 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0.0));
9533 xmlChar
* content
= xmlNodeGetContent(ctxt
->context
->node
);
9535 res
= xmlXPathStringEvalNumber(content
);
9536 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9543 cur
= valuePop(ctxt
);
9544 valuePush(ctxt
, xmlXPathCacheConvertNumber(ctxt
->context
, cur
));
9548 * xmlXPathSumFunction:
9549 * @ctxt: the XPath Parser context
9550 * @nargs: the number of arguments
9552 * Implement the sum() XPath function
9553 * number sum(node-set)
9554 * The sum function returns the sum of the values of the nodes in
9555 * the argument node-set.
9558 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9559 xmlXPathObjectPtr cur
;
9564 if ((ctxt
->value
== NULL
) ||
9565 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
9566 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
9567 XP_ERROR(XPATH_INVALID_TYPE
);
9568 cur
= valuePop(ctxt
);
9570 if ((cur
->nodesetval
!= NULL
) && (cur
->nodesetval
->nodeNr
!= 0)) {
9571 for (i
= 0; i
< cur
->nodesetval
->nodeNr
; i
++) {
9572 res
+= xmlXPathCastNodeToNumber(cur
->nodesetval
->nodeTab
[i
]);
9575 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9576 xmlXPathReleaseObject(ctxt
->context
, cur
);
9580 * xmlXPathFloorFunction:
9581 * @ctxt: the XPath Parser context
9582 * @nargs: the number of arguments
9584 * Implement the floor() XPath function
9585 * number floor(number)
9586 * The floor function returns the largest (closest to positive infinity)
9587 * number that is not greater than the argument and that is an integer.
9590 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9593 CHECK_TYPE(XPATH_NUMBER
);
9595 ctxt
->value
->floatval
= floor(ctxt
->value
->floatval
);
9599 * xmlXPathCeilingFunction:
9600 * @ctxt: the XPath Parser context
9601 * @nargs: the number of arguments
9603 * Implement the ceiling() XPath function
9604 * number ceiling(number)
9605 * The ceiling function returns the smallest (closest to negative infinity)
9606 * number that is not less than the argument and that is an integer.
9609 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9612 CHECK_TYPE(XPATH_NUMBER
);
9615 /* Work around buggy ceil() function on AIX */
9616 ctxt
->value
->floatval
= copysign(ceil(ctxt
->value
->floatval
), ctxt
->value
->floatval
);
9618 ctxt
->value
->floatval
= ceil(ctxt
->value
->floatval
);
9623 * xmlXPathRoundFunction:
9624 * @ctxt: the XPath Parser context
9625 * @nargs: the number of arguments
9627 * Implement the round() XPath function
9628 * number round(number)
9629 * The round function returns the number that is closest to the
9630 * argument and that is an integer. If there are two such numbers,
9631 * then the one that is closest to positive infinity is returned.
9634 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9639 CHECK_TYPE(XPATH_NUMBER
);
9641 f
= ctxt
->value
->floatval
;
9643 if ((f
>= -0.5) && (f
< 0.5)) {
9644 /* Handles negative zero. */
9645 ctxt
->value
->floatval
*= 0.0;
9648 double rounded
= floor(f
);
9649 if (f
- rounded
>= 0.5)
9651 ctxt
->value
->floatval
= rounded
;
9655 /************************************************************************
9659 ************************************************************************/
9662 * a few forward declarations since we use a recursive call based
9665 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
);
9666 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
);
9667 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
);
9668 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt
);
9669 static xmlChar
* xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
,
9673 * xmlXPathCurrentChar:
9674 * @ctxt: the XPath parser context
9675 * @cur: pointer to the beginning of the char
9676 * @len: pointer to the length of the char read
9678 * The current char value, if using UTF-8 this may actually span multiple
9679 * bytes in the input buffer.
9681 * Returns the current char value and its length
9685 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt
, int *len
) {
9695 * We are supposed to handle UTF8, check it's valid
9696 * From rfc2044: encoding of the Unicode values on UTF-8:
9698 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9699 * 0000 0000-0000 007F 0xxxxxxx
9700 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9701 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9703 * Check for the 0x110000 limit too
9707 if ((cur
[1] & 0xc0) != 0x80)
9708 goto encoding_error
;
9709 if ((c
& 0xe0) == 0xe0) {
9711 if ((cur
[2] & 0xc0) != 0x80)
9712 goto encoding_error
;
9713 if ((c
& 0xf0) == 0xf0) {
9714 if (((c
& 0xf8) != 0xf0) ||
9715 ((cur
[3] & 0xc0) != 0x80))
9716 goto encoding_error
;
9719 val
= (cur
[0] & 0x7) << 18;
9720 val
|= (cur
[1] & 0x3f) << 12;
9721 val
|= (cur
[2] & 0x3f) << 6;
9722 val
|= cur
[3] & 0x3f;
9726 val
= (cur
[0] & 0xf) << 12;
9727 val
|= (cur
[1] & 0x3f) << 6;
9728 val
|= cur
[2] & 0x3f;
9733 val
= (cur
[0] & 0x1f) << 6;
9734 val
|= cur
[1] & 0x3f;
9736 if (!IS_CHAR(val
)) {
9737 XP_ERROR0(XPATH_INVALID_CHAR_ERROR
);
9747 * If we detect an UTF8 error that probably means that the
9748 * input encoding didn't get properly advertised in the
9749 * declaration header. Report the error and switch the encoding
9750 * to ISO-Latin-1 (if you don't like this policy, just declare the
9754 XP_ERROR0(XPATH_ENCODING_ERROR
);
9758 * xmlXPathParseNCName:
9759 * @ctxt: the XPath Parser context
9761 * parse an XML namespace non qualified name.
9763 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9765 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9766 * CombiningChar | Extender
9768 * Returns the namespace name or NULL
9772 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt
) {
9777 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9779 * Accelerator for simple ASCII names
9782 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9783 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9786 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9787 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9788 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9789 (*in
== '_') || (*in
== '.') ||
9792 if ((*in
== ' ') || (*in
== '>') || (*in
== '/') ||
9793 (*in
== '[') || (*in
== ']') || (*in
== ':') ||
9794 (*in
== '@') || (*in
== '*')) {
9795 count
= in
- ctxt
->cur
;
9798 ret
= xmlStrndup(ctxt
->cur
, count
);
9803 return(xmlXPathParseNameComplex(ctxt
, 0));
9808 * xmlXPathParseQName:
9809 * @ctxt: the XPath Parser context
9810 * @prefix: a xmlChar **
9812 * parse an XML qualified name
9814 * [NS 5] QName ::= (Prefix ':')? LocalPart
9816 * [NS 6] Prefix ::= NCName
9818 * [NS 7] LocalPart ::= NCName
9820 * Returns the function returns the local part, and prefix is updated
9821 * to get the Prefix if any.
9825 xmlXPathParseQName(xmlXPathParserContextPtr ctxt
, xmlChar
**prefix
) {
9826 xmlChar
*ret
= NULL
;
9829 ret
= xmlXPathParseNCName(ctxt
);
9830 if (ret
&& CUR
== ':') {
9833 ret
= xmlXPathParseNCName(ctxt
);
9839 * xmlXPathParseName:
9840 * @ctxt: the XPath Parser context
9844 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9845 * CombiningChar | Extender
9847 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9849 * Returns the namespace name or NULL
9853 xmlXPathParseName(xmlXPathParserContextPtr ctxt
) {
9858 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9860 * Accelerator for simple ASCII names
9863 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9864 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9865 (*in
== '_') || (*in
== ':')) {
9867 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9868 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9869 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9870 (*in
== '_') || (*in
== '-') ||
9871 (*in
== ':') || (*in
== '.'))
9873 if ((*in
> 0) && (*in
< 0x80)) {
9874 count
= in
- ctxt
->cur
;
9875 if (count
> XML_MAX_NAME_LENGTH
) {
9877 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9879 ret
= xmlStrndup(ctxt
->cur
, count
);
9884 return(xmlXPathParseNameComplex(ctxt
, 1));
9888 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
, int qualified
) {
9889 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
9894 * Handler for more complex cases
9897 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
9898 (c
== '[') || (c
== ']') || (c
== '@') || /* accelerators */
9899 (c
== '*') || /* accelerators */
9900 (!IS_LETTER(c
) && (c
!= '_') &&
9901 ((!qualified
) || (c
!= ':')))) {
9905 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
9906 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
9907 (c
== '.') || (c
== '-') ||
9908 (c
== '_') || ((qualified
) && (c
== ':')) ||
9909 (IS_COMBINING(c
)) ||
9910 (IS_EXTENDER(c
)))) {
9911 COPY_BUF(l
,buf
,len
,c
);
9914 if (len
>= XML_MAX_NAMELEN
) {
9916 * Okay someone managed to make a huge name, so he's ready to pay
9917 * for the processing speed.
9922 if (len
> XML_MAX_NAME_LENGTH
) {
9923 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9925 buffer
= (xmlChar
*) xmlMallocAtomic(max
* sizeof(xmlChar
));
9926 if (buffer
== NULL
) {
9927 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
9929 memcpy(buffer
, buf
, len
);
9930 while ((IS_LETTER(c
)) || (IS_DIGIT(c
)) || /* test bigname.xml */
9931 (c
== '.') || (c
== '-') ||
9932 (c
== '_') || ((qualified
) && (c
== ':')) ||
9933 (IS_COMBINING(c
)) ||
9935 if (len
+ 10 > max
) {
9937 if (max
> XML_MAX_NAME_LENGTH
) {
9939 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9942 tmp
= (xmlChar
*) xmlRealloc(buffer
,
9943 max
* sizeof(xmlChar
));
9946 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
9950 COPY_BUF(l
,buffer
,len
,c
);
9960 return(xmlStrndup(buf
, len
));
9966 * xmlXPathStringEvalNumber:
9967 * @str: A string to scan
9969 * [30a] Float ::= Number ('e' Digits?)?
9971 * [30] Number ::= Digits ('.' Digits?)?
9973 * [31] Digits ::= [0-9]+
9975 * Compile a Number in the string
9976 * In complement of the Number expression, this function also handles
9977 * negative values : '-' Number.
9979 * Returns the double value.
9982 xmlXPathStringEvalNumber(const xmlChar
*str
) {
9983 const xmlChar
*cur
= str
;
9988 int is_exponent_negative
= 0;
9990 unsigned long tmp
= 0;
9993 if (cur
== NULL
) return(0);
9994 while (IS_BLANK_CH(*cur
)) cur
++;
9995 if ((*cur
!= '.') && ((*cur
< '0') || (*cur
> '9')) && (*cur
!= '-')) {
9996 return(xmlXPathNAN
);
10005 * tmp/temp is a workaround against a gcc compiler bug
10006 * http://veillard.com/gcc.bug
10009 while ((*cur
>= '0') && (*cur
<= '9')) {
10011 tmp
= (*cur
- '0');
10014 temp
= (double) tmp
;
10019 while ((*cur
>= '0') && (*cur
<= '9')) {
10020 ret
= ret
* 10 + (*cur
- '0');
10027 int v
, frac
= 0, max
;
10028 double fraction
= 0;
10031 if (((*cur
< '0') || (*cur
> '9')) && (!ok
)) {
10032 return(xmlXPathNAN
);
10034 while (*cur
== '0') {
10038 max
= frac
+ MAX_FRAC
;
10039 while (((*cur
>= '0') && (*cur
<= '9')) && (frac
< max
)) {
10041 fraction
= fraction
* 10 + v
;
10045 fraction
/= pow(10.0, frac
);
10046 ret
= ret
+ fraction
;
10047 while ((*cur
>= '0') && (*cur
<= '9'))
10050 if ((*cur
== 'e') || (*cur
== 'E')) {
10053 is_exponent_negative
= 1;
10055 } else if (*cur
== '+') {
10058 while ((*cur
>= '0') && (*cur
<= '9')) {
10059 if (exponent
< 1000000)
10060 exponent
= exponent
* 10 + (*cur
- '0');
10064 while (IS_BLANK_CH(*cur
)) cur
++;
10065 if (*cur
!= 0) return(xmlXPathNAN
);
10066 if (isneg
) ret
= -ret
;
10067 if (is_exponent_negative
) exponent
= -exponent
;
10068 ret
*= pow(10.0, (double)exponent
);
10073 * xmlXPathCompNumber:
10074 * @ctxt: the XPath Parser context
10076 * [30] Number ::= Digits ('.' Digits?)?
10078 * [31] Digits ::= [0-9]+
10080 * Compile a Number, then push it on the stack
10084 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt
)
10089 int is_exponent_negative
= 0;
10090 xmlXPathObjectPtr num
;
10092 unsigned long tmp
= 0;
10097 if ((CUR
!= '.') && ((CUR
< '0') || (CUR
> '9'))) {
10098 XP_ERROR(XPATH_NUMBER_ERROR
);
10102 * tmp/temp is a workaround against a gcc compiler bug
10103 * http://veillard.com/gcc.bug
10106 while ((CUR
>= '0') && (CUR
<= '9')) {
10111 temp
= (double) tmp
;
10116 while ((CUR
>= '0') && (CUR
<= '9')) {
10117 ret
= ret
* 10 + (CUR
- '0');
10123 int v
, frac
= 0, max
;
10124 double fraction
= 0;
10127 if (((CUR
< '0') || (CUR
> '9')) && (!ok
)) {
10128 XP_ERROR(XPATH_NUMBER_ERROR
);
10130 while (CUR
== '0') {
10134 max
= frac
+ MAX_FRAC
;
10135 while ((CUR
>= '0') && (CUR
<= '9') && (frac
< max
)) {
10137 fraction
= fraction
* 10 + v
;
10141 fraction
/= pow(10.0, frac
);
10142 ret
= ret
+ fraction
;
10143 while ((CUR
>= '0') && (CUR
<= '9'))
10146 if ((CUR
== 'e') || (CUR
== 'E')) {
10149 is_exponent_negative
= 1;
10151 } else if (CUR
== '+') {
10154 while ((CUR
>= '0') && (CUR
<= '9')) {
10155 if (exponent
< 1000000)
10156 exponent
= exponent
* 10 + (CUR
- '0');
10159 if (is_exponent_negative
)
10160 exponent
= -exponent
;
10161 ret
*= pow(10.0, (double) exponent
);
10163 num
= xmlXPathCacheNewFloat(ctxt
->context
, ret
);
10165 ctxt
->error
= XPATH_MEMORY_ERROR
;
10166 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_NUMBER
, 0, 0, num
,
10168 xmlXPathReleaseObject(ctxt
->context
, num
);
10173 * xmlXPathParseLiteral:
10174 * @ctxt: the XPath Parser context
10178 * [29] Literal ::= '"' [^"]* '"'
10181 * Returns the value found or NULL in case of error
10184 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt
) {
10186 xmlChar
*ret
= NULL
;
10191 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10193 if (!IS_CHAR_CH(CUR
)) {
10194 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10196 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10199 } else if (CUR
== '\'') {
10202 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10204 if (!IS_CHAR_CH(CUR
)) {
10205 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10207 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10211 XP_ERRORNULL(XPATH_START_LITERAL_ERROR
);
10217 * xmlXPathCompLiteral:
10218 * @ctxt: the XPath Parser context
10220 * Parse a Literal and push it on the stack.
10222 * [29] Literal ::= '"' [^"]* '"'
10225 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10228 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt
) {
10230 xmlChar
*ret
= NULL
;
10231 xmlXPathObjectPtr lit
;
10236 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10238 if (!IS_CHAR_CH(CUR
)) {
10239 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10241 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10244 } else if (CUR
== '\'') {
10247 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10249 if (!IS_CHAR_CH(CUR
)) {
10250 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10252 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10256 XP_ERROR(XPATH_START_LITERAL_ERROR
);
10258 if (ret
== NULL
) return;
10259 lit
= xmlXPathCacheNewString(ctxt
->context
, ret
);
10261 ctxt
->error
= XPATH_MEMORY_ERROR
;
10262 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_STRING
, 0, 0, lit
,
10264 xmlXPathReleaseObject(ctxt
->context
, lit
);
10270 * xmlXPathCompVariableReference:
10271 * @ctxt: the XPath Parser context
10273 * Parse a VariableReference, evaluate it and push it on the stack.
10275 * The variable bindings consist of a mapping from variable names
10276 * to variable values. The value of a variable is an object, which can be
10277 * of any of the types that are possible for the value of an expression,
10278 * and may also be of additional types not specified here.
10280 * Early evaluation is possible since:
10281 * The variable bindings [...] used to evaluate a subexpression are
10282 * always the same as those used to evaluate the containing expression.
10284 * [36] VariableReference ::= '$' QName
10287 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt
) {
10293 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10296 name
= xmlXPathParseQName(ctxt
, &prefix
);
10297 if (name
== NULL
) {
10299 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10301 ctxt
->comp
->last
= -1;
10302 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE
, 0, 0, 0, name
, prefix
) == -1) {
10307 if ((ctxt
->context
!= NULL
) && (ctxt
->context
->flags
& XML_XPATH_NOVAR
)) {
10308 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR
);
10313 * xmlXPathIsNodeType:
10314 * @name: a name string
10316 * Is the name given a NodeType one.
10318 * [38] NodeType ::= 'comment'
10320 * | 'processing-instruction'
10323 * Returns 1 if true 0 otherwise
10326 xmlXPathIsNodeType(const xmlChar
*name
) {
10330 if (xmlStrEqual(name
, BAD_CAST
"node"))
10332 if (xmlStrEqual(name
, BAD_CAST
"text"))
10334 if (xmlStrEqual(name
, BAD_CAST
"comment"))
10336 if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
10342 * xmlXPathCompFunctionCall:
10343 * @ctxt: the XPath Parser context
10345 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10346 * [17] Argument ::= Expr
10348 * Compile a function call, the evaluation of all arguments are
10349 * pushed on the stack
10352 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt
) {
10358 name
= xmlXPathParseQName(ctxt
, &prefix
);
10359 if (name
== NULL
) {
10361 XP_ERROR(XPATH_EXPR_ERROR
);
10365 if (prefix
== NULL
)
10366 xmlGenericError(xmlGenericErrorContext
, "Calling function %s\n",
10369 xmlGenericError(xmlGenericErrorContext
, "Calling function %s:%s\n",
10376 XP_ERROR(XPATH_EXPR_ERROR
);
10382 * Optimization for count(): we don't need the node-set to be sorted.
10384 if ((prefix
== NULL
) && (name
[0] == 'c') &&
10385 xmlStrEqual(name
, BAD_CAST
"count"))
10389 ctxt
->comp
->last
= -1;
10392 int op1
= ctxt
->comp
->last
;
10393 ctxt
->comp
->last
= -1;
10394 xmlXPathCompileExpr(ctxt
, sort
);
10395 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
10400 PUSH_BINARY_EXPR(XPATH_OP_ARG
, op1
, ctxt
->comp
->last
, 0, 0);
10402 if (CUR
== ')') break;
10406 XP_ERROR(XPATH_EXPR_ERROR
);
10412 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION
, nbargs
, 0, 0, name
, prefix
) == -1) {
10421 * xmlXPathCompPrimaryExpr:
10422 * @ctxt: the XPath Parser context
10424 * [15] PrimaryExpr ::= VariableReference
10430 * Compile a primary expression.
10433 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt
) {
10435 if (CUR
== '$') xmlXPathCompVariableReference(ctxt
);
10436 else if (CUR
== '(') {
10439 xmlXPathCompileExpr(ctxt
, 1);
10442 XP_ERROR(XPATH_EXPR_ERROR
);
10446 } else if (IS_ASCII_DIGIT(CUR
) || (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10447 xmlXPathCompNumber(ctxt
);
10448 } else if ((CUR
== '\'') || (CUR
== '"')) {
10449 xmlXPathCompLiteral(ctxt
);
10451 xmlXPathCompFunctionCall(ctxt
);
10457 * xmlXPathCompFilterExpr:
10458 * @ctxt: the XPath Parser context
10460 * [20] FilterExpr ::= PrimaryExpr
10461 * | FilterExpr Predicate
10463 * Compile a filter expression.
10464 * Square brackets are used to filter expressions in the same way that
10465 * they are used in location paths. It is an error if the expression to
10466 * be filtered does not evaluate to a node-set. The context node list
10467 * used for evaluating the expression in square brackets is the node-set
10468 * to be filtered listed in document order.
10472 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt
) {
10473 xmlXPathCompPrimaryExpr(ctxt
);
10477 while (CUR
== '[') {
10478 xmlXPathCompPredicate(ctxt
, 1);
10486 * xmlXPathScanName:
10487 * @ctxt: the XPath Parser context
10489 * Trickery: parse an XML name but without consuming the input flow
10490 * Needed to avoid insanity in the parser state.
10492 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10493 * CombiningChar | Extender
10495 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10497 * [6] Names ::= Name (S Name)*
10499 * Returns the Name parsed or NULL
10503 xmlXPathScanName(xmlXPathParserContextPtr ctxt
) {
10506 const xmlChar
*cur
;
10512 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
10513 (!IS_LETTER(c
) && (c
!= '_') &&
10518 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
10519 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
10520 (c
== '.') || (c
== '-') ||
10521 (c
== '_') || (c
== ':') ||
10522 (IS_COMBINING(c
)) ||
10523 (IS_EXTENDER(c
)))) {
10528 ret
= xmlStrndup(cur
, ctxt
->cur
- cur
);
10534 * xmlXPathCompPathExpr:
10535 * @ctxt: the XPath Parser context
10537 * [19] PathExpr ::= LocationPath
10539 * | FilterExpr '/' RelativeLocationPath
10540 * | FilterExpr '//' RelativeLocationPath
10542 * Compile a path expression.
10543 * The / operator and // operators combine an arbitrary expression
10544 * and a relative location path. It is an error if the expression
10545 * does not evaluate to a node-set.
10546 * The / operator does composition in the same way as when / is
10547 * used in a location path. As in location paths, // is short for
10548 * /descendant-or-self::node()/.
10552 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt
) {
10553 int lc
= 1; /* Should we branch to LocationPath ? */
10554 xmlChar
*name
= NULL
; /* we may have to preparse a name to find out */
10557 if ((CUR
== '$') || (CUR
== '(') ||
10558 (IS_ASCII_DIGIT(CUR
)) ||
10559 (CUR
== '\'') || (CUR
== '"') ||
10560 (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10562 } else if (CUR
== '*') {
10563 /* relative or absolute location path */
10565 } else if (CUR
== '/') {
10566 /* relative or absolute location path */
10568 } else if (CUR
== '@') {
10569 /* relative abbreviated attribute location path */
10571 } else if (CUR
== '.') {
10572 /* relative abbreviated attribute location path */
10576 * Problem is finding if we have a name here whether it's:
10578 * - a function call in which case it's followed by '('
10579 * - an axis in which case it's followed by ':'
10581 * We do an a priori analysis here rather than having to
10582 * maintain parsed token content through the recursive function
10583 * calls. This looks uglier but makes the code easier to
10584 * read/write/debug.
10587 name
= xmlXPathScanName(ctxt
);
10588 if ((name
!= NULL
) && (xmlStrstr(name
, (xmlChar
*) "::") != NULL
)) {
10590 xmlGenericError(xmlGenericErrorContext
,
10591 "PathExpr: Axis\n");
10595 } else if (name
!= NULL
) {
10596 int len
=xmlStrlen(name
);
10599 while (NXT(len
) != 0) {
10600 if (NXT(len
) == '/') {
10603 xmlGenericError(xmlGenericErrorContext
,
10604 "PathExpr: AbbrRelLocation\n");
10608 } else if (IS_BLANK_CH(NXT(len
))) {
10609 /* ignore blanks */
10611 } else if (NXT(len
) == ':') {
10613 xmlGenericError(xmlGenericErrorContext
,
10614 "PathExpr: AbbrRelLocation\n");
10618 } else if ((NXT(len
) == '(')) {
10619 /* Node Type or Function */
10620 if (xmlXPathIsNodeType(name
)) {
10622 xmlGenericError(xmlGenericErrorContext
,
10623 "PathExpr: Type search\n");
10626 #ifdef LIBXML_XPTR_ENABLED
10627 } else if (ctxt
->xptr
&&
10628 xmlStrEqual(name
, BAD_CAST
"range-to")) {
10633 xmlGenericError(xmlGenericErrorContext
,
10634 "PathExpr: function call\n");
10639 } else if ((NXT(len
) == '[')) {
10642 xmlGenericError(xmlGenericErrorContext
,
10643 "PathExpr: AbbrRelLocation\n");
10647 } else if ((NXT(len
) == '<') || (NXT(len
) == '>') ||
10648 (NXT(len
) == '=')) {
10657 if (NXT(len
) == 0) {
10659 xmlGenericError(xmlGenericErrorContext
,
10660 "PathExpr: AbbrRelLocation\n");
10667 /* make sure all cases are covered explicitly */
10668 XP_ERROR(XPATH_EXPR_ERROR
);
10674 PUSH_LEAVE_EXPR(XPATH_OP_ROOT
, 0, 0);
10676 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10678 xmlXPathCompLocationPath(ctxt
);
10680 xmlXPathCompFilterExpr(ctxt
);
10682 if ((CUR
== '/') && (NXT(1) == '/')) {
10686 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
10687 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
10689 xmlXPathCompRelativeLocationPath(ctxt
);
10690 } else if (CUR
== '/') {
10691 xmlXPathCompRelativeLocationPath(ctxt
);
10698 * xmlXPathCompUnionExpr:
10699 * @ctxt: the XPath Parser context
10701 * [18] UnionExpr ::= PathExpr
10702 * | UnionExpr '|' PathExpr
10704 * Compile an union expression.
10708 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt
) {
10709 xmlXPathCompPathExpr(ctxt
);
10712 while (CUR
== '|') {
10713 int op1
= ctxt
->comp
->last
;
10714 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10718 xmlXPathCompPathExpr(ctxt
);
10720 PUSH_BINARY_EXPR(XPATH_OP_UNION
, op1
, ctxt
->comp
->last
, 0, 0);
10727 * xmlXPathCompUnaryExpr:
10728 * @ctxt: the XPath Parser context
10730 * [27] UnaryExpr ::= UnionExpr
10733 * Compile an unary expression.
10737 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt
) {
10742 while (CUR
== '-') {
10749 xmlXPathCompUnionExpr(ctxt
);
10753 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 2, 0);
10755 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 3, 0);
10760 * xmlXPathCompMultiplicativeExpr:
10761 * @ctxt: the XPath Parser context
10763 * [26] MultiplicativeExpr ::= UnaryExpr
10764 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10765 * | MultiplicativeExpr 'div' UnaryExpr
10766 * | MultiplicativeExpr 'mod' UnaryExpr
10767 * [34] MultiplyOperator ::= '*'
10769 * Compile an Additive expression.
10773 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt
) {
10774 xmlXPathCompUnaryExpr(ctxt
);
10777 while ((CUR
== '*') ||
10778 ((CUR
== 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10779 ((CUR
== 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10781 int op1
= ctxt
->comp
->last
;
10786 } else if (CUR
== 'd') {
10789 } else if (CUR
== 'm') {
10794 xmlXPathCompUnaryExpr(ctxt
);
10796 PUSH_BINARY_EXPR(XPATH_OP_MULT
, op1
, ctxt
->comp
->last
, op
, 0);
10802 * xmlXPathCompAdditiveExpr:
10803 * @ctxt: the XPath Parser context
10805 * [25] AdditiveExpr ::= MultiplicativeExpr
10806 * | AdditiveExpr '+' MultiplicativeExpr
10807 * | AdditiveExpr '-' MultiplicativeExpr
10809 * Compile an Additive expression.
10813 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt
) {
10815 xmlXPathCompMultiplicativeExpr(ctxt
);
10818 while ((CUR
== '+') || (CUR
== '-')) {
10820 int op1
= ctxt
->comp
->last
;
10822 if (CUR
== '+') plus
= 1;
10826 xmlXPathCompMultiplicativeExpr(ctxt
);
10828 PUSH_BINARY_EXPR(XPATH_OP_PLUS
, op1
, ctxt
->comp
->last
, plus
, 0);
10834 * xmlXPathCompRelationalExpr:
10835 * @ctxt: the XPath Parser context
10837 * [24] RelationalExpr ::= AdditiveExpr
10838 * | RelationalExpr '<' AdditiveExpr
10839 * | RelationalExpr '>' AdditiveExpr
10840 * | RelationalExpr '<=' AdditiveExpr
10841 * | RelationalExpr '>=' AdditiveExpr
10843 * A <= B > C is allowed ? Answer from James, yes with
10844 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10845 * which is basically what got implemented.
10847 * Compile a Relational expression, then push the result
10852 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt
) {
10853 xmlXPathCompAdditiveExpr(ctxt
);
10856 while ((CUR
== '<') || (CUR
== '>')) {
10858 int op1
= ctxt
->comp
->last
;
10860 if (CUR
== '<') inf
= 1;
10862 if (NXT(1) == '=') strict
= 0;
10867 xmlXPathCompAdditiveExpr(ctxt
);
10869 PUSH_BINARY_EXPR(XPATH_OP_CMP
, op1
, ctxt
->comp
->last
, inf
, strict
);
10875 * xmlXPathCompEqualityExpr:
10876 * @ctxt: the XPath Parser context
10878 * [23] EqualityExpr ::= RelationalExpr
10879 * | EqualityExpr '=' RelationalExpr
10880 * | EqualityExpr '!=' RelationalExpr
10882 * A != B != C is allowed ? Answer from James, yes with
10883 * (RelationalExpr = RelationalExpr) = RelationalExpr
10884 * (RelationalExpr != RelationalExpr) != RelationalExpr
10885 * which is basically what got implemented.
10887 * Compile an Equality expression.
10891 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt
) {
10892 xmlXPathCompRelationalExpr(ctxt
);
10895 while ((CUR
== '=') || ((CUR
== '!') && (NXT(1) == '='))) {
10897 int op1
= ctxt
->comp
->last
;
10899 if (CUR
== '=') eq
= 1;
10904 xmlXPathCompRelationalExpr(ctxt
);
10906 PUSH_BINARY_EXPR(XPATH_OP_EQUAL
, op1
, ctxt
->comp
->last
, eq
, 0);
10912 * xmlXPathCompAndExpr:
10913 * @ctxt: the XPath Parser context
10915 * [22] AndExpr ::= EqualityExpr
10916 * | AndExpr 'and' EqualityExpr
10918 * Compile an AND expression.
10922 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt
) {
10923 xmlXPathCompEqualityExpr(ctxt
);
10926 while ((CUR
== 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10927 int op1
= ctxt
->comp
->last
;
10930 xmlXPathCompEqualityExpr(ctxt
);
10932 PUSH_BINARY_EXPR(XPATH_OP_AND
, op1
, ctxt
->comp
->last
, 0, 0);
10938 * xmlXPathCompileExpr:
10939 * @ctxt: the XPath Parser context
10941 * [14] Expr ::= OrExpr
10942 * [21] OrExpr ::= AndExpr
10943 * | OrExpr 'or' AndExpr
10945 * Parse and compile an expression
10948 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
) {
10949 xmlXPathContextPtr xpctxt
= ctxt
->context
;
10951 if (xpctxt
!= NULL
) {
10952 if (xpctxt
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
10953 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED
);
10955 * Parsing a single '(' pushes about 10 functions on the call stack
10956 * before recursing!
10958 xpctxt
->depth
+= 10;
10961 xmlXPathCompAndExpr(ctxt
);
10964 while ((CUR
== 'o') && (NXT(1) == 'r')) {
10965 int op1
= ctxt
->comp
->last
;
10968 xmlXPathCompAndExpr(ctxt
);
10970 PUSH_BINARY_EXPR(XPATH_OP_OR
, op1
, ctxt
->comp
->last
, 0, 0);
10973 if ((sort
) && (ctxt
->comp
->steps
[ctxt
->comp
->last
].op
!= XPATH_OP_VALUE
)) {
10974 /* more ops could be optimized too */
10976 * This is the main place to eliminate sorting for
10977 * operations which don't require a sorted node-set.
10980 PUSH_UNARY_EXPR(XPATH_OP_SORT
, ctxt
->comp
->last
, 0, 0);
10983 if (xpctxt
!= NULL
)
10984 xpctxt
->depth
-= 10;
10988 * xmlXPathCompPredicate:
10989 * @ctxt: the XPath Parser context
10990 * @filter: act as a filter
10992 * [8] Predicate ::= '[' PredicateExpr ']'
10993 * [9] PredicateExpr ::= Expr
10995 * Compile a predicate expression
10998 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
) {
10999 int op1
= ctxt
->comp
->last
;
11003 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11008 ctxt
->comp
->last
= -1;
11010 * This call to xmlXPathCompileExpr() will deactivate sorting
11011 * of the predicate result.
11012 * TODO: Sorting is still activated for filters, since I'm not
11013 * sure if needed. Normally sorting should not be needed, since
11014 * a filter can only diminish the number of items in a sequence,
11015 * but won't change its order; so if the initial sequence is sorted,
11016 * subsequent sorting is not needed.
11019 xmlXPathCompileExpr(ctxt
, 0);
11021 xmlXPathCompileExpr(ctxt
, 1);
11025 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11029 PUSH_BINARY_EXPR(XPATH_OP_FILTER
, op1
, ctxt
->comp
->last
, 0, 0);
11031 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE
, op1
, ctxt
->comp
->last
, 0, 0);
11038 * xmlXPathCompNodeTest:
11039 * @ctxt: the XPath Parser context
11040 * @test: pointer to a xmlXPathTestVal
11041 * @type: pointer to a xmlXPathTypeVal
11042 * @prefix: placeholder for a possible name prefix
11044 * [7] NodeTest ::= NameTest
11045 * | NodeType '(' ')'
11046 * | 'processing-instruction' '(' Literal ')'
11048 * [37] NameTest ::= '*'
11051 * [38] NodeType ::= 'comment'
11053 * | 'processing-instruction'
11056 * Returns the name found and updates @test, @type and @prefix appropriately
11059 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt
, xmlXPathTestVal
*test
,
11060 xmlXPathTypeVal
*type
, xmlChar
**prefix
,
11064 if ((test
== NULL
) || (type
== NULL
) || (prefix
== NULL
)) {
11068 *type
= (xmlXPathTypeVal
) 0;
11069 *test
= (xmlXPathTestVal
) 0;
11073 if ((name
== NULL
) && (CUR
== '*')) {
11078 *test
= NODE_TEST_ALL
;
11083 name
= xmlXPathParseNCName(ctxt
);
11084 if (name
== NULL
) {
11085 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11088 blanks
= IS_BLANK_CH(CUR
);
11093 * NodeType or PI search
11095 if (xmlStrEqual(name
, BAD_CAST
"comment"))
11096 *type
= NODE_TYPE_COMMENT
;
11097 else if (xmlStrEqual(name
, BAD_CAST
"node"))
11098 *type
= NODE_TYPE_NODE
;
11099 else if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
11100 *type
= NODE_TYPE_PI
;
11101 else if (xmlStrEqual(name
, BAD_CAST
"text"))
11102 *type
= NODE_TYPE_TEXT
;
11106 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11109 *test
= NODE_TEST_TYPE
;
11112 if (*type
== NODE_TYPE_PI
) {
11114 * Specific case: search a PI by name.
11120 name
= xmlXPathParseLiteral(ctxt
);
11121 if (name
== NULL
) {
11122 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11124 *test
= NODE_TEST_PI
;
11131 XP_ERRORNULL(XPATH_UNCLOSED_ERROR
);
11136 *test
= NODE_TEST_NAME
;
11137 if ((!blanks
) && (CUR
== ':')) {
11141 * Since currently the parser context don't have a
11142 * namespace list associated:
11143 * The namespace name for this prefix can be computed
11144 * only at evaluation time. The compilation is done
11145 * outside of any context.
11148 *prefix
= xmlXPathNsLookup(ctxt
->context
, name
);
11151 if (*prefix
== NULL
) {
11152 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
11163 *test
= NODE_TEST_ALL
;
11167 name
= xmlXPathParseNCName(ctxt
);
11168 if (name
== NULL
) {
11169 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11176 * xmlXPathIsAxisName:
11177 * @name: a preparsed name token
11179 * [6] AxisName ::= 'ancestor'
11180 * | 'ancestor-or-self'
11184 * | 'descendant-or-self'
11186 * | 'following-sibling'
11190 * | 'preceding-sibling'
11193 * Returns the axis or 0
11195 static xmlXPathAxisVal
11196 xmlXPathIsAxisName(const xmlChar
*name
) {
11197 xmlXPathAxisVal ret
= (xmlXPathAxisVal
) 0;
11200 if (xmlStrEqual(name
, BAD_CAST
"ancestor"))
11201 ret
= AXIS_ANCESTOR
;
11202 if (xmlStrEqual(name
, BAD_CAST
"ancestor-or-self"))
11203 ret
= AXIS_ANCESTOR_OR_SELF
;
11204 if (xmlStrEqual(name
, BAD_CAST
"attribute"))
11205 ret
= AXIS_ATTRIBUTE
;
11208 if (xmlStrEqual(name
, BAD_CAST
"child"))
11212 if (xmlStrEqual(name
, BAD_CAST
"descendant"))
11213 ret
= AXIS_DESCENDANT
;
11214 if (xmlStrEqual(name
, BAD_CAST
"descendant-or-self"))
11215 ret
= AXIS_DESCENDANT_OR_SELF
;
11218 if (xmlStrEqual(name
, BAD_CAST
"following"))
11219 ret
= AXIS_FOLLOWING
;
11220 if (xmlStrEqual(name
, BAD_CAST
"following-sibling"))
11221 ret
= AXIS_FOLLOWING_SIBLING
;
11224 if (xmlStrEqual(name
, BAD_CAST
"namespace"))
11225 ret
= AXIS_NAMESPACE
;
11228 if (xmlStrEqual(name
, BAD_CAST
"parent"))
11230 if (xmlStrEqual(name
, BAD_CAST
"preceding"))
11231 ret
= AXIS_PRECEDING
;
11232 if (xmlStrEqual(name
, BAD_CAST
"preceding-sibling"))
11233 ret
= AXIS_PRECEDING_SIBLING
;
11236 if (xmlStrEqual(name
, BAD_CAST
"self"))
11244 * xmlXPathCompStep:
11245 * @ctxt: the XPath Parser context
11247 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11248 * | AbbreviatedStep
11250 * [12] AbbreviatedStep ::= '.' | '..'
11252 * [5] AxisSpecifier ::= AxisName '::'
11253 * | AbbreviatedAxisSpecifier
11255 * [13] AbbreviatedAxisSpecifier ::= '@'?
11257 * Modified for XPtr range support as:
11259 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11260 * | AbbreviatedStep
11261 * | 'range-to' '(' Expr ')' Predicate*
11263 * Compile one step in a Location Path
11264 * A location step of . is short for self::node(). This is
11265 * particularly useful in conjunction with //. For example, the
11266 * location path .//para is short for
11267 * self::node()/descendant-or-self::node()/child::para
11268 * and so will select all para descendant elements of the context
11270 * Similarly, a location step of .. is short for parent::node().
11271 * For example, ../title is short for parent::node()/child::title
11272 * and so will select the title children of the parent of the context
11276 xmlXPathCompStep(xmlXPathParserContextPtr ctxt
) {
11277 #ifdef LIBXML_XPTR_ENABLED
11283 if ((CUR
== '.') && (NXT(1) == '.')) {
11286 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_PARENT
,
11287 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11288 } else if (CUR
== '.') {
11292 xmlChar
*name
= NULL
;
11293 xmlChar
*prefix
= NULL
;
11294 xmlXPathTestVal test
= (xmlXPathTestVal
) 0;
11295 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) 0;
11296 xmlXPathTypeVal type
= (xmlXPathTypeVal
) 0;
11300 * The modification needed for XPointer change to the production
11302 #ifdef LIBXML_XPTR_ENABLED
11304 name
= xmlXPathParseNCName(ctxt
);
11305 if ((name
!= NULL
) && (xmlStrEqual(name
, BAD_CAST
"range-to"))) {
11306 op2
= ctxt
->comp
->last
;
11310 XP_ERROR(XPATH_EXPR_ERROR
);
11315 xmlXPathCompileExpr(ctxt
, 1);
11316 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11321 XP_ERROR(XPATH_EXPR_ERROR
);
11325 goto eval_predicates
;
11333 name
= xmlXPathParseNCName(ctxt
);
11334 if (name
!= NULL
) {
11335 axis
= xmlXPathIsAxisName(name
);
11338 if ((CUR
== ':') && (NXT(1) == ':')) {
11343 /* an element name can conflict with an axis one :-\ */
11349 } else if (CUR
== '@') {
11351 axis
= AXIS_ATTRIBUTE
;
11357 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
11362 name
= xmlXPathCompNodeTest(ctxt
, &test
, &type
, &prefix
, name
);
11366 if ((prefix
!= NULL
) && (ctxt
->context
!= NULL
) &&
11367 (ctxt
->context
->flags
& XML_XPATH_CHECKNS
)) {
11368 if (xmlXPathNsLookup(ctxt
->context
, prefix
) == NULL
) {
11369 xmlXPathErr(ctxt
, XPATH_UNDEF_PREFIX_ERROR
);
11373 xmlGenericError(xmlGenericErrorContext
,
11374 "Basis : computing new set\n");
11378 xmlGenericError(xmlGenericErrorContext
, "Basis : ");
11379 if (ctxt
->value
== NULL
)
11380 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11381 else if (ctxt
->value
->nodesetval
== NULL
)
11382 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11384 xmlGenericErrorContextNodeSet(stdout
, ctxt
->value
->nodesetval
);
11387 #ifdef LIBXML_XPTR_ENABLED
11390 op1
= ctxt
->comp
->last
;
11391 ctxt
->comp
->last
= -1;
11394 while (CUR
== '[') {
11395 xmlXPathCompPredicate(ctxt
, 0);
11398 #ifdef LIBXML_XPTR_ENABLED
11400 PUSH_BINARY_EXPR(XPATH_OP_RANGETO
, op2
, op1
, 0, 0);
11403 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT
, op1
, ctxt
->comp
->last
, axis
,
11404 test
, type
, (void *)prefix
, (void *)name
) == -1) {
11410 xmlGenericError(xmlGenericErrorContext
, "Step : ");
11411 if (ctxt
->value
== NULL
)
11412 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11413 else if (ctxt
->value
->nodesetval
== NULL
)
11414 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11416 xmlGenericErrorContextNodeSet(xmlGenericErrorContext
,
11417 ctxt
->value
->nodesetval
);
11422 * xmlXPathCompRelativeLocationPath:
11423 * @ctxt: the XPath Parser context
11425 * [3] RelativeLocationPath ::= Step
11426 * | RelativeLocationPath '/' Step
11427 * | AbbreviatedRelativeLocationPath
11428 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11430 * Compile a relative location path.
11433 xmlXPathCompRelativeLocationPath
11434 (xmlXPathParserContextPtr ctxt
) {
11436 if ((CUR
== '/') && (NXT(1) == '/')) {
11439 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11440 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11441 } else if (CUR
== '/') {
11445 xmlXPathCompStep(ctxt
);
11448 while (CUR
== '/') {
11449 if ((CUR
== '/') && (NXT(1) == '/')) {
11452 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11453 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11454 xmlXPathCompStep(ctxt
);
11455 } else if (CUR
== '/') {
11458 xmlXPathCompStep(ctxt
);
11465 * xmlXPathCompLocationPath:
11466 * @ctxt: the XPath Parser context
11468 * [1] LocationPath ::= RelativeLocationPath
11469 * | AbsoluteLocationPath
11470 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11471 * | AbbreviatedAbsoluteLocationPath
11472 * [10] AbbreviatedAbsoluteLocationPath ::=
11473 * '//' RelativeLocationPath
11475 * Compile a location path
11477 * // is short for /descendant-or-self::node()/. For example,
11478 * //para is short for /descendant-or-self::node()/child::para and
11479 * so will select any para element in the document (even a para element
11480 * that is a document element will be selected by //para since the
11481 * document element node is a child of the root node); div//para is
11482 * short for div/descendant-or-self::node()/child::para and so will
11483 * select all para descendants of div children.
11486 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
) {
11489 xmlXPathCompRelativeLocationPath(ctxt
);
11491 while (CUR
== '/') {
11492 if ((CUR
== '/') && (NXT(1) == '/')) {
11495 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11496 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11497 xmlXPathCompRelativeLocationPath(ctxt
);
11498 } else if (CUR
== '/') {
11502 ((IS_ASCII_LETTER(CUR
)) || (CUR
== '_') || (CUR
== '.') ||
11503 (CUR
== '@') || (CUR
== '*')))
11504 xmlXPathCompRelativeLocationPath(ctxt
);
11511 /************************************************************************
11513 * XPath precompiled expression evaluation *
11515 ************************************************************************/
11518 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
);
11522 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op
,
11525 xmlGenericError(xmlGenericErrorContext
, "new step : ");
11526 switch (op
->value
) {
11527 case AXIS_ANCESTOR
:
11528 xmlGenericError(xmlGenericErrorContext
, "axis 'ancestors' ");
11530 case AXIS_ANCESTOR_OR_SELF
:
11531 xmlGenericError(xmlGenericErrorContext
,
11532 "axis 'ancestors-or-self' ");
11534 case AXIS_ATTRIBUTE
:
11535 xmlGenericError(xmlGenericErrorContext
, "axis 'attributes' ");
11538 xmlGenericError(xmlGenericErrorContext
, "axis 'child' ");
11540 case AXIS_DESCENDANT
:
11541 xmlGenericError(xmlGenericErrorContext
, "axis 'descendant' ");
11543 case AXIS_DESCENDANT_OR_SELF
:
11544 xmlGenericError(xmlGenericErrorContext
,
11545 "axis 'descendant-or-self' ");
11547 case AXIS_FOLLOWING
:
11548 xmlGenericError(xmlGenericErrorContext
, "axis 'following' ");
11550 case AXIS_FOLLOWING_SIBLING
:
11551 xmlGenericError(xmlGenericErrorContext
,
11552 "axis 'following-siblings' ");
11554 case AXIS_NAMESPACE
:
11555 xmlGenericError(xmlGenericErrorContext
, "axis 'namespace' ");
11558 xmlGenericError(xmlGenericErrorContext
, "axis 'parent' ");
11560 case AXIS_PRECEDING
:
11561 xmlGenericError(xmlGenericErrorContext
, "axis 'preceding' ");
11563 case AXIS_PRECEDING_SIBLING
:
11564 xmlGenericError(xmlGenericErrorContext
,
11565 "axis 'preceding-sibling' ");
11568 xmlGenericError(xmlGenericErrorContext
, "axis 'self' ");
11571 xmlGenericError(xmlGenericErrorContext
,
11572 " context contains %d nodes\n", nbNodes
);
11573 switch (op
->value2
) {
11574 case NODE_TEST_NONE
:
11575 xmlGenericError(xmlGenericErrorContext
,
11576 " searching for none !!!\n");
11578 case NODE_TEST_TYPE
:
11579 xmlGenericError(xmlGenericErrorContext
,
11580 " searching for type %d\n", op
->value3
);
11583 xmlGenericError(xmlGenericErrorContext
,
11584 " searching for PI !!!\n");
11586 case NODE_TEST_ALL
:
11587 xmlGenericError(xmlGenericErrorContext
,
11588 " searching for *\n");
11591 xmlGenericError(xmlGenericErrorContext
,
11592 " searching for namespace %s\n",
11595 case NODE_TEST_NAME
:
11596 xmlGenericError(xmlGenericErrorContext
,
11597 " searching for name %s\n", op
->value5
);
11599 xmlGenericError(xmlGenericErrorContext
,
11600 " with namespace %s\n", op
->value4
);
11603 xmlGenericError(xmlGenericErrorContext
, "Testing : ");
11605 #endif /* DEBUG_STEP */
11608 * xmlXPathNodeSetFilter:
11609 * @ctxt: the XPath Parser context
11610 * @set: the node set to filter
11611 * @filterOpIndex: the index of the predicate/filter op
11612 * @minPos: minimum position in the filtered set (1-based)
11613 * @maxPos: maximum position in the filtered set (1-based)
11614 * @hasNsNodes: true if the node set may contain namespace nodes
11616 * Filter a node set, keeping only nodes for which the predicate expression
11617 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11621 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt
,
11624 int minPos
, int maxPos
,
11627 xmlXPathContextPtr xpctxt
;
11628 xmlNodePtr oldnode
;
11630 xmlXPathStepOpPtr filterOp
;
11634 if ((set
== NULL
) || (set
->nodeNr
== 0))
11638 * Check if the node set contains a sufficient number of nodes for
11639 * the requested range.
11641 if (set
->nodeNr
< minPos
) {
11642 xmlXPathNodeSetClear(set
, hasNsNodes
);
11646 xpctxt
= ctxt
->context
;
11647 oldnode
= xpctxt
->node
;
11648 olddoc
= xpctxt
->doc
;
11649 oldcs
= xpctxt
->contextSize
;
11650 oldpp
= xpctxt
->proximityPosition
;
11651 filterOp
= &ctxt
->comp
->steps
[filterOpIndex
];
11653 xpctxt
->contextSize
= set
->nodeNr
;
11655 for (i
= 0, j
= 0, pos
= 1; i
< set
->nodeNr
; i
++) {
11656 xmlNodePtr node
= set
->nodeTab
[i
];
11659 xpctxt
->node
= node
;
11660 xpctxt
->proximityPosition
= i
+ 1;
11663 * Also set the xpath document in case things like
11664 * key() are evaluated in the predicate.
11666 * TODO: Get real doc for namespace nodes.
11668 if ((node
->type
!= XML_NAMESPACE_DECL
) &&
11669 (node
->doc
!= NULL
))
11670 xpctxt
->doc
= node
->doc
;
11672 res
= xmlXPathCompOpEvalToBoolean(ctxt
, filterOp
, 1);
11674 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
11677 /* Shouldn't happen */
11678 xmlXPathErr(ctxt
, XPATH_EXPR_ERROR
);
11682 if ((res
!= 0) && ((pos
>= minPos
) && (pos
<= maxPos
))) {
11684 set
->nodeTab
[j
] = node
;
11685 set
->nodeTab
[i
] = NULL
;
11690 /* Remove the entry from the initial node set. */
11691 set
->nodeTab
[i
] = NULL
;
11692 if (node
->type
== XML_NAMESPACE_DECL
)
11693 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
11697 if (pos
== maxPos
) {
11706 /* Free remaining nodes. */
11708 for (; i
< set
->nodeNr
; i
++) {
11709 xmlNodePtr node
= set
->nodeTab
[i
];
11710 if ((node
!= NULL
) && (node
->type
== XML_NAMESPACE_DECL
))
11711 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
11717 /* If too many elements were removed, shrink table to preserve memory. */
11718 if ((set
->nodeMax
> XML_NODESET_DEFAULT
) &&
11719 (set
->nodeNr
< set
->nodeMax
/ 2)) {
11721 int nodeMax
= set
->nodeNr
;
11723 if (nodeMax
< XML_NODESET_DEFAULT
)
11724 nodeMax
= XML_NODESET_DEFAULT
;
11725 tmp
= (xmlNodePtr
*) xmlRealloc(set
->nodeTab
,
11726 nodeMax
* sizeof(xmlNodePtr
));
11728 xmlXPathPErrMemory(ctxt
, "shrinking nodeset\n");
11730 set
->nodeTab
= tmp
;
11731 set
->nodeMax
= nodeMax
;
11735 xpctxt
->node
= oldnode
;
11736 xpctxt
->doc
= olddoc
;
11737 xpctxt
->contextSize
= oldcs
;
11738 xpctxt
->proximityPosition
= oldpp
;
11741 #ifdef LIBXML_XPTR_ENABLED
11743 * xmlXPathLocationSetFilter:
11744 * @ctxt: the XPath Parser context
11745 * @locset: the location set to filter
11746 * @filterOpIndex: the index of the predicate/filter op
11747 * @minPos: minimum position in the filtered set (1-based)
11748 * @maxPos: maximum position in the filtered set (1-based)
11750 * Filter a location set, keeping only nodes for which the predicate
11751 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11752 * in the filtered result.
11755 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt
,
11756 xmlLocationSetPtr locset
,
11758 int minPos
, int maxPos
)
11760 xmlXPathContextPtr xpctxt
;
11761 xmlNodePtr oldnode
;
11763 xmlXPathStepOpPtr filterOp
;
11767 if ((locset
== NULL
) || (locset
->locNr
== 0) || (filterOpIndex
== -1))
11770 xpctxt
= ctxt
->context
;
11771 oldnode
= xpctxt
->node
;
11772 olddoc
= xpctxt
->doc
;
11773 oldcs
= xpctxt
->contextSize
;
11774 oldpp
= xpctxt
->proximityPosition
;
11775 filterOp
= &ctxt
->comp
->steps
[filterOpIndex
];
11777 xpctxt
->contextSize
= locset
->locNr
;
11779 for (i
= 0, j
= 0, pos
= 1; i
< locset
->locNr
; i
++) {
11780 xmlNodePtr contextNode
= locset
->locTab
[i
]->user
;
11783 xpctxt
->node
= contextNode
;
11784 xpctxt
->proximityPosition
= i
+ 1;
11787 * Also set the xpath document in case things like
11788 * key() are evaluated in the predicate.
11790 * TODO: Get real doc for namespace nodes.
11792 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11793 (contextNode
->doc
!= NULL
))
11794 xpctxt
->doc
= contextNode
->doc
;
11796 res
= xmlXPathCompOpEvalToBoolean(ctxt
, filterOp
, 1);
11798 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
11801 /* Shouldn't happen */
11802 xmlXPathErr(ctxt
, XPATH_EXPR_ERROR
);
11806 if ((res
!= 0) && ((pos
>= minPos
) && (pos
<= maxPos
))) {
11808 locset
->locTab
[j
] = locset
->locTab
[i
];
11809 locset
->locTab
[i
] = NULL
;
11814 /* Remove the entry from the initial location set. */
11815 xmlXPathFreeObject(locset
->locTab
[i
]);
11816 locset
->locTab
[i
] = NULL
;
11820 if (pos
== maxPos
) {
11829 /* Free remaining nodes. */
11830 for (; i
< locset
->locNr
; i
++)
11831 xmlXPathFreeObject(locset
->locTab
[i
]);
11835 /* If too many elements were removed, shrink table to preserve memory. */
11836 if ((locset
->locMax
> XML_NODESET_DEFAULT
) &&
11837 (locset
->locNr
< locset
->locMax
/ 2)) {
11838 xmlXPathObjectPtr
*tmp
;
11839 int locMax
= locset
->locNr
;
11841 if (locMax
< XML_NODESET_DEFAULT
)
11842 locMax
= XML_NODESET_DEFAULT
;
11843 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(locset
->locTab
,
11844 locMax
* sizeof(xmlXPathObjectPtr
));
11846 xmlXPathPErrMemory(ctxt
, "shrinking locset\n");
11848 locset
->locTab
= tmp
;
11849 locset
->locMax
= locMax
;
11853 xpctxt
->node
= oldnode
;
11854 xpctxt
->doc
= olddoc
;
11855 xpctxt
->contextSize
= oldcs
;
11856 xpctxt
->proximityPosition
= oldpp
;
11858 #endif /* LIBXML_XPTR_ENABLED */
11861 * xmlXPathCompOpEvalPredicate:
11862 * @ctxt: the XPath Parser context
11863 * @op: the predicate op
11864 * @set: the node set to filter
11865 * @minPos: minimum position in the filtered set (1-based)
11866 * @maxPos: maximum position in the filtered set (1-based)
11867 * @hasNsNodes: true if the node set may contain namespace nodes
11869 * Filter a node set, keeping only nodes for which the sequence of predicate
11870 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11871 * in the filtered result.
11874 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt
,
11875 xmlXPathStepOpPtr op
,
11877 int minPos
, int maxPos
,
11880 if (op
->ch1
!= -1) {
11881 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11883 * Process inner predicates first.
11885 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11886 xmlGenericError(xmlGenericErrorContext
,
11887 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11888 XP_ERROR(XPATH_INVALID_OPERAND
);
11890 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
11891 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED
);
11892 ctxt
->context
->depth
+= 1;
11893 xmlXPathCompOpEvalPredicate(ctxt
, &comp
->steps
[op
->ch1
], set
,
11894 1, set
->nodeNr
, hasNsNodes
);
11895 ctxt
->context
->depth
-= 1;
11900 xmlXPathNodeSetFilter(ctxt
, set
, op
->ch2
, minPos
, maxPos
, hasNsNodes
);
11904 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt
,
11905 xmlXPathStepOpPtr op
,
11909 xmlXPathStepOpPtr exprOp
;
11912 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11916 * If not -1, then ch1 will point to:
11917 * 1) For predicates (XPATH_OP_PREDICATE):
11918 * - an inner predicate operator
11919 * 2) For filters (XPATH_OP_FILTER):
11920 * - an inner filter operator OR
11921 * - an expression selecting the node set.
11922 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11924 if ((op
->op
!= XPATH_OP_PREDICATE
) && (op
->op
!= XPATH_OP_FILTER
))
11927 if (op
->ch2
!= -1) {
11928 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11932 if ((exprOp
!= NULL
) &&
11933 (exprOp
->op
== XPATH_OP_VALUE
) &&
11934 (exprOp
->value4
!= NULL
) &&
11935 (((xmlXPathObjectPtr
) exprOp
->value4
)->type
== XPATH_NUMBER
))
11937 double floatval
= ((xmlXPathObjectPtr
) exprOp
->value4
)->floatval
;
11940 * We have a "[n]" predicate here.
11941 * TODO: Unfortunately this simplistic test here is not
11942 * able to detect a position() predicate in compound
11943 * expressions like "[@attr = 'a" and position() = 1],
11944 * and even not the usage of position() in
11945 * "[position() = 1]"; thus - obviously - a position-range,
11946 * like it "[position() < 5]", is also not detected.
11947 * Maybe we could rewrite the AST to ease the optimization.
11950 if ((floatval
> INT_MIN
) && (floatval
< INT_MAX
)) {
11951 *maxPos
= (int) floatval
;
11952 if (floatval
== (double) *maxPos
)
11960 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt
,
11961 xmlXPathStepOpPtr op
,
11962 xmlNodePtr
* first
, xmlNodePtr
* last
,
11966 #define XP_TEST_HIT \
11967 if (hasAxisRange != 0) { \
11968 if (++pos == maxPos) { \
11969 if (addNode(seq, cur) < 0) \
11970 ctxt->error = XPATH_MEMORY_ERROR; \
11971 goto axis_range_end; } \
11973 if (addNode(seq, cur) < 0) \
11974 ctxt->error = XPATH_MEMORY_ERROR; \
11975 if (breakOnFirstHit) goto first_hit; }
11977 #define XP_TEST_HIT_NS \
11978 if (hasAxisRange != 0) { \
11979 if (++pos == maxPos) { \
11981 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11982 ctxt->error = XPATH_MEMORY_ERROR; \
11983 goto axis_range_end; } \
11986 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11987 ctxt->error = XPATH_MEMORY_ERROR; \
11988 if (breakOnFirstHit) goto first_hit; }
11990 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) op
->value
;
11991 xmlXPathTestVal test
= (xmlXPathTestVal
) op
->value2
;
11992 xmlXPathTypeVal type
= (xmlXPathTypeVal
) op
->value3
;
11993 const xmlChar
*prefix
= op
->value4
;
11994 const xmlChar
*name
= op
->value5
;
11995 const xmlChar
*URI
= NULL
;
11998 int nbMatches
= 0, prevMatches
= 0;
12000 int total
= 0, hasNsNodes
= 0;
12001 /* The popped object holding the context nodes */
12002 xmlXPathObjectPtr obj
;
12003 /* The set of context nodes for the node tests */
12004 xmlNodeSetPtr contextSeq
;
12006 xmlNodePtr contextNode
;
12007 /* The final resulting node set wrt to all context nodes */
12008 xmlNodeSetPtr outSeq
;
12010 * The temporary resulting node set wrt 1 context node.
12011 * Used to feed predicate evaluation.
12015 /* First predicate operator */
12016 xmlXPathStepOpPtr predOp
;
12017 int maxPos
; /* The requested position() (when a "[n]" predicate) */
12018 int hasPredicateRange
, hasAxisRange
, pos
;
12019 int breakOnFirstHit
;
12021 xmlXPathTraversalFunction next
= NULL
;
12022 int (*addNode
) (xmlNodeSetPtr
, xmlNodePtr
);
12023 xmlXPathNodeSetMergeFunction mergeAndClear
;
12024 xmlNodePtr oldContextNode
;
12025 xmlXPathContextPtr xpctxt
= ctxt
->context
;
12028 CHECK_TYPE0(XPATH_NODESET
);
12029 obj
= valuePop(ctxt
);
12031 * Setup namespaces.
12033 if (prefix
!= NULL
) {
12034 URI
= xmlXPathNsLookup(xpctxt
, prefix
);
12036 xmlXPathReleaseObject(xpctxt
, obj
);
12037 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
12043 * MAYBE FUTURE TODO: merging optimizations:
12044 * - If the nodes to be traversed wrt to the initial nodes and
12045 * the current axis cannot overlap, then we could avoid searching
12046 * for duplicates during the merge.
12047 * But the question is how/when to evaluate if they cannot overlap.
12048 * Example: if we know that for two initial nodes, the one is
12049 * not in the ancestor-or-self axis of the other, then we could safely
12050 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12051 * the descendant-or-self axis.
12053 mergeAndClear
= xmlXPathNodeSetMergeAndClear
;
12055 case AXIS_ANCESTOR
:
12057 next
= xmlXPathNextAncestor
;
12059 case AXIS_ANCESTOR_OR_SELF
:
12061 next
= xmlXPathNextAncestorOrSelf
;
12063 case AXIS_ATTRIBUTE
:
12066 next
= xmlXPathNextAttribute
;
12067 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12071 if (((test
== NODE_TEST_NAME
) || (test
== NODE_TEST_ALL
)) &&
12072 (type
== NODE_TYPE_NODE
))
12075 * Optimization if an element node type is 'element'.
12077 next
= xmlXPathNextChildElement
;
12079 next
= xmlXPathNextChild
;
12080 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12082 case AXIS_DESCENDANT
:
12084 next
= xmlXPathNextDescendant
;
12086 case AXIS_DESCENDANT_OR_SELF
:
12088 next
= xmlXPathNextDescendantOrSelf
;
12090 case AXIS_FOLLOWING
:
12092 next
= xmlXPathNextFollowing
;
12094 case AXIS_FOLLOWING_SIBLING
:
12096 next
= xmlXPathNextFollowingSibling
;
12098 case AXIS_NAMESPACE
:
12101 next
= (xmlXPathTraversalFunction
) xmlXPathNextNamespace
;
12102 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12106 next
= xmlXPathNextParent
;
12108 case AXIS_PRECEDING
:
12110 next
= xmlXPathNextPrecedingInternal
;
12112 case AXIS_PRECEDING_SIBLING
:
12114 next
= xmlXPathNextPrecedingSibling
;
12119 next
= xmlXPathNextSelf
;
12120 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12125 xmlXPathDebugDumpStepAxis(op
,
12126 (obj
->nodesetval
!= NULL
) ? obj
->nodesetval
->nodeNr
: 0);
12129 if (next
== NULL
) {
12130 xmlXPathReleaseObject(xpctxt
, obj
);
12133 contextSeq
= obj
->nodesetval
;
12134 if ((contextSeq
== NULL
) || (contextSeq
->nodeNr
<= 0)) {
12135 xmlXPathReleaseObject(xpctxt
, obj
);
12136 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, NULL
));
12140 * Predicate optimization ---------------------------------------------
12141 * If this step has a last predicate, which contains a position(),
12142 * then we'll optimize (although not exactly "position()", but only
12143 * the short-hand form, i.e., "[n]".
12145 * Example - expression "/foo[parent::bar][1]":
12147 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12149 * PREDICATE -- op->ch2 (predOp)
12150 * PREDICATE -- predOp->ch1 = [parent::bar]
12152 * COLLECT 'parent' 'name' 'node' bar
12154 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12159 hasPredicateRange
= 0;
12161 if (op
->ch2
!= -1) {
12163 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12165 predOp
= &ctxt
->comp
->steps
[op
->ch2
];
12166 if (xmlXPathIsPositionalPredicate(ctxt
, predOp
, &maxPos
)) {
12167 if (predOp
->ch1
!= -1) {
12169 * Use the next inner predicate operator.
12171 predOp
= &ctxt
->comp
->steps
[predOp
->ch1
];
12172 hasPredicateRange
= 1;
12175 * There's no other predicate than the [n] predicate.
12182 breakOnFirstHit
= ((toBool
) && (predOp
== NULL
)) ? 1 : 0;
12184 * Axis traversal -----------------------------------------------------
12188 * - For the attribute axis, the principal node type is attribute.
12189 * - For the namespace axis, the principal node type is namespace.
12190 * - For other axes, the principal node type is element.
12192 * A node test * is true for any node of the
12193 * principal node type. For example, child::* will
12194 * select all element children of the context node
12196 oldContextNode
= xpctxt
->node
;
12197 addNode
= xmlXPathNodeSetAddUnique
;
12200 contextNode
= NULL
;
12204 while (((contextIdx
< contextSeq
->nodeNr
) || (contextNode
!= NULL
)) &&
12205 (ctxt
->error
== XPATH_EXPRESSION_OK
)) {
12206 xpctxt
->node
= contextSeq
->nodeTab
[contextIdx
++];
12209 seq
= xmlXPathNodeSetCreate(NULL
);
12211 /* TODO: Propagate memory error. */
12217 * Traverse the axis and test the nodes.
12223 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12226 cur
= next(ctxt
, cur
);
12231 * QUESTION TODO: What does the "first" and "last" stuff do?
12233 if ((first
!= NULL
) && (*first
!= NULL
)) {
12236 if (((total
% 256) == 0) &&
12237 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12238 (xmlXPathCmpNodesExt(*first
, cur
) >= 0))
12240 (xmlXPathCmpNodes(*first
, cur
) >= 0))
12246 if ((last
!= NULL
) && (*last
!= NULL
)) {
12249 if (((total
% 256) == 0) &&
12250 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12251 (xmlXPathCmpNodesExt(cur
, *last
) >= 0))
12253 (xmlXPathCmpNodes(cur
, *last
) >= 0))
12263 xmlGenericError(xmlGenericErrorContext
, " %s", cur
->name
);
12267 case NODE_TEST_NONE
:
12271 case NODE_TEST_TYPE
:
12272 if (type
== NODE_TYPE_NODE
) {
12273 switch (cur
->type
) {
12274 case XML_DOCUMENT_NODE
:
12275 case XML_HTML_DOCUMENT_NODE
:
12276 #ifdef LIBXML_DOCB_ENABLED
12277 case XML_DOCB_DOCUMENT_NODE
:
12279 case XML_ELEMENT_NODE
:
12280 case XML_ATTRIBUTE_NODE
:
12282 case XML_COMMENT_NODE
:
12283 case XML_CDATA_SECTION_NODE
:
12284 case XML_TEXT_NODE
:
12287 case XML_NAMESPACE_DECL
: {
12288 if (axis
== AXIS_NAMESPACE
) {
12299 } else if (cur
->type
== (xmlElementType
) type
) {
12300 if (cur
->type
== XML_NAMESPACE_DECL
)
12304 } else if ((type
== NODE_TYPE_TEXT
) &&
12305 (cur
->type
== XML_CDATA_SECTION_NODE
))
12311 if ((cur
->type
== XML_PI_NODE
) &&
12312 ((name
== NULL
) || xmlStrEqual(name
, cur
->name
)))
12317 case NODE_TEST_ALL
:
12318 if (axis
== AXIS_ATTRIBUTE
) {
12319 if (cur
->type
== XML_ATTRIBUTE_NODE
)
12321 if (prefix
== NULL
)
12324 } else if ((cur
->ns
!= NULL
) &&
12325 (xmlStrEqual(URI
, cur
->ns
->href
)))
12330 } else if (axis
== AXIS_NAMESPACE
) {
12331 if (cur
->type
== XML_NAMESPACE_DECL
)
12336 if (cur
->type
== XML_ELEMENT_NODE
) {
12337 if (prefix
== NULL
)
12341 } else if ((cur
->ns
!= NULL
) &&
12342 (xmlStrEqual(URI
, cur
->ns
->href
)))
12349 case NODE_TEST_NS
:{
12353 case NODE_TEST_NAME
:
12354 if (axis
== AXIS_ATTRIBUTE
) {
12355 if (cur
->type
!= XML_ATTRIBUTE_NODE
)
12357 } else if (axis
== AXIS_NAMESPACE
) {
12358 if (cur
->type
!= XML_NAMESPACE_DECL
)
12361 if (cur
->type
!= XML_ELEMENT_NODE
)
12364 switch (cur
->type
) {
12365 case XML_ELEMENT_NODE
:
12366 if (xmlStrEqual(name
, cur
->name
)) {
12367 if (prefix
== NULL
) {
12368 if (cur
->ns
== NULL
)
12373 if ((cur
->ns
!= NULL
) &&
12374 (xmlStrEqual(URI
, cur
->ns
->href
)))
12381 case XML_ATTRIBUTE_NODE
:{
12382 xmlAttrPtr attr
= (xmlAttrPtr
) cur
;
12384 if (xmlStrEqual(name
, attr
->name
)) {
12385 if (prefix
== NULL
) {
12386 if ((attr
->ns
== NULL
) ||
12387 (attr
->ns
->prefix
== NULL
))
12392 if ((attr
->ns
!= NULL
) &&
12402 case XML_NAMESPACE_DECL
:
12403 if (cur
->type
== XML_NAMESPACE_DECL
) {
12404 xmlNsPtr ns
= (xmlNsPtr
) cur
;
12406 if ((ns
->prefix
!= NULL
) && (name
!= NULL
)
12407 && (xmlStrEqual(ns
->prefix
, name
)))
12417 } /* switch(test) */
12418 } while ((cur
!= NULL
) && (ctxt
->error
== XPATH_EXPRESSION_OK
));
12420 goto apply_predicates
;
12422 axis_range_end
: /* ----------------------------------------------------- */
12424 * We have a "/foo[n]", and position() = n was reached.
12425 * Note that we can have as well "/foo/::parent::foo[1]", so
12426 * a duplicate-aware merge is still needed.
12427 * Merge with the result.
12429 if (outSeq
== NULL
) {
12433 /* TODO: Check memory error. */
12434 outSeq
= mergeAndClear(outSeq
, seq
);
12436 * Break if only a true/false result was requested.
12442 first_hit
: /* ---------------------------------------------------------- */
12444 * Break if only a true/false result was requested and
12445 * no predicates existed and a node test succeeded.
12447 if (outSeq
== NULL
) {
12451 /* TODO: Check memory error. */
12452 outSeq
= mergeAndClear(outSeq
, seq
);
12457 nbMatches
+= seq
->nodeNr
;
12460 apply_predicates
: /* --------------------------------------------------- */
12461 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
12465 * Apply predicates.
12467 if ((predOp
!= NULL
) && (seq
->nodeNr
> 0)) {
12469 * E.g. when we have a "/foo[some expression][n]".
12472 * QUESTION TODO: The old predicate evaluation took into
12473 * account location-sets.
12474 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12475 * Do we expect such a set here?
12476 * All what I learned now from the evaluation semantics
12477 * does not indicate that a location-set will be processed
12478 * here, so this looks OK.
12481 * Iterate over all predicates, starting with the outermost
12483 * TODO: Problem: we cannot execute the inner predicates first
12484 * since we cannot go back *up* the operator tree!
12486 * 1) Use of recursive functions (like is it currently done
12487 * via xmlXPathCompOpEval())
12488 * 2) Add a predicate evaluation information stack to the
12490 * 3) Change the way the operators are linked; we need a
12491 * "parent" field on xmlXPathStepOp
12493 * For the moment, I'll try to solve this with a recursive
12494 * function: xmlXPathCompOpEvalPredicate().
12496 if (hasPredicateRange
!= 0)
12497 xmlXPathCompOpEvalPredicate(ctxt
, predOp
, seq
, maxPos
, maxPos
,
12500 xmlXPathCompOpEvalPredicate(ctxt
, predOp
, seq
, 1, seq
->nodeNr
,
12503 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
12509 if (seq
->nodeNr
> 0) {
12511 * Add to result set.
12513 if (outSeq
== NULL
) {
12517 /* TODO: Check memory error. */
12518 outSeq
= mergeAndClear(outSeq
, seq
);
12527 if ((obj
->boolval
) && (obj
->user
!= NULL
)) {
12529 * QUESTION TODO: What does this do and why?
12530 * TODO: Do we have to do this also for the "error"
12531 * cleanup further down?
12533 ctxt
->value
->boolval
= 1;
12534 ctxt
->value
->user
= obj
->user
;
12538 xmlXPathReleaseObject(xpctxt
, obj
);
12541 * Ensure we return at least an empty set.
12543 if (outSeq
== NULL
) {
12544 if ((seq
!= NULL
) && (seq
->nodeNr
== 0))
12547 /* TODO: Check memory error. */
12548 outSeq
= xmlXPathNodeSetCreate(NULL
);
12550 if ((seq
!= NULL
) && (seq
!= outSeq
)) {
12551 xmlXPathFreeNodeSet(seq
);
12554 * Hand over the result. Better to push the set also in
12557 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, outSeq
));
12559 * Reset the context node.
12561 xpctxt
->node
= oldContextNode
;
12563 * When traversing the namespace axis in "toBool" mode, it's
12564 * possible that tmpNsList wasn't freed.
12566 if (xpctxt
->tmpNsList
!= NULL
) {
12567 xmlFree(xpctxt
->tmpNsList
);
12568 xpctxt
->tmpNsList
= NULL
;
12572 xmlGenericError(xmlGenericErrorContext
,
12573 "\nExamined %d nodes, found %d nodes at that step\n",
12581 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12582 xmlXPathStepOpPtr op
, xmlNodePtr
* first
);
12585 * xmlXPathCompOpEvalFirst:
12586 * @ctxt: the XPath parser context with the compiled expression
12587 * @op: an XPath compiled operation
12588 * @first: the first elem found so far
12590 * Evaluate the Precompiled XPath operation searching only the first
12591 * element in document order
12593 * Returns the number of examined objects.
12596 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
12597 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12599 int total
= 0, cur
;
12600 xmlXPathCompExprPtr comp
;
12601 xmlXPathObjectPtr arg1
, arg2
;
12604 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12606 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
12607 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED
);
12608 ctxt
->context
->depth
+= 1;
12613 case XPATH_OP_UNION
:
12615 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12618 if ((ctxt
->value
!= NULL
)
12619 && (ctxt
->value
->type
== XPATH_NODESET
)
12620 && (ctxt
->value
->nodesetval
!= NULL
)
12621 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12623 * limit tree traversing to first node in the result
12626 * OPTIMIZE TODO: This implicitly sorts
12627 * the result, even if not needed. E.g. if the argument
12628 * of the count() function, no sorting is needed.
12629 * OPTIMIZE TODO: How do we know if the node-list wasn't
12632 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12633 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12634 *first
= ctxt
->value
->nodesetval
->nodeTab
[0];
12637 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch2
],
12641 arg2
= valuePop(ctxt
);
12642 arg1
= valuePop(ctxt
);
12643 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12644 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12645 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12646 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12647 XP_ERROR0(XPATH_INVALID_TYPE
);
12649 if ((ctxt
->context
->opLimit
!= 0) &&
12650 (((arg1
->nodesetval
!= NULL
) &&
12651 (xmlXPathCheckOpLimit(ctxt
,
12652 arg1
->nodesetval
->nodeNr
) < 0)) ||
12653 ((arg2
->nodesetval
!= NULL
) &&
12654 (xmlXPathCheckOpLimit(ctxt
,
12655 arg2
->nodesetval
->nodeNr
) < 0)))) {
12656 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12657 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12661 /* TODO: Check memory error. */
12662 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12664 valuePush(ctxt
, arg1
);
12665 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12668 xmlXPathCompSwap(op
);
12671 case XPATH_OP_ROOT
:
12672 xmlXPathRoot(ctxt
);
12674 case XPATH_OP_NODE
:
12676 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12679 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12681 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12682 ctxt
->context
->node
));
12684 case XPATH_OP_COLLECT
:{
12688 total
= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12691 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, first
, NULL
, 0);
12694 case XPATH_OP_VALUE
:
12696 xmlXPathCacheObjectCopy(ctxt
->context
,
12697 (xmlXPathObjectPtr
) op
->value4
));
12699 case XPATH_OP_SORT
:
12702 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12705 if ((ctxt
->value
!= NULL
)
12706 && (ctxt
->value
->type
== XPATH_NODESET
)
12707 && (ctxt
->value
->nodesetval
!= NULL
)
12708 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12709 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12711 #ifdef XP_OPTIMIZED_FILTER_FIRST
12712 case XPATH_OP_FILTER
:
12713 total
+= xmlXPathCompOpEvalFilterFirst(ctxt
, op
, first
);
12717 total
+= xmlXPathCompOpEval(ctxt
, op
);
12721 ctxt
->context
->depth
-= 1;
12726 * xmlXPathCompOpEvalLast:
12727 * @ctxt: the XPath parser context with the compiled expression
12728 * @op: an XPath compiled operation
12729 * @last: the last elem found so far
12731 * Evaluate the Precompiled XPath operation searching only the last
12732 * element in document order
12734 * Returns the number of nodes traversed
12737 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
,
12740 int total
= 0, cur
;
12741 xmlXPathCompExprPtr comp
;
12742 xmlXPathObjectPtr arg1
, arg2
;
12745 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12747 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
12748 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED
);
12749 ctxt
->context
->depth
+= 1;
12754 case XPATH_OP_UNION
:
12756 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
], last
);
12758 if ((ctxt
->value
!= NULL
)
12759 && (ctxt
->value
->type
== XPATH_NODESET
)
12760 && (ctxt
->value
->nodesetval
!= NULL
)
12761 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12763 * limit tree traversing to first node in the result
12765 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12766 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12768 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->value
->
12769 nodesetval
->nodeNr
-
12773 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch2
], last
);
12775 if ((ctxt
->value
!= NULL
)
12776 && (ctxt
->value
->type
== XPATH_NODESET
)
12777 && (ctxt
->value
->nodesetval
!= NULL
)
12778 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) { /* TODO: NOP ? */
12781 arg2
= valuePop(ctxt
);
12782 arg1
= valuePop(ctxt
);
12783 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12784 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12785 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12786 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12787 XP_ERROR0(XPATH_INVALID_TYPE
);
12789 if ((ctxt
->context
->opLimit
!= 0) &&
12790 (((arg1
->nodesetval
!= NULL
) &&
12791 (xmlXPathCheckOpLimit(ctxt
,
12792 arg1
->nodesetval
->nodeNr
) < 0)) ||
12793 ((arg2
->nodesetval
!= NULL
) &&
12794 (xmlXPathCheckOpLimit(ctxt
,
12795 arg2
->nodesetval
->nodeNr
) < 0)))) {
12796 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12797 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12801 /* TODO: Check memory error. */
12802 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12804 valuePush(ctxt
, arg1
);
12805 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12808 xmlXPathCompSwap(op
);
12811 case XPATH_OP_ROOT
:
12812 xmlXPathRoot(ctxt
);
12814 case XPATH_OP_NODE
:
12816 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12819 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12821 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12822 ctxt
->context
->node
));
12824 case XPATH_OP_COLLECT
:{
12828 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12831 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, last
, 0);
12834 case XPATH_OP_VALUE
:
12836 xmlXPathCacheObjectCopy(ctxt
->context
,
12837 (xmlXPathObjectPtr
) op
->value4
));
12839 case XPATH_OP_SORT
:
12842 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
],
12845 if ((ctxt
->value
!= NULL
)
12846 && (ctxt
->value
->type
== XPATH_NODESET
)
12847 && (ctxt
->value
->nodesetval
!= NULL
)
12848 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12849 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12852 total
+= xmlXPathCompOpEval(ctxt
, op
);
12856 ctxt
->context
->depth
-= 1;
12860 #ifdef XP_OPTIMIZED_FILTER_FIRST
12862 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12863 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12866 xmlXPathCompExprPtr comp
;
12872 * Optimization for ()[last()] selection i.e. the last elem
12874 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
12875 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
12876 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
12877 int f
= comp
->steps
[op
->ch2
].ch1
;
12880 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
12881 (comp
->steps
[f
].value5
== NULL
) &&
12882 (comp
->steps
[f
].value
== 0) &&
12883 (comp
->steps
[f
].value4
!= NULL
) &&
12885 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
12886 xmlNodePtr last
= NULL
;
12889 xmlXPathCompOpEvalLast(ctxt
,
12890 &comp
->steps
[op
->ch1
],
12894 * The nodeset should be in document order,
12895 * Keep only the last value
12897 if ((ctxt
->value
!= NULL
) &&
12898 (ctxt
->value
->type
== XPATH_NODESET
) &&
12899 (ctxt
->value
->nodesetval
!= NULL
) &&
12900 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
12901 (ctxt
->value
->nodesetval
->nodeNr
> 1)) {
12902 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
12903 *first
= *(ctxt
->value
->nodesetval
->nodeTab
);
12910 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12914 if (ctxt
->value
== NULL
)
12917 #ifdef LIBXML_XPTR_ENABLED
12919 * Hum are we filtering the result of an XPointer expression
12921 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
12922 xmlLocationSetPtr locset
= ctxt
->value
->user
;
12924 if (locset
!= NULL
) {
12925 xmlXPathLocationSetFilter(ctxt
, locset
, op
->ch2
, 1, 1);
12926 if (locset
->locNr
> 0)
12927 *first
= (xmlNodePtr
) locset
->locTab
[0]->user
;
12932 #endif /* LIBXML_XPTR_ENABLED */
12934 CHECK_TYPE0(XPATH_NODESET
);
12935 set
= ctxt
->value
->nodesetval
;
12937 xmlXPathNodeSetFilter(ctxt
, set
, op
->ch2
, 1, 1, 1);
12938 if (set
->nodeNr
> 0)
12939 *first
= set
->nodeTab
[0];
12944 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12947 * xmlXPathCompOpEval:
12948 * @ctxt: the XPath parser context with the compiled expression
12949 * @op: an XPath compiled operation
12951 * Evaluate the Precompiled XPath operation
12952 * Returns the number of nodes traversed
12955 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
)
12959 xmlXPathCompExprPtr comp
;
12960 xmlXPathObjectPtr arg1
, arg2
;
12963 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12965 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
12966 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED
);
12967 ctxt
->context
->depth
+= 1;
12973 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12975 xmlXPathBooleanFunction(ctxt
, 1);
12976 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 0))
12978 arg2
= valuePop(ctxt
);
12979 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12981 xmlXPathFreeObject(arg2
);
12984 xmlXPathBooleanFunction(ctxt
, 1);
12985 if (ctxt
->value
!= NULL
)
12986 ctxt
->value
->boolval
&= arg2
->boolval
;
12987 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12990 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12992 xmlXPathBooleanFunction(ctxt
, 1);
12993 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 1))
12995 arg2
= valuePop(ctxt
);
12996 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12998 xmlXPathFreeObject(arg2
);
13001 xmlXPathBooleanFunction(ctxt
, 1);
13002 if (ctxt
->value
!= NULL
)
13003 ctxt
->value
->boolval
|= arg2
->boolval
;
13004 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13006 case XPATH_OP_EQUAL
:
13007 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13009 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13012 equal
= xmlXPathEqualValues(ctxt
);
13014 equal
= xmlXPathNotEqualValues(ctxt
);
13015 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, equal
));
13018 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13020 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13022 ret
= xmlXPathCompareValues(ctxt
, op
->value
, op
->value2
);
13023 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
13025 case XPATH_OP_PLUS
:
13026 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13028 if (op
->ch2
!= -1) {
13029 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13032 if (op
->value
== 0)
13033 xmlXPathSubValues(ctxt
);
13034 else if (op
->value
== 1)
13035 xmlXPathAddValues(ctxt
);
13036 else if (op
->value
== 2)
13037 xmlXPathValueFlipSign(ctxt
);
13038 else if (op
->value
== 3) {
13040 CHECK_TYPE0(XPATH_NUMBER
);
13043 case XPATH_OP_MULT
:
13044 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13046 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13048 if (op
->value
== 0)
13049 xmlXPathMultValues(ctxt
);
13050 else if (op
->value
== 1)
13051 xmlXPathDivValues(ctxt
);
13052 else if (op
->value
== 2)
13053 xmlXPathModValues(ctxt
);
13055 case XPATH_OP_UNION
:
13056 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13058 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13061 arg2
= valuePop(ctxt
);
13062 arg1
= valuePop(ctxt
);
13063 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
13064 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
13065 xmlXPathReleaseObject(ctxt
->context
, arg1
);
13066 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13067 XP_ERROR0(XPATH_INVALID_TYPE
);
13069 if ((ctxt
->context
->opLimit
!= 0) &&
13070 (((arg1
->nodesetval
!= NULL
) &&
13071 (xmlXPathCheckOpLimit(ctxt
,
13072 arg1
->nodesetval
->nodeNr
) < 0)) ||
13073 ((arg2
->nodesetval
!= NULL
) &&
13074 (xmlXPathCheckOpLimit(ctxt
,
13075 arg2
->nodesetval
->nodeNr
) < 0)))) {
13076 xmlXPathReleaseObject(ctxt
->context
, arg1
);
13077 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13081 if ((arg1
->nodesetval
== NULL
) ||
13082 ((arg2
->nodesetval
!= NULL
) &&
13083 (arg2
->nodesetval
->nodeNr
!= 0)))
13085 /* TODO: Check memory error. */
13086 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
13090 valuePush(ctxt
, arg1
);
13091 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13093 case XPATH_OP_ROOT
:
13094 xmlXPathRoot(ctxt
);
13096 case XPATH_OP_NODE
:
13098 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13101 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13103 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
13104 ctxt
->context
->node
));
13106 case XPATH_OP_COLLECT
:{
13110 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13113 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 0);
13116 case XPATH_OP_VALUE
:
13118 xmlXPathCacheObjectCopy(ctxt
->context
,
13119 (xmlXPathObjectPtr
) op
->value4
));
13121 case XPATH_OP_VARIABLE
:{
13122 xmlXPathObjectPtr val
;
13126 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13127 if (op
->value5
== NULL
) {
13128 val
= xmlXPathVariableLookup(ctxt
->context
, op
->value4
);
13130 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13131 valuePush(ctxt
, val
);
13133 const xmlChar
*URI
;
13135 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13137 xmlGenericError(xmlGenericErrorContext
,
13138 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13139 (char *) op
->value4
, (char *)op
->value5
);
13140 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13143 val
= xmlXPathVariableLookupNS(ctxt
->context
,
13146 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13147 valuePush(ctxt
, val
);
13151 case XPATH_OP_FUNCTION
:{
13152 xmlXPathFunction func
;
13153 const xmlChar
*oldFunc
, *oldFuncURI
;
13157 frame
= xmlXPathSetFrame(ctxt
);
13158 if (op
->ch1
!= -1) {
13160 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13161 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13162 xmlXPathPopFrame(ctxt
, frame
);
13166 if (ctxt
->valueNr
< ctxt
->valueFrame
+ op
->value
) {
13167 xmlGenericError(xmlGenericErrorContext
,
13168 "xmlXPathCompOpEval: parameter error\n");
13169 ctxt
->error
= XPATH_INVALID_OPERAND
;
13170 xmlXPathPopFrame(ctxt
, frame
);
13173 for (i
= 0; i
< op
->value
; i
++) {
13174 if (ctxt
->valueTab
[(ctxt
->valueNr
- 1) - i
] == NULL
) {
13175 xmlGenericError(xmlGenericErrorContext
,
13176 "xmlXPathCompOpEval: parameter error\n");
13177 ctxt
->error
= XPATH_INVALID_OPERAND
;
13178 xmlXPathPopFrame(ctxt
, frame
);
13182 if (op
->cache
!= NULL
)
13185 const xmlChar
*URI
= NULL
;
13187 if (op
->value5
== NULL
)
13189 xmlXPathFunctionLookup(ctxt
->context
,
13192 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13194 xmlGenericError(xmlGenericErrorContext
,
13195 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13196 (char *)op
->value4
, (char *)op
->value5
);
13197 xmlXPathPopFrame(ctxt
, frame
);
13198 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13201 func
= xmlXPathFunctionLookupNS(ctxt
->context
,
13204 if (func
== NULL
) {
13205 xmlGenericError(xmlGenericErrorContext
,
13206 "xmlXPathCompOpEval: function %s not found\n",
13207 (char *)op
->value4
);
13208 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR
);
13211 op
->cacheURI
= (void *) URI
;
13213 oldFunc
= ctxt
->context
->function
;
13214 oldFuncURI
= ctxt
->context
->functionURI
;
13215 ctxt
->context
->function
= op
->value4
;
13216 ctxt
->context
->functionURI
= op
->cacheURI
;
13217 func(ctxt
, op
->value
);
13218 ctxt
->context
->function
= oldFunc
;
13219 ctxt
->context
->functionURI
= oldFuncURI
;
13220 if ((ctxt
->error
== XPATH_EXPRESSION_OK
) &&
13221 (ctxt
->valueNr
!= ctxt
->valueFrame
+ 1))
13222 XP_ERROR0(XPATH_STACK_ERROR
);
13223 xmlXPathPopFrame(ctxt
, frame
);
13227 if (op
->ch1
!= -1) {
13228 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13231 if (op
->ch2
!= -1) {
13232 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13236 case XPATH_OP_PREDICATE
:
13237 case XPATH_OP_FILTER
:{
13241 * Optimization for ()[1] selection i.e. the first elem
13243 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13244 #ifdef XP_OPTIMIZED_FILTER_FIRST
13246 * FILTER TODO: Can we assume that the inner processing
13247 * will result in an ordered list if we have an
13249 * What about an additional field or flag on
13250 * xmlXPathObject like @sorted ? This way we wouldn't need
13251 * to assume anything, so it would be more robust and
13252 * easier to optimize.
13254 ((comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) || /* 18 */
13255 (comp
->steps
[op
->ch1
].op
== XPATH_OP_FILTER
)) && /* 17 */
13257 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13259 (comp
->steps
[op
->ch2
].op
== XPATH_OP_VALUE
)) { /* 12 */
13260 xmlXPathObjectPtr val
;
13262 val
= comp
->steps
[op
->ch2
].value4
;
13263 if ((val
!= NULL
) && (val
->type
== XPATH_NUMBER
) &&
13264 (val
->floatval
== 1.0)) {
13265 xmlNodePtr first
= NULL
;
13268 xmlXPathCompOpEvalFirst(ctxt
,
13269 &comp
->steps
[op
->ch1
],
13273 * The nodeset should be in document order,
13274 * Keep only the first value
13276 if ((ctxt
->value
!= NULL
) &&
13277 (ctxt
->value
->type
== XPATH_NODESET
) &&
13278 (ctxt
->value
->nodesetval
!= NULL
) &&
13279 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13280 xmlXPathNodeSetClearFromPos(ctxt
->value
->nodesetval
,
13286 * Optimization for ()[last()] selection i.e. the last elem
13288 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13289 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13290 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
13291 int f
= comp
->steps
[op
->ch2
].ch1
;
13294 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
13295 (comp
->steps
[f
].value5
== NULL
) &&
13296 (comp
->steps
[f
].value
== 0) &&
13297 (comp
->steps
[f
].value4
!= NULL
) &&
13299 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
13300 xmlNodePtr last
= NULL
;
13303 xmlXPathCompOpEvalLast(ctxt
,
13304 &comp
->steps
[op
->ch1
],
13308 * The nodeset should be in document order,
13309 * Keep only the last value
13311 if ((ctxt
->value
!= NULL
) &&
13312 (ctxt
->value
->type
== XPATH_NODESET
) &&
13313 (ctxt
->value
->nodesetval
!= NULL
) &&
13314 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
13315 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13316 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
13321 * Process inner predicates first.
13322 * Example "index[parent::book][1]":
13324 * PREDICATE <-- we are here "[1]"
13325 * PREDICATE <-- process "[parent::book]" first
13327 * COLLECT 'parent' 'name' 'node' book
13329 * ELEM Object is a number : 1
13333 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13337 if (ctxt
->value
== NULL
)
13340 #ifdef LIBXML_XPTR_ENABLED
13342 * Hum are we filtering the result of an XPointer expression
13344 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13345 xmlLocationSetPtr locset
= ctxt
->value
->user
;
13346 xmlXPathLocationSetFilter(ctxt
, locset
, op
->ch2
,
13350 #endif /* LIBXML_XPTR_ENABLED */
13352 CHECK_TYPE0(XPATH_NODESET
);
13353 set
= ctxt
->value
->nodesetval
;
13355 xmlXPathNodeSetFilter(ctxt
, set
, op
->ch2
,
13356 1, set
->nodeNr
, 1);
13359 case XPATH_OP_SORT
:
13361 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13363 if ((ctxt
->value
!= NULL
) &&
13364 (ctxt
->value
->type
== XPATH_NODESET
) &&
13365 (ctxt
->value
->nodesetval
!= NULL
) &&
13366 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13368 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
13371 #ifdef LIBXML_XPTR_ENABLED
13372 case XPATH_OP_RANGETO
:{
13373 xmlXPathObjectPtr range
;
13374 xmlXPathObjectPtr res
, obj
;
13375 xmlXPathObjectPtr tmp
;
13376 xmlLocationSetPtr newlocset
= NULL
;
13377 xmlLocationSetPtr oldlocset
;
13378 xmlNodeSetPtr oldset
;
13379 xmlNodePtr oldnode
= ctxt
->context
->node
;
13380 int oldcs
= ctxt
->context
->contextSize
;
13381 int oldpp
= ctxt
->context
->proximityPosition
;
13384 if (op
->ch1
!= -1) {
13386 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13389 if (ctxt
->value
== NULL
) {
13390 XP_ERROR0(XPATH_INVALID_OPERAND
);
13395 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13397 * Extract the old locset, and then evaluate the result of the
13398 * expression for all the element in the locset. use it to grow
13401 CHECK_TYPE0(XPATH_LOCATIONSET
);
13403 if ((ctxt
->value
->user
== NULL
) ||
13404 (((xmlLocationSetPtr
) ctxt
->value
->user
)->locNr
== 0))
13407 obj
= valuePop(ctxt
);
13408 oldlocset
= obj
->user
;
13410 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13412 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13414 * Run the evaluation with a node list made of a
13415 * single item in the nodelocset.
13417 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13418 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13419 ctxt
->context
->proximityPosition
= i
+ 1;
13420 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13421 ctxt
->context
->node
);
13422 valuePush(ctxt
, tmp
);
13426 xmlXPathCompOpEval(ctxt
,
13427 &comp
->steps
[op
->ch2
]);
13428 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13429 xmlXPtrFreeLocationSet(newlocset
);
13430 goto rangeto_error
;
13433 res
= valuePop(ctxt
);
13434 if (res
->type
== XPATH_LOCATIONSET
) {
13435 xmlLocationSetPtr rloc
=
13436 (xmlLocationSetPtr
)res
->user
;
13437 for (j
=0; j
<rloc
->locNr
; j
++) {
13438 range
= xmlXPtrNewRange(
13439 oldlocset
->locTab
[i
]->user
,
13440 oldlocset
->locTab
[i
]->index
,
13441 rloc
->locTab
[j
]->user2
,
13442 rloc
->locTab
[j
]->index2
);
13443 if (range
!= NULL
) {
13444 xmlXPtrLocationSetAdd(newlocset
, range
);
13448 range
= xmlXPtrNewRangeNodeObject(
13449 (xmlNodePtr
)oldlocset
->locTab
[i
]->user
, res
);
13450 if (range
!= NULL
) {
13451 xmlXPtrLocationSetAdd(newlocset
,range
);
13459 xmlXPathReleaseObject(ctxt
->context
, res
);
13461 if (ctxt
->value
== tmp
) {
13462 res
= valuePop(ctxt
);
13463 xmlXPathReleaseObject(ctxt
->context
, res
);
13466 } else { /* Not a location set */
13467 CHECK_TYPE0(XPATH_NODESET
);
13468 obj
= valuePop(ctxt
);
13469 oldset
= obj
->nodesetval
;
13471 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13473 if (oldset
!= NULL
) {
13474 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13476 * Run the evaluation with a node list made of a single item
13479 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13481 * OPTIMIZE TODO: Avoid recreation for every iteration.
13483 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13484 ctxt
->context
->node
);
13485 valuePush(ctxt
, tmp
);
13489 xmlXPathCompOpEval(ctxt
,
13490 &comp
->steps
[op
->ch2
]);
13491 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13492 xmlXPtrFreeLocationSet(newlocset
);
13493 goto rangeto_error
;
13496 res
= valuePop(ctxt
);
13498 xmlXPtrNewRangeNodeObject(oldset
->nodeTab
[i
],
13500 if (range
!= NULL
) {
13501 xmlXPtrLocationSetAdd(newlocset
, range
);
13508 xmlXPathReleaseObject(ctxt
->context
, res
);
13510 if (ctxt
->value
== tmp
) {
13511 res
= valuePop(ctxt
);
13512 xmlXPathReleaseObject(ctxt
->context
, res
);
13519 * The result is used as the new evaluation set.
13521 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13523 xmlXPathReleaseObject(ctxt
->context
, obj
);
13524 ctxt
->context
->node
= oldnode
;
13525 ctxt
->context
->contextSize
= oldcs
;
13526 ctxt
->context
->proximityPosition
= oldpp
;
13529 #endif /* LIBXML_XPTR_ENABLED */
13531 xmlGenericError(xmlGenericErrorContext
,
13532 "XPath: unknown precompiled operation %d\n", op
->op
);
13533 ctxt
->error
= XPATH_INVALID_OPERAND
;
13537 ctxt
->context
->depth
-= 1;
13542 * xmlXPathCompOpEvalToBoolean:
13543 * @ctxt: the XPath parser context
13545 * Evaluates if the expression evaluates to true.
13547 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13550 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
13551 xmlXPathStepOpPtr op
,
13554 xmlXPathObjectPtr resObj
= NULL
;
13557 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
13559 /* comp = ctxt->comp; */
13563 case XPATH_OP_VALUE
:
13564 resObj
= (xmlXPathObjectPtr
) op
->value4
;
13566 return(xmlXPathEvaluatePredicateResult(ctxt
, resObj
));
13567 return(xmlXPathCastToBoolean(resObj
));
13568 case XPATH_OP_SORT
:
13570 * We don't need sorting for boolean results. Skip this one.
13572 if (op
->ch1
!= -1) {
13573 op
= &ctxt
->comp
->steps
[op
->ch1
];
13577 case XPATH_OP_COLLECT
:
13581 xmlXPathCompOpEval(ctxt
, &ctxt
->comp
->steps
[op
->ch1
]);
13582 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13585 xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 1);
13586 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13589 resObj
= valuePop(ctxt
);
13590 if (resObj
== NULL
)
13595 * Fallback to call xmlXPathCompOpEval().
13597 xmlXPathCompOpEval(ctxt
, op
);
13598 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13601 resObj
= valuePop(ctxt
);
13602 if (resObj
== NULL
)
13610 if (resObj
->type
== XPATH_BOOLEAN
) {
13611 res
= resObj
->boolval
;
13612 } else if (isPredicate
) {
13614 * For predicates a result of type "number" is handled
13617 * "If the result is a number, the result will be converted
13618 * to true if the number is equal to the context position
13619 * and will be converted to false otherwise;"
13621 res
= xmlXPathEvaluatePredicateResult(ctxt
, resObj
);
13623 res
= xmlXPathCastToBoolean(resObj
);
13625 xmlXPathReleaseObject(ctxt
->context
, resObj
);
13632 #ifdef XPATH_STREAMING
13634 * xmlXPathRunStreamEval:
13635 * @ctxt: the XPath parser context with the compiled expression
13637 * Evaluate the Precompiled Streamable XPath expression in the given context.
13640 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt
, xmlPatternPtr comp
,
13641 xmlXPathObjectPtr
*resultSeq
, int toBool
)
13643 int max_depth
, min_depth
;
13646 int eval_all_nodes
;
13647 xmlNodePtr cur
= NULL
, limit
= NULL
;
13648 xmlStreamCtxtPtr patstream
= NULL
;
13652 if ((ctxt
== NULL
) || (comp
== NULL
))
13654 max_depth
= xmlPatternMaxDepth(comp
);
13655 if (max_depth
== -1)
13657 if (max_depth
== -2)
13659 min_depth
= xmlPatternMinDepth(comp
);
13660 if (min_depth
== -1)
13662 from_root
= xmlPatternFromRoot(comp
);
13666 printf("stream eval: depth %d from root %d\n", max_depth
, from_root
);
13670 if (resultSeq
== NULL
)
13672 *resultSeq
= xmlXPathCacheNewNodeSet(ctxt
, NULL
);
13673 if (*resultSeq
== NULL
)
13678 * handle the special cases of "/" amd "." being matched
13680 if (min_depth
== 0) {
13685 /* TODO: Check memory error. */
13686 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
,
13687 (xmlNodePtr
) ctxt
->doc
);
13689 /* Select "self::node()" */
13692 /* TODO: Check memory error. */
13693 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, ctxt
->node
);
13696 if (max_depth
== 0) {
13701 cur
= (xmlNodePtr
)ctxt
->doc
;
13702 } else if (ctxt
->node
!= NULL
) {
13703 switch (ctxt
->node
->type
) {
13704 case XML_ELEMENT_NODE
:
13705 case XML_DOCUMENT_NODE
:
13706 case XML_DOCUMENT_FRAG_NODE
:
13707 case XML_HTML_DOCUMENT_NODE
:
13708 #ifdef LIBXML_DOCB_ENABLED
13709 case XML_DOCB_DOCUMENT_NODE
:
13713 case XML_ATTRIBUTE_NODE
:
13714 case XML_TEXT_NODE
:
13715 case XML_CDATA_SECTION_NODE
:
13716 case XML_ENTITY_REF_NODE
:
13717 case XML_ENTITY_NODE
:
13719 case XML_COMMENT_NODE
:
13720 case XML_NOTATION_NODE
:
13722 case XML_DOCUMENT_TYPE_NODE
:
13723 case XML_ELEMENT_DECL
:
13724 case XML_ATTRIBUTE_DECL
:
13725 case XML_ENTITY_DECL
:
13726 case XML_NAMESPACE_DECL
:
13727 case XML_XINCLUDE_START
:
13728 case XML_XINCLUDE_END
:
13737 patstream
= xmlPatternGetStreamCtxt(comp
);
13738 if (patstream
== NULL
) {
13740 * QUESTION TODO: Is this an error?
13745 eval_all_nodes
= xmlStreamWantsAnyNode(patstream
);
13748 ret
= xmlStreamPush(patstream
, NULL
, NULL
);
13750 } else if (ret
== 1) {
13753 /* TODO: Check memory error. */
13754 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
);
13758 goto scan_children
;
13761 if (ctxt
->opLimit
!= 0) {
13762 if (ctxt
->opCount
>= ctxt
->opLimit
) {
13763 xmlGenericError(xmlGenericErrorContext
,
13764 "XPath operation limit exceeded\n");
13765 xmlFreeStreamCtxt(patstream
);
13773 switch (cur
->type
) {
13774 case XML_ELEMENT_NODE
:
13775 case XML_TEXT_NODE
:
13776 case XML_CDATA_SECTION_NODE
:
13777 case XML_COMMENT_NODE
:
13779 if (cur
->type
== XML_ELEMENT_NODE
) {
13780 ret
= xmlStreamPush(patstream
, cur
->name
,
13781 (cur
->ns
? cur
->ns
->href
: NULL
));
13782 } else if (eval_all_nodes
)
13783 ret
= xmlStreamPushNode(patstream
, NULL
, NULL
, cur
->type
);
13789 } else if (ret
== 1) {
13792 if (xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
)
13794 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
13795 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
13798 if ((cur
->children
== NULL
) || (depth
>= max_depth
)) {
13799 ret
= xmlStreamPop(patstream
);
13800 while (cur
->next
!= NULL
) {
13802 if ((cur
->type
!= XML_ENTITY_DECL
) &&
13803 (cur
->type
!= XML_DTD_NODE
))
13812 if (cur
->type
== XML_NAMESPACE_DECL
) break;
13813 if ((cur
->children
!= NULL
) && (depth
< max_depth
)) {
13815 * Do not descend on entities declarations
13817 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
13818 cur
= cur
->children
;
13823 if (cur
->type
!= XML_DTD_NODE
)
13831 while (cur
->next
!= NULL
) {
13833 if ((cur
->type
!= XML_ENTITY_DECL
) &&
13834 (cur
->type
!= XML_DTD_NODE
))
13841 if ((cur
== NULL
) || (cur
== limit
) ||
13842 (cur
->type
== XML_DOCUMENT_NODE
))
13844 if (cur
->type
== XML_ELEMENT_NODE
) {
13845 ret
= xmlStreamPop(patstream
);
13846 } else if ((eval_all_nodes
) &&
13847 ((cur
->type
== XML_TEXT_NODE
) ||
13848 (cur
->type
== XML_CDATA_SECTION_NODE
) ||
13849 (cur
->type
== XML_COMMENT_NODE
) ||
13850 (cur
->type
== XML_PI_NODE
)))
13852 ret
= xmlStreamPop(patstream
);
13854 if (cur
->next
!= NULL
) {
13858 } while (cur
!= NULL
);
13860 } while ((cur
!= NULL
) && (depth
>= 0));
13865 printf("stream eval: checked %d nodes selected %d\n",
13866 nb_nodes
, retObj
->nodesetval
->nodeNr
);
13870 xmlFreeStreamCtxt(patstream
);
13875 xmlFreeStreamCtxt(patstream
);
13878 #endif /* XPATH_STREAMING */
13882 * @ctxt: the XPath parser context with the compiled expression
13883 * @toBool: evaluate to a boolean result
13885 * Evaluate the Precompiled XPath expression in the given context.
13888 xmlXPathRunEval(xmlXPathParserContextPtr ctxt
, int toBool
)
13890 xmlXPathCompExprPtr comp
;
13892 if ((ctxt
== NULL
) || (ctxt
->comp
== NULL
))
13895 ctxt
->context
->depth
= 0;
13897 if (ctxt
->valueTab
== NULL
) {
13898 /* Allocate the value stack */
13899 ctxt
->valueTab
= (xmlXPathObjectPtr
*)
13900 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
13901 if (ctxt
->valueTab
== NULL
) {
13902 xmlXPathPErrMemory(ctxt
, "creating evaluation context\n");
13906 ctxt
->valueMax
= 10;
13907 ctxt
->value
= NULL
;
13908 ctxt
->valueFrame
= 0;
13910 #ifdef XPATH_STREAMING
13911 if (ctxt
->comp
->stream
) {
13916 * Evaluation to boolean result.
13918 res
= xmlXPathRunStreamEval(ctxt
->context
,
13919 ctxt
->comp
->stream
, NULL
, 1);
13923 xmlXPathObjectPtr resObj
= NULL
;
13926 * Evaluation to a sequence.
13928 res
= xmlXPathRunStreamEval(ctxt
->context
,
13929 ctxt
->comp
->stream
, &resObj
, 0);
13931 if ((res
!= -1) && (resObj
!= NULL
)) {
13932 valuePush(ctxt
, resObj
);
13935 if (resObj
!= NULL
)
13936 xmlXPathReleaseObject(ctxt
->context
, resObj
);
13939 * QUESTION TODO: This falls back to normal XPath evaluation
13940 * if res == -1. Is this intended?
13945 if (comp
->last
< 0) {
13946 xmlGenericError(xmlGenericErrorContext
,
13947 "xmlXPathRunEval: last is less than zero\n");
13951 return(xmlXPathCompOpEvalToBoolean(ctxt
,
13952 &comp
->steps
[comp
->last
], 0));
13954 xmlXPathCompOpEval(ctxt
, &comp
->steps
[comp
->last
]);
13959 /************************************************************************
13961 * Public interfaces *
13963 ************************************************************************/
13966 * xmlXPathEvalPredicate:
13967 * @ctxt: the XPath context
13968 * @res: the Predicate Expression evaluation result
13970 * Evaluate a predicate result for the current node.
13971 * A PredicateExpr is evaluated by evaluating the Expr and converting
13972 * the result to a boolean. If the result is a number, the result will
13973 * be converted to true if the number is equal to the position of the
13974 * context node in the context node list (as returned by the position
13975 * function) and will be converted to false otherwise; if the result
13976 * is not a number, then the result will be converted as if by a call
13977 * to the boolean function.
13979 * Returns 1 if predicate is true, 0 otherwise
13982 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr res
) {
13983 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
13984 switch (res
->type
) {
13985 case XPATH_BOOLEAN
:
13986 return(res
->boolval
);
13988 return(res
->floatval
== ctxt
->proximityPosition
);
13989 case XPATH_NODESET
:
13990 case XPATH_XSLT_TREE
:
13991 if (res
->nodesetval
== NULL
)
13993 return(res
->nodesetval
->nodeNr
!= 0);
13995 return((res
->stringval
!= NULL
) &&
13996 (xmlStrlen(res
->stringval
) != 0));
14004 * xmlXPathEvaluatePredicateResult:
14005 * @ctxt: the XPath Parser context
14006 * @res: the Predicate Expression evaluation result
14008 * Evaluate a predicate result for the current node.
14009 * A PredicateExpr is evaluated by evaluating the Expr and converting
14010 * the result to a boolean. If the result is a number, the result will
14011 * be converted to true if the number is equal to the position of the
14012 * context node in the context node list (as returned by the position
14013 * function) and will be converted to false otherwise; if the result
14014 * is not a number, then the result will be converted as if by a call
14015 * to the boolean function.
14017 * Returns 1 if predicate is true, 0 otherwise
14020 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt
,
14021 xmlXPathObjectPtr res
) {
14022 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14023 switch (res
->type
) {
14024 case XPATH_BOOLEAN
:
14025 return(res
->boolval
);
14027 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14028 return((res
->floatval
== ctxt
->context
->proximityPosition
) &&
14029 (!xmlXPathIsNaN(res
->floatval
))); /* MSC pbm Mark Vakoc !*/
14031 return(res
->floatval
== ctxt
->context
->proximityPosition
);
14033 case XPATH_NODESET
:
14034 case XPATH_XSLT_TREE
:
14035 if (res
->nodesetval
== NULL
)
14037 return(res
->nodesetval
->nodeNr
!= 0);
14039 return((res
->stringval
!= NULL
) && (res
->stringval
[0] != 0));
14040 #ifdef LIBXML_XPTR_ENABLED
14041 case XPATH_LOCATIONSET
:{
14042 xmlLocationSetPtr ptr
= res
->user
;
14045 return (ptr
->locNr
!= 0);
14054 #ifdef XPATH_STREAMING
14056 * xmlXPathTryStreamCompile:
14057 * @ctxt: an XPath context
14058 * @str: the XPath expression
14060 * Try to compile the XPath expression as a streamable subset.
14062 * Returns the compiled expression or NULL if failed to compile.
14064 static xmlXPathCompExprPtr
14065 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14067 * Optimization: use streaming patterns when the XPath expression can
14068 * be compiled to a stream lookup
14070 xmlPatternPtr stream
;
14071 xmlXPathCompExprPtr comp
;
14072 xmlDictPtr dict
= NULL
;
14073 const xmlChar
**namespaces
= NULL
;
14077 if ((!xmlStrchr(str
, '[')) && (!xmlStrchr(str
, '(')) &&
14078 (!xmlStrchr(str
, '@'))) {
14079 const xmlChar
*tmp
;
14082 * We don't try to handle expressions using the verbose axis
14083 * specifiers ("::"), just the simplified form at this point.
14084 * Additionally, if there is no list of namespaces available and
14085 * there's a ":" in the expression, indicating a prefixed QName,
14086 * then we won't try to compile either. xmlPatterncompile() needs
14087 * to have a list of namespaces at compilation time in order to
14088 * compile prefixed name tests.
14090 tmp
= xmlStrchr(str
, ':');
14091 if ((tmp
!= NULL
) &&
14092 ((ctxt
== NULL
) || (ctxt
->nsNr
== 0) || (tmp
[1] == ':')))
14095 if (ctxt
!= NULL
) {
14097 if (ctxt
->nsNr
> 0) {
14098 namespaces
= xmlMalloc(2 * (ctxt
->nsNr
+ 1) * sizeof(xmlChar
*));
14099 if (namespaces
== NULL
) {
14100 xmlXPathErrMemory(ctxt
, "allocating namespaces array\n");
14103 for (i
= 0, j
= 0; (j
< ctxt
->nsNr
); j
++) {
14104 ns
= ctxt
->namespaces
[j
];
14105 namespaces
[i
++] = ns
->href
;
14106 namespaces
[i
++] = ns
->prefix
;
14108 namespaces
[i
++] = NULL
;
14109 namespaces
[i
] = NULL
;
14113 stream
= xmlPatterncompile(str
, dict
, XML_PATTERN_XPATH
, namespaces
);
14114 if (namespaces
!= NULL
) {
14115 xmlFree((xmlChar
**)namespaces
);
14117 if ((stream
!= NULL
) && (xmlPatternStreamable(stream
) == 1)) {
14118 comp
= xmlXPathNewCompExpr();
14119 if (comp
== NULL
) {
14120 xmlXPathErrMemory(ctxt
, "allocating streamable expression\n");
14123 comp
->stream
= stream
;
14126 xmlDictReference(comp
->dict
);
14129 xmlFreePattern(stream
);
14133 #endif /* XPATH_STREAMING */
14136 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt
,
14137 xmlXPathStepOpPtr op
)
14139 xmlXPathCompExprPtr comp
= pctxt
->comp
;
14140 xmlXPathContextPtr ctxt
;
14143 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14144 * internal representation.
14147 if ((op
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14149 (op
->ch2
== -1 /* no predicate */))
14151 xmlXPathStepOpPtr prevop
= &comp
->steps
[op
->ch1
];
14153 if ((prevop
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14154 ((xmlXPathAxisVal
) prevop
->value
==
14155 AXIS_DESCENDANT_OR_SELF
) &&
14156 (prevop
->ch2
== -1) &&
14157 ((xmlXPathTestVal
) prevop
->value2
== NODE_TEST_TYPE
) &&
14158 ((xmlXPathTypeVal
) prevop
->value3
== NODE_TYPE_NODE
))
14161 * This is a "descendant-or-self::node()" without predicates.
14162 * Try to eliminate it.
14165 switch ((xmlXPathAxisVal
) op
->value
) {
14167 case AXIS_DESCENDANT
:
14169 * Convert "descendant-or-self::node()/child::" or
14170 * "descendant-or-self::node()/descendant::" to
14173 op
->ch1
= prevop
->ch1
;
14174 op
->value
= AXIS_DESCENDANT
;
14177 case AXIS_DESCENDANT_OR_SELF
:
14179 * Convert "descendant-or-self::node()/self::" or
14180 * "descendant-or-self::node()/descendant-or-self::" to
14181 * to "descendant-or-self::"
14183 op
->ch1
= prevop
->ch1
;
14184 op
->value
= AXIS_DESCENDANT_OR_SELF
;
14192 /* OP_VALUE has invalid ch1. */
14193 if (op
->op
== XPATH_OP_VALUE
)
14197 ctxt
= pctxt
->context
;
14198 if (ctxt
!= NULL
) {
14199 if (ctxt
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
14204 xmlXPathOptimizeExpression(pctxt
, &comp
->steps
[op
->ch1
]);
14206 xmlXPathOptimizeExpression(pctxt
, &comp
->steps
[op
->ch2
]);
14212 * xmlXPathCtxtCompile:
14213 * @ctxt: an XPath context
14214 * @str: the XPath expression
14216 * Compile an XPath expression
14218 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14219 * the caller has to free the object.
14221 xmlXPathCompExprPtr
14222 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14223 xmlXPathParserContextPtr pctxt
;
14224 xmlXPathCompExprPtr comp
;
14226 #ifdef XPATH_STREAMING
14227 comp
= xmlXPathTryStreamCompile(ctxt
, str
);
14234 pctxt
= xmlXPathNewParserContext(str
, ctxt
);
14239 xmlXPathCompileExpr(pctxt
, 1);
14241 if( pctxt
->error
!= XPATH_EXPRESSION_OK
)
14243 xmlXPathFreeParserContext(pctxt
);
14247 if (*pctxt
->cur
!= 0) {
14249 * aleksey: in some cases this line prints *second* error message
14250 * (see bug #78858) and probably this should be fixed.
14251 * However, we are not sure that all error messages are printed
14252 * out in other places. It's not critical so we leave it as-is for now
14254 xmlXPatherror(pctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
14257 comp
= pctxt
->comp
;
14258 if ((comp
->nbStep
> 1) && (comp
->last
>= 0)) {
14261 xmlXPathOptimizeExpression(pctxt
, &comp
->steps
[comp
->last
]);
14263 pctxt
->comp
= NULL
;
14265 xmlXPathFreeParserContext(pctxt
);
14267 if (comp
!= NULL
) {
14268 comp
->expr
= xmlStrdup(str
);
14269 #ifdef DEBUG_EVAL_COUNTS
14270 comp
->string
= xmlStrdup(str
);
14279 * @str: the XPath expression
14281 * Compile an XPath expression
14283 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14284 * the caller has to free the object.
14286 xmlXPathCompExprPtr
14287 xmlXPathCompile(const xmlChar
*str
) {
14288 return(xmlXPathCtxtCompile(NULL
, str
));
14292 * xmlXPathCompiledEvalInternal:
14293 * @comp: the compiled XPath expression
14294 * @ctxt: the XPath context
14295 * @resObj: the resulting XPath object or NULL
14296 * @toBool: 1 if only a boolean result is requested
14298 * Evaluate the Precompiled XPath expression in the given context.
14299 * The caller has to free @resObj.
14301 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14302 * the caller has to free the object.
14305 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp
,
14306 xmlXPathContextPtr ctxt
,
14307 xmlXPathObjectPtr
*resObjPtr
,
14310 xmlXPathParserContextPtr pctxt
;
14311 xmlXPathObjectPtr resObj
;
14312 #ifndef LIBXML_THREAD_ENABLED
14313 static int reentance
= 0;
14317 CHECK_CTXT_NEG(ctxt
)
14323 #ifndef LIBXML_THREAD_ENABLED
14326 xmlXPathDisableOptimizer
= 1;
14329 #ifdef DEBUG_EVAL_COUNTS
14331 if ((comp
->string
!= NULL
) && (comp
->nb
> 100)) {
14332 fprintf(stderr
, "100 x %s\n", comp
->string
);
14336 pctxt
= xmlXPathCompParserContext(comp
, ctxt
);
14337 res
= xmlXPathRunEval(pctxt
, toBool
);
14339 if (pctxt
->error
!= XPATH_EXPRESSION_OK
) {
14342 resObj
= valuePop(pctxt
);
14343 if (resObj
== NULL
) {
14345 xmlGenericError(xmlGenericErrorContext
,
14346 "xmlXPathCompiledEval: No result on the stack.\n");
14347 } else if (pctxt
->valueNr
> 0) {
14348 xmlGenericError(xmlGenericErrorContext
,
14349 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14355 *resObjPtr
= resObj
;
14357 xmlXPathReleaseObject(ctxt
, resObj
);
14359 pctxt
->comp
= NULL
;
14360 xmlXPathFreeParserContext(pctxt
);
14361 #ifndef LIBXML_THREAD_ENABLED
14369 * xmlXPathCompiledEval:
14370 * @comp: the compiled XPath expression
14371 * @ctx: the XPath context
14373 * Evaluate the Precompiled XPath expression in the given context.
14375 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14376 * the caller has to free the object.
14379 xmlXPathCompiledEval(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctx
)
14381 xmlXPathObjectPtr res
= NULL
;
14383 xmlXPathCompiledEvalInternal(comp
, ctx
, &res
, 0);
14388 * xmlXPathCompiledEvalToBoolean:
14389 * @comp: the compiled XPath expression
14390 * @ctxt: the XPath context
14392 * Applies the XPath boolean() function on the result of the given
14393 * compiled expression.
14395 * Returns 1 if the expression evaluated to true, 0 if to false and
14396 * -1 in API and internal errors.
14399 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp
,
14400 xmlXPathContextPtr ctxt
)
14402 return(xmlXPathCompiledEvalInternal(comp
, ctxt
, NULL
, 1));
14406 * xmlXPathEvalExpr:
14407 * @ctxt: the XPath Parser context
14409 * Parse and evaluate an XPath expression in the given context,
14410 * then push the result on the context stack
14413 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt
) {
14414 #ifdef XPATH_STREAMING
14415 xmlXPathCompExprPtr comp
;
14418 if (ctxt
== NULL
) return;
14420 #ifdef XPATH_STREAMING
14421 comp
= xmlXPathTryStreamCompile(ctxt
->context
, ctxt
->base
);
14422 if (comp
!= NULL
) {
14423 if (ctxt
->comp
!= NULL
)
14424 xmlXPathFreeCompExpr(ctxt
->comp
);
14429 if (ctxt
->context
!= NULL
)
14430 ctxt
->context
->depth
= 0;
14431 xmlXPathCompileExpr(ctxt
, 1);
14434 /* Check for trailing characters. */
14435 if (*ctxt
->cur
!= 0)
14436 XP_ERROR(XPATH_EXPR_ERROR
);
14438 if ((ctxt
->comp
->nbStep
> 1) && (ctxt
->comp
->last
>= 0)) {
14439 if (ctxt
->context
!= NULL
)
14440 ctxt
->context
->depth
= 0;
14441 xmlXPathOptimizeExpression(ctxt
,
14442 &ctxt
->comp
->steps
[ctxt
->comp
->last
]);
14446 xmlXPathRunEval(ctxt
, 0);
14451 * @str: the XPath expression
14452 * @ctx: the XPath context
14454 * Evaluate the XPath Location Path in the given context.
14456 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14457 * the caller has to free the object.
14460 xmlXPathEval(const xmlChar
*str
, xmlXPathContextPtr ctx
) {
14461 xmlXPathParserContextPtr ctxt
;
14462 xmlXPathObjectPtr res
;
14468 ctxt
= xmlXPathNewParserContext(str
, ctx
);
14471 xmlXPathEvalExpr(ctxt
);
14473 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14476 res
= valuePop(ctxt
);
14478 xmlGenericError(xmlGenericErrorContext
,
14479 "xmlXPathCompiledEval: No result on the stack.\n");
14480 } else if (ctxt
->valueNr
> 0) {
14481 xmlGenericError(xmlGenericErrorContext
,
14482 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14487 xmlXPathFreeParserContext(ctxt
);
14492 * xmlXPathSetContextNode:
14493 * @node: the node to to use as the context node
14494 * @ctx: the XPath context
14496 * Sets 'node' as the context node. The node must be in the same
14497 * document as that associated with the context.
14499 * Returns -1 in case of error or 0 if successful
14502 xmlXPathSetContextNode(xmlNodePtr node
, xmlXPathContextPtr ctx
) {
14503 if ((node
== NULL
) || (ctx
== NULL
))
14506 if (node
->doc
== ctx
->doc
) {
14514 * xmlXPathNodeEval:
14515 * @node: the node to to use as the context node
14516 * @str: the XPath expression
14517 * @ctx: the XPath context
14519 * Evaluate the XPath Location Path in the given context. The node 'node'
14520 * is set as the context node. The context node is not restored.
14522 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14523 * the caller has to free the object.
14526 xmlXPathNodeEval(xmlNodePtr node
, const xmlChar
*str
, xmlXPathContextPtr ctx
) {
14529 if (xmlXPathSetContextNode(node
, ctx
) < 0)
14531 return(xmlXPathEval(str
, ctx
));
14535 * xmlXPathEvalExpression:
14536 * @str: the XPath expression
14537 * @ctxt: the XPath context
14539 * Alias for xmlXPathEval().
14541 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14542 * the caller has to free the object.
14545 xmlXPathEvalExpression(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
14546 return(xmlXPathEval(str
, ctxt
));
14549 /************************************************************************
14551 * Extra functions not pertaining to the XPath spec *
14553 ************************************************************************/
14555 * xmlXPathEscapeUriFunction:
14556 * @ctxt: the XPath Parser context
14557 * @nargs: the number of arguments
14559 * Implement the escape-uri() XPath function
14560 * string escape-uri(string $str, bool $escape-reserved)
14562 * This function applies the URI escaping rules defined in section 2 of [RFC
14563 * 2396] to the string supplied as $uri-part, which typically represents all
14564 * or part of a URI. The effect of the function is to replace any special
14565 * character in the string by an escape sequence of the form %xx%yy...,
14566 * where xxyy... is the hexadecimal representation of the octets used to
14567 * represent the character in UTF-8.
14569 * The set of characters that are escaped depends on the setting of the
14570 * boolean argument $escape-reserved.
14572 * If $escape-reserved is true, all characters are escaped other than lower
14573 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14574 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14575 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14576 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14579 * If $escape-reserved is false, the behavior differs in that characters
14580 * referred to in [RFC 2396] as reserved characters are not escaped. These
14581 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14583 * [RFC 2396] does not define whether escaped URIs should use lower case or
14584 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14585 * compared using string comparison functions, this function must always use
14586 * the upper-case letters A-F.
14588 * Generally, $escape-reserved should be set to true when escaping a string
14589 * that is to form a single part of a URI, and to false when escaping an
14590 * entire URI or URI reference.
14592 * In the case of non-ascii characters, the string is encoded according to
14593 * utf-8 and then converted according to RFC 2396.
14596 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14597 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14598 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14599 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14603 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
14604 xmlXPathObjectPtr str
;
14605 int escape_reserved
;
14612 escape_reserved
= xmlXPathPopBoolean(ctxt
);
14615 str
= valuePop(ctxt
);
14617 target
= xmlBufCreate();
14623 for (cptr
= str
->stringval
; *cptr
; cptr
++) {
14624 if ((*cptr
>= 'A' && *cptr
<= 'Z') ||
14625 (*cptr
>= 'a' && *cptr
<= 'z') ||
14626 (*cptr
>= '0' && *cptr
<= '9') ||
14627 *cptr
== '-' || *cptr
== '_' || *cptr
== '.' ||
14628 *cptr
== '!' || *cptr
== '~' || *cptr
== '*' ||
14629 *cptr
== '\''|| *cptr
== '(' || *cptr
== ')' ||
14631 ((cptr
[1] >= 'A' && cptr
[1] <= 'F') ||
14632 (cptr
[1] >= 'a' && cptr
[1] <= 'f') ||
14633 (cptr
[1] >= '0' && cptr
[1] <= '9')) &&
14634 ((cptr
[2] >= 'A' && cptr
[2] <= 'F') ||
14635 (cptr
[2] >= 'a' && cptr
[2] <= 'f') ||
14636 (cptr
[2] >= '0' && cptr
[2] <= '9'))) ||
14637 (!escape_reserved
&&
14638 (*cptr
== ';' || *cptr
== '/' || *cptr
== '?' ||
14639 *cptr
== ':' || *cptr
== '@' || *cptr
== '&' ||
14640 *cptr
== '=' || *cptr
== '+' || *cptr
== '$' ||
14642 xmlBufAdd(target
, cptr
, 1);
14644 if ((*cptr
>> 4) < 10)
14645 escape
[1] = '0' + (*cptr
>> 4);
14647 escape
[1] = 'A' - 10 + (*cptr
>> 4);
14648 if ((*cptr
& 0xF) < 10)
14649 escape
[2] = '0' + (*cptr
& 0xF);
14651 escape
[2] = 'A' - 10 + (*cptr
& 0xF);
14653 xmlBufAdd(target
, &escape
[0], 3);
14657 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
14658 xmlBufContent(target
)));
14659 xmlBufFree(target
);
14660 xmlXPathReleaseObject(ctxt
->context
, str
);
14664 * xmlXPathRegisterAllFunctions:
14665 * @ctxt: the XPath context
14667 * Registers all default XPath functions in this context
14670 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt
)
14672 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"boolean",
14673 xmlXPathBooleanFunction
);
14674 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"ceiling",
14675 xmlXPathCeilingFunction
);
14676 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"count",
14677 xmlXPathCountFunction
);
14678 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"concat",
14679 xmlXPathConcatFunction
);
14680 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"contains",
14681 xmlXPathContainsFunction
);
14682 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"id",
14683 xmlXPathIdFunction
);
14684 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"false",
14685 xmlXPathFalseFunction
);
14686 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"floor",
14687 xmlXPathFloorFunction
);
14688 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"last",
14689 xmlXPathLastFunction
);
14690 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"lang",
14691 xmlXPathLangFunction
);
14692 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"local-name",
14693 xmlXPathLocalNameFunction
);
14694 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"not",
14695 xmlXPathNotFunction
);
14696 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"name",
14697 xmlXPathNameFunction
);
14698 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"namespace-uri",
14699 xmlXPathNamespaceURIFunction
);
14700 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"normalize-space",
14701 xmlXPathNormalizeFunction
);
14702 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"number",
14703 xmlXPathNumberFunction
);
14704 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"position",
14705 xmlXPathPositionFunction
);
14706 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"round",
14707 xmlXPathRoundFunction
);
14708 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string",
14709 xmlXPathStringFunction
);
14710 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string-length",
14711 xmlXPathStringLengthFunction
);
14712 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"starts-with",
14713 xmlXPathStartsWithFunction
);
14714 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring",
14715 xmlXPathSubstringFunction
);
14716 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-before",
14717 xmlXPathSubstringBeforeFunction
);
14718 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-after",
14719 xmlXPathSubstringAfterFunction
);
14720 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"sum",
14721 xmlXPathSumFunction
);
14722 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"true",
14723 xmlXPathTrueFunction
);
14724 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"translate",
14725 xmlXPathTranslateFunction
);
14727 xmlXPathRegisterFuncNS(ctxt
, (const xmlChar
*)"escape-uri",
14728 (const xmlChar
*)"http://www.w3.org/2002/08/xquery-functions",
14729 xmlXPathEscapeUriFunction
);
14732 #endif /* LIBXML_XPATH_ENABLED */
14733 #define bottom_xpath
14734 #include "elfgcchack.h"