2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
4 * designed to be used by both XSLT and XPointer
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
9 * http://www.w3.org/TR/xpath
11 * See Copyright for the status of this software
13 * Author: daniel@veillard.com
17 /* To avoid EBCDIC trouble when parsing on zOS */
19 #pragma convert("ISO8859-1")
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
45 #include <libxml/xmlmemory.h>
46 #include <libxml/tree.h>
47 #include <libxml/valid.h>
48 #include <libxml/xpath.h>
49 #include <libxml/xpathInternals.h>
50 #include <libxml/parserInternals.h>
51 #include <libxml/hash.h>
52 #ifdef LIBXML_XPTR_ENABLED
53 #include <libxml/xpointer.h>
55 #ifdef LIBXML_DEBUG_ENABLED
56 #include <libxml/debugXML.h>
58 #include <libxml/xmlerror.h>
59 #include <libxml/threads.h>
60 #include <libxml/globals.h>
61 #ifdef LIBXML_PATTERN_ENABLED
62 #include <libxml/pattern.h>
67 #ifdef LIBXML_PATTERN_ENABLED
68 #define XPATH_STREAMING
72 xmlGenericError(xmlGenericErrorContext, \
73 "Unimplemented block at %s:%d\n", \
79 * Use the Timsort algorithm provided in timsort.h to sort
80 * nodeset as this is a great improvement over the old Shell sort
81 * used in xmlXPathNodeSetSort()
86 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
87 * If defined, this will use xmlXPathCmpNodesExt() instead of
88 * xmlXPathCmpNodes(). The new function is optimized comparison of
89 * non-element nodes; actually it will speed up comparison only if
90 * xmlXPathOrderDocElems() was called in order to index the elements of
91 * a tree in document order; Libxslt does such an indexing, thus it will
92 * benefit from this optimization.
94 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
97 * XP_OPTIMIZED_FILTER_FIRST:
98 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
99 * in a way, that it stop evaluation at the first node.
101 #define XP_OPTIMIZED_FILTER_FIRST
104 * XP_DEBUG_OBJ_USAGE:
105 * Internal flag to enable tracking of how much XPath objects have been
108 /* #define XP_DEBUG_OBJ_USAGE */
112 * when compiling an XPath expression we arbitrary limit the maximum
113 * number of step operation in the compiled expression. 1000000 is
114 * an insanely large value which should never be reached under normal
117 #define XPATH_MAX_STEPS 1000000
120 * XPATH_MAX_STACK_DEPTH:
121 * when evaluating an XPath expression we arbitrary limit the maximum
122 * number of object allowed to be pushed on the stack. 1000000 is
123 * an insanely large value which should never be reached under normal
126 #define XPATH_MAX_STACK_DEPTH 1000000
129 * XPATH_MAX_NODESET_LENGTH:
130 * when evaluating an XPath expression nodesets are created and we
131 * arbitrary limit the maximum length of those node set. 10000000 is
132 * an insanely large value which should never be reached under normal
133 * circumstances, one would first need to construct an in memory tree
134 * with more than 10 millions nodes.
136 #define XPATH_MAX_NODESET_LENGTH 10000000
140 * There are a few spots where some tests are done which depend upon ascii
141 * data. These should be enhanced for full UTF8 support (see particularly
142 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
145 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
147 * xmlXPathCmpNodesExt:
148 * @node1: the first node
149 * @node2: the second node
151 * Compare two nodes w.r.t document order.
152 * This one is optimized for handling of non-element nodes.
154 * Returns -2 in case of error 1 if first point < second point, 0 if
155 * it's the same node, -1 otherwise
158 xmlXPathCmpNodesExt(xmlNodePtr node1
, xmlNodePtr node2
) {
160 int misc
= 0, precedence1
= 0, precedence2
= 0;
161 xmlNodePtr miscNode1
= NULL
, miscNode2
= NULL
;
162 xmlNodePtr cur
, root
;
165 if ((node1
== NULL
) || (node2
== NULL
))
172 * a couple of optimizations which will avoid computations in most cases
174 switch (node1
->type
) {
175 case XML_ELEMENT_NODE
:
176 if (node2
->type
== XML_ELEMENT_NODE
) {
177 if ((0 > (ptrdiff_t) node1
->content
) &&
178 (0 > (ptrdiff_t) node2
->content
) &&
179 (node1
->doc
== node2
->doc
))
181 l1
= -((ptrdiff_t) node1
->content
);
182 l2
= -((ptrdiff_t) node2
->content
);
188 goto turtle_comparison
;
191 case XML_ATTRIBUTE_NODE
:
192 precedence1
= 1; /* element is owner */
194 node1
= node1
->parent
;
198 case XML_CDATA_SECTION_NODE
:
199 case XML_COMMENT_NODE
:
203 * Find nearest element node.
205 if (node1
->prev
!= NULL
) {
208 if (node1
->type
== XML_ELEMENT_NODE
) {
209 precedence1
= 3; /* element in prev-sibl axis */
212 if (node1
->prev
== NULL
) {
213 precedence1
= 2; /* element is parent */
215 * URGENT TODO: Are there any cases, where the
216 * parent of such a node is not an element node?
218 node1
= node1
->parent
;
223 precedence1
= 2; /* element is parent */
224 node1
= node1
->parent
;
226 if ((node1
== NULL
) || (node1
->type
!= XML_ELEMENT_NODE
) ||
227 (0 <= (ptrdiff_t) node1
->content
)) {
229 * Fallback for whatever case.
237 case XML_NAMESPACE_DECL
:
239 * TODO: why do we return 1 for namespace nodes?
245 switch (node2
->type
) {
246 case XML_ELEMENT_NODE
:
248 case XML_ATTRIBUTE_NODE
:
249 precedence2
= 1; /* element is owner */
251 node2
= node2
->parent
;
255 case XML_CDATA_SECTION_NODE
:
256 case XML_COMMENT_NODE
:
259 if (node2
->prev
!= NULL
) {
262 if (node2
->type
== XML_ELEMENT_NODE
) {
263 precedence2
= 3; /* element in prev-sibl axis */
266 if (node2
->prev
== NULL
) {
267 precedence2
= 2; /* element is parent */
268 node2
= node2
->parent
;
273 precedence2
= 2; /* element is parent */
274 node2
= node2
->parent
;
276 if ((node2
== NULL
) || (node2
->type
!= XML_ELEMENT_NODE
) ||
277 (0 <= (ptrdiff_t) node2
->content
))
285 case XML_NAMESPACE_DECL
:
291 if (node1
== node2
) {
292 if (precedence1
== precedence2
) {
294 * The ugly case; but normally there aren't many
295 * adjacent non-element nodes around.
297 cur
= miscNode2
->prev
;
298 while (cur
!= NULL
) {
299 if (cur
== miscNode1
)
301 if (cur
->type
== XML_ELEMENT_NODE
)
308 * Evaluate based on higher precedence wrt to the element.
309 * TODO: This assumes attributes are sorted before content.
310 * Is this 100% correct?
312 if (precedence1
< precedence2
)
319 * Special case: One of the helper-elements is contained by the other.
322 * <node1>Text-1(precedence1 == 2)</node1>
324 * Text-6(precedence2 == 3)
327 if ((precedence2
== 3) && (precedence1
> 1)) {
335 if ((precedence1
== 3) && (precedence2
> 1)) {
346 * Speedup using document order if availble.
348 if ((node1
->type
== XML_ELEMENT_NODE
) &&
349 (node2
->type
== XML_ELEMENT_NODE
) &&
350 (0 > (ptrdiff_t) node1
->content
) &&
351 (0 > (ptrdiff_t) node2
->content
) &&
352 (node1
->doc
== node2
->doc
)) {
354 l1
= -((ptrdiff_t) node1
->content
);
355 l2
= -((ptrdiff_t) node2
->content
);
364 if (node1
== node2
->prev
)
366 if (node1
== node2
->next
)
369 * compute depth to root
371 for (depth2
= 0, cur
= node2
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
372 if (cur
->parent
== node1
)
377 for (depth1
= 0, cur
= node1
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
378 if (cur
->parent
== node2
)
383 * Distinct document (or distinct entities :-( ) case.
389 * get the nearest common ancestor.
391 while (depth1
> depth2
) {
393 node1
= node1
->parent
;
395 while (depth2
> depth1
) {
397 node2
= node2
->parent
;
399 while (node1
->parent
!= node2
->parent
) {
400 node1
= node1
->parent
;
401 node2
= node2
->parent
;
402 /* should not happen but just in case ... */
403 if ((node1
== NULL
) || (node2
== NULL
))
409 if (node1
== node2
->prev
)
411 if (node1
== node2
->next
)
414 * Speedup using document order if availble.
416 if ((node1
->type
== XML_ELEMENT_NODE
) &&
417 (node2
->type
== XML_ELEMENT_NODE
) &&
418 (0 > (ptrdiff_t) node1
->content
) &&
419 (0 > (ptrdiff_t) node2
->content
) &&
420 (node1
->doc
== node2
->doc
)) {
422 l1
= -((ptrdiff_t) node1
->content
);
423 l2
= -((ptrdiff_t) node2
->content
);
430 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
433 return(-1); /* assume there is no sibling list corruption */
435 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
438 * Wrapper for the Timsort argorithm from timsort.h
441 #define SORT_NAME libxml_domnode
442 #define SORT_TYPE xmlNodePtr
448 * Comparison function for the Timsort implementation
450 * Returns -2 in case of error -1 if first point < second point, 0 if
451 * it's the same node, +1 otherwise
454 int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
);
455 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
456 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
458 int res
= xmlXPathCmpNodesExt(x
, y
);
459 return res
== -2 ? res
: -res
;
462 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
464 int res
= xmlXPathCmpNodes(x
, y
);
465 return res
== -2 ? res
: -res
;
468 #define SORT_CMP(x, y) (wrap_cmp(x, y))
470 #endif /* WITH_TIM_SORT */
472 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
474 /************************************************************************
476 * Floating point stuff *
478 ************************************************************************/
481 #define INFINITY (DBL_MAX * DBL_MAX)
485 #define NAN (INFINITY / INFINITY)
495 * Initialize the XPath environment
500 xmlXPathPINF
= INFINITY
;
501 xmlXPathNINF
= -INFINITY
;
506 * @val: a double value
508 * Returns 1 if the value is a NaN, 0 otherwise
511 xmlXPathIsNaN(double val
) {
515 return !(val
== val
);
521 * @val: a double value
523 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
526 xmlXPathIsInf(double val
) {
528 return isinf(val
) ? (val
> 0 ? 1 : -1) : 0;
532 if (val
<= -INFINITY
)
538 #endif /* SCHEMAS or XPATH */
540 #ifdef LIBXML_XPATH_ENABLED
543 * TODO: when compatibility allows remove all "fake node libxslt" strings
544 * the test should just be name[0] = ' '
546 #ifdef DEBUG_XPATH_EXPRESSION
549 #define DEBUG_EVAL_COUNTS
552 static xmlNs xmlXPathXMLNamespaceStruct
= {
560 static xmlNsPtr xmlXPathXMLNamespace
= &xmlXPathXMLNamespaceStruct
;
561 #ifndef LIBXML_THREAD_ENABLED
563 * Optimizer is disabled only when threaded apps are detected while
564 * the library ain't compiled for thread safety.
566 static int xmlXPathDisableOptimizer
= 0;
569 /************************************************************************
571 * Error handling routines *
573 ************************************************************************/
579 * Macro to raise an XPath error and return NULL.
581 #define XP_ERRORNULL(X) \
582 { xmlXPathErr(ctxt, X); return(NULL); }
585 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
587 static const char *xmlXPathErrorMessages
[] = {
590 "Unfinished literal\n",
591 "Start of literal\n",
592 "Expected $ for variable reference\n",
593 "Undefined variable\n",
594 "Invalid predicate\n",
595 "Invalid expression\n",
596 "Missing closing curly brace\n",
597 "Unregistered function\n",
600 "Invalid number of arguments\n",
601 "Invalid context size\n",
602 "Invalid context position\n",
603 "Memory allocation error\n",
606 "Sub resource error\n",
607 "Undefined namespace prefix\n",
609 "Char out of XML range\n",
610 "Invalid or incomplete context\n",
611 "Stack usage error\n",
612 "Forbidden variable\n",
613 "?? Unknown error ??\n" /* Must be last in the list! */
615 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
616 sizeof(xmlXPathErrorMessages[0])) - 1)
619 * @ctxt: an XPath context
620 * @extra: extra informations
622 * Handle a redefinition of attribute error
625 xmlXPathErrMemory(xmlXPathContextPtr ctxt
, const char *extra
)
631 xmlStrPrintf(buf
, 200,
632 "Memory allocation failed : %s\n",
634 ctxt
->lastError
.message
= (char *) xmlStrdup(buf
);
636 ctxt
->lastError
.message
= (char *)
637 xmlStrdup(BAD_CAST
"Memory allocation failed\n");
639 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
640 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
641 if (ctxt
->error
!= NULL
)
642 ctxt
->error(ctxt
->userData
, &ctxt
->lastError
);
645 __xmlRaiseError(NULL
, NULL
, NULL
,
646 NULL
, NULL
, XML_FROM_XPATH
,
647 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
648 extra
, NULL
, NULL
, 0, 0,
649 "Memory allocation failed : %s\n", extra
);
651 __xmlRaiseError(NULL
, NULL
, NULL
,
652 NULL
, NULL
, XML_FROM_XPATH
,
653 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
654 NULL
, NULL
, NULL
, 0, 0,
655 "Memory allocation failed\n");
660 * xmlXPathPErrMemory:
661 * @ctxt: an XPath parser context
662 * @extra: extra informations
664 * Handle a redefinition of attribute error
667 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt
, const char *extra
)
670 xmlXPathErrMemory(NULL
, extra
);
672 ctxt
->error
= XPATH_MEMORY_ERROR
;
673 xmlXPathErrMemory(ctxt
->context
, extra
);
679 * @ctxt: a XPath parser context
680 * @error: the error code
682 * Handle an XPath error
685 xmlXPathErr(xmlXPathParserContextPtr ctxt
, int error
)
687 if ((error
< 0) || (error
> MAXERRNO
))
690 __xmlRaiseError(NULL
, NULL
, NULL
,
691 NULL
, NULL
, XML_FROM_XPATH
,
692 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
693 XML_ERR_ERROR
, NULL
, 0,
694 NULL
, NULL
, NULL
, 0, 0,
695 "%s", xmlXPathErrorMessages
[error
]);
699 if (ctxt
->context
== NULL
) {
700 __xmlRaiseError(NULL
, NULL
, NULL
,
701 NULL
, NULL
, XML_FROM_XPATH
,
702 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
703 XML_ERR_ERROR
, NULL
, 0,
704 (const char *) ctxt
->base
, NULL
, NULL
,
705 ctxt
->cur
- ctxt
->base
, 0,
706 "%s", xmlXPathErrorMessages
[error
]);
710 /* cleanup current last error */
711 xmlResetError(&ctxt
->context
->lastError
);
713 ctxt
->context
->lastError
.domain
= XML_FROM_XPATH
;
714 ctxt
->context
->lastError
.code
= error
+ XML_XPATH_EXPRESSION_OK
-
716 ctxt
->context
->lastError
.level
= XML_ERR_ERROR
;
717 ctxt
->context
->lastError
.str1
= (char *) xmlStrdup(ctxt
->base
);
718 ctxt
->context
->lastError
.int1
= ctxt
->cur
- ctxt
->base
;
719 ctxt
->context
->lastError
.node
= ctxt
->context
->debugNode
;
720 if (ctxt
->context
->error
!= NULL
) {
721 ctxt
->context
->error(ctxt
->context
->userData
,
722 &ctxt
->context
->lastError
);
724 __xmlRaiseError(NULL
, NULL
, NULL
,
725 NULL
, ctxt
->context
->debugNode
, XML_FROM_XPATH
,
726 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
727 XML_ERR_ERROR
, NULL
, 0,
728 (const char *) ctxt
->base
, NULL
, NULL
,
729 ctxt
->cur
- ctxt
->base
, 0,
730 "%s", xmlXPathErrorMessages
[error
]);
737 * @ctxt: the XPath Parser context
738 * @file: the file name
739 * @line: the line number
740 * @no: the error number
742 * Formats an error message.
745 xmlXPatherror(xmlXPathParserContextPtr ctxt
, const char *file ATTRIBUTE_UNUSED
,
746 int line ATTRIBUTE_UNUSED
, int no
) {
747 xmlXPathErr(ctxt
, no
);
750 /************************************************************************
754 ************************************************************************/
759 * Pointer-list for various purposes.
761 typedef struct _xmlPointerList xmlPointerList
;
762 typedef xmlPointerList
*xmlPointerListPtr
;
763 struct _xmlPointerList
{
769 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
770 * and here, we should make the functions public.
773 xmlPointerListAddSize(xmlPointerListPtr list
,
777 if (list
->items
== NULL
) {
778 if (initialSize
<= 0)
780 list
->items
= (void **) xmlMalloc(initialSize
* sizeof(void *));
781 if (list
->items
== NULL
) {
782 xmlXPathErrMemory(NULL
,
783 "xmlPointerListCreate: allocating item\n");
787 list
->size
= initialSize
;
788 } else if (list
->size
<= list
->number
) {
789 if (list
->size
> 50000000) {
790 xmlXPathErrMemory(NULL
,
791 "xmlPointerListAddSize: re-allocating item\n");
795 list
->items
= (void **) xmlRealloc(list
->items
,
796 list
->size
* sizeof(void *));
797 if (list
->items
== NULL
) {
798 xmlXPathErrMemory(NULL
,
799 "xmlPointerListAddSize: re-allocating item\n");
804 list
->items
[list
->number
++] = item
;
809 * xsltPointerListCreate:
811 * Creates an xsltPointerList structure.
813 * Returns a xsltPointerList structure or NULL in case of an error.
815 static xmlPointerListPtr
816 xmlPointerListCreate(int initialSize
)
818 xmlPointerListPtr ret
;
820 ret
= xmlMalloc(sizeof(xmlPointerList
));
822 xmlXPathErrMemory(NULL
,
823 "xmlPointerListCreate: allocating item\n");
826 memset(ret
, 0, sizeof(xmlPointerList
));
827 if (initialSize
> 0) {
828 xmlPointerListAddSize(ret
, NULL
, initialSize
);
835 * xsltPointerListFree:
837 * Frees the xsltPointerList structure. This does not free
838 * the content of the list.
841 xmlPointerListFree(xmlPointerListPtr list
)
845 if (list
->items
!= NULL
)
846 xmlFree(list
->items
);
850 /************************************************************************
854 ************************************************************************/
872 XPATH_OP_VALUE
, /* 11 */
877 XPATH_OP_FILTER
, /* 16 */
878 XPATH_OP_SORT
/* 17 */
879 #ifdef LIBXML_XPTR_ENABLED
886 AXIS_ANCESTOR_OR_SELF
,
890 AXIS_DESCENDANT_OR_SELF
,
892 AXIS_FOLLOWING_SIBLING
,
896 AXIS_PRECEDING_SIBLING
,
911 NODE_TYPE_COMMENT
= XML_COMMENT_NODE
,
912 NODE_TYPE_TEXT
= XML_TEXT_NODE
,
913 NODE_TYPE_PI
= XML_PI_NODE
916 typedef struct _xmlXPathStepOp xmlXPathStepOp
;
917 typedef xmlXPathStepOp
*xmlXPathStepOpPtr
;
918 struct _xmlXPathStepOp
{
919 xmlXPathOp op
; /* The identifier of the operation */
920 int ch1
; /* First child */
921 int ch2
; /* Second child */
927 xmlXPathFunction cache
;
931 struct _xmlXPathCompExpr
{
932 int nbStep
; /* Number of steps in this expression */
933 int maxStep
; /* Maximum number of steps allocated */
934 xmlXPathStepOp
*steps
; /* ops for computation of this expression */
935 int last
; /* index of last step in expression */
936 xmlChar
*expr
; /* the expression being computed */
937 xmlDictPtr dict
; /* the dictionary to use if any */
938 #ifdef DEBUG_EVAL_COUNTS
942 #ifdef XPATH_STREAMING
943 xmlPatternPtr stream
;
947 /************************************************************************
949 * Forward declarations *
951 ************************************************************************/
953 xmlXPathFreeValueTree(xmlNodeSetPtr obj
);
955 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
);
957 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
958 xmlXPathStepOpPtr op
, xmlNodePtr
*first
);
960 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
961 xmlXPathStepOpPtr op
,
964 xmlXPathFreeObjectEntry(void *obj
, const xmlChar
*name
);
966 /************************************************************************
968 * Parser Type functions *
970 ************************************************************************/
973 * xmlXPathNewCompExpr:
975 * Create a new Xpath component
977 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
979 static xmlXPathCompExprPtr
980 xmlXPathNewCompExpr(void) {
981 xmlXPathCompExprPtr cur
;
983 cur
= (xmlXPathCompExprPtr
) xmlMalloc(sizeof(xmlXPathCompExpr
));
985 xmlXPathErrMemory(NULL
, "allocating component\n");
988 memset(cur
, 0, sizeof(xmlXPathCompExpr
));
991 cur
->steps
= (xmlXPathStepOp
*) xmlMalloc(cur
->maxStep
*
992 sizeof(xmlXPathStepOp
));
993 if (cur
->steps
== NULL
) {
994 xmlXPathErrMemory(NULL
, "allocating steps\n");
998 memset(cur
->steps
, 0, cur
->maxStep
* sizeof(xmlXPathStepOp
));
1000 #ifdef DEBUG_EVAL_COUNTS
1007 * xmlXPathFreeCompExpr:
1008 * @comp: an XPATH comp
1010 * Free up the memory allocated by @comp
1013 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp
)
1015 xmlXPathStepOpPtr op
;
1020 if (comp
->dict
== NULL
) {
1021 for (i
= 0; i
< comp
->nbStep
; i
++) {
1022 op
= &comp
->steps
[i
];
1023 if (op
->value4
!= NULL
) {
1024 if (op
->op
== XPATH_OP_VALUE
)
1025 xmlXPathFreeObject(op
->value4
);
1027 xmlFree(op
->value4
);
1029 if (op
->value5
!= NULL
)
1030 xmlFree(op
->value5
);
1033 for (i
= 0; i
< comp
->nbStep
; i
++) {
1034 op
= &comp
->steps
[i
];
1035 if (op
->value4
!= NULL
) {
1036 if (op
->op
== XPATH_OP_VALUE
)
1037 xmlXPathFreeObject(op
->value4
);
1040 xmlDictFree(comp
->dict
);
1042 if (comp
->steps
!= NULL
) {
1043 xmlFree(comp
->steps
);
1045 #ifdef DEBUG_EVAL_COUNTS
1046 if (comp
->string
!= NULL
) {
1047 xmlFree(comp
->string
);
1050 #ifdef XPATH_STREAMING
1051 if (comp
->stream
!= NULL
) {
1052 xmlFreePatternList(comp
->stream
);
1055 if (comp
->expr
!= NULL
) {
1056 xmlFree(comp
->expr
);
1063 * xmlXPathCompExprAdd:
1064 * @comp: the compiled expression
1065 * @ch1: first child index
1066 * @ch2: second child index
1068 * @value: the first int value
1069 * @value2: the second int value
1070 * @value3: the third int value
1071 * @value4: the first string value
1072 * @value5: the second string value
1074 * Add a step to an XPath Compiled Expression
1076 * Returns -1 in case of failure, the index otherwise
1079 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp
, int ch1
, int ch2
,
1080 xmlXPathOp op
, int value
,
1081 int value2
, int value3
, void *value4
, void *value5
) {
1082 if (comp
->nbStep
>= comp
->maxStep
) {
1083 xmlXPathStepOp
*real
;
1085 if (comp
->maxStep
>= XPATH_MAX_STEPS
) {
1086 xmlXPathErrMemory(NULL
, "adding step\n");
1090 real
= (xmlXPathStepOp
*) xmlRealloc(comp
->steps
,
1091 comp
->maxStep
* sizeof(xmlXPathStepOp
));
1094 xmlXPathErrMemory(NULL
, "adding step\n");
1099 comp
->last
= comp
->nbStep
;
1100 comp
->steps
[comp
->nbStep
].ch1
= ch1
;
1101 comp
->steps
[comp
->nbStep
].ch2
= ch2
;
1102 comp
->steps
[comp
->nbStep
].op
= op
;
1103 comp
->steps
[comp
->nbStep
].value
= value
;
1104 comp
->steps
[comp
->nbStep
].value2
= value2
;
1105 comp
->steps
[comp
->nbStep
].value3
= value3
;
1106 if ((comp
->dict
!= NULL
) &&
1107 ((op
== XPATH_OP_FUNCTION
) || (op
== XPATH_OP_VARIABLE
) ||
1108 (op
== XPATH_OP_COLLECT
))) {
1109 if (value4
!= NULL
) {
1110 comp
->steps
[comp
->nbStep
].value4
= (xmlChar
*)
1111 (void *)xmlDictLookup(comp
->dict
, value4
, -1);
1114 comp
->steps
[comp
->nbStep
].value4
= NULL
;
1115 if (value5
!= NULL
) {
1116 comp
->steps
[comp
->nbStep
].value5
= (xmlChar
*)
1117 (void *)xmlDictLookup(comp
->dict
, value5
, -1);
1120 comp
->steps
[comp
->nbStep
].value5
= NULL
;
1122 comp
->steps
[comp
->nbStep
].value4
= value4
;
1123 comp
->steps
[comp
->nbStep
].value5
= value5
;
1125 comp
->steps
[comp
->nbStep
].cache
= NULL
;
1126 return(comp
->nbStep
++);
1131 * @comp: the compiled expression
1132 * @op: operation index
1134 * Swaps 2 operations in the compiled expression
1137 xmlXPathCompSwap(xmlXPathStepOpPtr op
) {
1140 #ifndef LIBXML_THREAD_ENABLED
1142 * Since this manipulates possibly shared variables, this is
1143 * disabled if one detects that the library is used in a multithreaded
1146 if (xmlXPathDisableOptimizer
)
1155 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1156 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1157 (op), (val), (val2), (val3), (val4), (val5))
1158 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1159 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1160 (op), (val), (val2), (val3), (val4), (val5))
1162 #define PUSH_LEAVE_EXPR(op, val, val2) \
1163 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1165 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1166 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1168 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1169 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1170 (val), (val2), 0 ,NULL ,NULL)
1172 /************************************************************************
1174 * XPath object cache structures *
1176 ************************************************************************/
1178 /* #define XP_DEFAULT_CACHE_ON */
1180 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1182 typedef struct _xmlXPathContextCache xmlXPathContextCache
;
1183 typedef xmlXPathContextCache
*xmlXPathContextCachePtr
;
1184 struct _xmlXPathContextCache
{
1185 xmlPointerListPtr nodesetObjs
; /* contains xmlXPathObjectPtr */
1186 xmlPointerListPtr stringObjs
; /* contains xmlXPathObjectPtr */
1187 xmlPointerListPtr booleanObjs
; /* contains xmlXPathObjectPtr */
1188 xmlPointerListPtr numberObjs
; /* contains xmlXPathObjectPtr */
1189 xmlPointerListPtr miscObjs
; /* contains xmlXPathObjectPtr */
1195 #ifdef XP_DEBUG_OBJ_USAGE
1197 int dbgCachedNodeset
;
1198 int dbgCachedString
;
1200 int dbgCachedNumber
;
1203 int dbgCachedLocset
;
1205 int dbgCachedXSLTTree
;
1206 int dbgCachedUndefined
;
1210 int dbgReusedNodeset
;
1211 int dbgReusedString
;
1213 int dbgReusedNumber
;
1216 int dbgReusedLocset
;
1218 int dbgReusedXSLTTree
;
1219 int dbgReusedUndefined
;
1224 /************************************************************************
1226 * Debugging related functions *
1228 ************************************************************************/
1231 xmlGenericError(xmlGenericErrorContext, \
1232 "Internal error at %s:%d\n", \
1233 __FILE__, __LINE__);
1235 #ifdef LIBXML_DEBUG_ENABLED
1237 xmlXPathDebugDumpNode(FILE *output
, xmlNodePtr cur
, int depth
) {
1241 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1242 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1243 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1245 fprintf(output
, "%s", shift
);
1246 fprintf(output
, "Node is NULL !\n");
1251 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
1252 (cur
->type
== XML_HTML_DOCUMENT_NODE
)) {
1253 fprintf(output
, "%s", shift
);
1254 fprintf(output
, " /\n");
1255 } else if (cur
->type
== XML_ATTRIBUTE_NODE
)
1256 xmlDebugDumpAttr(output
, (xmlAttrPtr
)cur
, depth
);
1258 xmlDebugDumpOneNode(output
, cur
, depth
);
1261 xmlXPathDebugDumpNodeList(FILE *output
, xmlNodePtr cur
, int depth
) {
1266 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1267 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1268 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1270 fprintf(output
, "%s", shift
);
1271 fprintf(output
, "Node is NULL !\n");
1276 while (cur
!= NULL
) {
1279 xmlDebugDumpOneNode(output
, tmp
, depth
);
1284 xmlXPathDebugDumpNodeSet(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1288 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1289 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1290 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1293 fprintf(output
, "%s", shift
);
1294 fprintf(output
, "NodeSet is NULL !\n");
1300 fprintf(output
, "Set contains %d nodes:\n", cur
->nodeNr
);
1301 for (i
= 0;i
< cur
->nodeNr
;i
++) {
1302 fprintf(output
, "%s", shift
);
1303 fprintf(output
, "%d", i
+ 1);
1304 xmlXPathDebugDumpNode(output
, cur
->nodeTab
[i
], depth
+ 1);
1310 xmlXPathDebugDumpValueTree(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1314 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1315 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1316 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1318 if ((cur
== NULL
) || (cur
->nodeNr
== 0) || (cur
->nodeTab
[0] == NULL
)) {
1319 fprintf(output
, "%s", shift
);
1320 fprintf(output
, "Value Tree is NULL !\n");
1325 fprintf(output
, "%s", shift
);
1326 fprintf(output
, "%d", i
+ 1);
1327 xmlXPathDebugDumpNodeList(output
, cur
->nodeTab
[0]->children
, depth
+ 1);
1329 #if defined(LIBXML_XPTR_ENABLED)
1331 xmlXPathDebugDumpLocationSet(FILE *output
, xmlLocationSetPtr cur
, int depth
) {
1335 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1336 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1337 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1340 fprintf(output
, "%s", shift
);
1341 fprintf(output
, "LocationSet is NULL !\n");
1346 for (i
= 0;i
< cur
->locNr
;i
++) {
1347 fprintf(output
, "%s", shift
);
1348 fprintf(output
, "%d : ", i
+ 1);
1349 xmlXPathDebugDumpObject(output
, cur
->locTab
[i
], depth
+ 1);
1352 #endif /* LIBXML_XPTR_ENABLED */
1355 * xmlXPathDebugDumpObject:
1356 * @output: the FILE * to dump the output
1357 * @cur: the object to inspect
1358 * @depth: indentation level
1360 * Dump the content of the object for debugging purposes
1363 xmlXPathDebugDumpObject(FILE *output
, xmlXPathObjectPtr cur
, int depth
) {
1367 if (output
== NULL
) return;
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
);
1377 fprintf(output
, "Object is empty (NULL)\n");
1381 case XPATH_UNDEFINED
:
1382 fprintf(output
, "Object is uninitialized\n");
1385 fprintf(output
, "Object is a Node Set :\n");
1386 xmlXPathDebugDumpNodeSet(output
, cur
->nodesetval
, depth
);
1388 case XPATH_XSLT_TREE
:
1389 fprintf(output
, "Object is an XSLT value tree :\n");
1390 xmlXPathDebugDumpValueTree(output
, cur
->nodesetval
, depth
);
1393 fprintf(output
, "Object is a Boolean : ");
1394 if (cur
->boolval
) fprintf(output
, "true\n");
1395 else fprintf(output
, "false\n");
1398 switch (xmlXPathIsInf(cur
->floatval
)) {
1400 fprintf(output
, "Object is a number : Infinity\n");
1403 fprintf(output
, "Object is a number : -Infinity\n");
1406 if (xmlXPathIsNaN(cur
->floatval
)) {
1407 fprintf(output
, "Object is a number : NaN\n");
1408 } else if (cur
->floatval
== 0) {
1409 /* Omit sign for negative zero. */
1410 fprintf(output
, "Object is a number : 0\n");
1412 fprintf(output
, "Object is a number : %0g\n", cur
->floatval
);
1417 fprintf(output
, "Object is a string : ");
1418 xmlDebugDumpString(output
, cur
->stringval
);
1419 fprintf(output
, "\n");
1422 fprintf(output
, "Object is a point : index %d in node", cur
->index
);
1423 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
, depth
+ 1);
1424 fprintf(output
, "\n");
1427 if ((cur
->user2
== NULL
) ||
1428 ((cur
->user2
== cur
->user
) && (cur
->index
== cur
->index2
))) {
1429 fprintf(output
, "Object is a collapsed range :\n");
1430 fprintf(output
, "%s", shift
);
1431 if (cur
->index
>= 0)
1432 fprintf(output
, "index %d in ", cur
->index
);
1433 fprintf(output
, "node\n");
1434 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1437 fprintf(output
, "Object is a range :\n");
1438 fprintf(output
, "%s", shift
);
1439 fprintf(output
, "From ");
1440 if (cur
->index
>= 0)
1441 fprintf(output
, "index %d in ", cur
->index
);
1442 fprintf(output
, "node\n");
1443 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1445 fprintf(output
, "%s", shift
);
1446 fprintf(output
, "To ");
1447 if (cur
->index2
>= 0)
1448 fprintf(output
, "index %d in ", cur
->index2
);
1449 fprintf(output
, "node\n");
1450 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user2
,
1452 fprintf(output
, "\n");
1455 case XPATH_LOCATIONSET
:
1456 #if defined(LIBXML_XPTR_ENABLED)
1457 fprintf(output
, "Object is a Location Set:\n");
1458 xmlXPathDebugDumpLocationSet(output
,
1459 (xmlLocationSetPtr
) cur
->user
, depth
);
1463 fprintf(output
, "Object is user defined\n");
1469 xmlXPathDebugDumpStepOp(FILE *output
, xmlXPathCompExprPtr comp
,
1470 xmlXPathStepOpPtr op
, int depth
) {
1474 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1475 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1476 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1478 fprintf(output
, "%s", shift
);
1480 fprintf(output
, "Step is NULL\n");
1485 fprintf(output
, "END"); break;
1487 fprintf(output
, "AND"); break;
1489 fprintf(output
, "OR"); break;
1490 case XPATH_OP_EQUAL
:
1492 fprintf(output
, "EQUAL =");
1494 fprintf(output
, "EQUAL !=");
1498 fprintf(output
, "CMP <");
1500 fprintf(output
, "CMP >");
1502 fprintf(output
, "=");
1506 fprintf(output
, "PLUS -");
1507 else if (op
->value
== 1)
1508 fprintf(output
, "PLUS +");
1509 else if (op
->value
== 2)
1510 fprintf(output
, "PLUS unary -");
1511 else if (op
->value
== 3)
1512 fprintf(output
, "PLUS unary - -");
1516 fprintf(output
, "MULT *");
1517 else if (op
->value
== 1)
1518 fprintf(output
, "MULT div");
1520 fprintf(output
, "MULT mod");
1522 case XPATH_OP_UNION
:
1523 fprintf(output
, "UNION"); break;
1525 fprintf(output
, "ROOT"); break;
1527 fprintf(output
, "NODE"); break;
1529 fprintf(output
, "SORT"); break;
1530 case XPATH_OP_COLLECT
: {
1531 xmlXPathAxisVal axis
= (xmlXPathAxisVal
)op
->value
;
1532 xmlXPathTestVal test
= (xmlXPathTestVal
)op
->value2
;
1533 xmlXPathTypeVal type
= (xmlXPathTypeVal
)op
->value3
;
1534 const xmlChar
*prefix
= op
->value4
;
1535 const xmlChar
*name
= op
->value5
;
1537 fprintf(output
, "COLLECT ");
1540 fprintf(output
, " 'ancestors' "); break;
1541 case AXIS_ANCESTOR_OR_SELF
:
1542 fprintf(output
, " 'ancestors-or-self' "); break;
1543 case AXIS_ATTRIBUTE
:
1544 fprintf(output
, " 'attributes' "); break;
1546 fprintf(output
, " 'child' "); break;
1547 case AXIS_DESCENDANT
:
1548 fprintf(output
, " 'descendant' "); break;
1549 case AXIS_DESCENDANT_OR_SELF
:
1550 fprintf(output
, " 'descendant-or-self' "); break;
1551 case AXIS_FOLLOWING
:
1552 fprintf(output
, " 'following' "); break;
1553 case AXIS_FOLLOWING_SIBLING
:
1554 fprintf(output
, " 'following-siblings' "); break;
1555 case AXIS_NAMESPACE
:
1556 fprintf(output
, " 'namespace' "); break;
1558 fprintf(output
, " 'parent' "); break;
1559 case AXIS_PRECEDING
:
1560 fprintf(output
, " 'preceding' "); break;
1561 case AXIS_PRECEDING_SIBLING
:
1562 fprintf(output
, " 'preceding-sibling' "); break;
1564 fprintf(output
, " 'self' "); break;
1567 case NODE_TEST_NONE
:
1568 fprintf(output
, "'none' "); break;
1569 case NODE_TEST_TYPE
:
1570 fprintf(output
, "'type' "); break;
1572 fprintf(output
, "'PI' "); break;
1574 fprintf(output
, "'all' "); break;
1576 fprintf(output
, "'namespace' "); break;
1577 case NODE_TEST_NAME
:
1578 fprintf(output
, "'name' "); break;
1581 case NODE_TYPE_NODE
:
1582 fprintf(output
, "'node' "); break;
1583 case NODE_TYPE_COMMENT
:
1584 fprintf(output
, "'comment' "); break;
1585 case NODE_TYPE_TEXT
:
1586 fprintf(output
, "'text' "); break;
1588 fprintf(output
, "'PI' "); break;
1591 fprintf(output
, "%s:", prefix
);
1593 fprintf(output
, "%s", (const char *) name
);
1597 case XPATH_OP_VALUE
: {
1598 xmlXPathObjectPtr object
= (xmlXPathObjectPtr
) op
->value4
;
1600 fprintf(output
, "ELEM ");
1601 xmlXPathDebugDumpObject(output
, object
, 0);
1604 case XPATH_OP_VARIABLE
: {
1605 const xmlChar
*prefix
= op
->value5
;
1606 const xmlChar
*name
= op
->value4
;
1609 fprintf(output
, "VARIABLE %s:%s", prefix
, name
);
1611 fprintf(output
, "VARIABLE %s", name
);
1614 case XPATH_OP_FUNCTION
: {
1615 int nbargs
= op
->value
;
1616 const xmlChar
*prefix
= op
->value5
;
1617 const xmlChar
*name
= op
->value4
;
1620 fprintf(output
, "FUNCTION %s:%s(%d args)",
1621 prefix
, name
, nbargs
);
1623 fprintf(output
, "FUNCTION %s(%d args)", name
, nbargs
);
1626 case XPATH_OP_ARG
: fprintf(output
, "ARG"); break;
1627 case XPATH_OP_PREDICATE
: fprintf(output
, "PREDICATE"); break;
1628 case XPATH_OP_FILTER
: fprintf(output
, "FILTER"); break;
1629 #ifdef LIBXML_XPTR_ENABLED
1630 case XPATH_OP_RANGETO
: fprintf(output
, "RANGETO"); break;
1633 fprintf(output
, "UNKNOWN %d\n", op
->op
); return;
1635 fprintf(output
, "\n");
1638 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch1
], depth
+ 1);
1640 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch2
], depth
+ 1);
1644 * xmlXPathDebugDumpCompExpr:
1645 * @output: the FILE * for the output
1646 * @comp: the precompiled XPath expression
1647 * @depth: the indentation level.
1649 * Dumps the tree of the compiled XPath expression.
1652 xmlXPathDebugDumpCompExpr(FILE *output
, xmlXPathCompExprPtr comp
,
1657 if ((output
== NULL
) || (comp
== NULL
)) return;
1659 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1660 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1661 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1663 fprintf(output
, "%s", shift
);
1665 #ifdef XPATH_STREAMING
1667 fprintf(output
, "Streaming Expression\n");
1671 fprintf(output
, "Compiled Expression : %d elements\n",
1674 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[i
], depth
+ 1);
1678 #ifdef XP_DEBUG_OBJ_USAGE
1681 * XPath object usage related debugging variables.
1683 static int xmlXPathDebugObjCounterUndefined
= 0;
1684 static int xmlXPathDebugObjCounterNodeset
= 0;
1685 static int xmlXPathDebugObjCounterBool
= 0;
1686 static int xmlXPathDebugObjCounterNumber
= 0;
1687 static int xmlXPathDebugObjCounterString
= 0;
1688 static int xmlXPathDebugObjCounterPoint
= 0;
1689 static int xmlXPathDebugObjCounterRange
= 0;
1690 static int xmlXPathDebugObjCounterLocset
= 0;
1691 static int xmlXPathDebugObjCounterUsers
= 0;
1692 static int xmlXPathDebugObjCounterXSLTTree
= 0;
1693 static int xmlXPathDebugObjCounterAll
= 0;
1695 static int xmlXPathDebugObjTotalUndefined
= 0;
1696 static int xmlXPathDebugObjTotalNodeset
= 0;
1697 static int xmlXPathDebugObjTotalBool
= 0;
1698 static int xmlXPathDebugObjTotalNumber
= 0;
1699 static int xmlXPathDebugObjTotalString
= 0;
1700 static int xmlXPathDebugObjTotalPoint
= 0;
1701 static int xmlXPathDebugObjTotalRange
= 0;
1702 static int xmlXPathDebugObjTotalLocset
= 0;
1703 static int xmlXPathDebugObjTotalUsers
= 0;
1704 static int xmlXPathDebugObjTotalXSLTTree
= 0;
1705 static int xmlXPathDebugObjTotalAll
= 0;
1707 static int xmlXPathDebugObjMaxUndefined
= 0;
1708 static int xmlXPathDebugObjMaxNodeset
= 0;
1709 static int xmlXPathDebugObjMaxBool
= 0;
1710 static int xmlXPathDebugObjMaxNumber
= 0;
1711 static int xmlXPathDebugObjMaxString
= 0;
1712 static int xmlXPathDebugObjMaxPoint
= 0;
1713 static int xmlXPathDebugObjMaxRange
= 0;
1714 static int xmlXPathDebugObjMaxLocset
= 0;
1715 static int xmlXPathDebugObjMaxUsers
= 0;
1716 static int xmlXPathDebugObjMaxXSLTTree
= 0;
1717 static int xmlXPathDebugObjMaxAll
= 0;
1719 /* REVISIT TODO: Make this static when committing */
1721 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt
)
1724 if (ctxt
->cache
!= NULL
) {
1725 xmlXPathContextCachePtr cache
=
1726 (xmlXPathContextCachePtr
) ctxt
->cache
;
1728 cache
->dbgCachedAll
= 0;
1729 cache
->dbgCachedNodeset
= 0;
1730 cache
->dbgCachedString
= 0;
1731 cache
->dbgCachedBool
= 0;
1732 cache
->dbgCachedNumber
= 0;
1733 cache
->dbgCachedPoint
= 0;
1734 cache
->dbgCachedRange
= 0;
1735 cache
->dbgCachedLocset
= 0;
1736 cache
->dbgCachedUsers
= 0;
1737 cache
->dbgCachedXSLTTree
= 0;
1738 cache
->dbgCachedUndefined
= 0;
1740 cache
->dbgReusedAll
= 0;
1741 cache
->dbgReusedNodeset
= 0;
1742 cache
->dbgReusedString
= 0;
1743 cache
->dbgReusedBool
= 0;
1744 cache
->dbgReusedNumber
= 0;
1745 cache
->dbgReusedPoint
= 0;
1746 cache
->dbgReusedRange
= 0;
1747 cache
->dbgReusedLocset
= 0;
1748 cache
->dbgReusedUsers
= 0;
1749 cache
->dbgReusedXSLTTree
= 0;
1750 cache
->dbgReusedUndefined
= 0;
1754 xmlXPathDebugObjCounterUndefined
= 0;
1755 xmlXPathDebugObjCounterNodeset
= 0;
1756 xmlXPathDebugObjCounterBool
= 0;
1757 xmlXPathDebugObjCounterNumber
= 0;
1758 xmlXPathDebugObjCounterString
= 0;
1759 xmlXPathDebugObjCounterPoint
= 0;
1760 xmlXPathDebugObjCounterRange
= 0;
1761 xmlXPathDebugObjCounterLocset
= 0;
1762 xmlXPathDebugObjCounterUsers
= 0;
1763 xmlXPathDebugObjCounterXSLTTree
= 0;
1764 xmlXPathDebugObjCounterAll
= 0;
1766 xmlXPathDebugObjTotalUndefined
= 0;
1767 xmlXPathDebugObjTotalNodeset
= 0;
1768 xmlXPathDebugObjTotalBool
= 0;
1769 xmlXPathDebugObjTotalNumber
= 0;
1770 xmlXPathDebugObjTotalString
= 0;
1771 xmlXPathDebugObjTotalPoint
= 0;
1772 xmlXPathDebugObjTotalRange
= 0;
1773 xmlXPathDebugObjTotalLocset
= 0;
1774 xmlXPathDebugObjTotalUsers
= 0;
1775 xmlXPathDebugObjTotalXSLTTree
= 0;
1776 xmlXPathDebugObjTotalAll
= 0;
1778 xmlXPathDebugObjMaxUndefined
= 0;
1779 xmlXPathDebugObjMaxNodeset
= 0;
1780 xmlXPathDebugObjMaxBool
= 0;
1781 xmlXPathDebugObjMaxNumber
= 0;
1782 xmlXPathDebugObjMaxString
= 0;
1783 xmlXPathDebugObjMaxPoint
= 0;
1784 xmlXPathDebugObjMaxRange
= 0;
1785 xmlXPathDebugObjMaxLocset
= 0;
1786 xmlXPathDebugObjMaxUsers
= 0;
1787 xmlXPathDebugObjMaxXSLTTree
= 0;
1788 xmlXPathDebugObjMaxAll
= 0;
1793 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt
,
1794 xmlXPathObjectType objType
)
1799 if (ctxt
->cache
!= NULL
) {
1800 xmlXPathContextCachePtr cache
=
1801 (xmlXPathContextCachePtr
) ctxt
->cache
;
1805 cache
->dbgReusedAll
++;
1807 case XPATH_UNDEFINED
:
1808 cache
->dbgReusedUndefined
++;
1811 cache
->dbgReusedNodeset
++;
1814 cache
->dbgReusedBool
++;
1817 cache
->dbgReusedNumber
++;
1820 cache
->dbgReusedString
++;
1823 cache
->dbgReusedPoint
++;
1826 cache
->dbgReusedRange
++;
1828 case XPATH_LOCATIONSET
:
1829 cache
->dbgReusedLocset
++;
1832 cache
->dbgReusedUsers
++;
1834 case XPATH_XSLT_TREE
:
1835 cache
->dbgReusedXSLTTree
++;
1844 case XPATH_UNDEFINED
:
1846 xmlXPathDebugObjTotalUndefined
++;
1847 xmlXPathDebugObjCounterUndefined
++;
1848 if (xmlXPathDebugObjCounterUndefined
>
1849 xmlXPathDebugObjMaxUndefined
)
1850 xmlXPathDebugObjMaxUndefined
=
1851 xmlXPathDebugObjCounterUndefined
;
1855 xmlXPathDebugObjTotalNodeset
++;
1856 xmlXPathDebugObjCounterNodeset
++;
1857 if (xmlXPathDebugObjCounterNodeset
>
1858 xmlXPathDebugObjMaxNodeset
)
1859 xmlXPathDebugObjMaxNodeset
=
1860 xmlXPathDebugObjCounterNodeset
;
1864 xmlXPathDebugObjTotalBool
++;
1865 xmlXPathDebugObjCounterBool
++;
1866 if (xmlXPathDebugObjCounterBool
>
1867 xmlXPathDebugObjMaxBool
)
1868 xmlXPathDebugObjMaxBool
=
1869 xmlXPathDebugObjCounterBool
;
1873 xmlXPathDebugObjTotalNumber
++;
1874 xmlXPathDebugObjCounterNumber
++;
1875 if (xmlXPathDebugObjCounterNumber
>
1876 xmlXPathDebugObjMaxNumber
)
1877 xmlXPathDebugObjMaxNumber
=
1878 xmlXPathDebugObjCounterNumber
;
1882 xmlXPathDebugObjTotalString
++;
1883 xmlXPathDebugObjCounterString
++;
1884 if (xmlXPathDebugObjCounterString
>
1885 xmlXPathDebugObjMaxString
)
1886 xmlXPathDebugObjMaxString
=
1887 xmlXPathDebugObjCounterString
;
1891 xmlXPathDebugObjTotalPoint
++;
1892 xmlXPathDebugObjCounterPoint
++;
1893 if (xmlXPathDebugObjCounterPoint
>
1894 xmlXPathDebugObjMaxPoint
)
1895 xmlXPathDebugObjMaxPoint
=
1896 xmlXPathDebugObjCounterPoint
;
1900 xmlXPathDebugObjTotalRange
++;
1901 xmlXPathDebugObjCounterRange
++;
1902 if (xmlXPathDebugObjCounterRange
>
1903 xmlXPathDebugObjMaxRange
)
1904 xmlXPathDebugObjMaxRange
=
1905 xmlXPathDebugObjCounterRange
;
1907 case XPATH_LOCATIONSET
:
1909 xmlXPathDebugObjTotalLocset
++;
1910 xmlXPathDebugObjCounterLocset
++;
1911 if (xmlXPathDebugObjCounterLocset
>
1912 xmlXPathDebugObjMaxLocset
)
1913 xmlXPathDebugObjMaxLocset
=
1914 xmlXPathDebugObjCounterLocset
;
1918 xmlXPathDebugObjTotalUsers
++;
1919 xmlXPathDebugObjCounterUsers
++;
1920 if (xmlXPathDebugObjCounterUsers
>
1921 xmlXPathDebugObjMaxUsers
)
1922 xmlXPathDebugObjMaxUsers
=
1923 xmlXPathDebugObjCounterUsers
;
1925 case XPATH_XSLT_TREE
:
1927 xmlXPathDebugObjTotalXSLTTree
++;
1928 xmlXPathDebugObjCounterXSLTTree
++;
1929 if (xmlXPathDebugObjCounterXSLTTree
>
1930 xmlXPathDebugObjMaxXSLTTree
)
1931 xmlXPathDebugObjMaxXSLTTree
=
1932 xmlXPathDebugObjCounterXSLTTree
;
1938 xmlXPathDebugObjTotalAll
++;
1939 xmlXPathDebugObjCounterAll
++;
1940 if (xmlXPathDebugObjCounterAll
>
1941 xmlXPathDebugObjMaxAll
)
1942 xmlXPathDebugObjMaxAll
=
1943 xmlXPathDebugObjCounterAll
;
1947 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt
,
1948 xmlXPathObjectType objType
)
1953 if (ctxt
->cache
!= NULL
) {
1954 xmlXPathContextCachePtr cache
=
1955 (xmlXPathContextCachePtr
) ctxt
->cache
;
1959 cache
->dbgCachedAll
++;
1961 case XPATH_UNDEFINED
:
1962 cache
->dbgCachedUndefined
++;
1965 cache
->dbgCachedNodeset
++;
1968 cache
->dbgCachedBool
++;
1971 cache
->dbgCachedNumber
++;
1974 cache
->dbgCachedString
++;
1977 cache
->dbgCachedPoint
++;
1980 cache
->dbgCachedRange
++;
1982 case XPATH_LOCATIONSET
:
1983 cache
->dbgCachedLocset
++;
1986 cache
->dbgCachedUsers
++;
1988 case XPATH_XSLT_TREE
:
1989 cache
->dbgCachedXSLTTree
++;
1998 case XPATH_UNDEFINED
:
1999 xmlXPathDebugObjCounterUndefined
--;
2002 xmlXPathDebugObjCounterNodeset
--;
2005 xmlXPathDebugObjCounterBool
--;
2008 xmlXPathDebugObjCounterNumber
--;
2011 xmlXPathDebugObjCounterString
--;
2014 xmlXPathDebugObjCounterPoint
--;
2017 xmlXPathDebugObjCounterRange
--;
2019 case XPATH_LOCATIONSET
:
2020 xmlXPathDebugObjCounterLocset
--;
2023 xmlXPathDebugObjCounterUsers
--;
2025 case XPATH_XSLT_TREE
:
2026 xmlXPathDebugObjCounterXSLTTree
--;
2031 xmlXPathDebugObjCounterAll
--;
2034 /* REVISIT TODO: Make this static when committing */
2036 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt
)
2038 int reqAll
, reqNodeset
, reqString
, reqBool
, reqNumber
,
2039 reqXSLTTree
, reqUndefined
;
2040 int caAll
= 0, caNodeset
= 0, caString
= 0, caBool
= 0,
2041 caNumber
= 0, caXSLTTree
= 0, caUndefined
= 0;
2042 int reAll
= 0, reNodeset
= 0, reString
= 0, reBool
= 0,
2043 reNumber
= 0, reXSLTTree
= 0, reUndefined
= 0;
2044 int leftObjs
= xmlXPathDebugObjCounterAll
;
2046 reqAll
= xmlXPathDebugObjTotalAll
;
2047 reqNodeset
= xmlXPathDebugObjTotalNodeset
;
2048 reqString
= xmlXPathDebugObjTotalString
;
2049 reqBool
= xmlXPathDebugObjTotalBool
;
2050 reqNumber
= xmlXPathDebugObjTotalNumber
;
2051 reqXSLTTree
= xmlXPathDebugObjTotalXSLTTree
;
2052 reqUndefined
= xmlXPathDebugObjTotalUndefined
;
2054 printf("# XPath object usage:\n");
2057 if (ctxt
->cache
!= NULL
) {
2058 xmlXPathContextCachePtr cache
=
2059 (xmlXPathContextCachePtr
) ctxt
->cache
;
2061 reAll
= cache
->dbgReusedAll
;
2063 reNodeset
= cache
->dbgReusedNodeset
;
2064 reqNodeset
+= reNodeset
;
2065 reString
= cache
->dbgReusedString
;
2066 reqString
+= reString
;
2067 reBool
= cache
->dbgReusedBool
;
2069 reNumber
= cache
->dbgReusedNumber
;
2070 reqNumber
+= reNumber
;
2071 reXSLTTree
= cache
->dbgReusedXSLTTree
;
2072 reqXSLTTree
+= reXSLTTree
;
2073 reUndefined
= cache
->dbgReusedUndefined
;
2074 reqUndefined
+= reUndefined
;
2076 caAll
= cache
->dbgCachedAll
;
2077 caBool
= cache
->dbgCachedBool
;
2078 caNodeset
= cache
->dbgCachedNodeset
;
2079 caString
= cache
->dbgCachedString
;
2080 caNumber
= cache
->dbgCachedNumber
;
2081 caXSLTTree
= cache
->dbgCachedXSLTTree
;
2082 caUndefined
= cache
->dbgCachedUndefined
;
2084 if (cache
->nodesetObjs
)
2085 leftObjs
-= cache
->nodesetObjs
->number
;
2086 if (cache
->stringObjs
)
2087 leftObjs
-= cache
->stringObjs
->number
;
2088 if (cache
->booleanObjs
)
2089 leftObjs
-= cache
->booleanObjs
->number
;
2090 if (cache
->numberObjs
)
2091 leftObjs
-= cache
->numberObjs
->number
;
2092 if (cache
->miscObjs
)
2093 leftObjs
-= cache
->miscObjs
->number
;
2098 printf("# total : %d\n", reqAll
);
2099 printf("# left : %d\n", leftObjs
);
2100 printf("# created: %d\n", xmlXPathDebugObjTotalAll
);
2101 printf("# reused : %d\n", reAll
);
2102 printf("# max : %d\n", xmlXPathDebugObjMaxAll
);
2104 printf("# node-sets\n");
2105 printf("# total : %d\n", reqNodeset
);
2106 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset
);
2107 printf("# reused : %d\n", reNodeset
);
2108 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset
);
2110 printf("# strings\n");
2111 printf("# total : %d\n", reqString
);
2112 printf("# created: %d\n", xmlXPathDebugObjTotalString
);
2113 printf("# reused : %d\n", reString
);
2114 printf("# max : %d\n", xmlXPathDebugObjMaxString
);
2116 printf("# booleans\n");
2117 printf("# total : %d\n", reqBool
);
2118 printf("# created: %d\n", xmlXPathDebugObjTotalBool
);
2119 printf("# reused : %d\n", reBool
);
2120 printf("# max : %d\n", xmlXPathDebugObjMaxBool
);
2122 printf("# numbers\n");
2123 printf("# total : %d\n", reqNumber
);
2124 printf("# created: %d\n", xmlXPathDebugObjTotalNumber
);
2125 printf("# reused : %d\n", reNumber
);
2126 printf("# max : %d\n", xmlXPathDebugObjMaxNumber
);
2128 printf("# XSLT result tree fragments\n");
2129 printf("# total : %d\n", reqXSLTTree
);
2130 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree
);
2131 printf("# reused : %d\n", reXSLTTree
);
2132 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree
);
2134 printf("# undefined\n");
2135 printf("# total : %d\n", reqUndefined
);
2136 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined
);
2137 printf("# reused : %d\n", reUndefined
);
2138 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined
);
2142 #endif /* XP_DEBUG_OBJ_USAGE */
2144 #endif /* LIBXML_DEBUG_ENABLED */
2146 /************************************************************************
2148 * XPath object caching *
2150 ************************************************************************/
2155 * Create a new object cache
2157 * Returns the xmlXPathCache just allocated.
2159 static xmlXPathContextCachePtr
2160 xmlXPathNewCache(void)
2162 xmlXPathContextCachePtr ret
;
2164 ret
= (xmlXPathContextCachePtr
) xmlMalloc(sizeof(xmlXPathContextCache
));
2166 xmlXPathErrMemory(NULL
, "creating object cache\n");
2169 memset(ret
, 0 , (size_t) sizeof(xmlXPathContextCache
));
2170 ret
->maxNodeset
= 100;
2171 ret
->maxString
= 100;
2172 ret
->maxBoolean
= 100;
2173 ret
->maxNumber
= 100;
2179 xmlXPathCacheFreeObjectList(xmlPointerListPtr list
)
2182 xmlXPathObjectPtr obj
;
2187 for (i
= 0; i
< list
->number
; i
++) {
2188 obj
= list
->items
[i
];
2190 * Note that it is already assured that we don't need to
2191 * look out for namespace nodes in the node-set.
2193 if (obj
->nodesetval
!= NULL
) {
2194 if (obj
->nodesetval
->nodeTab
!= NULL
)
2195 xmlFree(obj
->nodesetval
->nodeTab
);
2196 xmlFree(obj
->nodesetval
);
2199 #ifdef XP_DEBUG_OBJ_USAGE
2200 xmlXPathDebugObjCounterAll
--;
2203 xmlPointerListFree(list
);
2207 xmlXPathFreeCache(xmlXPathContextCachePtr cache
)
2211 if (cache
->nodesetObjs
)
2212 xmlXPathCacheFreeObjectList(cache
->nodesetObjs
);
2213 if (cache
->stringObjs
)
2214 xmlXPathCacheFreeObjectList(cache
->stringObjs
);
2215 if (cache
->booleanObjs
)
2216 xmlXPathCacheFreeObjectList(cache
->booleanObjs
);
2217 if (cache
->numberObjs
)
2218 xmlXPathCacheFreeObjectList(cache
->numberObjs
);
2219 if (cache
->miscObjs
)
2220 xmlXPathCacheFreeObjectList(cache
->miscObjs
);
2225 * xmlXPathContextSetCache:
2227 * @ctxt: the XPath context
2228 * @active: enables/disables (creates/frees) the cache
2229 * @value: a value with semantics dependant on @options
2230 * @options: options (currently only the value 0 is used)
2232 * Creates/frees an object cache on the XPath context.
2233 * If activates XPath objects (xmlXPathObject) will be cached internally
2236 * 0: This will set the XPath object caching:
2238 * This will set the maximum number of XPath objects
2239 * to be cached per slot
2240 * There are 5 slots for: node-set, string, number, boolean, and
2241 * misc objects. Use <0 for the default number (100).
2242 * Other values for @options have currently no effect.
2244 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2247 xmlXPathContextSetCache(xmlXPathContextPtr ctxt
,
2255 xmlXPathContextCachePtr cache
;
2257 if (ctxt
->cache
== NULL
) {
2258 ctxt
->cache
= xmlXPathNewCache();
2259 if (ctxt
->cache
== NULL
)
2262 cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2266 cache
->maxNodeset
= value
;
2267 cache
->maxString
= value
;
2268 cache
->maxNumber
= value
;
2269 cache
->maxBoolean
= value
;
2270 cache
->maxMisc
= value
;
2272 } else if (ctxt
->cache
!= NULL
) {
2273 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
2280 * xmlXPathCacheWrapNodeSet:
2281 * @ctxt: the XPath context
2282 * @val: the NodePtr value
2284 * This is the cached version of xmlXPathWrapNodeSet().
2285 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2287 * Returns the created or reused object.
2289 static xmlXPathObjectPtr
2290 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt
, xmlNodeSetPtr val
)
2292 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2293 xmlXPathContextCachePtr cache
=
2294 (xmlXPathContextCachePtr
) ctxt
->cache
;
2296 if ((cache
->miscObjs
!= NULL
) &&
2297 (cache
->miscObjs
->number
!= 0))
2299 xmlXPathObjectPtr ret
;
2301 ret
= (xmlXPathObjectPtr
)
2302 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2303 ret
->type
= XPATH_NODESET
;
2304 ret
->nodesetval
= val
;
2305 #ifdef XP_DEBUG_OBJ_USAGE
2306 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2312 return(xmlXPathWrapNodeSet(val
));
2317 * xmlXPathCacheWrapString:
2318 * @ctxt: the XPath context
2319 * @val: the xmlChar * value
2321 * This is the cached version of xmlXPathWrapString().
2322 * Wraps the @val string into an XPath object.
2324 * Returns the created or reused object.
2326 static xmlXPathObjectPtr
2327 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt
, xmlChar
*val
)
2329 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2330 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2332 if ((cache
->stringObjs
!= NULL
) &&
2333 (cache
->stringObjs
->number
!= 0))
2336 xmlXPathObjectPtr ret
;
2338 ret
= (xmlXPathObjectPtr
)
2339 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2340 ret
->type
= XPATH_STRING
;
2341 ret
->stringval
= val
;
2342 #ifdef XP_DEBUG_OBJ_USAGE
2343 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2346 } else if ((cache
->miscObjs
!= NULL
) &&
2347 (cache
->miscObjs
->number
!= 0))
2349 xmlXPathObjectPtr ret
;
2351 * Fallback to misc-cache.
2353 ret
= (xmlXPathObjectPtr
)
2354 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2356 ret
->type
= XPATH_STRING
;
2357 ret
->stringval
= val
;
2358 #ifdef XP_DEBUG_OBJ_USAGE
2359 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2364 return(xmlXPathWrapString(val
));
2368 * xmlXPathCacheNewNodeSet:
2369 * @ctxt: the XPath context
2370 * @val: the NodePtr value
2372 * This is the cached version of xmlXPathNewNodeSet().
2373 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2374 * it with the single Node @val
2376 * Returns the created or reused object.
2378 static xmlXPathObjectPtr
2379 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt
, xmlNodePtr val
)
2381 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2382 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2384 if ((cache
->nodesetObjs
!= NULL
) &&
2385 (cache
->nodesetObjs
->number
!= 0))
2387 xmlXPathObjectPtr ret
;
2389 * Use the nodset-cache.
2391 ret
= (xmlXPathObjectPtr
)
2392 cache
->nodesetObjs
->items
[--cache
->nodesetObjs
->number
];
2393 ret
->type
= XPATH_NODESET
;
2396 if ((ret
->nodesetval
->nodeMax
== 0) ||
2397 (val
->type
== XML_NAMESPACE_DECL
))
2399 xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
);
2401 ret
->nodesetval
->nodeTab
[0] = val
;
2402 ret
->nodesetval
->nodeNr
= 1;
2405 #ifdef XP_DEBUG_OBJ_USAGE
2406 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2409 } else if ((cache
->miscObjs
!= NULL
) &&
2410 (cache
->miscObjs
->number
!= 0))
2412 xmlXPathObjectPtr ret
;
2414 * Fallback to misc-cache.
2417 ret
= (xmlXPathObjectPtr
)
2418 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2420 ret
->type
= XPATH_NODESET
;
2422 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
2423 if (ret
->nodesetval
== NULL
) {
2424 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
2425 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
2428 #ifdef XP_DEBUG_OBJ_USAGE
2429 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2434 return(xmlXPathNewNodeSet(val
));
2438 * xmlXPathCacheNewCString:
2439 * @ctxt: the XPath context
2440 * @val: the char * value
2442 * This is the cached version of xmlXPathNewCString().
2443 * Acquire an xmlXPathObjectPtr of type string and of value @val
2445 * Returns the created or reused object.
2447 static xmlXPathObjectPtr
2448 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt
, const char *val
)
2450 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2451 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2453 if ((cache
->stringObjs
!= NULL
) &&
2454 (cache
->stringObjs
->number
!= 0))
2456 xmlXPathObjectPtr ret
;
2458 ret
= (xmlXPathObjectPtr
)
2459 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2461 ret
->type
= XPATH_STRING
;
2462 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2463 #ifdef XP_DEBUG_OBJ_USAGE
2464 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2467 } else if ((cache
->miscObjs
!= NULL
) &&
2468 (cache
->miscObjs
->number
!= 0))
2470 xmlXPathObjectPtr ret
;
2472 ret
= (xmlXPathObjectPtr
)
2473 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2475 ret
->type
= XPATH_STRING
;
2476 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2477 #ifdef XP_DEBUG_OBJ_USAGE
2478 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2483 return(xmlXPathNewCString(val
));
2487 * xmlXPathCacheNewString:
2488 * @ctxt: the XPath context
2489 * @val: the xmlChar * value
2491 * This is the cached version of xmlXPathNewString().
2492 * Acquire an xmlXPathObjectPtr of type string and of value @val
2494 * Returns the created or reused object.
2496 static xmlXPathObjectPtr
2497 xmlXPathCacheNewString(xmlXPathContextPtr ctxt
, const xmlChar
*val
)
2499 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2500 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2502 if ((cache
->stringObjs
!= NULL
) &&
2503 (cache
->stringObjs
->number
!= 0))
2505 xmlXPathObjectPtr ret
;
2507 ret
= (xmlXPathObjectPtr
)
2508 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2509 ret
->type
= XPATH_STRING
;
2511 ret
->stringval
= xmlStrdup(val
);
2513 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2514 #ifdef XP_DEBUG_OBJ_USAGE
2515 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2518 } else if ((cache
->miscObjs
!= NULL
) &&
2519 (cache
->miscObjs
->number
!= 0))
2521 xmlXPathObjectPtr ret
;
2523 ret
= (xmlXPathObjectPtr
)
2524 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2526 ret
->type
= XPATH_STRING
;
2528 ret
->stringval
= xmlStrdup(val
);
2530 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2537 return(xmlXPathNewString(val
));
2541 * xmlXPathCacheNewBoolean:
2542 * @ctxt: the XPath context
2543 * @val: the boolean value
2545 * This is the cached version of xmlXPathNewBoolean().
2546 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2548 * Returns the created or reused object.
2550 static xmlXPathObjectPtr
2551 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt
, int val
)
2553 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2554 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2556 if ((cache
->booleanObjs
!= NULL
) &&
2557 (cache
->booleanObjs
->number
!= 0))
2559 xmlXPathObjectPtr ret
;
2561 ret
= (xmlXPathObjectPtr
)
2562 cache
->booleanObjs
->items
[--cache
->booleanObjs
->number
];
2563 ret
->type
= XPATH_BOOLEAN
;
2564 ret
->boolval
= (val
!= 0);
2565 #ifdef XP_DEBUG_OBJ_USAGE
2566 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2569 } else if ((cache
->miscObjs
!= NULL
) &&
2570 (cache
->miscObjs
->number
!= 0))
2572 xmlXPathObjectPtr ret
;
2574 ret
= (xmlXPathObjectPtr
)
2575 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2577 ret
->type
= XPATH_BOOLEAN
;
2578 ret
->boolval
= (val
!= 0);
2579 #ifdef XP_DEBUG_OBJ_USAGE
2580 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2585 return(xmlXPathNewBoolean(val
));
2589 * xmlXPathCacheNewFloat:
2590 * @ctxt: the XPath context
2591 * @val: the double value
2593 * This is the cached version of xmlXPathNewFloat().
2594 * Acquires an xmlXPathObjectPtr of type double and of value @val
2596 * Returns the created or reused object.
2598 static xmlXPathObjectPtr
2599 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt
, double val
)
2601 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2602 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2604 if ((cache
->numberObjs
!= NULL
) &&
2605 (cache
->numberObjs
->number
!= 0))
2607 xmlXPathObjectPtr ret
;
2609 ret
= (xmlXPathObjectPtr
)
2610 cache
->numberObjs
->items
[--cache
->numberObjs
->number
];
2611 ret
->type
= XPATH_NUMBER
;
2612 ret
->floatval
= val
;
2613 #ifdef XP_DEBUG_OBJ_USAGE
2614 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2617 } else if ((cache
->miscObjs
!= NULL
) &&
2618 (cache
->miscObjs
->number
!= 0))
2620 xmlXPathObjectPtr ret
;
2622 ret
= (xmlXPathObjectPtr
)
2623 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2625 ret
->type
= XPATH_NUMBER
;
2626 ret
->floatval
= val
;
2627 #ifdef XP_DEBUG_OBJ_USAGE
2628 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2633 return(xmlXPathNewFloat(val
));
2637 * xmlXPathCacheConvertString:
2638 * @ctxt: the XPath context
2639 * @val: an XPath object
2641 * This is the cached version of xmlXPathConvertString().
2642 * Converts an existing object to its string() equivalent
2644 * Returns a created or reused object, the old one is freed (cached)
2645 * (or the operation is done directly on @val)
2648 static xmlXPathObjectPtr
2649 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2650 xmlChar
*res
= NULL
;
2653 return(xmlXPathCacheNewCString(ctxt
, ""));
2655 switch (val
->type
) {
2656 case XPATH_UNDEFINED
:
2658 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
2662 case XPATH_XSLT_TREE
:
2663 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
2668 res
= xmlXPathCastBooleanToString(val
->boolval
);
2671 res
= xmlXPathCastNumberToString(val
->floatval
);
2676 case XPATH_LOCATIONSET
:
2680 xmlXPathReleaseObject(ctxt
, val
);
2682 return(xmlXPathCacheNewCString(ctxt
, ""));
2683 return(xmlXPathCacheWrapString(ctxt
, res
));
2687 * xmlXPathCacheObjectCopy:
2688 * @ctxt: the XPath context
2689 * @val: the original object
2691 * This is the cached version of xmlXPathObjectCopy().
2692 * Acquire a copy of a given object
2694 * Returns a created or reused created object.
2696 static xmlXPathObjectPtr
2697 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
)
2702 if (XP_HAS_CACHE(ctxt
)) {
2703 switch (val
->type
) {
2705 return(xmlXPathCacheWrapNodeSet(ctxt
,
2706 xmlXPathNodeSetMerge(NULL
, val
->nodesetval
)));
2708 return(xmlXPathCacheNewString(ctxt
, val
->stringval
));
2710 return(xmlXPathCacheNewBoolean(ctxt
, val
->boolval
));
2712 return(xmlXPathCacheNewFloat(ctxt
, val
->floatval
));
2717 return(xmlXPathObjectCopy(val
));
2721 * xmlXPathCacheConvertBoolean:
2722 * @ctxt: the XPath context
2723 * @val: an XPath object
2725 * This is the cached version of xmlXPathConvertBoolean().
2726 * Converts an existing object to its boolean() equivalent
2728 * Returns a created or reused object, the old one is freed (or the operation
2729 * is done directly on @val)
2731 static xmlXPathObjectPtr
2732 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2733 xmlXPathObjectPtr ret
;
2736 return(xmlXPathCacheNewBoolean(ctxt
, 0));
2737 if (val
->type
== XPATH_BOOLEAN
)
2739 ret
= xmlXPathCacheNewBoolean(ctxt
, xmlXPathCastToBoolean(val
));
2740 xmlXPathReleaseObject(ctxt
, val
);
2745 * xmlXPathCacheConvertNumber:
2746 * @ctxt: the XPath context
2747 * @val: an XPath object
2749 * This is the cached version of xmlXPathConvertNumber().
2750 * Converts an existing object to its number() equivalent
2752 * Returns a created or reused object, the old one is freed (or the operation
2753 * is done directly on @val)
2755 static xmlXPathObjectPtr
2756 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2757 xmlXPathObjectPtr ret
;
2760 return(xmlXPathCacheNewFloat(ctxt
, 0.0));
2761 if (val
->type
== XPATH_NUMBER
)
2763 ret
= xmlXPathCacheNewFloat(ctxt
, xmlXPathCastToNumber(val
));
2764 xmlXPathReleaseObject(ctxt
, val
);
2768 /************************************************************************
2770 * Parser stacks related functions and macros *
2772 ************************************************************************/
2776 * @ctxt: an XPath parser context
2778 * Set the callee evaluation frame
2780 * Returns the previous frame value to be restored once done
2783 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt
) {
2788 ret
= ctxt
->valueFrame
;
2789 ctxt
->valueFrame
= ctxt
->valueNr
;
2795 * @ctxt: an XPath parser context
2796 * @frame: the previous frame value
2798 * Remove the callee evaluation frame
2801 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt
, int frame
) {
2804 if (ctxt
->valueNr
< ctxt
->valueFrame
) {
2805 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2807 ctxt
->valueFrame
= frame
;
2812 * @ctxt: an XPath evaluation context
2814 * Pops the top XPath object from the value stack
2816 * Returns the XPath object just removed
2819 valuePop(xmlXPathParserContextPtr ctxt
)
2821 xmlXPathObjectPtr ret
;
2823 if ((ctxt
== NULL
) || (ctxt
->valueNr
<= 0))
2826 if (ctxt
->valueNr
<= ctxt
->valueFrame
) {
2827 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2832 if (ctxt
->valueNr
> 0)
2833 ctxt
->value
= ctxt
->valueTab
[ctxt
->valueNr
- 1];
2836 ret
= ctxt
->valueTab
[ctxt
->valueNr
];
2837 ctxt
->valueTab
[ctxt
->valueNr
] = NULL
;
2842 * @ctxt: an XPath evaluation context
2843 * @value: the XPath object
2845 * Pushes a new XPath object on top of the value stack
2847 * returns the number of items on the value stack
2850 valuePush(xmlXPathParserContextPtr ctxt
, xmlXPathObjectPtr value
)
2852 if ((ctxt
== NULL
) || (value
== NULL
)) return(-1);
2853 if (ctxt
->valueNr
>= ctxt
->valueMax
) {
2854 xmlXPathObjectPtr
*tmp
;
2856 if (ctxt
->valueMax
>= XPATH_MAX_STACK_DEPTH
) {
2857 xmlXPathErrMemory(NULL
, "XPath stack depth limit reached\n");
2858 ctxt
->error
= XPATH_MEMORY_ERROR
;
2861 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(ctxt
->valueTab
,
2862 2 * ctxt
->valueMax
*
2863 sizeof(ctxt
->valueTab
[0]));
2865 xmlXPathErrMemory(NULL
, "pushing value\n");
2866 ctxt
->error
= XPATH_MEMORY_ERROR
;
2869 ctxt
->valueMax
*= 2;
2870 ctxt
->valueTab
= tmp
;
2872 ctxt
->valueTab
[ctxt
->valueNr
] = value
;
2873 ctxt
->value
= value
;
2874 return (ctxt
->valueNr
++);
2878 * xmlXPathPopBoolean:
2879 * @ctxt: an XPath parser context
2881 * Pops a boolean from the stack, handling conversion if needed.
2882 * Check error with #xmlXPathCheckError.
2884 * Returns the boolean
2887 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt
) {
2888 xmlXPathObjectPtr obj
;
2891 obj
= valuePop(ctxt
);
2893 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2896 if (obj
->type
!= XPATH_BOOLEAN
)
2897 ret
= xmlXPathCastToBoolean(obj
);
2900 xmlXPathReleaseObject(ctxt
->context
, obj
);
2905 * xmlXPathPopNumber:
2906 * @ctxt: an XPath parser context
2908 * Pops a number from the stack, handling conversion if needed.
2909 * Check error with #xmlXPathCheckError.
2911 * Returns the number
2914 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt
) {
2915 xmlXPathObjectPtr obj
;
2918 obj
= valuePop(ctxt
);
2920 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2923 if (obj
->type
!= XPATH_NUMBER
)
2924 ret
= xmlXPathCastToNumber(obj
);
2926 ret
= obj
->floatval
;
2927 xmlXPathReleaseObject(ctxt
->context
, obj
);
2932 * xmlXPathPopString:
2933 * @ctxt: an XPath parser context
2935 * Pops a string from the stack, handling conversion if needed.
2936 * Check error with #xmlXPathCheckError.
2938 * Returns the string
2941 xmlXPathPopString (xmlXPathParserContextPtr ctxt
) {
2942 xmlXPathObjectPtr obj
;
2945 obj
= valuePop(ctxt
);
2947 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2950 ret
= xmlXPathCastToString(obj
); /* this does required strdup */
2951 /* TODO: needs refactoring somewhere else */
2952 if (obj
->stringval
== ret
)
2953 obj
->stringval
= NULL
;
2954 xmlXPathReleaseObject(ctxt
->context
, obj
);
2959 * xmlXPathPopNodeSet:
2960 * @ctxt: an XPath parser context
2962 * Pops a node-set from the stack, handling conversion if needed.
2963 * Check error with #xmlXPathCheckError.
2965 * Returns the node-set
2968 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt
) {
2969 xmlXPathObjectPtr obj
;
2972 if (ctxt
== NULL
) return(NULL
);
2973 if (ctxt
->value
== NULL
) {
2974 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2977 if (!xmlXPathStackIsNodeSet(ctxt
)) {
2978 xmlXPathSetTypeError(ctxt
);
2981 obj
= valuePop(ctxt
);
2982 ret
= obj
->nodesetval
;
2984 /* to fix memory leak of not clearing obj->user */
2985 if (obj
->boolval
&& obj
->user
!= NULL
)
2986 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
2988 obj
->nodesetval
= NULL
;
2989 xmlXPathReleaseObject(ctxt
->context
, obj
);
2994 * xmlXPathPopExternal:
2995 * @ctxt: an XPath parser context
2997 * Pops an external object from the stack, handling conversion if needed.
2998 * Check error with #xmlXPathCheckError.
3000 * Returns the object
3003 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt
) {
3004 xmlXPathObjectPtr obj
;
3007 if ((ctxt
== NULL
) || (ctxt
->value
== NULL
)) {
3008 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
3011 if (ctxt
->value
->type
!= XPATH_USERS
) {
3012 xmlXPathSetTypeError(ctxt
);
3015 obj
= valuePop(ctxt
);
3018 xmlXPathReleaseObject(ctxt
->context
, obj
);
3023 * Macros for accessing the content. Those should be used only by the parser,
3026 * Dirty macros, i.e. one need to make assumption on the context to use them
3028 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3029 * CUR returns the current xmlChar value, i.e. a 8 bit value
3030 * in ISO-Latin or UTF-8.
3031 * This should be used internally by the parser
3032 * only to compare to ASCII values otherwise it would break when
3033 * running with UTF-8 encoding.
3034 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3035 * to compare on ASCII based substring.
3036 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3037 * strings within the parser.
3038 * CURRENT Returns the current char value, with the full decoding of
3039 * UTF-8 if we are using this mode. It returns an int.
3040 * NEXT Skip to the next character, this does the proper decoding
3041 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3042 * It returns the pointer to the current xmlChar.
3045 #define CUR (*ctxt->cur)
3046 #define SKIP(val) ctxt->cur += (val)
3047 #define NXT(val) ctxt->cur[(val)]
3048 #define CUR_PTR ctxt->cur
3049 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3051 #define COPY_BUF(l,b,i,v) \
3052 if (l == 1) b[i++] = (xmlChar) v; \
3053 else i += xmlCopyChar(l,&b[i],v)
3055 #define NEXTL(l) ctxt->cur += l
3057 #define SKIP_BLANKS \
3058 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3060 #define CURRENT (*ctxt->cur)
3061 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3068 #define DBL_EPSILON 1E-9
3071 #define UPPER_DOUBLE 1E9
3072 #define LOWER_DOUBLE 1E-5
3073 #define LOWER_DOUBLE_EXP 5
3075 #define INTEGER_DIGITS DBL_DIG
3076 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3077 #define EXPONENT_DIGITS (3 + 2)
3080 * xmlXPathFormatNumber:
3081 * @number: number to format
3082 * @buffer: output buffer
3083 * @buffersize: size of output buffer
3085 * Convert the number into a string representation.
3088 xmlXPathFormatNumber(double number
, char buffer
[], int buffersize
)
3090 switch (xmlXPathIsInf(number
)) {
3092 if (buffersize
> (int)sizeof("Infinity"))
3093 snprintf(buffer
, buffersize
, "Infinity");
3096 if (buffersize
> (int)sizeof("-Infinity"))
3097 snprintf(buffer
, buffersize
, "-Infinity");
3100 if (xmlXPathIsNaN(number
)) {
3101 if (buffersize
> (int)sizeof("NaN"))
3102 snprintf(buffer
, buffersize
, "NaN");
3103 } else if (number
== 0) {
3104 /* Omit sign for negative zero. */
3105 snprintf(buffer
, buffersize
, "0");
3106 } else if ((number
> INT_MIN
) && (number
< INT_MAX
) &&
3107 (number
== (int) number
)) {
3110 int value
= (int) number
;
3116 snprintf(work
, 29, "%d", value
);
3118 while ((*cur
) && (ptr
- buffer
< buffersize
)) {
3122 if (ptr
- buffer
< buffersize
) {
3124 } else if (buffersize
> 0) {
3130 For the dimension of work,
3131 DBL_DIG is number of significant digits
3132 EXPONENT is only needed for "scientific notation"
3133 3 is sign, decimal point, and terminating zero
3134 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3135 Note that this dimension is slightly (a few characters)
3136 larger than actually necessary.
3138 char work
[DBL_DIG
+ EXPONENT_DIGITS
+ 3 + LOWER_DOUBLE_EXP
];
3139 int integer_place
, fraction_place
;
3141 char *after_fraction
;
3142 double absolute_value
;
3145 absolute_value
= fabs(number
);
3148 * First choose format - scientific or regular floating point.
3149 * In either case, result is in work, and after_fraction points
3150 * just past the fractional part.
3152 if ( ((absolute_value
> UPPER_DOUBLE
) ||
3153 (absolute_value
< LOWER_DOUBLE
)) &&
3154 (absolute_value
!= 0.0) ) {
3155 /* Use scientific notation */
3156 integer_place
= DBL_DIG
+ EXPONENT_DIGITS
+ 1;
3157 fraction_place
= DBL_DIG
- 1;
3158 size
= snprintf(work
, sizeof(work
),"%*.*e",
3159 integer_place
, fraction_place
, number
);
3160 while ((size
> 0) && (work
[size
] != 'e')) size
--;
3164 /* Use regular notation */
3165 if (absolute_value
> 0.0) {
3166 integer_place
= (int)log10(absolute_value
);
3167 if (integer_place
> 0)
3168 fraction_place
= DBL_DIG
- integer_place
- 1;
3170 fraction_place
= DBL_DIG
- integer_place
;
3174 size
= snprintf(work
, sizeof(work
), "%0.*f",
3175 fraction_place
, number
);
3178 /* Remove leading spaces sometimes inserted by snprintf */
3179 while (work
[0] == ' ') {
3180 for (ptr
= &work
[0];(ptr
[0] = ptr
[1]);ptr
++);
3184 /* Remove fractional trailing zeroes */
3185 after_fraction
= work
+ size
;
3186 ptr
= after_fraction
;
3187 while (*(--ptr
) == '0')
3191 while ((*ptr
++ = *after_fraction
++) != 0);
3193 /* Finally copy result back to caller */
3194 size
= strlen(work
) + 1;
3195 if (size
> buffersize
) {
3196 work
[buffersize
- 1] = 0;
3199 memmove(buffer
, work
, size
);
3206 /************************************************************************
3208 * Routines to handle NodeSets *
3210 ************************************************************************/
3213 * xmlXPathOrderDocElems:
3214 * @doc: an input document
3216 * Call this routine to speed up XPath computation on static documents.
3217 * This stamps all the element nodes with the document order
3218 * Like for line information, the order is kept in the element->content
3219 * field, the value stored is actually - the node number (starting at -1)
3220 * to be able to differentiate from line numbers.
3222 * Returns the number of elements found in the document or -1 in case
3226 xmlXPathOrderDocElems(xmlDocPtr doc
) {
3227 ptrdiff_t count
= 0;
3232 cur
= doc
->children
;
3233 while (cur
!= NULL
) {
3234 if (cur
->type
== XML_ELEMENT_NODE
) {
3235 cur
->content
= (void *) (-(++count
));
3236 if (cur
->children
!= NULL
) {
3237 cur
= cur
->children
;
3241 if (cur
->next
!= NULL
) {
3249 if (cur
== (xmlNodePtr
) doc
) {
3253 if (cur
->next
!= NULL
) {
3257 } while (cur
!= NULL
);
3259 return((long) count
);
3264 * @node1: the first node
3265 * @node2: the second node
3267 * Compare two nodes w.r.t document order
3269 * Returns -2 in case of error 1 if first point < second point, 0 if
3270 * it's the same node, -1 otherwise
3273 xmlXPathCmpNodes(xmlNodePtr node1
, xmlNodePtr node2
) {
3275 int attr1
= 0, attr2
= 0;
3276 xmlNodePtr attrNode1
= NULL
, attrNode2
= NULL
;
3277 xmlNodePtr cur
, root
;
3279 if ((node1
== NULL
) || (node2
== NULL
))
3282 * a couple of optimizations which will avoid computations in most cases
3284 if (node1
== node2
) /* trivial case */
3286 if (node1
->type
== XML_ATTRIBUTE_NODE
) {
3289 node1
= node1
->parent
;
3291 if (node2
->type
== XML_ATTRIBUTE_NODE
) {
3294 node2
= node2
->parent
;
3296 if (node1
== node2
) {
3297 if (attr1
== attr2
) {
3298 /* not required, but we keep attributes in order */
3300 cur
= attrNode2
->prev
;
3301 while (cur
!= NULL
) {
3302 if (cur
== attrNode1
)
3314 if ((node1
->type
== XML_NAMESPACE_DECL
) ||
3315 (node2
->type
== XML_NAMESPACE_DECL
))
3317 if (node1
== node2
->prev
)
3319 if (node1
== node2
->next
)
3323 * Speedup using document order if availble.
3325 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3326 (node2
->type
== XML_ELEMENT_NODE
) &&
3327 (0 > (ptrdiff_t) node1
->content
) &&
3328 (0 > (ptrdiff_t) node2
->content
) &&
3329 (node1
->doc
== node2
->doc
)) {
3332 l1
= -((ptrdiff_t) node1
->content
);
3333 l2
= -((ptrdiff_t) node2
->content
);
3341 * compute depth to root
3343 for (depth2
= 0, cur
= node2
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3344 if (cur
->parent
== node1
)
3349 for (depth1
= 0, cur
= node1
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3350 if (cur
->parent
== node2
)
3355 * Distinct document (or distinct entities :-( ) case.
3361 * get the nearest common ancestor.
3363 while (depth1
> depth2
) {
3365 node1
= node1
->parent
;
3367 while (depth2
> depth1
) {
3369 node2
= node2
->parent
;
3371 while (node1
->parent
!= node2
->parent
) {
3372 node1
= node1
->parent
;
3373 node2
= node2
->parent
;
3374 /* should not happen but just in case ... */
3375 if ((node1
== NULL
) || (node2
== NULL
))
3381 if (node1
== node2
->prev
)
3383 if (node1
== node2
->next
)
3386 * Speedup using document order if availble.
3388 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3389 (node2
->type
== XML_ELEMENT_NODE
) &&
3390 (0 > (ptrdiff_t) node1
->content
) &&
3391 (0 > (ptrdiff_t) node2
->content
) &&
3392 (node1
->doc
== node2
->doc
)) {
3395 l1
= -((ptrdiff_t) node1
->content
);
3396 l2
= -((ptrdiff_t) node2
->content
);
3403 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
3406 return(-1); /* assume there is no sibling list corruption */
3410 * xmlXPathNodeSetSort:
3411 * @set: the node set
3413 * Sort the node set in document order
3416 xmlXPathNodeSetSort(xmlNodeSetPtr set
) {
3417 #ifndef WITH_TIM_SORT
3418 int i
, j
, incr
, len
;
3425 #ifndef WITH_TIM_SORT
3427 * Use the old Shell's sort implementation to sort the node-set
3428 * Timsort ought to be quite faster
3431 for (incr
= len
/ 2; incr
> 0; incr
/= 2) {
3432 for (i
= incr
; i
< len
; i
++) {
3435 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3436 if (xmlXPathCmpNodesExt(set
->nodeTab
[j
],
3437 set
->nodeTab
[j
+ incr
]) == -1)
3439 if (xmlXPathCmpNodes(set
->nodeTab
[j
],
3440 set
->nodeTab
[j
+ incr
]) == -1)
3443 tmp
= set
->nodeTab
[j
];
3444 set
->nodeTab
[j
] = set
->nodeTab
[j
+ incr
];
3445 set
->nodeTab
[j
+ incr
] = tmp
;
3452 #else /* WITH_TIM_SORT */
3453 libxml_domnode_tim_sort(set
->nodeTab
, set
->nodeNr
);
3454 #endif /* WITH_TIM_SORT */
3457 #define XML_NODESET_DEFAULT 10
3459 * xmlXPathNodeSetDupNs:
3460 * @node: the parent node of the namespace XPath node
3461 * @ns: the libxml namespace declaration node.
3463 * Namespace node in libxml don't match the XPath semantic. In a node set
3464 * the namespace nodes are duplicated and the next pointer is set to the
3465 * parent node in the XPath semantic.
3467 * Returns the newly created object.
3470 xmlXPathNodeSetDupNs(xmlNodePtr node
, xmlNsPtr ns
) {
3473 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3475 if ((node
== NULL
) || (node
->type
== XML_NAMESPACE_DECL
))
3476 return((xmlNodePtr
) ns
);
3479 * Allocate a new Namespace and fill the fields.
3481 cur
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
3483 xmlXPathErrMemory(NULL
, "duplicating namespace\n");
3486 memset(cur
, 0, sizeof(xmlNs
));
3487 cur
->type
= XML_NAMESPACE_DECL
;
3488 if (ns
->href
!= NULL
)
3489 cur
->href
= xmlStrdup(ns
->href
);
3490 if (ns
->prefix
!= NULL
)
3491 cur
->prefix
= xmlStrdup(ns
->prefix
);
3492 cur
->next
= (xmlNsPtr
) node
;
3493 return((xmlNodePtr
) cur
);
3497 * xmlXPathNodeSetFreeNs:
3498 * @ns: the XPath namespace node found in a nodeset.
3500 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3501 * the namespace nodes are duplicated and the next pointer is set to the
3502 * parent node in the XPath semantic. Check if such a node needs to be freed
3505 xmlXPathNodeSetFreeNs(xmlNsPtr ns
) {
3506 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3509 if ((ns
->next
!= NULL
) && (ns
->next
->type
!= XML_NAMESPACE_DECL
)) {
3510 if (ns
->href
!= NULL
)
3511 xmlFree((xmlChar
*)ns
->href
);
3512 if (ns
->prefix
!= NULL
)
3513 xmlFree((xmlChar
*)ns
->prefix
);
3519 * xmlXPathNodeSetCreate:
3520 * @val: an initial xmlNodePtr, or NULL
3522 * Create a new xmlNodeSetPtr of type double and of value @val
3524 * Returns the newly created object.
3527 xmlXPathNodeSetCreate(xmlNodePtr val
) {
3530 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3532 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3535 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3537 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3538 sizeof(xmlNodePtr
));
3539 if (ret
->nodeTab
== NULL
) {
3540 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3544 memset(ret
->nodeTab
, 0 ,
3545 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3546 ret
->nodeMax
= XML_NODESET_DEFAULT
;
3547 if (val
->type
== XML_NAMESPACE_DECL
) {
3548 xmlNsPtr ns
= (xmlNsPtr
) val
;
3550 ret
->nodeTab
[ret
->nodeNr
++] =
3551 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3553 ret
->nodeTab
[ret
->nodeNr
++] = val
;
3559 * xmlXPathNodeSetCreateSize:
3560 * @size: the initial size of the set
3562 * Create a new xmlNodeSetPtr of type double and of value @val
3564 * Returns the newly created object.
3566 static xmlNodeSetPtr
3567 xmlXPathNodeSetCreateSize(int size
) {
3570 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3572 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3575 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3576 if (size
< XML_NODESET_DEFAULT
)
3577 size
= XML_NODESET_DEFAULT
;
3578 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(size
* sizeof(xmlNodePtr
));
3579 if (ret
->nodeTab
== NULL
) {
3580 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3584 memset(ret
->nodeTab
, 0 , size
* (size_t) sizeof(xmlNodePtr
));
3585 ret
->nodeMax
= size
;
3590 * xmlXPathNodeSetContains:
3591 * @cur: the node-set
3594 * checks whether @cur contains @val
3596 * Returns true (1) if @cur contains @val, false (0) otherwise
3599 xmlXPathNodeSetContains (xmlNodeSetPtr cur
, xmlNodePtr val
) {
3602 if ((cur
== NULL
) || (val
== NULL
)) return(0);
3603 if (val
->type
== XML_NAMESPACE_DECL
) {
3604 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3605 if (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
3608 ns1
= (xmlNsPtr
) val
;
3609 ns2
= (xmlNsPtr
) cur
->nodeTab
[i
];
3612 if ((ns1
->next
!= NULL
) && (ns2
->next
== ns1
->next
) &&
3613 (xmlStrEqual(ns1
->prefix
, ns2
->prefix
)))
3618 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3619 if (cur
->nodeTab
[i
] == val
)
3627 * xmlXPathNodeSetAddNs:
3628 * @cur: the initial node set
3629 * @node: the hosting node
3630 * @ns: a the namespace node
3632 * add a new namespace node to an existing NodeSet
3634 * Returns 0 in case of success and -1 in case of error
3637 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur
, xmlNodePtr node
, xmlNsPtr ns
) {
3641 if ((cur
== NULL
) || (ns
== NULL
) || (node
== NULL
) ||
3642 (ns
->type
!= XML_NAMESPACE_DECL
) ||
3643 (node
->type
!= XML_ELEMENT_NODE
))
3646 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3648 * prevent duplicates
3650 for (i
= 0;i
< cur
->nodeNr
;i
++) {
3651 if ((cur
->nodeTab
[i
] != NULL
) &&
3652 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) &&
3653 (((xmlNsPtr
)cur
->nodeTab
[i
])->next
== (xmlNsPtr
) node
) &&
3654 (xmlStrEqual(ns
->prefix
, ((xmlNsPtr
)cur
->nodeTab
[i
])->prefix
)))
3659 * grow the nodeTab if needed
3661 if (cur
->nodeMax
== 0) {
3662 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3663 sizeof(xmlNodePtr
));
3664 if (cur
->nodeTab
== NULL
) {
3665 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3668 memset(cur
->nodeTab
, 0 ,
3669 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3670 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3671 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3674 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3675 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3678 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3679 sizeof(xmlNodePtr
));
3681 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3685 cur
->nodeTab
= temp
;
3687 cur
->nodeTab
[cur
->nodeNr
++] = xmlXPathNodeSetDupNs(node
, ns
);
3692 * xmlXPathNodeSetAdd:
3693 * @cur: the initial node set
3694 * @val: a new xmlNodePtr
3696 * add a new xmlNodePtr to an existing NodeSet
3698 * Returns 0 in case of success, and -1 in case of error
3701 xmlXPathNodeSetAdd(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3704 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3706 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3708 * prevent duplicates
3710 for (i
= 0;i
< cur
->nodeNr
;i
++)
3711 if (cur
->nodeTab
[i
] == val
) return(0);
3714 * grow the nodeTab if needed
3716 if (cur
->nodeMax
== 0) {
3717 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3718 sizeof(xmlNodePtr
));
3719 if (cur
->nodeTab
== NULL
) {
3720 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3723 memset(cur
->nodeTab
, 0 ,
3724 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3725 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3726 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3729 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3730 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3733 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3734 sizeof(xmlNodePtr
));
3736 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3740 cur
->nodeTab
= temp
;
3742 if (val
->type
== XML_NAMESPACE_DECL
) {
3743 xmlNsPtr ns
= (xmlNsPtr
) val
;
3745 cur
->nodeTab
[cur
->nodeNr
++] =
3746 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3748 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3753 * xmlXPathNodeSetAddUnique:
3754 * @cur: the initial node set
3755 * @val: a new xmlNodePtr
3757 * add a new xmlNodePtr to an existing NodeSet, optimized version
3758 * when we are sure the node is not already in the set.
3760 * Returns 0 in case of success and -1 in case of failure
3763 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3764 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3766 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3768 * grow the nodeTab if needed
3770 if (cur
->nodeMax
== 0) {
3771 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3772 sizeof(xmlNodePtr
));
3773 if (cur
->nodeTab
== NULL
) {
3774 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3777 memset(cur
->nodeTab
, 0 ,
3778 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3779 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3780 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3783 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3784 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3787 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3788 sizeof(xmlNodePtr
));
3790 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3793 cur
->nodeTab
= temp
;
3796 if (val
->type
== XML_NAMESPACE_DECL
) {
3797 xmlNsPtr ns
= (xmlNsPtr
) val
;
3799 cur
->nodeTab
[cur
->nodeNr
++] =
3800 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3802 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3807 * xmlXPathNodeSetMerge:
3808 * @val1: the first NodeSet or NULL
3809 * @val2: the second NodeSet
3811 * Merges two nodesets, all nodes from @val2 are added to @val1
3812 * if @val1 is NULL, a new set is created and copied from @val2
3814 * Returns @val1 once extended or NULL in case of error.
3817 xmlXPathNodeSetMerge(xmlNodeSetPtr val1
, xmlNodeSetPtr val2
) {
3818 int i
, j
, initNr
, skip
;
3821 if (val2
== NULL
) return(val1
);
3823 val1
= xmlXPathNodeSetCreate(NULL
);
3828 * TODO: The optimization won't work in every case, since
3829 * those nasty namespace nodes need to be added with
3830 * xmlXPathNodeSetDupNs() to the set; thus a pure
3831 * memcpy is not possible.
3832 * If there was a flag on the nodesetval, indicating that
3833 * some temporary nodes are in, that would be helpfull.
3836 * Optimization: Create an equally sized node-set
3837 * and memcpy the content.
3839 val1
= xmlXPathNodeSetCreateSize(val2
->nodeNr
);
3842 if (val2
->nodeNr
!= 0) {
3843 if (val2
->nodeNr
== 1)
3844 *(val1
->nodeTab
) = *(val2
->nodeTab
);
3846 memcpy(val1
->nodeTab
, val2
->nodeTab
,
3847 val2
->nodeNr
* sizeof(xmlNodePtr
));
3849 val1
->nodeNr
= val2
->nodeNr
;
3855 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3856 initNr
= val1
->nodeNr
;
3858 for (i
= 0;i
< val2
->nodeNr
;i
++) {
3859 n2
= val2
->nodeTab
[i
];
3861 * check against duplicates
3864 for (j
= 0; j
< initNr
; j
++) {
3865 n1
= val1
->nodeTab
[j
];
3869 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3870 (n2
->type
== XML_NAMESPACE_DECL
)) {
3871 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3872 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3873 ((xmlNsPtr
) n2
)->prefix
)))
3884 * grow the nodeTab if needed
3886 if (val1
->nodeMax
== 0) {
3887 val1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3888 sizeof(xmlNodePtr
));
3889 if (val1
->nodeTab
== NULL
) {
3890 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3893 memset(val1
->nodeTab
, 0 ,
3894 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3895 val1
->nodeMax
= XML_NODESET_DEFAULT
;
3896 } else if (val1
->nodeNr
== val1
->nodeMax
) {
3899 if (val1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3900 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
3903 temp
= (xmlNodePtr
*) xmlRealloc(val1
->nodeTab
, val1
->nodeMax
* 2 *
3904 sizeof(xmlNodePtr
));
3906 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3909 val1
->nodeTab
= temp
;
3912 if (n2
->type
== XML_NAMESPACE_DECL
) {
3913 xmlNsPtr ns
= (xmlNsPtr
) n2
;
3915 val1
->nodeTab
[val1
->nodeNr
++] =
3916 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3918 val1
->nodeTab
[val1
->nodeNr
++] = n2
;
3926 * xmlXPathNodeSetMergeAndClear:
3927 * @set1: the first NodeSet or NULL
3928 * @set2: the second NodeSet
3929 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3931 * Merges two nodesets, all nodes from @set2 are added to @set1
3932 * if @set1 is NULL, a new set is created and copied from @set2.
3933 * Checks for duplicate nodes. Clears set2.
3935 * Returns @set1 once extended or NULL in case of error.
3937 static xmlNodeSetPtr
3938 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
,
3941 if ((set1
== NULL
) && (hasNullEntries
== 0)) {
3943 * Note that doing a memcpy of the list, namespace nodes are
3944 * just assigned to set1, since set2 is cleared anyway.
3946 set1
= xmlXPathNodeSetCreateSize(set2
->nodeNr
);
3949 if (set2
->nodeNr
!= 0) {
3950 memcpy(set1
->nodeTab
, set2
->nodeTab
,
3951 set2
->nodeNr
* sizeof(xmlNodePtr
));
3952 set1
->nodeNr
= set2
->nodeNr
;
3955 int i
, j
, initNbSet1
;
3959 set1
= xmlXPathNodeSetCreate(NULL
);
3963 initNbSet1
= set1
->nodeNr
;
3964 for (i
= 0;i
< set2
->nodeNr
;i
++) {
3965 n2
= set2
->nodeTab
[i
];
3967 * Skip NULLed entries.
3974 for (j
= 0; j
< initNbSet1
; j
++) {
3975 n1
= set1
->nodeTab
[j
];
3978 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3979 (n2
->type
== XML_NAMESPACE_DECL
))
3981 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3982 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3983 ((xmlNsPtr
) n2
)->prefix
)))
3986 * Free the namespace node.
3988 set2
->nodeTab
[i
] = NULL
;
3989 xmlXPathNodeSetFreeNs((xmlNsPtr
) n2
);
3995 * grow the nodeTab if needed
3997 if (set1
->nodeMax
== 0) {
3998 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
3999 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4000 if (set1
->nodeTab
== NULL
) {
4001 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4004 memset(set1
->nodeTab
, 0,
4005 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4006 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4007 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4010 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4011 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4014 temp
= (xmlNodePtr
*) xmlRealloc(
4015 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4017 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4020 set1
->nodeTab
= temp
;
4023 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4033 * xmlXPathNodeSetMergeAndClearNoDupls:
4034 * @set1: the first NodeSet or NULL
4035 * @set2: the second NodeSet
4036 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4038 * Merges two nodesets, all nodes from @set2 are added to @set1
4039 * if @set1 is NULL, a new set is created and copied from @set2.
4040 * Doesn't chack for duplicate nodes. Clears set2.
4042 * Returns @set1 once extended or NULL in case of error.
4044 static xmlNodeSetPtr
4045 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
,
4050 if ((set1
== NULL
) && (hasNullEntries
== 0)) {
4052 * Note that doing a memcpy of the list, namespace nodes are
4053 * just assigned to set1, since set2 is cleared anyway.
4055 set1
= xmlXPathNodeSetCreateSize(set2
->nodeNr
);
4058 if (set2
->nodeNr
!= 0) {
4059 memcpy(set1
->nodeTab
, set2
->nodeTab
,
4060 set2
->nodeNr
* sizeof(xmlNodePtr
));
4061 set1
->nodeNr
= set2
->nodeNr
;
4068 set1
= xmlXPathNodeSetCreate(NULL
);
4072 for (i
= 0;i
< set2
->nodeNr
;i
++) {
4073 n2
= set2
->nodeTab
[i
];
4075 * Skip NULLed entries.
4079 if (set1
->nodeMax
== 0) {
4080 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
4081 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4082 if (set1
->nodeTab
== NULL
) {
4083 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4086 memset(set1
->nodeTab
, 0,
4087 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4088 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4089 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4092 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4093 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4096 temp
= (xmlNodePtr
*) xmlRealloc(
4097 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4099 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4102 set1
->nodeTab
= temp
;
4105 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4113 * xmlXPathNodeSetDel:
4114 * @cur: the initial node set
4115 * @val: an xmlNodePtr
4117 * Removes an xmlNodePtr from an existing NodeSet
4120 xmlXPathNodeSetDel(xmlNodeSetPtr cur
, xmlNodePtr val
) {
4123 if (cur
== NULL
) return;
4124 if (val
== NULL
) return;
4127 * find node in nodeTab
4129 for (i
= 0;i
< cur
->nodeNr
;i
++)
4130 if (cur
->nodeTab
[i
] == val
) break;
4132 if (i
>= cur
->nodeNr
) { /* not found */
4134 xmlGenericError(xmlGenericErrorContext
,
4135 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4140 if ((cur
->nodeTab
[i
] != NULL
) &&
4141 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4142 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[i
]);
4144 for (;i
< cur
->nodeNr
;i
++)
4145 cur
->nodeTab
[i
] = cur
->nodeTab
[i
+ 1];
4146 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4150 * xmlXPathNodeSetRemove:
4151 * @cur: the initial node set
4152 * @val: the index to remove
4154 * Removes an entry from an existing NodeSet list.
4157 xmlXPathNodeSetRemove(xmlNodeSetPtr cur
, int val
) {
4158 if (cur
== NULL
) return;
4159 if (val
>= cur
->nodeNr
) return;
4160 if ((cur
->nodeTab
[val
] != NULL
) &&
4161 (cur
->nodeTab
[val
]->type
== XML_NAMESPACE_DECL
))
4162 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[val
]);
4164 for (;val
< cur
->nodeNr
;val
++)
4165 cur
->nodeTab
[val
] = cur
->nodeTab
[val
+ 1];
4166 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4170 * xmlXPathFreeNodeSet:
4171 * @obj: the xmlNodeSetPtr to free
4173 * Free the NodeSet compound (not the actual nodes !).
4176 xmlXPathFreeNodeSet(xmlNodeSetPtr obj
) {
4177 if (obj
== NULL
) return;
4178 if (obj
->nodeTab
!= NULL
) {
4181 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4182 for (i
= 0;i
< obj
->nodeNr
;i
++)
4183 if ((obj
->nodeTab
[i
] != NULL
) &&
4184 (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4185 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4186 xmlFree(obj
->nodeTab
);
4192 * xmlXPathNodeSetClearFromPos:
4193 * @set: the node set to be cleared
4194 * @pos: the start position to clear from
4196 * Clears the list from temporary XPath objects (e.g. namespace nodes
4197 * are feed) starting with the entry at @pos, but does *not* free the list
4198 * itself. Sets the length of the list to @pos.
4201 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set
, int pos
, int hasNsNodes
)
4203 if ((set
== NULL
) || (pos
>= set
->nodeNr
))
4205 else if ((hasNsNodes
)) {
4209 for (i
= pos
; i
< set
->nodeNr
; i
++) {
4210 node
= set
->nodeTab
[i
];
4211 if ((node
!= NULL
) &&
4212 (node
->type
== XML_NAMESPACE_DECL
))
4213 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4220 * xmlXPathNodeSetClear:
4221 * @set: the node set to clear
4223 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4224 * are feed), but does *not* free the list itself. Sets the length of the
4228 xmlXPathNodeSetClear(xmlNodeSetPtr set
, int hasNsNodes
)
4230 xmlXPathNodeSetClearFromPos(set
, 0, hasNsNodes
);
4234 * xmlXPathNodeSetKeepLast:
4235 * @set: the node set to be cleared
4237 * Move the last node to the first position and clear temporary XPath objects
4238 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4242 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set
)
4247 if ((set
== NULL
) || (set
->nodeNr
<= 1))
4249 for (i
= 0; i
< set
->nodeNr
- 1; i
++) {
4250 node
= set
->nodeTab
[i
];
4251 if ((node
!= NULL
) &&
4252 (node
->type
== XML_NAMESPACE_DECL
))
4253 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4255 set
->nodeTab
[0] = set
->nodeTab
[set
->nodeNr
-1];
4260 * xmlXPathFreeValueTree:
4261 * @obj: the xmlNodeSetPtr to free
4263 * Free the NodeSet compound and the actual tree, this is different
4264 * from xmlXPathFreeNodeSet()
4267 xmlXPathFreeValueTree(xmlNodeSetPtr obj
) {
4270 if (obj
== NULL
) return;
4272 if (obj
->nodeTab
!= NULL
) {
4273 for (i
= 0;i
< obj
->nodeNr
;i
++) {
4274 if (obj
->nodeTab
[i
] != NULL
) {
4275 if (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
4276 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4278 xmlFreeNodeList(obj
->nodeTab
[i
]);
4282 xmlFree(obj
->nodeTab
);
4287 #if defined(DEBUG) || defined(DEBUG_STEP)
4289 * xmlGenericErrorContextNodeSet:
4290 * @output: a FILE * for the output
4291 * @obj: the xmlNodeSetPtr to display
4293 * Quick display of a NodeSet
4296 xmlGenericErrorContextNodeSet(FILE *output
, xmlNodeSetPtr obj
) {
4299 if (output
== NULL
) output
= xmlGenericErrorContext
;
4301 fprintf(output
, "NodeSet == NULL !\n");
4304 if (obj
->nodeNr
== 0) {
4305 fprintf(output
, "NodeSet is empty\n");
4308 if (obj
->nodeTab
== NULL
) {
4309 fprintf(output
, " nodeTab == NULL !\n");
4312 for (i
= 0; i
< obj
->nodeNr
; i
++) {
4313 if (obj
->nodeTab
[i
] == NULL
) {
4314 fprintf(output
, " NULL !\n");
4317 if ((obj
->nodeTab
[i
]->type
== XML_DOCUMENT_NODE
) ||
4318 (obj
->nodeTab
[i
]->type
== XML_HTML_DOCUMENT_NODE
))
4319 fprintf(output
, " /");
4320 else if (obj
->nodeTab
[i
]->name
== NULL
)
4321 fprintf(output
, " noname!");
4322 else fprintf(output
, " %s", obj
->nodeTab
[i
]->name
);
4324 fprintf(output
, "\n");
4329 * xmlXPathNewNodeSet:
4330 * @val: the NodePtr value
4332 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4333 * it with the single Node @val
4335 * Returns the newly created object.
4338 xmlXPathNewNodeSet(xmlNodePtr val
) {
4339 xmlXPathObjectPtr ret
;
4341 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4343 xmlXPathErrMemory(NULL
, "creating nodeset\n");
4346 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4347 ret
->type
= XPATH_NODESET
;
4349 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4350 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4351 #ifdef XP_DEBUG_OBJ_USAGE
4352 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4358 * xmlXPathNewValueTree:
4359 * @val: the NodePtr value
4361 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4362 * it with the tree root @val
4364 * Returns the newly created object.
4367 xmlXPathNewValueTree(xmlNodePtr val
) {
4368 xmlXPathObjectPtr ret
;
4370 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4372 xmlXPathErrMemory(NULL
, "creating result value tree\n");
4375 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4376 ret
->type
= XPATH_XSLT_TREE
;
4378 ret
->user
= (void *) val
;
4379 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4380 #ifdef XP_DEBUG_OBJ_USAGE
4381 xmlXPathDebugObjUsageRequested(NULL
, XPATH_XSLT_TREE
);
4387 * xmlXPathNewNodeSetList:
4388 * @val: an existing NodeSet
4390 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4391 * it with the Nodeset @val
4393 * Returns the newly created object.
4396 xmlXPathNewNodeSetList(xmlNodeSetPtr val
)
4398 xmlXPathObjectPtr ret
;
4403 else if (val
->nodeTab
== NULL
)
4404 ret
= xmlXPathNewNodeSet(NULL
);
4406 ret
= xmlXPathNewNodeSet(val
->nodeTab
[0]);
4408 for (i
= 1; i
< val
->nodeNr
; ++i
) {
4409 if (xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
->nodeTab
[i
])
4419 * xmlXPathWrapNodeSet:
4420 * @val: the NodePtr value
4422 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4424 * Returns the newly created object.
4427 xmlXPathWrapNodeSet(xmlNodeSetPtr val
) {
4428 xmlXPathObjectPtr ret
;
4430 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4432 xmlXPathErrMemory(NULL
, "creating node set object\n");
4435 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4436 ret
->type
= XPATH_NODESET
;
4437 ret
->nodesetval
= val
;
4438 #ifdef XP_DEBUG_OBJ_USAGE
4439 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4445 * xmlXPathFreeNodeSetList:
4446 * @obj: an existing NodeSetList object
4448 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4449 * the list contrary to xmlXPathFreeObject().
4452 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj
) {
4453 if (obj
== NULL
) return;
4454 #ifdef XP_DEBUG_OBJ_USAGE
4455 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
4461 * xmlXPathDifference:
4462 * @nodes1: a node-set
4463 * @nodes2: a node-set
4465 * Implements the EXSLT - Sets difference() function:
4466 * node-set set:difference (node-set, node-set)
4468 * Returns the difference between the two node sets, or nodes1 if
4472 xmlXPathDifference (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4477 if (xmlXPathNodeSetIsEmpty(nodes2
))
4480 ret
= xmlXPathNodeSetCreate(NULL
);
4481 if (xmlXPathNodeSetIsEmpty(nodes1
))
4484 l1
= xmlXPathNodeSetGetLength(nodes1
);
4486 for (i
= 0; i
< l1
; i
++) {
4487 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4488 if (!xmlXPathNodeSetContains(nodes2
, cur
)) {
4489 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4497 * xmlXPathIntersection:
4498 * @nodes1: a node-set
4499 * @nodes2: a node-set
4501 * Implements the EXSLT - Sets intersection() function:
4502 * node-set set:intersection (node-set, node-set)
4504 * Returns a node set comprising the nodes that are within both the
4505 * node sets passed as arguments
4508 xmlXPathIntersection (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4509 xmlNodeSetPtr ret
= xmlXPathNodeSetCreate(NULL
);
4515 if (xmlXPathNodeSetIsEmpty(nodes1
))
4517 if (xmlXPathNodeSetIsEmpty(nodes2
))
4520 l1
= xmlXPathNodeSetGetLength(nodes1
);
4522 for (i
= 0; i
< l1
; i
++) {
4523 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4524 if (xmlXPathNodeSetContains(nodes2
, cur
)) {
4525 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4533 * xmlXPathDistinctSorted:
4534 * @nodes: a node-set, sorted by document order
4536 * Implements the EXSLT - Sets distinct() function:
4537 * node-set set:distinct (node-set)
4539 * Returns a subset of the nodes contained in @nodes, or @nodes if
4543 xmlXPathDistinctSorted (xmlNodeSetPtr nodes
) {
4545 xmlHashTablePtr hash
;
4550 if (xmlXPathNodeSetIsEmpty(nodes
))
4553 ret
= xmlXPathNodeSetCreate(NULL
);
4556 l
= xmlXPathNodeSetGetLength(nodes
);
4557 hash
= xmlHashCreate (l
);
4558 for (i
= 0; i
< l
; i
++) {
4559 cur
= xmlXPathNodeSetItem(nodes
, i
);
4560 strval
= xmlXPathCastNodeToString(cur
);
4561 if (xmlHashLookup(hash
, strval
) == NULL
) {
4562 xmlHashAddEntry(hash
, strval
, strval
);
4563 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4569 xmlHashFree(hash
, xmlHashDefaultDeallocator
);
4575 * @nodes: a node-set
4577 * Implements the EXSLT - Sets distinct() function:
4578 * node-set set:distinct (node-set)
4579 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4580 * is called with the sorted node-set
4582 * Returns a subset of the nodes contained in @nodes, or @nodes if
4586 xmlXPathDistinct (xmlNodeSetPtr nodes
) {
4587 if (xmlXPathNodeSetIsEmpty(nodes
))
4590 xmlXPathNodeSetSort(nodes
);
4591 return(xmlXPathDistinctSorted(nodes
));
4595 * xmlXPathHasSameNodes:
4596 * @nodes1: a node-set
4597 * @nodes2: a node-set
4599 * Implements the EXSLT - Sets has-same-nodes function:
4600 * boolean set:has-same-node(node-set, node-set)
4602 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4606 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4610 if (xmlXPathNodeSetIsEmpty(nodes1
) ||
4611 xmlXPathNodeSetIsEmpty(nodes2
))
4614 l
= xmlXPathNodeSetGetLength(nodes1
);
4615 for (i
= 0; i
< l
; i
++) {
4616 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4617 if (xmlXPathNodeSetContains(nodes2
, cur
))
4624 * xmlXPathNodeLeadingSorted:
4625 * @nodes: a node-set, sorted by document order
4628 * Implements the EXSLT - Sets leading() function:
4629 * node-set set:leading (node-set, node-set)
4631 * Returns the nodes in @nodes that precede @node in document order,
4632 * @nodes if @node is NULL or an empty node-set if @nodes
4633 * doesn't contain @node
4636 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4644 ret
= xmlXPathNodeSetCreate(NULL
);
4647 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4648 (!xmlXPathNodeSetContains(nodes
, node
)))
4651 l
= xmlXPathNodeSetGetLength(nodes
);
4652 for (i
= 0; i
< l
; i
++) {
4653 cur
= xmlXPathNodeSetItem(nodes
, i
);
4656 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4663 * xmlXPathNodeLeading:
4664 * @nodes: a node-set
4667 * Implements the EXSLT - Sets leading() function:
4668 * node-set set:leading (node-set, node-set)
4669 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4672 * Returns the nodes in @nodes that precede @node in document order,
4673 * @nodes if @node is NULL or an empty node-set if @nodes
4674 * doesn't contain @node
4677 xmlXPathNodeLeading (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4678 xmlXPathNodeSetSort(nodes
);
4679 return(xmlXPathNodeLeadingSorted(nodes
, node
));
4683 * xmlXPathLeadingSorted:
4684 * @nodes1: a node-set, sorted by document order
4685 * @nodes2: a node-set, sorted by document order
4687 * Implements the EXSLT - Sets leading() function:
4688 * node-set set:leading (node-set, node-set)
4690 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4691 * in document order, @nodes1 if @nodes2 is NULL or empty or
4692 * an empty node-set if @nodes1 doesn't contain @nodes2
4695 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4696 if (xmlXPathNodeSetIsEmpty(nodes2
))
4698 return(xmlXPathNodeLeadingSorted(nodes1
,
4699 xmlXPathNodeSetItem(nodes2
, 1)));
4704 * @nodes1: a node-set
4705 * @nodes2: a node-set
4707 * Implements the EXSLT - Sets leading() function:
4708 * node-set set:leading (node-set, node-set)
4709 * @nodes1 and @nodes2 are sorted by document order, then
4710 * #exslSetsLeadingSorted is called.
4712 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4713 * in document order, @nodes1 if @nodes2 is NULL or empty or
4714 * an empty node-set if @nodes1 doesn't contain @nodes2
4717 xmlXPathLeading (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4718 if (xmlXPathNodeSetIsEmpty(nodes2
))
4720 if (xmlXPathNodeSetIsEmpty(nodes1
))
4721 return(xmlXPathNodeSetCreate(NULL
));
4722 xmlXPathNodeSetSort(nodes1
);
4723 xmlXPathNodeSetSort(nodes2
);
4724 return(xmlXPathNodeLeadingSorted(nodes1
,
4725 xmlXPathNodeSetItem(nodes2
, 1)));
4729 * xmlXPathNodeTrailingSorted:
4730 * @nodes: a node-set, sorted by document order
4733 * Implements the EXSLT - Sets trailing() function:
4734 * node-set set:trailing (node-set, node-set)
4736 * Returns the nodes in @nodes that follow @node in document order,
4737 * @nodes if @node is NULL or an empty node-set if @nodes
4738 * doesn't contain @node
4741 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4749 ret
= xmlXPathNodeSetCreate(NULL
);
4752 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4753 (!xmlXPathNodeSetContains(nodes
, node
)))
4756 l
= xmlXPathNodeSetGetLength(nodes
);
4757 for (i
= l
- 1; i
>= 0; i
--) {
4758 cur
= xmlXPathNodeSetItem(nodes
, i
);
4761 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4764 xmlXPathNodeSetSort(ret
); /* bug 413451 */
4769 * xmlXPathNodeTrailing:
4770 * @nodes: a node-set
4773 * Implements the EXSLT - Sets trailing() function:
4774 * node-set set:trailing (node-set, node-set)
4775 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4778 * Returns the nodes in @nodes that follow @node in document order,
4779 * @nodes if @node is NULL or an empty node-set if @nodes
4780 * doesn't contain @node
4783 xmlXPathNodeTrailing (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4784 xmlXPathNodeSetSort(nodes
);
4785 return(xmlXPathNodeTrailingSorted(nodes
, node
));
4789 * xmlXPathTrailingSorted:
4790 * @nodes1: a node-set, sorted by document order
4791 * @nodes2: a node-set, sorted by document order
4793 * Implements the EXSLT - Sets trailing() function:
4794 * node-set set:trailing (node-set, node-set)
4796 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4797 * in document order, @nodes1 if @nodes2 is NULL or empty or
4798 * an empty node-set if @nodes1 doesn't contain @nodes2
4801 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4802 if (xmlXPathNodeSetIsEmpty(nodes2
))
4804 return(xmlXPathNodeTrailingSorted(nodes1
,
4805 xmlXPathNodeSetItem(nodes2
, 0)));
4810 * @nodes1: a node-set
4811 * @nodes2: a node-set
4813 * Implements the EXSLT - Sets trailing() function:
4814 * node-set set:trailing (node-set, node-set)
4815 * @nodes1 and @nodes2 are sorted by document order, then
4816 * #xmlXPathTrailingSorted is called.
4818 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4819 * in document order, @nodes1 if @nodes2 is NULL or empty or
4820 * an empty node-set if @nodes1 doesn't contain @nodes2
4823 xmlXPathTrailing (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4824 if (xmlXPathNodeSetIsEmpty(nodes2
))
4826 if (xmlXPathNodeSetIsEmpty(nodes1
))
4827 return(xmlXPathNodeSetCreate(NULL
));
4828 xmlXPathNodeSetSort(nodes1
);
4829 xmlXPathNodeSetSort(nodes2
);
4830 return(xmlXPathNodeTrailingSorted(nodes1
,
4831 xmlXPathNodeSetItem(nodes2
, 0)));
4834 /************************************************************************
4836 * Routines to handle extra functions *
4838 ************************************************************************/
4841 * xmlXPathRegisterFunc:
4842 * @ctxt: the XPath context
4843 * @name: the function name
4844 * @f: the function implementation or NULL
4846 * Register a new function. If @f is NULL it unregisters the function
4848 * Returns 0 in case of success, -1 in case of error
4851 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4852 xmlXPathFunction f
) {
4853 return(xmlXPathRegisterFuncNS(ctxt
, name
, NULL
, f
));
4857 * xmlXPathRegisterFuncNS:
4858 * @ctxt: the XPath context
4859 * @name: the function name
4860 * @ns_uri: the function namespace URI
4861 * @f: the function implementation or NULL
4863 * Register a new function. If @f is NULL it unregisters the function
4865 * Returns 0 in case of success, -1 in case of error
4868 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4869 const xmlChar
*ns_uri
, xmlXPathFunction f
) {
4875 if (ctxt
->funcHash
== NULL
)
4876 ctxt
->funcHash
= xmlHashCreate(0);
4877 if (ctxt
->funcHash
== NULL
)
4880 return(xmlHashRemoveEntry2(ctxt
->funcHash
, name
, ns_uri
, NULL
));
4881 XML_IGNORE_PEDANTIC_WARNINGS
4882 return(xmlHashAddEntry2(ctxt
->funcHash
, name
, ns_uri
, (void *) f
));
4887 * xmlXPathRegisterFuncLookup:
4888 * @ctxt: the XPath context
4889 * @f: the lookup function
4890 * @funcCtxt: the lookup data
4892 * Registers an external mechanism to do function lookup.
4895 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt
,
4896 xmlXPathFuncLookupFunc f
,
4900 ctxt
->funcLookupFunc
= f
;
4901 ctxt
->funcLookupData
= funcCtxt
;
4905 * xmlXPathFunctionLookup:
4906 * @ctxt: the XPath context
4907 * @name: the function name
4909 * Search in the Function array of the context for the given
4912 * Returns the xmlXPathFunction or NULL if not found
4915 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
4919 if (ctxt
->funcLookupFunc
!= NULL
) {
4920 xmlXPathFunction ret
;
4921 xmlXPathFuncLookupFunc f
;
4923 f
= ctxt
->funcLookupFunc
;
4924 ret
= f(ctxt
->funcLookupData
, name
, NULL
);
4928 return(xmlXPathFunctionLookupNS(ctxt
, name
, NULL
));
4932 * xmlXPathFunctionLookupNS:
4933 * @ctxt: the XPath context
4934 * @name: the function name
4935 * @ns_uri: the function namespace URI
4937 * Search in the Function array of the context for the given
4940 * Returns the xmlXPathFunction or NULL if not found
4943 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4944 const xmlChar
*ns_uri
) {
4945 xmlXPathFunction ret
;
4952 if (ctxt
->funcLookupFunc
!= NULL
) {
4953 xmlXPathFuncLookupFunc f
;
4955 f
= ctxt
->funcLookupFunc
;
4956 ret
= f(ctxt
->funcLookupData
, name
, ns_uri
);
4961 if (ctxt
->funcHash
== NULL
)
4964 XML_IGNORE_PEDANTIC_WARNINGS
4965 ret
= (xmlXPathFunction
) xmlHashLookup2(ctxt
->funcHash
, name
, ns_uri
);
4971 * xmlXPathRegisteredFuncsCleanup:
4972 * @ctxt: the XPath context
4974 * Cleanup the XPath context data associated to registered functions
4977 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt
) {
4981 xmlHashFree(ctxt
->funcHash
, NULL
);
4982 ctxt
->funcHash
= NULL
;
4985 /************************************************************************
4987 * Routines to handle Variables *
4989 ************************************************************************/
4992 * xmlXPathRegisterVariable:
4993 * @ctxt: the XPath context
4994 * @name: the variable name
4995 * @value: the variable value or NULL
4997 * Register a new variable value. If @value is NULL it unregisters
5000 * Returns 0 in case of success, -1 in case of error
5003 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5004 xmlXPathObjectPtr value
) {
5005 return(xmlXPathRegisterVariableNS(ctxt
, name
, NULL
, value
));
5009 * xmlXPathRegisterVariableNS:
5010 * @ctxt: the XPath context
5011 * @name: the variable name
5012 * @ns_uri: the variable namespace URI
5013 * @value: the variable value or NULL
5015 * Register a new variable value. If @value is NULL it unregisters
5018 * Returns 0 in case of success, -1 in case of error
5021 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5022 const xmlChar
*ns_uri
,
5023 xmlXPathObjectPtr value
) {
5029 if (ctxt
->varHash
== NULL
)
5030 ctxt
->varHash
= xmlHashCreate(0);
5031 if (ctxt
->varHash
== NULL
)
5034 return(xmlHashRemoveEntry2(ctxt
->varHash
, name
, ns_uri
,
5035 xmlXPathFreeObjectEntry
));
5036 return(xmlHashUpdateEntry2(ctxt
->varHash
, name
, ns_uri
,
5037 (void *) value
, xmlXPathFreeObjectEntry
));
5041 * xmlXPathRegisterVariableLookup:
5042 * @ctxt: the XPath context
5043 * @f: the lookup function
5044 * @data: the lookup data
5046 * register an external mechanism to do variable lookup
5049 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt
,
5050 xmlXPathVariableLookupFunc f
, void *data
) {
5053 ctxt
->varLookupFunc
= f
;
5054 ctxt
->varLookupData
= data
;
5058 * xmlXPathVariableLookup:
5059 * @ctxt: the XPath context
5060 * @name: the variable name
5062 * Search in the Variable array of the context for the given
5065 * Returns a copy of the value or NULL if not found
5068 xmlXPathVariableLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
5072 if (ctxt
->varLookupFunc
!= NULL
) {
5073 xmlXPathObjectPtr ret
;
5075 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5076 (ctxt
->varLookupData
, name
, NULL
);
5079 return(xmlXPathVariableLookupNS(ctxt
, name
, NULL
));
5083 * xmlXPathVariableLookupNS:
5084 * @ctxt: the XPath context
5085 * @name: the variable name
5086 * @ns_uri: the variable namespace URI
5088 * Search in the Variable array of the context for the given
5091 * Returns the a copy of the value or NULL if not found
5094 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5095 const xmlChar
*ns_uri
) {
5099 if (ctxt
->varLookupFunc
!= NULL
) {
5100 xmlXPathObjectPtr ret
;
5102 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5103 (ctxt
->varLookupData
, name
, ns_uri
);
5104 if (ret
!= NULL
) return(ret
);
5107 if (ctxt
->varHash
== NULL
)
5112 return(xmlXPathCacheObjectCopy(ctxt
, (xmlXPathObjectPtr
)
5113 xmlHashLookup2(ctxt
->varHash
, name
, ns_uri
)));
5117 * xmlXPathRegisteredVariablesCleanup:
5118 * @ctxt: the XPath context
5120 * Cleanup the XPath context data associated to registered variables
5123 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt
) {
5127 xmlHashFree(ctxt
->varHash
, xmlXPathFreeObjectEntry
);
5128 ctxt
->varHash
= NULL
;
5132 * xmlXPathRegisterNs:
5133 * @ctxt: the XPath context
5134 * @prefix: the namespace prefix cannot be NULL or empty string
5135 * @ns_uri: the namespace name
5137 * Register a new namespace. If @ns_uri is NULL it unregisters
5140 * Returns 0 in case of success, -1 in case of error
5143 xmlXPathRegisterNs(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
,
5144 const xmlChar
*ns_uri
) {
5152 if (ctxt
->nsHash
== NULL
)
5153 ctxt
->nsHash
= xmlHashCreate(10);
5154 if (ctxt
->nsHash
== NULL
)
5157 return(xmlHashRemoveEntry(ctxt
->nsHash
, prefix
,
5158 xmlHashDefaultDeallocator
));
5159 return(xmlHashUpdateEntry(ctxt
->nsHash
, prefix
, (void *) xmlStrdup(ns_uri
),
5160 xmlHashDefaultDeallocator
));
5165 * @ctxt: the XPath context
5166 * @prefix: the namespace prefix value
5168 * Search in the namespace declaration array of the context for the given
5169 * namespace name associated to the given prefix
5171 * Returns the value or NULL if not found
5174 xmlXPathNsLookup(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
) {
5180 #ifdef XML_XML_NAMESPACE
5181 if (xmlStrEqual(prefix
, (const xmlChar
*) "xml"))
5182 return(XML_XML_NAMESPACE
);
5185 if (ctxt
->namespaces
!= NULL
) {
5188 for (i
= 0;i
< ctxt
->nsNr
;i
++) {
5189 if ((ctxt
->namespaces
[i
] != NULL
) &&
5190 (xmlStrEqual(ctxt
->namespaces
[i
]->prefix
, prefix
)))
5191 return(ctxt
->namespaces
[i
]->href
);
5195 return((const xmlChar
*) xmlHashLookup(ctxt
->nsHash
, prefix
));
5199 * xmlXPathRegisteredNsCleanup:
5200 * @ctxt: the XPath context
5202 * Cleanup the XPath context data associated to registered variables
5205 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt
) {
5209 xmlHashFree(ctxt
->nsHash
, xmlHashDefaultDeallocator
);
5210 ctxt
->nsHash
= NULL
;
5213 /************************************************************************
5215 * Routines to handle Values *
5217 ************************************************************************/
5219 /* Allocations are terrible, one needs to optimize all this !!! */
5223 * @val: the double value
5225 * Create a new xmlXPathObjectPtr of type double and of value @val
5227 * Returns the newly created object.
5230 xmlXPathNewFloat(double val
) {
5231 xmlXPathObjectPtr ret
;
5233 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5235 xmlXPathErrMemory(NULL
, "creating float object\n");
5238 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5239 ret
->type
= XPATH_NUMBER
;
5240 ret
->floatval
= val
;
5241 #ifdef XP_DEBUG_OBJ_USAGE
5242 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NUMBER
);
5248 * xmlXPathNewBoolean:
5249 * @val: the boolean value
5251 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5253 * Returns the newly created object.
5256 xmlXPathNewBoolean(int val
) {
5257 xmlXPathObjectPtr ret
;
5259 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5261 xmlXPathErrMemory(NULL
, "creating boolean object\n");
5264 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5265 ret
->type
= XPATH_BOOLEAN
;
5266 ret
->boolval
= (val
!= 0);
5267 #ifdef XP_DEBUG_OBJ_USAGE
5268 xmlXPathDebugObjUsageRequested(NULL
, XPATH_BOOLEAN
);
5274 * xmlXPathNewString:
5275 * @val: the xmlChar * value
5277 * Create a new xmlXPathObjectPtr of type string and of value @val
5279 * Returns the newly created object.
5282 xmlXPathNewString(const xmlChar
*val
) {
5283 xmlXPathObjectPtr ret
;
5285 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5287 xmlXPathErrMemory(NULL
, "creating string object\n");
5290 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5291 ret
->type
= XPATH_STRING
;
5293 ret
->stringval
= xmlStrdup(val
);
5295 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
5296 #ifdef XP_DEBUG_OBJ_USAGE
5297 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5303 * xmlXPathWrapString:
5304 * @val: the xmlChar * value
5306 * Wraps the @val string into an XPath object.
5308 * Returns the newly created object.
5311 xmlXPathWrapString (xmlChar
*val
) {
5312 xmlXPathObjectPtr ret
;
5314 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5316 xmlXPathErrMemory(NULL
, "creating string object\n");
5319 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5320 ret
->type
= XPATH_STRING
;
5321 ret
->stringval
= val
;
5322 #ifdef XP_DEBUG_OBJ_USAGE
5323 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5329 * xmlXPathNewCString:
5330 * @val: the char * value
5332 * Create a new xmlXPathObjectPtr of type string and of value @val
5334 * Returns the newly created object.
5337 xmlXPathNewCString(const char *val
) {
5338 xmlXPathObjectPtr ret
;
5340 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5342 xmlXPathErrMemory(NULL
, "creating string object\n");
5345 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5346 ret
->type
= XPATH_STRING
;
5347 ret
->stringval
= xmlStrdup(BAD_CAST val
);
5348 #ifdef XP_DEBUG_OBJ_USAGE
5349 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5355 * xmlXPathWrapCString:
5356 * @val: the char * value
5358 * Wraps a string into an XPath object.
5360 * Returns the newly created object.
5363 xmlXPathWrapCString (char * val
) {
5364 return(xmlXPathWrapString((xmlChar
*)(val
)));
5368 * xmlXPathWrapExternal:
5369 * @val: the user data
5371 * Wraps the @val data into an XPath object.
5373 * Returns the newly created object.
5376 xmlXPathWrapExternal (void *val
) {
5377 xmlXPathObjectPtr ret
;
5379 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5381 xmlXPathErrMemory(NULL
, "creating user object\n");
5384 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5385 ret
->type
= XPATH_USERS
;
5387 #ifdef XP_DEBUG_OBJ_USAGE
5388 xmlXPathDebugObjUsageRequested(NULL
, XPATH_USERS
);
5394 * xmlXPathObjectCopy:
5395 * @val: the original object
5397 * allocate a new copy of a given object
5399 * Returns the newly created object.
5402 xmlXPathObjectCopy(xmlXPathObjectPtr val
) {
5403 xmlXPathObjectPtr ret
;
5408 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5410 xmlXPathErrMemory(NULL
, "copying object\n");
5413 memcpy(ret
, val
, (size_t) sizeof(xmlXPathObject
));
5414 #ifdef XP_DEBUG_OBJ_USAGE
5415 xmlXPathDebugObjUsageRequested(NULL
, val
->type
);
5417 switch (val
->type
) {
5424 ret
->stringval
= xmlStrdup(val
->stringval
);
5426 case XPATH_XSLT_TREE
:
5429 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5430 this previous handling is no longer correct, and can cause some serious
5431 problems (ref. bug 145547)
5433 if ((val
->nodesetval
!= NULL
) &&
5434 (val
->nodesetval
->nodeTab
!= NULL
)) {
5435 xmlNodePtr cur
, tmp
;
5439 top
= xmlNewDoc(NULL
);
5440 top
->name
= (char *)
5441 xmlStrdup(val
->nodesetval
->nodeTab
[0]->name
);
5445 cur
= val
->nodesetval
->nodeTab
[0]->children
;
5446 while (cur
!= NULL
) {
5447 tmp
= xmlDocCopyNode(cur
, top
, 1);
5448 xmlAddChild((xmlNodePtr
) top
, tmp
);
5453 ret
->nodesetval
= xmlXPathNodeSetCreate((xmlNodePtr
) top
);
5455 ret
->nodesetval
= xmlXPathNodeSetCreate(NULL
);
5456 /* Deallocate the copied tree value */
5460 ret
->nodesetval
= xmlXPathNodeSetMerge(NULL
, val
->nodesetval
);
5461 /* Do not deallocate the copied tree value */
5464 case XPATH_LOCATIONSET
:
5465 #ifdef LIBXML_XPTR_ENABLED
5467 xmlLocationSetPtr loc
= val
->user
;
5468 ret
->user
= (void *) xmlXPtrLocationSetMerge(NULL
, loc
);
5473 ret
->user
= val
->user
;
5475 case XPATH_UNDEFINED
:
5476 xmlGenericError(xmlGenericErrorContext
,
5477 "xmlXPathObjectCopy: unsupported type %d\n",
5485 * xmlXPathFreeObject:
5486 * @obj: the object to free
5488 * Free up an xmlXPathObjectPtr object.
5491 xmlXPathFreeObject(xmlXPathObjectPtr obj
) {
5492 if (obj
== NULL
) return;
5493 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
5496 if (obj
->user
!= NULL
) {
5497 xmlXPathFreeNodeSet(obj
->nodesetval
);
5498 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
5501 obj
->type
= XPATH_XSLT_TREE
; /* TODO: Just for debugging. */
5502 if (obj
->nodesetval
!= NULL
)
5503 xmlXPathFreeValueTree(obj
->nodesetval
);
5505 if (obj
->nodesetval
!= NULL
)
5506 xmlXPathFreeNodeSet(obj
->nodesetval
);
5508 #ifdef LIBXML_XPTR_ENABLED
5509 } else if (obj
->type
== XPATH_LOCATIONSET
) {
5510 if (obj
->user
!= NULL
)
5511 xmlXPtrFreeLocationSet(obj
->user
);
5513 } else if (obj
->type
== XPATH_STRING
) {
5514 if (obj
->stringval
!= NULL
)
5515 xmlFree(obj
->stringval
);
5517 #ifdef XP_DEBUG_OBJ_USAGE
5518 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5524 xmlXPathFreeObjectEntry(void *obj
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
5525 xmlXPathFreeObject((xmlXPathObjectPtr
) obj
);
5529 * xmlXPathReleaseObject:
5530 * @obj: the xmlXPathObjectPtr to free or to cache
5532 * Depending on the state of the cache this frees the given
5533 * XPath object or stores it in the cache.
5536 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
)
5538 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5539 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5540 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5542 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5546 if ((ctxt
== NULL
) || (ctxt
->cache
== NULL
)) {
5547 xmlXPathFreeObject(obj
);
5549 xmlXPathContextCachePtr cache
=
5550 (xmlXPathContextCachePtr
) ctxt
->cache
;
5552 switch (obj
->type
) {
5554 case XPATH_XSLT_TREE
:
5555 if (obj
->nodesetval
!= NULL
) {
5558 * It looks like the @boolval is used for
5559 * evaluation if this an XSLT Result Tree Fragment.
5560 * TODO: Check if this assumption is correct.
5562 obj
->type
= XPATH_XSLT_TREE
; /* just for debugging */
5563 xmlXPathFreeValueTree(obj
->nodesetval
);
5564 obj
->nodesetval
= NULL
;
5565 } else if ((obj
->nodesetval
->nodeMax
<= 40) &&
5566 (XP_CACHE_WANTS(cache
->nodesetObjs
,
5567 cache
->maxNodeset
)))
5569 XP_CACHE_ADD(cache
->nodesetObjs
, obj
);
5572 xmlXPathFreeNodeSet(obj
->nodesetval
);
5573 obj
->nodesetval
= NULL
;
5578 if (obj
->stringval
!= NULL
)
5579 xmlFree(obj
->stringval
);
5581 if (XP_CACHE_WANTS(cache
->stringObjs
, cache
->maxString
)) {
5582 XP_CACHE_ADD(cache
->stringObjs
, obj
);
5587 if (XP_CACHE_WANTS(cache
->booleanObjs
, cache
->maxBoolean
)) {
5588 XP_CACHE_ADD(cache
->booleanObjs
, obj
);
5593 if (XP_CACHE_WANTS(cache
->numberObjs
, cache
->maxNumber
)) {
5594 XP_CACHE_ADD(cache
->numberObjs
, obj
);
5598 #ifdef LIBXML_XPTR_ENABLED
5599 case XPATH_LOCATIONSET
:
5600 if (obj
->user
!= NULL
) {
5601 xmlXPtrFreeLocationSet(obj
->user
);
5610 * Fallback to adding to the misc-objects slot.
5612 if (XP_CACHE_WANTS(cache
->miscObjs
, cache
->maxMisc
)) {
5613 XP_CACHE_ADD(cache
->miscObjs
, obj
);
5619 #ifdef XP_DEBUG_OBJ_USAGE
5620 xmlXPathDebugObjUsageReleased(ctxt
, obj
->type
);
5623 if (obj
->nodesetval
!= NULL
) {
5624 xmlNodeSetPtr tmpset
= obj
->nodesetval
;
5627 * TODO: Due to those nasty ns-nodes, we need to traverse
5628 * the list and free the ns-nodes.
5629 * URGENT TODO: Check if it's actually slowing things down.
5630 * Maybe we shouldn't try to preserve the list.
5632 if (tmpset
->nodeNr
> 1) {
5636 for (i
= 0; i
< tmpset
->nodeNr
; i
++) {
5637 node
= tmpset
->nodeTab
[i
];
5638 if ((node
!= NULL
) &&
5639 (node
->type
== XML_NAMESPACE_DECL
))
5641 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
5644 } else if (tmpset
->nodeNr
== 1) {
5645 if ((tmpset
->nodeTab
[0] != NULL
) &&
5646 (tmpset
->nodeTab
[0]->type
== XML_NAMESPACE_DECL
))
5647 xmlXPathNodeSetFreeNs((xmlNsPtr
) tmpset
->nodeTab
[0]);
5650 memset(obj
, 0, sizeof(xmlXPathObject
));
5651 obj
->nodesetval
= tmpset
;
5653 memset(obj
, 0, sizeof(xmlXPathObject
));
5659 * Cache is full; free the object.
5661 if (obj
->nodesetval
!= NULL
)
5662 xmlXPathFreeNodeSet(obj
->nodesetval
);
5663 #ifdef XP_DEBUG_OBJ_USAGE
5664 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5672 /************************************************************************
5674 * Type Casting Routines *
5676 ************************************************************************/
5679 * xmlXPathCastBooleanToString:
5682 * Converts a boolean to its string value.
5684 * Returns a newly allocated string.
5687 xmlXPathCastBooleanToString (int val
) {
5690 ret
= xmlStrdup((const xmlChar
*) "true");
5692 ret
= xmlStrdup((const xmlChar
*) "false");
5697 * xmlXPathCastNumberToString:
5700 * Converts a number to its string value.
5702 * Returns a newly allocated string.
5705 xmlXPathCastNumberToString (double val
) {
5707 switch (xmlXPathIsInf(val
)) {
5709 ret
= xmlStrdup((const xmlChar
*) "Infinity");
5712 ret
= xmlStrdup((const xmlChar
*) "-Infinity");
5715 if (xmlXPathIsNaN(val
)) {
5716 ret
= xmlStrdup((const xmlChar
*) "NaN");
5717 } else if (val
== 0) {
5718 /* Omit sign for negative zero. */
5719 ret
= xmlStrdup((const xmlChar
*) "0");
5721 /* could be improved */
5723 xmlXPathFormatNumber(val
, buf
, 99);
5725 ret
= xmlStrdup((const xmlChar
*) buf
);
5732 * xmlXPathCastNodeToString:
5735 * Converts a node to its string value.
5737 * Returns a newly allocated string.
5740 xmlXPathCastNodeToString (xmlNodePtr node
) {
5742 if ((ret
= xmlNodeGetContent(node
)) == NULL
)
5743 ret
= xmlStrdup((const xmlChar
*) "");
5748 * xmlXPathCastNodeSetToString:
5751 * Converts a node-set to its string value.
5753 * Returns a newly allocated string.
5756 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns
) {
5757 if ((ns
== NULL
) || (ns
->nodeNr
== 0) || (ns
->nodeTab
== NULL
))
5758 return(xmlStrdup((const xmlChar
*) ""));
5761 xmlXPathNodeSetSort(ns
);
5762 return(xmlXPathCastNodeToString(ns
->nodeTab
[0]));
5766 * xmlXPathCastToString:
5767 * @val: an XPath object
5769 * Converts an existing object to its string() equivalent
5771 * Returns the allocated string value of the object, NULL in case of error.
5772 * It's up to the caller to free the string memory with xmlFree().
5775 xmlXPathCastToString(xmlXPathObjectPtr val
) {
5776 xmlChar
*ret
= NULL
;
5779 return(xmlStrdup((const xmlChar
*) ""));
5780 switch (val
->type
) {
5781 case XPATH_UNDEFINED
:
5783 xmlGenericError(xmlGenericErrorContext
, "String: undefined\n");
5785 ret
= xmlStrdup((const xmlChar
*) "");
5788 case XPATH_XSLT_TREE
:
5789 ret
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5792 return(xmlStrdup(val
->stringval
));
5794 ret
= xmlXPathCastBooleanToString(val
->boolval
);
5796 case XPATH_NUMBER
: {
5797 ret
= xmlXPathCastNumberToString(val
->floatval
);
5803 case XPATH_LOCATIONSET
:
5805 ret
= xmlStrdup((const xmlChar
*) "");
5812 * xmlXPathConvertString:
5813 * @val: an XPath object
5815 * Converts an existing object to its string() equivalent
5817 * Returns the new object, the old one is freed (or the operation
5818 * is done directly on @val)
5821 xmlXPathConvertString(xmlXPathObjectPtr val
) {
5822 xmlChar
*res
= NULL
;
5825 return(xmlXPathNewCString(""));
5827 switch (val
->type
) {
5828 case XPATH_UNDEFINED
:
5830 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
5834 case XPATH_XSLT_TREE
:
5835 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5840 res
= xmlXPathCastBooleanToString(val
->boolval
);
5843 res
= xmlXPathCastNumberToString(val
->floatval
);
5848 case XPATH_LOCATIONSET
:
5852 xmlXPathFreeObject(val
);
5854 return(xmlXPathNewCString(""));
5855 return(xmlXPathWrapString(res
));
5859 * xmlXPathCastBooleanToNumber:
5862 * Converts a boolean to its number value
5864 * Returns the number value
5867 xmlXPathCastBooleanToNumber(int val
) {
5874 * xmlXPathCastStringToNumber:
5877 * Converts a string to its number value
5879 * Returns the number value
5882 xmlXPathCastStringToNumber(const xmlChar
* val
) {
5883 return(xmlXPathStringEvalNumber(val
));
5887 * xmlXPathCastNodeToNumber:
5890 * Converts a node to its number value
5892 * Returns the number value
5895 xmlXPathCastNodeToNumber (xmlNodePtr node
) {
5901 strval
= xmlXPathCastNodeToString(node
);
5904 ret
= xmlXPathCastStringToNumber(strval
);
5911 * xmlXPathCastNodeSetToNumber:
5914 * Converts a node-set to its number value
5916 * Returns the number value
5919 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns
) {
5925 str
= xmlXPathCastNodeSetToString(ns
);
5926 ret
= xmlXPathCastStringToNumber(str
);
5932 * xmlXPathCastToNumber:
5933 * @val: an XPath object
5935 * Converts an XPath object to its number value
5937 * Returns the number value
5940 xmlXPathCastToNumber(xmlXPathObjectPtr val
) {
5945 switch (val
->type
) {
5946 case XPATH_UNDEFINED
:
5948 xmlGenericError(xmlGenericErrorContext
, "NUMBER: undefined\n");
5953 case XPATH_XSLT_TREE
:
5954 ret
= xmlXPathCastNodeSetToNumber(val
->nodesetval
);
5957 ret
= xmlXPathCastStringToNumber(val
->stringval
);
5960 ret
= val
->floatval
;
5963 ret
= xmlXPathCastBooleanToNumber(val
->boolval
);
5968 case XPATH_LOCATIONSET
:
5977 * xmlXPathConvertNumber:
5978 * @val: an XPath object
5980 * Converts an existing object to its number() equivalent
5982 * Returns the new object, the old one is freed (or the operation
5983 * is done directly on @val)
5986 xmlXPathConvertNumber(xmlXPathObjectPtr val
) {
5987 xmlXPathObjectPtr ret
;
5990 return(xmlXPathNewFloat(0.0));
5991 if (val
->type
== XPATH_NUMBER
)
5993 ret
= xmlXPathNewFloat(xmlXPathCastToNumber(val
));
5994 xmlXPathFreeObject(val
);
5999 * xmlXPathCastNumberToBoolean:
6002 * Converts a number to its boolean value
6004 * Returns the boolean value
6007 xmlXPathCastNumberToBoolean (double val
) {
6008 if (xmlXPathIsNaN(val
) || (val
== 0.0))
6014 * xmlXPathCastStringToBoolean:
6017 * Converts a string to its boolean value
6019 * Returns the boolean value
6022 xmlXPathCastStringToBoolean (const xmlChar
*val
) {
6023 if ((val
== NULL
) || (xmlStrlen(val
) == 0))
6029 * xmlXPathCastNodeSetToBoolean:
6032 * Converts a node-set to its boolean value
6034 * Returns the boolean value
6037 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns
) {
6038 if ((ns
== NULL
) || (ns
->nodeNr
== 0))
6044 * xmlXPathCastToBoolean:
6045 * @val: an XPath object
6047 * Converts an XPath object to its boolean value
6049 * Returns the boolean value
6052 xmlXPathCastToBoolean (xmlXPathObjectPtr val
) {
6057 switch (val
->type
) {
6058 case XPATH_UNDEFINED
:
6060 xmlGenericError(xmlGenericErrorContext
, "BOOLEAN: undefined\n");
6065 case XPATH_XSLT_TREE
:
6066 ret
= xmlXPathCastNodeSetToBoolean(val
->nodesetval
);
6069 ret
= xmlXPathCastStringToBoolean(val
->stringval
);
6072 ret
= xmlXPathCastNumberToBoolean(val
->floatval
);
6080 case XPATH_LOCATIONSET
:
6090 * xmlXPathConvertBoolean:
6091 * @val: an XPath object
6093 * Converts an existing object to its boolean() equivalent
6095 * Returns the new object, the old one is freed (or the operation
6096 * is done directly on @val)
6099 xmlXPathConvertBoolean(xmlXPathObjectPtr val
) {
6100 xmlXPathObjectPtr ret
;
6103 return(xmlXPathNewBoolean(0));
6104 if (val
->type
== XPATH_BOOLEAN
)
6106 ret
= xmlXPathNewBoolean(xmlXPathCastToBoolean(val
));
6107 xmlXPathFreeObject(val
);
6111 /************************************************************************
6113 * Routines to handle XPath contexts *
6115 ************************************************************************/
6118 * xmlXPathNewContext:
6119 * @doc: the XML document
6121 * Create a new xmlXPathContext
6123 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6126 xmlXPathNewContext(xmlDocPtr doc
) {
6127 xmlXPathContextPtr ret
;
6129 ret
= (xmlXPathContextPtr
) xmlMalloc(sizeof(xmlXPathContext
));
6131 xmlXPathErrMemory(NULL
, "creating context\n");
6134 memset(ret
, 0 , (size_t) sizeof(xmlXPathContext
));
6138 ret
->varHash
= NULL
;
6144 ret
->funcHash
= xmlHashCreate(0);
6153 ret
->contextSize
= -1;
6154 ret
->proximityPosition
= -1;
6156 #ifdef XP_DEFAULT_CACHE_ON
6157 if (xmlXPathContextSetCache(ret
, 1, -1, 0) == -1) {
6158 xmlXPathFreeContext(ret
);
6163 xmlXPathRegisterAllFunctions(ret
);
6169 * xmlXPathFreeContext:
6170 * @ctxt: the context to free
6172 * Free up an xmlXPathContext
6175 xmlXPathFreeContext(xmlXPathContextPtr ctxt
) {
6176 if (ctxt
== NULL
) return;
6178 if (ctxt
->cache
!= NULL
)
6179 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
6180 xmlXPathRegisteredNsCleanup(ctxt
);
6181 xmlXPathRegisteredFuncsCleanup(ctxt
);
6182 xmlXPathRegisteredVariablesCleanup(ctxt
);
6183 xmlResetError(&ctxt
->lastError
);
6187 /************************************************************************
6189 * Routines to handle XPath parser contexts *
6191 ************************************************************************/
6193 #define CHECK_CTXT(ctxt) \
6194 if (ctxt == NULL) { \
6195 __xmlRaiseError(NULL, NULL, NULL, \
6196 NULL, NULL, XML_FROM_XPATH, \
6197 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6198 __FILE__, __LINE__, \
6199 NULL, NULL, NULL, 0, 0, \
6200 "NULL context pointer\n"); \
6204 #define CHECK_CTXT_NEG(ctxt) \
6205 if (ctxt == NULL) { \
6206 __xmlRaiseError(NULL, NULL, NULL, \
6207 NULL, NULL, XML_FROM_XPATH, \
6208 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6209 __FILE__, __LINE__, \
6210 NULL, NULL, NULL, 0, 0, \
6211 "NULL context pointer\n"); \
6216 #define CHECK_CONTEXT(ctxt) \
6217 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6218 (ctxt->doc->children == NULL)) { \
6219 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6225 * xmlXPathNewParserContext:
6226 * @str: the XPath expression
6227 * @ctxt: the XPath context
6229 * Create a new xmlXPathParserContext
6231 * Returns the xmlXPathParserContext just allocated.
6233 xmlXPathParserContextPtr
6234 xmlXPathNewParserContext(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
6235 xmlXPathParserContextPtr ret
;
6237 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6239 xmlXPathErrMemory(ctxt
, "creating parser context\n");
6242 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6243 ret
->cur
= ret
->base
= str
;
6244 ret
->context
= ctxt
;
6246 ret
->comp
= xmlXPathNewCompExpr();
6247 if (ret
->comp
== NULL
) {
6248 xmlFree(ret
->valueTab
);
6252 if ((ctxt
!= NULL
) && (ctxt
->dict
!= NULL
)) {
6253 ret
->comp
->dict
= ctxt
->dict
;
6254 xmlDictReference(ret
->comp
->dict
);
6261 * xmlXPathCompParserContext:
6262 * @comp: the XPath compiled expression
6263 * @ctxt: the XPath context
6265 * Create a new xmlXPathParserContext when processing a compiled expression
6267 * Returns the xmlXPathParserContext just allocated.
6269 static xmlXPathParserContextPtr
6270 xmlXPathCompParserContext(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctxt
) {
6271 xmlXPathParserContextPtr ret
;
6273 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6275 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6278 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6280 /* Allocate the value stack */
6281 ret
->valueTab
= (xmlXPathObjectPtr
*)
6282 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
6283 if (ret
->valueTab
== NULL
) {
6285 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6291 ret
->valueFrame
= 0;
6293 ret
->context
= ctxt
;
6300 * xmlXPathFreeParserContext:
6301 * @ctxt: the context to free
6303 * Free up an xmlXPathParserContext
6306 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt
) {
6309 if (ctxt
->valueTab
!= NULL
) {
6310 for (i
= 0; i
< ctxt
->valueNr
; i
++) {
6312 xmlXPathReleaseObject(ctxt
->context
, ctxt
->valueTab
[i
]);
6314 xmlXPathFreeObject(ctxt
->valueTab
[i
]);
6316 xmlFree(ctxt
->valueTab
);
6318 if (ctxt
->comp
!= NULL
) {
6319 #ifdef XPATH_STREAMING
6320 if (ctxt
->comp
->stream
!= NULL
) {
6321 xmlFreePatternList(ctxt
->comp
->stream
);
6322 ctxt
->comp
->stream
= NULL
;
6325 xmlXPathFreeCompExpr(ctxt
->comp
);
6330 /************************************************************************
6332 * The implicit core function library *
6334 ************************************************************************/
6337 * xmlXPathNodeValHash:
6338 * @node: a node pointer
6340 * Function computing the beginning of the string value of the node,
6341 * used to speed up comparisons
6343 * Returns an int usable as a hash
6346 xmlXPathNodeValHash(xmlNodePtr node
) {
6348 const xmlChar
* string
= NULL
;
6349 xmlNodePtr tmp
= NULL
;
6350 unsigned int ret
= 0;
6355 if (node
->type
== XML_DOCUMENT_NODE
) {
6356 tmp
= xmlDocGetRootElement((xmlDocPtr
) node
);
6358 node
= node
->children
;
6366 switch (node
->type
) {
6367 case XML_COMMENT_NODE
:
6369 case XML_CDATA_SECTION_NODE
:
6371 string
= node
->content
;
6376 return(((unsigned int) string
[0]) +
6377 (((unsigned int) string
[1]) << 8));
6378 case XML_NAMESPACE_DECL
:
6379 string
= ((xmlNsPtr
)node
)->href
;
6384 return(((unsigned int) string
[0]) +
6385 (((unsigned int) string
[1]) << 8));
6386 case XML_ATTRIBUTE_NODE
:
6387 tmp
= ((xmlAttrPtr
) node
)->children
;
6389 case XML_ELEMENT_NODE
:
6390 tmp
= node
->children
;
6395 while (tmp
!= NULL
) {
6396 switch (tmp
->type
) {
6397 case XML_CDATA_SECTION_NODE
:
6399 string
= tmp
->content
;
6405 if ((string
!= NULL
) && (string
[0] != 0)) {
6407 return(ret
+ (((unsigned int) string
[0]) << 8));
6409 if (string
[1] == 0) {
6411 ret
= (unsigned int) string
[0];
6413 return(((unsigned int) string
[0]) +
6414 (((unsigned int) string
[1]) << 8));
6420 if ((tmp
->children
!= NULL
) && (tmp
->type
!= XML_DTD_NODE
)) {
6421 if (tmp
->children
->type
!= XML_ENTITY_DECL
) {
6422 tmp
= tmp
->children
;
6429 if (tmp
->next
!= NULL
) {
6442 if (tmp
->next
!= NULL
) {
6446 } while (tmp
!= NULL
);
6452 * xmlXPathStringHash:
6455 * Function computing the beginning of the string value of the node,
6456 * used to speed up comparisons
6458 * Returns an int usable as a hash
6461 xmlXPathStringHash(const xmlChar
* string
) {
6463 return((unsigned int) 0);
6466 return(((unsigned int) string
[0]) +
6467 (((unsigned int) string
[1]) << 8));
6471 * xmlXPathCompareNodeSetFloat:
6472 * @ctxt: the XPath Parser context
6473 * @inf: less than (1) or greater than (0)
6474 * @strict: is the comparison strict
6475 * @arg: the node set
6478 * Implement the compare operation between a nodeset and a number
6479 * @ns < @val (1, 1, ...
6480 * @ns <= @val (1, 0, ...
6481 * @ns > @val (0, 1, ...
6482 * @ns >= @val (0, 0, ...
6484 * If one object to be compared is a node-set and the other is a number,
6485 * then the comparison will be true if and only if there is a node in the
6486 * node-set such that the result of performing the comparison on the number
6487 * to be compared and on the result of converting the string-value of that
6488 * node to a number using the number function is true.
6490 * Returns 0 or 1 depending on the results of the test.
6493 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6494 xmlXPathObjectPtr arg
, xmlXPathObjectPtr f
) {
6499 if ((f
== NULL
) || (arg
== NULL
) ||
6500 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6501 xmlXPathReleaseObject(ctxt
->context
, arg
);
6502 xmlXPathReleaseObject(ctxt
->context
, f
);
6505 ns
= arg
->nodesetval
;
6507 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6508 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6511 xmlXPathCacheNewString(ctxt
->context
, str2
));
6513 xmlXPathNumberFunction(ctxt
, 1);
6514 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, f
));
6515 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6521 xmlXPathReleaseObject(ctxt
->context
, arg
);
6522 xmlXPathReleaseObject(ctxt
->context
, f
);
6527 * xmlXPathCompareNodeSetString:
6528 * @ctxt: the XPath Parser context
6529 * @inf: less than (1) or greater than (0)
6530 * @strict: is the comparison strict
6531 * @arg: the node set
6534 * Implement the compare operation between a nodeset and a string
6535 * @ns < @val (1, 1, ...
6536 * @ns <= @val (1, 0, ...
6537 * @ns > @val (0, 1, ...
6538 * @ns >= @val (0, 0, ...
6540 * If one object to be compared is a node-set and the other is a string,
6541 * then the comparison will be true if and only if there is a node in
6542 * the node-set such that the result of performing the comparison on the
6543 * string-value of the node and the other string is true.
6545 * Returns 0 or 1 depending on the results of the test.
6548 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6549 xmlXPathObjectPtr arg
, xmlXPathObjectPtr s
) {
6554 if ((s
== NULL
) || (arg
== NULL
) ||
6555 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6556 xmlXPathReleaseObject(ctxt
->context
, arg
);
6557 xmlXPathReleaseObject(ctxt
->context
, s
);
6560 ns
= arg
->nodesetval
;
6562 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6563 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6566 xmlXPathCacheNewString(ctxt
->context
, str2
));
6568 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, s
));
6569 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6575 xmlXPathReleaseObject(ctxt
->context
, arg
);
6576 xmlXPathReleaseObject(ctxt
->context
, s
);
6581 * xmlXPathCompareNodeSets:
6582 * @inf: less than (1) or greater than (0)
6583 * @strict: is the comparison strict
6584 * @arg1: the first node set object
6585 * @arg2: the second node set object
6587 * Implement the compare operation on nodesets:
6589 * If both objects to be compared are node-sets, then the comparison
6590 * will be true if and only if there is a node in the first node-set
6591 * and a node in the second node-set such that the result of performing
6592 * the comparison on the string-values of the two nodes is true.
6594 * When neither object to be compared is a node-set and the operator
6595 * is <=, <, >= or >, then the objects are compared by converting both
6596 * objects to numbers and comparing the numbers according to IEEE 754.
6598 * The number function converts its argument to a number as follows:
6599 * - a string that consists of optional whitespace followed by an
6600 * optional minus sign followed by a Number followed by whitespace
6601 * is converted to the IEEE 754 number that is nearest (according
6602 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6603 * represented by the string; any other string is converted to NaN
6605 * Conclusion all nodes need to be converted first to their string value
6606 * and then the comparison must be done when possible
6609 xmlXPathCompareNodeSets(int inf
, int strict
,
6610 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6618 if ((arg1
== NULL
) ||
6619 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
))) {
6620 xmlXPathFreeObject(arg2
);
6623 if ((arg2
== NULL
) ||
6624 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
))) {
6625 xmlXPathFreeObject(arg1
);
6626 xmlXPathFreeObject(arg2
);
6630 ns1
= arg1
->nodesetval
;
6631 ns2
= arg2
->nodesetval
;
6633 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0)) {
6634 xmlXPathFreeObject(arg1
);
6635 xmlXPathFreeObject(arg2
);
6638 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0)) {
6639 xmlXPathFreeObject(arg1
);
6640 xmlXPathFreeObject(arg2
);
6644 values2
= (double *) xmlMalloc(ns2
->nodeNr
* sizeof(double));
6645 if (values2
== NULL
) {
6646 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6647 xmlXPathFreeObject(arg1
);
6648 xmlXPathFreeObject(arg2
);
6651 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6652 val1
= xmlXPathCastNodeToNumber(ns1
->nodeTab
[i
]);
6653 if (xmlXPathIsNaN(val1
))
6655 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6657 values2
[j
] = xmlXPathCastNodeToNumber(ns2
->nodeTab
[j
]);
6659 if (xmlXPathIsNaN(values2
[j
]))
6662 ret
= (val1
< values2
[j
]);
6663 else if (inf
&& !strict
)
6664 ret
= (val1
<= values2
[j
]);
6665 else if (!inf
&& strict
)
6666 ret
= (val1
> values2
[j
]);
6667 else if (!inf
&& !strict
)
6668 ret
= (val1
>= values2
[j
]);
6677 xmlXPathFreeObject(arg1
);
6678 xmlXPathFreeObject(arg2
);
6683 * xmlXPathCompareNodeSetValue:
6684 * @ctxt: the XPath Parser context
6685 * @inf: less than (1) or greater than (0)
6686 * @strict: is the comparison strict
6687 * @arg: the node set
6690 * Implement the compare operation between a nodeset and a value
6691 * @ns < @val (1, 1, ...
6692 * @ns <= @val (1, 0, ...
6693 * @ns > @val (0, 1, ...
6694 * @ns >= @val (0, 0, ...
6696 * If one object to be compared is a node-set and the other is a boolean,
6697 * then the comparison will be true if and only if the result of performing
6698 * the comparison on the boolean and on the result of converting
6699 * the node-set to a boolean using the boolean function is true.
6701 * Returns 0 or 1 depending on the results of the test.
6704 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6705 xmlXPathObjectPtr arg
, xmlXPathObjectPtr val
) {
6706 if ((val
== NULL
) || (arg
== NULL
) ||
6707 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6712 return(xmlXPathCompareNodeSetFloat(ctxt
, inf
, strict
, arg
, val
));
6714 case XPATH_XSLT_TREE
:
6715 return(xmlXPathCompareNodeSets(inf
, strict
, arg
, val
));
6717 return(xmlXPathCompareNodeSetString(ctxt
, inf
, strict
, arg
, val
));
6719 valuePush(ctxt
, arg
);
6720 xmlXPathBooleanFunction(ctxt
, 1);
6721 valuePush(ctxt
, val
);
6722 return(xmlXPathCompareValues(ctxt
, inf
, strict
));
6724 xmlGenericError(xmlGenericErrorContext
,
6725 "xmlXPathCompareNodeSetValue: Can't compare node set "
6726 "and object of type %d\n",
6728 xmlXPathReleaseObject(ctxt
->context
, arg
);
6729 xmlXPathReleaseObject(ctxt
->context
, val
);
6730 XP_ERROR0(XPATH_INVALID_TYPE
);
6736 * xmlXPathEqualNodeSetString:
6737 * @arg: the nodeset object argument
6738 * @str: the string to compare to.
6739 * @neq: flag to show whether for '=' (0) or '!=' (1)
6741 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6742 * If one object to be compared is a node-set and the other is a string,
6743 * then the comparison will be true if and only if there is a node in
6744 * the node-set such that the result of performing the comparison on the
6745 * string-value of the node and the other string is true.
6747 * Returns 0 or 1 depending on the results of the test.
6750 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg
, const xmlChar
* str
, int neq
)
6757 if ((str
== NULL
) || (arg
== NULL
) ||
6758 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6760 ns
= arg
->nodesetval
;
6762 * A NULL nodeset compared with a string is always false
6763 * (since there is no node equal, and no node not equal)
6765 if ((ns
== NULL
) || (ns
->nodeNr
<= 0) )
6767 hash
= xmlXPathStringHash(str
);
6768 for (i
= 0; i
< ns
->nodeNr
; i
++) {
6769 if (xmlXPathNodeValHash(ns
->nodeTab
[i
]) == hash
) {
6770 str2
= xmlNodeGetContent(ns
->nodeTab
[i
]);
6771 if ((str2
!= NULL
) && (xmlStrEqual(str
, str2
))) {
6776 } else if ((str2
== NULL
) && (xmlStrEqual(str
, BAD_CAST
""))) {
6794 * xmlXPathEqualNodeSetFloat:
6795 * @arg: the nodeset object argument
6796 * @f: the float to compare to
6797 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6799 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6800 * If one object to be compared is a node-set and the other is a number,
6801 * then the comparison will be true if and only if there is a node in
6802 * the node-set such that the result of performing the comparison on the
6803 * number to be compared and on the result of converting the string-value
6804 * of that node to a number using the number function is true.
6806 * Returns 0 or 1 depending on the results of the test.
6809 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt
,
6810 xmlXPathObjectPtr arg
, double f
, int neq
) {
6814 xmlXPathObjectPtr val
;
6817 if ((arg
== NULL
) ||
6818 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6821 ns
= arg
->nodesetval
;
6823 for (i
=0;i
<ns
->nodeNr
;i
++) {
6824 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6826 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, str2
));
6828 xmlXPathNumberFunction(ctxt
, 1);
6829 val
= valuePop(ctxt
);
6831 xmlXPathReleaseObject(ctxt
->context
, val
);
6832 if (!xmlXPathIsNaN(v
)) {
6833 if ((!neq
) && (v
==f
)) {
6836 } else if ((neq
) && (v
!=f
)) {
6840 } else { /* NaN is unequal to any value */
6853 * xmlXPathEqualNodeSets:
6854 * @arg1: first nodeset object argument
6855 * @arg2: second nodeset object argument
6856 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6858 * Implement the equal / not equal operation on XPath nodesets:
6859 * @arg1 == @arg2 or @arg1 != @arg2
6860 * If both objects to be compared are node-sets, then the comparison
6861 * will be true if and only if there is a node in the first node-set and
6862 * a node in the second node-set such that the result of performing the
6863 * comparison on the string-values of the two nodes is true.
6865 * (needless to say, this is a costly operation)
6867 * Returns 0 or 1 depending on the results of the test.
6870 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
, int neq
) {
6872 unsigned int *hashs1
;
6873 unsigned int *hashs2
;
6880 if ((arg1
== NULL
) ||
6881 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)))
6883 if ((arg2
== NULL
) ||
6884 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
)))
6887 ns1
= arg1
->nodesetval
;
6888 ns2
= arg2
->nodesetval
;
6890 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0))
6892 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0))
6896 * for equal, check if there is a node pertaining to both sets
6899 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6900 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6901 if (ns1
->nodeTab
[i
] == ns2
->nodeTab
[j
])
6904 values1
= (xmlChar
**) xmlMalloc(ns1
->nodeNr
* sizeof(xmlChar
*));
6905 if (values1
== NULL
) {
6906 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6909 hashs1
= (unsigned int *) xmlMalloc(ns1
->nodeNr
* sizeof(unsigned int));
6910 if (hashs1
== NULL
) {
6911 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6915 memset(values1
, 0, ns1
->nodeNr
* sizeof(xmlChar
*));
6916 values2
= (xmlChar
**) xmlMalloc(ns2
->nodeNr
* sizeof(xmlChar
*));
6917 if (values2
== NULL
) {
6918 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6923 hashs2
= (unsigned int *) xmlMalloc(ns2
->nodeNr
* sizeof(unsigned int));
6924 if (hashs2
== NULL
) {
6925 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6931 memset(values2
, 0, ns2
->nodeNr
* sizeof(xmlChar
*));
6932 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6933 hashs1
[i
] = xmlXPathNodeValHash(ns1
->nodeTab
[i
]);
6934 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6936 hashs2
[j
] = xmlXPathNodeValHash(ns2
->nodeTab
[j
]);
6937 if (hashs1
[i
] != hashs2
[j
]) {
6944 if (values1
[i
] == NULL
)
6945 values1
[i
] = xmlNodeGetContent(ns1
->nodeTab
[i
]);
6946 if (values2
[j
] == NULL
)
6947 values2
[j
] = xmlNodeGetContent(ns2
->nodeTab
[j
]);
6948 ret
= xmlStrEqual(values1
[i
], values2
[j
]) ^ neq
;
6956 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6957 if (values1
[i
] != NULL
)
6958 xmlFree(values1
[i
]);
6959 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6960 if (values2
[j
] != NULL
)
6961 xmlFree(values2
[j
]);
6970 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt
,
6971 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6974 *At this point we are assured neither arg1 nor arg2
6975 *is a nodeset, so we can just pick the appropriate routine.
6977 switch (arg1
->type
) {
6978 case XPATH_UNDEFINED
:
6980 xmlGenericError(xmlGenericErrorContext
,
6981 "Equal: undefined\n");
6985 switch (arg2
->type
) {
6986 case XPATH_UNDEFINED
:
6988 xmlGenericError(xmlGenericErrorContext
,
6989 "Equal: undefined\n");
6994 xmlGenericError(xmlGenericErrorContext
,
6995 "Equal: %d boolean %d \n",
6996 arg1
->boolval
, arg2
->boolval
);
6998 ret
= (arg1
->boolval
== arg2
->boolval
);
7001 ret
= (arg1
->boolval
==
7002 xmlXPathCastNumberToBoolean(arg2
->floatval
));
7005 if ((arg2
->stringval
== NULL
) ||
7006 (arg2
->stringval
[0] == 0)) ret
= 0;
7009 ret
= (arg1
->boolval
== ret
);
7014 case XPATH_LOCATIONSET
:
7018 case XPATH_XSLT_TREE
:
7023 switch (arg2
->type
) {
7024 case XPATH_UNDEFINED
:
7026 xmlGenericError(xmlGenericErrorContext
,
7027 "Equal: undefined\n");
7031 ret
= (arg2
->boolval
==
7032 xmlXPathCastNumberToBoolean(arg1
->floatval
));
7035 valuePush(ctxt
, arg2
);
7036 xmlXPathNumberFunction(ctxt
, 1);
7037 arg2
= valuePop(ctxt
);
7038 /* Falls through. */
7040 /* Hand check NaN and Infinity equalities */
7041 if (xmlXPathIsNaN(arg1
->floatval
) ||
7042 xmlXPathIsNaN(arg2
->floatval
)) {
7044 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7045 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7049 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7050 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7054 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7055 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7059 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7060 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7065 ret
= (arg1
->floatval
== arg2
->floatval
);
7071 case XPATH_LOCATIONSET
:
7075 case XPATH_XSLT_TREE
:
7080 switch (arg2
->type
) {
7081 case XPATH_UNDEFINED
:
7083 xmlGenericError(xmlGenericErrorContext
,
7084 "Equal: undefined\n");
7088 if ((arg1
->stringval
== NULL
) ||
7089 (arg1
->stringval
[0] == 0)) ret
= 0;
7092 ret
= (arg2
->boolval
== ret
);
7095 ret
= xmlStrEqual(arg1
->stringval
, arg2
->stringval
);
7098 valuePush(ctxt
, arg1
);
7099 xmlXPathNumberFunction(ctxt
, 1);
7100 arg1
= valuePop(ctxt
);
7101 /* Hand check NaN and Infinity equalities */
7102 if (xmlXPathIsNaN(arg1
->floatval
) ||
7103 xmlXPathIsNaN(arg2
->floatval
)) {
7105 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7106 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7110 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7111 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7115 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7116 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7120 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7121 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7126 ret
= (arg1
->floatval
== arg2
->floatval
);
7132 case XPATH_LOCATIONSET
:
7136 case XPATH_XSLT_TREE
:
7143 case XPATH_LOCATIONSET
:
7147 case XPATH_XSLT_TREE
:
7150 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7151 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7156 * xmlXPathEqualValues:
7157 * @ctxt: the XPath Parser context
7159 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7161 * Returns 0 or 1 depending on the results of the test.
7164 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt
) {
7165 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7168 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7169 arg2
= valuePop(ctxt
);
7170 arg1
= valuePop(ctxt
);
7171 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7173 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7175 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7176 XP_ERROR0(XPATH_INVALID_OPERAND
);
7181 xmlGenericError(xmlGenericErrorContext
,
7182 "Equal: by pointer\n");
7184 xmlXPathFreeObject(arg1
);
7189 *If either argument is a nodeset, it's a 'special case'
7191 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7192 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7194 *Hack it to assure arg1 is the nodeset
7196 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7201 switch (arg2
->type
) {
7202 case XPATH_UNDEFINED
:
7204 xmlGenericError(xmlGenericErrorContext
,
7205 "Equal: undefined\n");
7209 case XPATH_XSLT_TREE
:
7210 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 0);
7213 if ((arg1
->nodesetval
== NULL
) ||
7214 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7217 ret
= (ret
== arg2
->boolval
);
7220 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 0);
7223 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
, 0);
7228 case XPATH_LOCATIONSET
:
7232 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7233 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7237 return (xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7241 * xmlXPathNotEqualValues:
7242 * @ctxt: the XPath Parser context
7244 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7246 * Returns 0 or 1 depending on the results of the test.
7249 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt
) {
7250 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7253 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7254 arg2
= valuePop(ctxt
);
7255 arg1
= valuePop(ctxt
);
7256 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7258 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7260 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7261 XP_ERROR0(XPATH_INVALID_OPERAND
);
7266 xmlGenericError(xmlGenericErrorContext
,
7267 "NotEqual: by pointer\n");
7269 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7274 *If either argument is a nodeset, it's a 'special case'
7276 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7277 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7279 *Hack it to assure arg1 is the nodeset
7281 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7286 switch (arg2
->type
) {
7287 case XPATH_UNDEFINED
:
7289 xmlGenericError(xmlGenericErrorContext
,
7290 "NotEqual: undefined\n");
7294 case XPATH_XSLT_TREE
:
7295 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 1);
7298 if ((arg1
->nodesetval
== NULL
) ||
7299 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7302 ret
= (ret
!= arg2
->boolval
);
7305 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 1);
7308 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
,1);
7313 case XPATH_LOCATIONSET
:
7317 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7318 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7322 return (!xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7326 * xmlXPathCompareValues:
7327 * @ctxt: the XPath Parser context
7328 * @inf: less than (1) or greater than (0)
7329 * @strict: is the comparison strict
7331 * Implement the compare operation on XPath objects:
7332 * @arg1 < @arg2 (1, 1, ...
7333 * @arg1 <= @arg2 (1, 0, ...
7334 * @arg1 > @arg2 (0, 1, ...
7335 * @arg1 >= @arg2 (0, 0, ...
7337 * When neither object to be compared is a node-set and the operator is
7338 * <=, <, >=, >, then the objects are compared by converted both objects
7339 * to numbers and comparing the numbers according to IEEE 754. The <
7340 * comparison will be true if and only if the first number is less than the
7341 * second number. The <= comparison will be true if and only if the first
7342 * number is less than or equal to the second number. The > comparison
7343 * will be true if and only if the first number is greater than the second
7344 * number. The >= comparison will be true if and only if the first number
7345 * is greater than or equal to the second number.
7347 * Returns 1 if the comparison succeeded, 0 if it failed
7350 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt
, int inf
, int strict
) {
7351 int ret
= 0, arg1i
= 0, arg2i
= 0;
7352 xmlXPathObjectPtr arg1
, arg2
;
7354 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7355 arg2
= valuePop(ctxt
);
7356 arg1
= valuePop(ctxt
);
7357 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7359 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7361 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7362 XP_ERROR0(XPATH_INVALID_OPERAND
);
7365 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7366 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7368 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7369 * are not freed from within this routine; they will be freed from the
7370 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7372 if (((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
)) &&
7373 ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
))){
7374 ret
= xmlXPathCompareNodeSets(inf
, strict
, arg1
, arg2
);
7376 if ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7377 ret
= xmlXPathCompareNodeSetValue(ctxt
, inf
, strict
,
7380 ret
= xmlXPathCompareNodeSetValue(ctxt
, !inf
, strict
,
7387 if (arg1
->type
!= XPATH_NUMBER
) {
7388 valuePush(ctxt
, arg1
);
7389 xmlXPathNumberFunction(ctxt
, 1);
7390 arg1
= valuePop(ctxt
);
7392 if (arg1
->type
!= XPATH_NUMBER
) {
7393 xmlXPathFreeObject(arg1
);
7394 xmlXPathFreeObject(arg2
);
7395 XP_ERROR0(XPATH_INVALID_OPERAND
);
7397 if (arg2
->type
!= XPATH_NUMBER
) {
7398 valuePush(ctxt
, arg2
);
7399 xmlXPathNumberFunction(ctxt
, 1);
7400 arg2
= valuePop(ctxt
);
7402 if (arg2
->type
!= XPATH_NUMBER
) {
7403 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7404 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7405 XP_ERROR0(XPATH_INVALID_OPERAND
);
7408 * Add tests for infinity and nan
7409 * => feedback on 3.4 for Inf and NaN
7411 /* Hand check NaN and Infinity comparisons */
7412 if (xmlXPathIsNaN(arg1
->floatval
) || xmlXPathIsNaN(arg2
->floatval
)) {
7415 arg1i
=xmlXPathIsInf(arg1
->floatval
);
7416 arg2i
=xmlXPathIsInf(arg2
->floatval
);
7417 if (inf
&& strict
) {
7418 if ((arg1i
== -1 && arg2i
!= -1) ||
7419 (arg2i
== 1 && arg1i
!= 1)) {
7421 } else if (arg1i
== 0 && arg2i
== 0) {
7422 ret
= (arg1
->floatval
< arg2
->floatval
);
7427 else if (inf
&& !strict
) {
7428 if (arg1i
== -1 || arg2i
== 1) {
7430 } else if (arg1i
== 0 && arg2i
== 0) {
7431 ret
= (arg1
->floatval
<= arg2
->floatval
);
7436 else if (!inf
&& strict
) {
7437 if ((arg1i
== 1 && arg2i
!= 1) ||
7438 (arg2i
== -1 && arg1i
!= -1)) {
7440 } else if (arg1i
== 0 && arg2i
== 0) {
7441 ret
= (arg1
->floatval
> arg2
->floatval
);
7446 else if (!inf
&& !strict
) {
7447 if (arg1i
== 1 || arg2i
== -1) {
7449 } else if (arg1i
== 0 && arg2i
== 0) {
7450 ret
= (arg1
->floatval
>= arg2
->floatval
);
7456 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7457 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7462 * xmlXPathValueFlipSign:
7463 * @ctxt: the XPath Parser context
7465 * Implement the unary - operation on an XPath object
7466 * The numeric operators convert their operands to numbers as if
7467 * by calling the number function.
7470 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt
) {
7471 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return;
7473 CHECK_TYPE(XPATH_NUMBER
);
7474 ctxt
->value
->floatval
= -ctxt
->value
->floatval
;
7478 * xmlXPathAddValues:
7479 * @ctxt: the XPath Parser context
7481 * Implement the add operation on XPath objects:
7482 * The numeric operators convert their operands to numbers as if
7483 * by calling the number function.
7486 xmlXPathAddValues(xmlXPathParserContextPtr ctxt
) {
7487 xmlXPathObjectPtr arg
;
7490 arg
= valuePop(ctxt
);
7492 XP_ERROR(XPATH_INVALID_OPERAND
);
7493 val
= xmlXPathCastToNumber(arg
);
7494 xmlXPathReleaseObject(ctxt
->context
, arg
);
7496 CHECK_TYPE(XPATH_NUMBER
);
7497 ctxt
->value
->floatval
+= val
;
7501 * xmlXPathSubValues:
7502 * @ctxt: the XPath Parser context
7504 * Implement the subtraction operation on XPath objects:
7505 * The numeric operators convert their operands to numbers as if
7506 * by calling the number function.
7509 xmlXPathSubValues(xmlXPathParserContextPtr ctxt
) {
7510 xmlXPathObjectPtr arg
;
7513 arg
= valuePop(ctxt
);
7515 XP_ERROR(XPATH_INVALID_OPERAND
);
7516 val
= xmlXPathCastToNumber(arg
);
7517 xmlXPathReleaseObject(ctxt
->context
, arg
);
7519 CHECK_TYPE(XPATH_NUMBER
);
7520 ctxt
->value
->floatval
-= val
;
7524 * xmlXPathMultValues:
7525 * @ctxt: the XPath Parser context
7527 * Implement the multiply operation on XPath objects:
7528 * The numeric operators convert their operands to numbers as if
7529 * by calling the number function.
7532 xmlXPathMultValues(xmlXPathParserContextPtr ctxt
) {
7533 xmlXPathObjectPtr arg
;
7536 arg
= valuePop(ctxt
);
7538 XP_ERROR(XPATH_INVALID_OPERAND
);
7539 val
= xmlXPathCastToNumber(arg
);
7540 xmlXPathReleaseObject(ctxt
->context
, arg
);
7542 CHECK_TYPE(XPATH_NUMBER
);
7543 ctxt
->value
->floatval
*= val
;
7547 * xmlXPathDivValues:
7548 * @ctxt: the XPath Parser context
7550 * Implement the div operation on XPath objects @arg1 / @arg2:
7551 * The numeric operators convert their operands to numbers as if
7552 * by calling the number function.
7555 xmlXPathDivValues(xmlXPathParserContextPtr ctxt
) {
7556 xmlXPathObjectPtr arg
;
7559 arg
= valuePop(ctxt
);
7561 XP_ERROR(XPATH_INVALID_OPERAND
);
7562 val
= xmlXPathCastToNumber(arg
);
7563 xmlXPathReleaseObject(ctxt
->context
, arg
);
7565 CHECK_TYPE(XPATH_NUMBER
);
7566 ctxt
->value
->floatval
/= val
;
7570 * xmlXPathModValues:
7571 * @ctxt: the XPath Parser context
7573 * Implement the mod operation on XPath objects: @arg1 / @arg2
7574 * The numeric operators convert their operands to numbers as if
7575 * by calling the number function.
7578 xmlXPathModValues(xmlXPathParserContextPtr ctxt
) {
7579 xmlXPathObjectPtr arg
;
7582 arg
= valuePop(ctxt
);
7584 XP_ERROR(XPATH_INVALID_OPERAND
);
7585 arg2
= xmlXPathCastToNumber(arg
);
7586 xmlXPathReleaseObject(ctxt
->context
, arg
);
7588 CHECK_TYPE(XPATH_NUMBER
);
7589 arg1
= ctxt
->value
->floatval
;
7591 ctxt
->value
->floatval
= NAN
;
7593 ctxt
->value
->floatval
= fmod(arg1
, arg2
);
7597 /************************************************************************
7599 * The traversal functions *
7601 ************************************************************************/
7604 * A traversal function enumerates nodes along an axis.
7605 * Initially it must be called with NULL, and it indicates
7606 * termination on the axis by returning NULL.
7608 typedef xmlNodePtr (*xmlXPathTraversalFunction
)
7609 (xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
);
7612 * xmlXPathTraversalFunctionExt:
7613 * A traversal function enumerates nodes along an axis.
7614 * Initially it must be called with NULL, and it indicates
7615 * termination on the axis by returning NULL.
7616 * The context node of the traversal is specified via @contextNode.
7618 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt
)
7619 (xmlNodePtr cur
, xmlNodePtr contextNode
);
7622 * xmlXPathNodeSetMergeFunction:
7623 * Used for merging node sets in xmlXPathCollectAndTest().
7625 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction
)
7626 (xmlNodeSetPtr
, xmlNodeSetPtr
, int);
7631 * @ctxt: the XPath Parser context
7632 * @cur: the current node in the traversal
7634 * Traversal function for the "self" direction
7635 * The self axis contains just the context node itself
7637 * Returns the next element following that axis
7640 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7641 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7643 return(ctxt
->context
->node
);
7648 * xmlXPathNextChild:
7649 * @ctxt: the XPath Parser context
7650 * @cur: the current node in the traversal
7652 * Traversal function for the "child" direction
7653 * The child axis contains the children of the context node in document order.
7655 * Returns the next element following that axis
7658 xmlXPathNextChild(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7659 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7661 if (ctxt
->context
->node
== NULL
) return(NULL
);
7662 switch (ctxt
->context
->node
->type
) {
7663 case XML_ELEMENT_NODE
:
7665 case XML_CDATA_SECTION_NODE
:
7666 case XML_ENTITY_REF_NODE
:
7667 case XML_ENTITY_NODE
:
7669 case XML_COMMENT_NODE
:
7670 case XML_NOTATION_NODE
:
7672 return(ctxt
->context
->node
->children
);
7673 case XML_DOCUMENT_NODE
:
7674 case XML_DOCUMENT_TYPE_NODE
:
7675 case XML_DOCUMENT_FRAG_NODE
:
7676 case XML_HTML_DOCUMENT_NODE
:
7677 #ifdef LIBXML_DOCB_ENABLED
7678 case XML_DOCB_DOCUMENT_NODE
:
7680 return(((xmlDocPtr
) ctxt
->context
->node
)->children
);
7681 case XML_ELEMENT_DECL
:
7682 case XML_ATTRIBUTE_DECL
:
7683 case XML_ENTITY_DECL
:
7684 case XML_ATTRIBUTE_NODE
:
7685 case XML_NAMESPACE_DECL
:
7686 case XML_XINCLUDE_START
:
7687 case XML_XINCLUDE_END
:
7692 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
7693 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
7699 * xmlXPathNextChildElement:
7700 * @ctxt: the XPath Parser context
7701 * @cur: the current node in the traversal
7703 * Traversal function for the "child" direction and nodes of type element.
7704 * The child axis contains the children of the context node in document order.
7706 * Returns the next element following that axis
7709 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7710 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7712 cur
= ctxt
->context
->node
;
7713 if (cur
== NULL
) return(NULL
);
7715 * Get the first element child.
7717 switch (cur
->type
) {
7718 case XML_ELEMENT_NODE
:
7719 case XML_DOCUMENT_FRAG_NODE
:
7720 case XML_ENTITY_REF_NODE
: /* URGENT TODO: entify-refs as well? */
7721 case XML_ENTITY_NODE
:
7722 cur
= cur
->children
;
7724 if (cur
->type
== XML_ELEMENT_NODE
)
7728 } while ((cur
!= NULL
) &&
7729 (cur
->type
!= XML_ELEMENT_NODE
));
7733 case XML_DOCUMENT_NODE
:
7734 case XML_HTML_DOCUMENT_NODE
:
7735 #ifdef LIBXML_DOCB_ENABLED
7736 case XML_DOCB_DOCUMENT_NODE
:
7738 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7745 * Get the next sibling element node.
7747 switch (cur
->type
) {
7748 case XML_ELEMENT_NODE
:
7750 case XML_ENTITY_REF_NODE
:
7751 case XML_ENTITY_NODE
:
7752 case XML_CDATA_SECTION_NODE
:
7754 case XML_COMMENT_NODE
:
7755 case XML_XINCLUDE_END
:
7757 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7761 if (cur
->next
!= NULL
) {
7762 if (cur
->next
->type
== XML_ELEMENT_NODE
)
7767 } while ((cur
!= NULL
) && (cur
->type
!= XML_ELEMENT_NODE
));
7775 * xmlXPathNextDescendantOrSelfElemParent:
7776 * @ctxt: the XPath Parser context
7777 * @cur: the current node in the traversal
7779 * Traversal function for the "descendant-or-self" axis.
7780 * Additionally it returns only nodes which can be parents of
7784 * Returns the next element following that axis
7787 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur
,
7788 xmlNodePtr contextNode
)
7791 if (contextNode
== NULL
)
7793 switch (contextNode
->type
) {
7794 case XML_ELEMENT_NODE
:
7795 case XML_XINCLUDE_START
:
7796 case XML_DOCUMENT_FRAG_NODE
:
7797 case XML_DOCUMENT_NODE
:
7798 #ifdef LIBXML_DOCB_ENABLED
7799 case XML_DOCB_DOCUMENT_NODE
:
7801 case XML_HTML_DOCUMENT_NODE
:
7802 return(contextNode
);
7808 xmlNodePtr start
= cur
;
7810 while (cur
!= NULL
) {
7811 switch (cur
->type
) {
7812 case XML_ELEMENT_NODE
:
7813 /* TODO: OK to have XInclude here? */
7814 case XML_XINCLUDE_START
:
7815 case XML_DOCUMENT_FRAG_NODE
:
7818 if (cur
->children
!= NULL
) {
7819 cur
= cur
->children
;
7823 /* Not sure if we need those here. */
7824 case XML_DOCUMENT_NODE
:
7825 #ifdef LIBXML_DOCB_ENABLED
7826 case XML_DOCB_DOCUMENT_NODE
:
7828 case XML_HTML_DOCUMENT_NODE
:
7831 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7837 if ((cur
== NULL
) || (cur
== contextNode
))
7839 if (cur
->next
!= NULL
) {
7852 * xmlXPathNextDescendant:
7853 * @ctxt: the XPath Parser context
7854 * @cur: the current node in the traversal
7856 * Traversal function for the "descendant" direction
7857 * the descendant axis contains the descendants of the context node in document
7858 * order; a descendant is a child or a child of a child and so on.
7860 * Returns the next element following that axis
7863 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7864 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7866 if (ctxt
->context
->node
== NULL
)
7868 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7869 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7872 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
7873 return(ctxt
->context
->doc
->children
);
7874 return(ctxt
->context
->node
->children
);
7877 if (cur
->type
== XML_NAMESPACE_DECL
)
7879 if (cur
->children
!= NULL
) {
7881 * Do not descend on entities declarations
7883 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
7884 cur
= cur
->children
;
7888 if (cur
->type
!= XML_DTD_NODE
)
7893 if (cur
== ctxt
->context
->node
) return(NULL
);
7895 while (cur
->next
!= NULL
) {
7897 if ((cur
->type
!= XML_ENTITY_DECL
) &&
7898 (cur
->type
!= XML_DTD_NODE
))
7904 if (cur
== NULL
) break;
7905 if (cur
== ctxt
->context
->node
) return(NULL
);
7906 if (cur
->next
!= NULL
) {
7910 } while (cur
!= NULL
);
7915 * xmlXPathNextDescendantOrSelf:
7916 * @ctxt: the XPath Parser context
7917 * @cur: the current node in the traversal
7919 * Traversal function for the "descendant-or-self" direction
7920 * the descendant-or-self axis contains the context node and the descendants
7921 * of the context node in document order; thus the context node is the first
7922 * node on the axis, and the first child of the context node is the second node
7925 * Returns the next element following that axis
7928 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7929 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7931 return(ctxt
->context
->node
);
7933 if (ctxt
->context
->node
== NULL
)
7935 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7936 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7939 return(xmlXPathNextDescendant(ctxt
, cur
));
7943 * xmlXPathNextParent:
7944 * @ctxt: the XPath Parser context
7945 * @cur: the current node in the traversal
7947 * Traversal function for the "parent" direction
7948 * The parent axis contains the parent of the context node, if there is one.
7950 * Returns the next element following that axis
7953 xmlXPathNextParent(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7954 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7956 * the parent of an attribute or namespace node is the element
7957 * to which the attribute or namespace node is attached
7958 * Namespace handling !!!
7961 if (ctxt
->context
->node
== NULL
) return(NULL
);
7962 switch (ctxt
->context
->node
->type
) {
7963 case XML_ELEMENT_NODE
:
7965 case XML_CDATA_SECTION_NODE
:
7966 case XML_ENTITY_REF_NODE
:
7967 case XML_ENTITY_NODE
:
7969 case XML_COMMENT_NODE
:
7970 case XML_NOTATION_NODE
:
7972 case XML_ELEMENT_DECL
:
7973 case XML_ATTRIBUTE_DECL
:
7974 case XML_XINCLUDE_START
:
7975 case XML_XINCLUDE_END
:
7976 case XML_ENTITY_DECL
:
7977 if (ctxt
->context
->node
->parent
== NULL
)
7978 return((xmlNodePtr
) ctxt
->context
->doc
);
7979 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
7980 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
7981 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
7982 BAD_CAST
"fake node libxslt"))))
7984 return(ctxt
->context
->node
->parent
);
7985 case XML_ATTRIBUTE_NODE
: {
7986 xmlAttrPtr att
= (xmlAttrPtr
) ctxt
->context
->node
;
7988 return(att
->parent
);
7990 case XML_DOCUMENT_NODE
:
7991 case XML_DOCUMENT_TYPE_NODE
:
7992 case XML_DOCUMENT_FRAG_NODE
:
7993 case XML_HTML_DOCUMENT_NODE
:
7994 #ifdef LIBXML_DOCB_ENABLED
7995 case XML_DOCB_DOCUMENT_NODE
:
7998 case XML_NAMESPACE_DECL
: {
7999 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8001 if ((ns
->next
!= NULL
) &&
8002 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8003 return((xmlNodePtr
) ns
->next
);
8012 * xmlXPathNextAncestor:
8013 * @ctxt: the XPath Parser context
8014 * @cur: the current node in the traversal
8016 * Traversal function for the "ancestor" direction
8017 * the ancestor axis contains the ancestors of the context node; the ancestors
8018 * of the context node consist of the parent of context node and the parent's
8019 * parent and so on; the nodes are ordered in reverse document order; thus the
8020 * parent is the first node on the axis, and the parent's parent is the second
8023 * Returns the next element following that axis
8026 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8027 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8029 * the parent of an attribute or namespace node is the element
8030 * to which the attribute or namespace node is attached
8034 if (ctxt
->context
->node
== NULL
) return(NULL
);
8035 switch (ctxt
->context
->node
->type
) {
8036 case XML_ELEMENT_NODE
:
8038 case XML_CDATA_SECTION_NODE
:
8039 case XML_ENTITY_REF_NODE
:
8040 case XML_ENTITY_NODE
:
8042 case XML_COMMENT_NODE
:
8044 case XML_ELEMENT_DECL
:
8045 case XML_ATTRIBUTE_DECL
:
8046 case XML_ENTITY_DECL
:
8047 case XML_NOTATION_NODE
:
8048 case XML_XINCLUDE_START
:
8049 case XML_XINCLUDE_END
:
8050 if (ctxt
->context
->node
->parent
== NULL
)
8051 return((xmlNodePtr
) ctxt
->context
->doc
);
8052 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
8053 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
8054 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
8055 BAD_CAST
"fake node libxslt"))))
8057 return(ctxt
->context
->node
->parent
);
8058 case XML_ATTRIBUTE_NODE
: {
8059 xmlAttrPtr tmp
= (xmlAttrPtr
) ctxt
->context
->node
;
8061 return(tmp
->parent
);
8063 case XML_DOCUMENT_NODE
:
8064 case XML_DOCUMENT_TYPE_NODE
:
8065 case XML_DOCUMENT_FRAG_NODE
:
8066 case XML_HTML_DOCUMENT_NODE
:
8067 #ifdef LIBXML_DOCB_ENABLED
8068 case XML_DOCB_DOCUMENT_NODE
:
8071 case XML_NAMESPACE_DECL
: {
8072 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8074 if ((ns
->next
!= NULL
) &&
8075 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8076 return((xmlNodePtr
) ns
->next
);
8077 /* Bad, how did that namespace end up here ? */
8083 if (cur
== ctxt
->context
->doc
->children
)
8084 return((xmlNodePtr
) ctxt
->context
->doc
);
8085 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8087 switch (cur
->type
) {
8088 case XML_ELEMENT_NODE
:
8090 case XML_CDATA_SECTION_NODE
:
8091 case XML_ENTITY_REF_NODE
:
8092 case XML_ENTITY_NODE
:
8094 case XML_COMMENT_NODE
:
8095 case XML_NOTATION_NODE
:
8097 case XML_ELEMENT_DECL
:
8098 case XML_ATTRIBUTE_DECL
:
8099 case XML_ENTITY_DECL
:
8100 case XML_XINCLUDE_START
:
8101 case XML_XINCLUDE_END
:
8102 if (cur
->parent
== NULL
)
8104 if ((cur
->parent
->type
== XML_ELEMENT_NODE
) &&
8105 ((cur
->parent
->name
[0] == ' ') ||
8106 (xmlStrEqual(cur
->parent
->name
,
8107 BAD_CAST
"fake node libxslt"))))
8109 return(cur
->parent
);
8110 case XML_ATTRIBUTE_NODE
: {
8111 xmlAttrPtr att
= (xmlAttrPtr
) cur
;
8113 return(att
->parent
);
8115 case XML_NAMESPACE_DECL
: {
8116 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8118 if ((ns
->next
!= NULL
) &&
8119 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8120 return((xmlNodePtr
) ns
->next
);
8121 /* Bad, how did that namespace end up here ? */
8124 case XML_DOCUMENT_NODE
:
8125 case XML_DOCUMENT_TYPE_NODE
:
8126 case XML_DOCUMENT_FRAG_NODE
:
8127 case XML_HTML_DOCUMENT_NODE
:
8128 #ifdef LIBXML_DOCB_ENABLED
8129 case XML_DOCB_DOCUMENT_NODE
:
8137 * xmlXPathNextAncestorOrSelf:
8138 * @ctxt: the XPath Parser context
8139 * @cur: the current node in the traversal
8141 * Traversal function for the "ancestor-or-self" direction
8142 * he ancestor-or-self axis contains the context node and ancestors of
8143 * the context node in reverse document order; thus the context node is
8144 * the first node on the axis, and the context node's parent the second;
8145 * parent here is defined the same as with the parent axis.
8147 * Returns the next element following that axis
8150 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8151 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8153 return(ctxt
->context
->node
);
8154 return(xmlXPathNextAncestor(ctxt
, cur
));
8158 * xmlXPathNextFollowingSibling:
8159 * @ctxt: the XPath Parser context
8160 * @cur: the current node in the traversal
8162 * Traversal function for the "following-sibling" direction
8163 * The following-sibling axis contains the following siblings of the context
8164 * node in document order.
8166 * Returns the next element following that axis
8169 xmlXPathNextFollowingSibling(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
->next
);
8182 * xmlXPathNextPrecedingSibling:
8183 * @ctxt: the XPath Parser context
8184 * @cur: the current node in the traversal
8186 * Traversal function for the "preceding-sibling" direction
8187 * The preceding-sibling axis contains the preceding siblings of the context
8188 * node in reverse document order; the first preceding sibling is first on the
8189 * axis; the sibling preceding that node is the second on the axis and so on.
8191 * Returns the next element following that axis
8194 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8195 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8196 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8197 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8199 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8202 return(ctxt
->context
->node
->prev
);
8203 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
)) {
8206 return(ctxt
->context
->node
->prev
);
8212 * xmlXPathNextFollowing:
8213 * @ctxt: the XPath Parser context
8214 * @cur: the current node in the traversal
8216 * Traversal function for the "following" direction
8217 * The following axis contains all nodes in the same document as the context
8218 * node that are after the context node in document order, excluding any
8219 * descendants and excluding attribute nodes and namespace nodes; the nodes
8220 * are ordered in document order
8222 * Returns the next element following that axis
8225 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8226 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8227 if ((cur
!= NULL
) && (cur
->type
!= XML_ATTRIBUTE_NODE
) &&
8228 (cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->children
!= NULL
))
8229 return(cur
->children
);
8232 cur
= ctxt
->context
->node
;
8233 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8235 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8236 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8238 if ((ns
->next
== NULL
) ||
8239 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8241 cur
= (xmlNodePtr
) ns
->next
;
8244 if (cur
== NULL
) return(NULL
) ; /* ERROR */
8245 if (cur
->next
!= NULL
) return(cur
->next
) ;
8248 if (cur
== NULL
) break;
8249 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
) return(NULL
);
8250 if (cur
->next
!= NULL
) return(cur
->next
);
8251 } while (cur
!= NULL
);
8256 * xmlXPathIsAncestor:
8257 * @ancestor: the ancestor node
8258 * @node: the current node
8260 * Check that @ancestor is a @node's ancestor
8262 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8265 xmlXPathIsAncestor(xmlNodePtr ancestor
, xmlNodePtr node
) {
8266 if ((ancestor
== NULL
) || (node
== NULL
)) return(0);
8267 if (node
->type
== XML_NAMESPACE_DECL
)
8269 if (ancestor
->type
== XML_NAMESPACE_DECL
)
8271 /* nodes need to be in the same document */
8272 if (ancestor
->doc
!= node
->doc
) return(0);
8273 /* avoid searching if ancestor or node is the root node */
8274 if (ancestor
== (xmlNodePtr
) node
->doc
) return(1);
8275 if (node
== (xmlNodePtr
) ancestor
->doc
) return(0);
8276 while (node
->parent
!= NULL
) {
8277 if (node
->parent
== ancestor
)
8279 node
= node
->parent
;
8285 * xmlXPathNextPreceding:
8286 * @ctxt: the XPath Parser context
8287 * @cur: the current node in the traversal
8289 * Traversal function for the "preceding" direction
8290 * the preceding axis contains all nodes in the same document as the context
8291 * node that are before the context node in document order, excluding any
8292 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293 * ordered in reverse document order
8295 * Returns the next element following that axis
8298 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
)
8300 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8302 cur
= ctxt
->context
->node
;
8303 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8305 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8306 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8308 if ((ns
->next
== NULL
) ||
8309 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8311 cur
= (xmlNodePtr
) ns
->next
;
8314 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
8316 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8319 if (cur
->prev
!= NULL
) {
8320 for (cur
= cur
->prev
; cur
->last
!= NULL
; cur
= cur
->last
) ;
8327 if (cur
== ctxt
->context
->doc
->children
)
8329 } while (xmlXPathIsAncestor(cur
, ctxt
->context
->node
));
8334 * xmlXPathNextPrecedingInternal:
8335 * @ctxt: the XPath Parser context
8336 * @cur: the current node in the traversal
8338 * Traversal function for the "preceding" direction
8339 * the preceding axis contains all nodes in the same document as the context
8340 * node that are before the context node in document order, excluding any
8341 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8342 * ordered in reverse document order
8343 * This is a faster implementation but internal only since it requires a
8344 * state kept in the parser context: ctxt->ancestor.
8346 * Returns the next element following that axis
8349 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt
,
8352 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8354 cur
= ctxt
->context
->node
;
8357 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8359 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8360 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8362 if ((ns
->next
== NULL
) ||
8363 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8365 cur
= (xmlNodePtr
) ns
->next
;
8367 ctxt
->ancestor
= cur
->parent
;
8369 if (cur
->type
== XML_NAMESPACE_DECL
)
8371 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8373 while (cur
->prev
== NULL
) {
8377 if (cur
== ctxt
->context
->doc
->children
)
8379 if (cur
!= ctxt
->ancestor
)
8381 ctxt
->ancestor
= cur
->parent
;
8384 while (cur
->last
!= NULL
)
8390 * xmlXPathNextNamespace:
8391 * @ctxt: the XPath Parser context
8392 * @cur: the current attribute in the traversal
8394 * Traversal function for the "namespace" direction
8395 * the namespace axis contains the namespace nodes of the context node;
8396 * the order of nodes on this axis is implementation-defined; the axis will
8397 * be empty unless the context node is an element
8399 * We keep the XML namespace node at the end of the list.
8401 * Returns the next element following that axis
8404 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8405 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8406 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
) return(NULL
);
8408 if (ctxt
->context
->tmpNsList
!= NULL
)
8409 xmlFree(ctxt
->context
->tmpNsList
);
8410 ctxt
->context
->tmpNsList
=
8411 xmlGetNsList(ctxt
->context
->doc
, ctxt
->context
->node
);
8412 ctxt
->context
->tmpNsNr
= 0;
8413 if (ctxt
->context
->tmpNsList
!= NULL
) {
8414 while (ctxt
->context
->tmpNsList
[ctxt
->context
->tmpNsNr
] != NULL
) {
8415 ctxt
->context
->tmpNsNr
++;
8418 return((xmlNodePtr
) xmlXPathXMLNamespace
);
8420 if (ctxt
->context
->tmpNsNr
> 0) {
8421 return (xmlNodePtr
)ctxt
->context
->tmpNsList
[--ctxt
->context
->tmpNsNr
];
8423 if (ctxt
->context
->tmpNsList
!= NULL
)
8424 xmlFree(ctxt
->context
->tmpNsList
);
8425 ctxt
->context
->tmpNsList
= NULL
;
8431 * xmlXPathNextAttribute:
8432 * @ctxt: the XPath Parser context
8433 * @cur: the current attribute in the traversal
8435 * Traversal function for the "attribute" direction
8436 * TODO: support DTD inherited default attributes
8438 * Returns the next element following that axis
8441 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8442 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8443 if (ctxt
->context
->node
== NULL
)
8445 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
)
8448 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
8450 return((xmlNodePtr
)ctxt
->context
->node
->properties
);
8452 return((xmlNodePtr
)cur
->next
);
8455 /************************************************************************
8457 * NodeTest Functions *
8459 ************************************************************************/
8461 #define IS_FUNCTION 200
8464 /************************************************************************
8466 * Implicit tree core function library *
8468 ************************************************************************/
8472 * @ctxt: the XPath Parser context
8474 * Initialize the context to the root of the document
8477 xmlXPathRoot(xmlXPathParserContextPtr ctxt
) {
8478 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8480 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8481 (xmlNodePtr
) ctxt
->context
->doc
));
8484 /************************************************************************
8486 * The explicit core function library *
8487 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8489 ************************************************************************/
8493 * xmlXPathLastFunction:
8494 * @ctxt: the XPath Parser context
8495 * @nargs: the number of arguments
8497 * Implement the last() XPath function
8499 * The last function returns the number of nodes in the context node list.
8502 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8504 if (ctxt
->context
->contextSize
>= 0) {
8506 xmlXPathCacheNewFloat(ctxt
->context
,
8507 (double) ctxt
->context
->contextSize
));
8509 xmlGenericError(xmlGenericErrorContext
,
8510 "last() : %d\n", ctxt
->context
->contextSize
);
8513 XP_ERROR(XPATH_INVALID_CTXT_SIZE
);
8518 * xmlXPathPositionFunction:
8519 * @ctxt: the XPath Parser context
8520 * @nargs: the number of arguments
8522 * Implement the position() XPath function
8524 * The position function returns the position of the context node in the
8525 * context node list. The first position is 1, and so the last position
8526 * will be equal to last().
8529 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8531 if (ctxt
->context
->proximityPosition
>= 0) {
8533 xmlXPathCacheNewFloat(ctxt
->context
,
8534 (double) ctxt
->context
->proximityPosition
));
8536 xmlGenericError(xmlGenericErrorContext
, "position() : %d\n",
8537 ctxt
->context
->proximityPosition
);
8540 XP_ERROR(XPATH_INVALID_CTXT_POSITION
);
8545 * xmlXPathCountFunction:
8546 * @ctxt: the XPath Parser context
8547 * @nargs: the number of arguments
8549 * Implement the count() XPath function
8550 * number count(node-set)
8553 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8554 xmlXPathObjectPtr cur
;
8557 if ((ctxt
->value
== NULL
) ||
8558 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8559 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8560 XP_ERROR(XPATH_INVALID_TYPE
);
8561 cur
= valuePop(ctxt
);
8563 if ((cur
== NULL
) || (cur
->nodesetval
== NULL
))
8564 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8565 else if ((cur
->type
== XPATH_NODESET
) || (cur
->type
== XPATH_XSLT_TREE
)) {
8566 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8567 (double) cur
->nodesetval
->nodeNr
));
8569 if ((cur
->nodesetval
->nodeNr
!= 1) ||
8570 (cur
->nodesetval
->nodeTab
== NULL
)) {
8571 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8576 tmp
= cur
->nodesetval
->nodeTab
[0];
8577 if ((tmp
!= NULL
) && (tmp
->type
!= XML_NAMESPACE_DECL
)) {
8578 tmp
= tmp
->children
;
8579 while (tmp
!= NULL
) {
8584 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) i
));
8587 xmlXPathReleaseObject(ctxt
->context
, cur
);
8591 * xmlXPathGetElementsByIds:
8592 * @doc: the document
8593 * @ids: a whitespace separated list of IDs
8595 * Selects elements by their unique ID.
8597 * Returns a node-set of selected elements.
8599 static xmlNodeSetPtr
8600 xmlXPathGetElementsByIds (xmlDocPtr doc
, const xmlChar
*ids
) {
8602 const xmlChar
*cur
= ids
;
8605 xmlNodePtr elem
= NULL
;
8607 if (ids
== NULL
) return(NULL
);
8609 ret
= xmlXPathNodeSetCreate(NULL
);
8613 while (IS_BLANK_CH(*cur
)) cur
++;
8615 while ((!IS_BLANK_CH(*cur
)) && (*cur
!= 0))
8618 ID
= xmlStrndup(ids
, cur
- ids
);
8621 * We used to check the fact that the value passed
8622 * was an NCName, but this generated much troubles for
8623 * me and Aleksey Sanin, people blatantly violated that
8624 * constaint, like Visa3D spec.
8625 * if (xmlValidateNCName(ID, 1) == 0)
8627 attr
= xmlGetID(doc
, ID
);
8629 if (attr
->type
== XML_ATTRIBUTE_NODE
)
8630 elem
= attr
->parent
;
8631 else if (attr
->type
== XML_ELEMENT_NODE
)
8632 elem
= (xmlNodePtr
) attr
;
8636 xmlXPathNodeSetAdd(ret
, elem
);
8641 while (IS_BLANK_CH(*cur
)) cur
++;
8648 * xmlXPathIdFunction:
8649 * @ctxt: the XPath Parser context
8650 * @nargs: the number of arguments
8652 * Implement the id() XPath function
8653 * node-set id(object)
8654 * The id function selects elements by their unique ID
8655 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8656 * then the result is the union of the result of applying id to the
8657 * string value of each of the nodes in the argument node-set. When the
8658 * argument to id is of any other type, the argument is converted to a
8659 * string as if by a call to the string function; the string is split
8660 * into a whitespace-separated list of tokens (whitespace is any sequence
8661 * of characters matching the production S); the result is a node-set
8662 * containing the elements in the same document as the context node that
8663 * have a unique ID equal to any of the tokens in the list.
8666 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8669 xmlXPathObjectPtr obj
;
8672 obj
= valuePop(ctxt
);
8673 if (obj
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8674 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
8678 ret
= xmlXPathNodeSetCreate(NULL
);
8680 * FIXME -- in an out-of-memory condition this will behave badly.
8681 * The solution is not clear -- we already popped an item from
8682 * ctxt, so the object is in a corrupt state.
8685 if (obj
->nodesetval
!= NULL
) {
8686 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
8688 xmlXPathCastNodeToString(obj
->nodesetval
->nodeTab
[i
]);
8689 ns
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, tokens
);
8690 ret
= xmlXPathNodeSetMerge(ret
, ns
);
8691 xmlXPathFreeNodeSet(ns
);
8696 xmlXPathReleaseObject(ctxt
->context
, obj
);
8697 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8700 obj
= xmlXPathCacheConvertString(ctxt
->context
, obj
);
8701 ret
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, obj
->stringval
);
8702 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8703 xmlXPathReleaseObject(ctxt
->context
, obj
);
8708 * xmlXPathLocalNameFunction:
8709 * @ctxt: the XPath Parser context
8710 * @nargs: the number of arguments
8712 * Implement the local-name() XPath function
8713 * string local-name(node-set?)
8714 * The local-name function returns a string containing the local part
8715 * of the name of the node in the argument node-set that is first in
8716 * document order. If the node-set is empty or the first node has no
8717 * name, an empty string is returned. If the argument is omitted it
8718 * defaults to the context node.
8721 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8722 xmlXPathObjectPtr cur
;
8724 if (ctxt
== NULL
) return;
8727 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8728 ctxt
->context
->node
));
8733 if ((ctxt
->value
== NULL
) ||
8734 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8735 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8736 XP_ERROR(XPATH_INVALID_TYPE
);
8737 cur
= valuePop(ctxt
);
8739 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8740 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8742 int i
= 0; /* Should be first in document order !!!!! */
8743 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8744 case XML_ELEMENT_NODE
:
8745 case XML_ATTRIBUTE_NODE
:
8747 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8748 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8751 xmlXPathCacheNewString(ctxt
->context
,
8752 cur
->nodesetval
->nodeTab
[i
]->name
));
8754 case XML_NAMESPACE_DECL
:
8755 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8756 ((xmlNsPtr
)cur
->nodesetval
->nodeTab
[i
])->prefix
));
8759 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8762 xmlXPathReleaseObject(ctxt
->context
, cur
);
8766 * xmlXPathNamespaceURIFunction:
8767 * @ctxt: the XPath Parser context
8768 * @nargs: the number of arguments
8770 * Implement the namespace-uri() XPath function
8771 * string namespace-uri(node-set?)
8772 * The namespace-uri function returns a string containing the
8773 * namespace URI of the expanded name of the node in the argument
8774 * node-set that is first in document order. If the node-set is empty,
8775 * the first node has no name, or the expanded name has no namespace
8776 * URI, an empty string is returned. If the argument is omitted it
8777 * defaults to the context node.
8780 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8781 xmlXPathObjectPtr cur
;
8783 if (ctxt
== NULL
) return;
8786 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8787 ctxt
->context
->node
));
8791 if ((ctxt
->value
== NULL
) ||
8792 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8793 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8794 XP_ERROR(XPATH_INVALID_TYPE
);
8795 cur
= valuePop(ctxt
);
8797 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8798 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8800 int i
= 0; /* Should be first in document order !!!!! */
8801 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8802 case XML_ELEMENT_NODE
:
8803 case XML_ATTRIBUTE_NODE
:
8804 if (cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
)
8805 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8807 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8808 cur
->nodesetval
->nodeTab
[i
]->ns
->href
));
8811 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8814 xmlXPathReleaseObject(ctxt
->context
, cur
);
8818 * xmlXPathNameFunction:
8819 * @ctxt: the XPath Parser context
8820 * @nargs: the number of arguments
8822 * Implement the name() XPath function
8823 * string name(node-set?)
8824 * The name function returns a string containing a QName representing
8825 * the name of the node in the argument node-set that is first in document
8826 * order. The QName must represent the name with respect to the namespace
8827 * declarations in effect on the node whose name is being represented.
8828 * Typically, this will be the form in which the name occurred in the XML
8829 * source. This need not be the case if there are namespace declarations
8830 * in effect on the node that associate multiple prefixes with the same
8831 * namespace. However, an implementation may include information about
8832 * the original prefix in its representation of nodes; in this case, an
8833 * implementation can ensure that the returned string is always the same
8834 * as the QName used in the XML source. If the argument it omitted it
8835 * defaults to the context node.
8836 * Libxml keep the original prefix so the "real qualified name" used is
8840 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
8842 xmlXPathObjectPtr cur
;
8845 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8846 ctxt
->context
->node
));
8851 if ((ctxt
->value
== NULL
) ||
8852 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8853 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8854 XP_ERROR(XPATH_INVALID_TYPE
);
8855 cur
= valuePop(ctxt
);
8857 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8858 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8860 int i
= 0; /* Should be first in document order !!!!! */
8862 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8863 case XML_ELEMENT_NODE
:
8864 case XML_ATTRIBUTE_NODE
:
8865 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8867 xmlXPathCacheNewCString(ctxt
->context
, ""));
8868 else if ((cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
) ||
8869 (cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
== NULL
)) {
8871 xmlXPathCacheNewString(ctxt
->context
,
8872 cur
->nodesetval
->nodeTab
[i
]->name
));
8876 fullname
= xmlBuildQName(cur
->nodesetval
->nodeTab
[i
]->name
,
8877 cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
,
8879 if (fullname
== cur
->nodesetval
->nodeTab
[i
]->name
)
8880 fullname
= xmlStrdup(cur
->nodesetval
->nodeTab
[i
]->name
);
8881 if (fullname
== NULL
) {
8882 XP_ERROR(XPATH_MEMORY_ERROR
);
8884 valuePush(ctxt
, xmlXPathCacheWrapString(
8885 ctxt
->context
, fullname
));
8889 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8890 cur
->nodesetval
->nodeTab
[i
]));
8891 xmlXPathLocalNameFunction(ctxt
, 1);
8894 xmlXPathReleaseObject(ctxt
->context
, cur
);
8899 * xmlXPathStringFunction:
8900 * @ctxt: the XPath Parser context
8901 * @nargs: the number of arguments
8903 * Implement the string() XPath function
8904 * string string(object?)
8905 * The string function converts an object to a string as follows:
8906 * - A node-set is converted to a string by returning the value of
8907 * the node in the node-set that is first in document order.
8908 * If the node-set is empty, an empty string is returned.
8909 * - A number is converted to a string as follows
8910 * + NaN is converted to the string NaN
8911 * + positive zero is converted to the string 0
8912 * + negative zero is converted to the string 0
8913 * + positive infinity is converted to the string Infinity
8914 * + negative infinity is converted to the string -Infinity
8915 * + if the number is an integer, the number is represented in
8916 * decimal form as a Number with no decimal point and no leading
8917 * zeros, preceded by a minus sign (-) if the number is negative
8918 * + otherwise, the number is represented in decimal form as a
8919 * Number including a decimal point with at least one digit
8920 * before the decimal point and at least one digit after the
8921 * decimal point, preceded by a minus sign (-) if the number
8922 * is negative; there must be no leading zeros before the decimal
8923 * point apart possibly from the one required digit immediately
8924 * before the decimal point; beyond the one required digit
8925 * after the decimal point there must be as many, but only as
8926 * many, more digits as are needed to uniquely distinguish the
8927 * number from all other IEEE 754 numeric values.
8928 * - The boolean false value is converted to the string false.
8929 * The boolean true value is converted to the string true.
8931 * If the argument is omitted, it defaults to a node-set with the
8932 * context node as its only member.
8935 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8936 xmlXPathObjectPtr cur
;
8938 if (ctxt
== NULL
) return;
8941 xmlXPathCacheWrapString(ctxt
->context
,
8942 xmlXPathCastNodeToString(ctxt
->context
->node
)));
8947 cur
= valuePop(ctxt
);
8948 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8949 valuePush(ctxt
, xmlXPathCacheConvertString(ctxt
->context
, cur
));
8953 * xmlXPathStringLengthFunction:
8954 * @ctxt: the XPath Parser context
8955 * @nargs: the number of arguments
8957 * Implement the string-length() XPath function
8958 * number string-length(string?)
8959 * The string-length returns the number of characters in the string
8960 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8961 * the context node converted to a string, in other words the value
8962 * of the context node.
8965 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8966 xmlXPathObjectPtr cur
;
8969 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8971 if (ctxt
->context
->node
== NULL
) {
8972 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0));
8976 content
= xmlXPathCastNodeToString(ctxt
->context
->node
);
8977 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8978 xmlUTF8Strlen(content
)));
8985 CHECK_TYPE(XPATH_STRING
);
8986 cur
= valuePop(ctxt
);
8987 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8988 xmlUTF8Strlen(cur
->stringval
)));
8989 xmlXPathReleaseObject(ctxt
->context
, cur
);
8993 * xmlXPathConcatFunction:
8994 * @ctxt: the XPath Parser context
8995 * @nargs: the number of arguments
8997 * Implement the concat() XPath function
8998 * string concat(string, string, string*)
8999 * The concat function returns the concatenation of its arguments.
9002 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9003 xmlXPathObjectPtr cur
, newobj
;
9006 if (ctxt
== NULL
) return;
9012 cur
= valuePop(ctxt
);
9013 if ((cur
== NULL
) || (cur
->type
!= XPATH_STRING
)) {
9014 xmlXPathReleaseObject(ctxt
->context
, cur
);
9021 newobj
= valuePop(ctxt
);
9022 if ((newobj
== NULL
) || (newobj
->type
!= XPATH_STRING
)) {
9023 xmlXPathReleaseObject(ctxt
->context
, newobj
);
9024 xmlXPathReleaseObject(ctxt
->context
, cur
);
9025 XP_ERROR(XPATH_INVALID_TYPE
);
9027 tmp
= xmlStrcat(newobj
->stringval
, cur
->stringval
);
9028 newobj
->stringval
= cur
->stringval
;
9029 cur
->stringval
= tmp
;
9030 xmlXPathReleaseObject(ctxt
->context
, newobj
);
9033 valuePush(ctxt
, cur
);
9037 * xmlXPathContainsFunction:
9038 * @ctxt: the XPath Parser context
9039 * @nargs: the number of arguments
9041 * Implement the contains() XPath function
9042 * boolean contains(string, string)
9043 * The contains function returns true if the first argument string
9044 * contains the second argument string, and otherwise returns false.
9047 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9048 xmlXPathObjectPtr hay
, needle
;
9052 CHECK_TYPE(XPATH_STRING
);
9053 needle
= valuePop(ctxt
);
9055 hay
= valuePop(ctxt
);
9057 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9058 xmlXPathReleaseObject(ctxt
->context
, hay
);
9059 xmlXPathReleaseObject(ctxt
->context
, needle
);
9060 XP_ERROR(XPATH_INVALID_TYPE
);
9062 if (xmlStrstr(hay
->stringval
, needle
->stringval
))
9063 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9065 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9066 xmlXPathReleaseObject(ctxt
->context
, hay
);
9067 xmlXPathReleaseObject(ctxt
->context
, needle
);
9071 * xmlXPathStartsWithFunction:
9072 * @ctxt: the XPath Parser context
9073 * @nargs: the number of arguments
9075 * Implement the starts-with() XPath function
9076 * boolean starts-with(string, string)
9077 * The starts-with function returns true if the first argument string
9078 * starts with the second argument string, and otherwise returns false.
9081 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9082 xmlXPathObjectPtr hay
, needle
;
9087 CHECK_TYPE(XPATH_STRING
);
9088 needle
= valuePop(ctxt
);
9090 hay
= valuePop(ctxt
);
9092 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9093 xmlXPathReleaseObject(ctxt
->context
, hay
);
9094 xmlXPathReleaseObject(ctxt
->context
, needle
);
9095 XP_ERROR(XPATH_INVALID_TYPE
);
9097 n
= xmlStrlen(needle
->stringval
);
9098 if (xmlStrncmp(hay
->stringval
, needle
->stringval
, n
))
9099 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9101 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9102 xmlXPathReleaseObject(ctxt
->context
, hay
);
9103 xmlXPathReleaseObject(ctxt
->context
, needle
);
9107 * xmlXPathSubstringFunction:
9108 * @ctxt: the XPath Parser context
9109 * @nargs: the number of arguments
9111 * Implement the substring() XPath function
9112 * string substring(string, number, number?)
9113 * The substring function returns the substring of the first argument
9114 * starting at the position specified in the second argument with
9115 * length specified in the third argument. For example,
9116 * substring("12345",2,3) returns "234". If the third argument is not
9117 * specified, it returns the substring starting at the position specified
9118 * in the second argument and continuing to the end of the string. For
9119 * example, substring("12345",2) returns "2345". More precisely, each
9120 * character in the string (see [3.6 Strings]) is considered to have a
9121 * numeric position: the position of the first character is 1, the position
9122 * of the second character is 2 and so on. The returned substring contains
9123 * those characters for which the position of the character is greater than
9124 * or equal to the second argument and, if the third argument is specified,
9125 * less than the sum of the second and third arguments; the comparisons
9126 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9127 * - substring("12345", 1.5, 2.6) returns "234"
9128 * - substring("12345", 0, 3) returns "12"
9129 * - substring("12345", 0 div 0, 3) returns ""
9130 * - substring("12345", 1, 0 div 0) returns ""
9131 * - substring("12345", -42, 1 div 0) returns "12345"
9132 * - substring("12345", -1 div 0, 1 div 0) returns ""
9135 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9136 xmlXPathObjectPtr str
, start
, len
;
9148 * take care of possible last (position) argument
9152 CHECK_TYPE(XPATH_NUMBER
);
9153 len
= valuePop(ctxt
);
9155 xmlXPathReleaseObject(ctxt
->context
, len
);
9159 CHECK_TYPE(XPATH_NUMBER
);
9160 start
= valuePop(ctxt
);
9161 in
= start
->floatval
;
9162 xmlXPathReleaseObject(ctxt
->context
, start
);
9164 CHECK_TYPE(XPATH_STRING
);
9165 str
= valuePop(ctxt
);
9166 m
= xmlUTF8Strlen((const unsigned char *)str
->stringval
);
9169 * If last pos not present, calculate last position
9177 /* Need to check for the special cases where either
9178 * the index is NaN, the length is NaN, or both
9179 * arguments are infinity (relying on Inf + -Inf = NaN)
9181 if (!xmlXPathIsInf(in
) && !xmlXPathIsNaN(in
+ le
)) {
9183 * To meet the requirements of the spec, the arguments
9184 * must be converted to integer format before
9185 * initial index calculations are done
9187 * First we go to integer form, rounding up
9188 * and checking for special cases
9191 if (((double)i
)+0.5 <= in
) i
++;
9193 if (xmlXPathIsInf(le
) == 1) {
9198 else if (xmlXPathIsInf(le
) == -1 || le
< 0.0)
9202 if (((double)l
)+0.5 <= le
) l
++;
9205 /* Now we normalize inidices */
9213 /* number of chars to copy */
9216 ret
= xmlUTF8Strsub(str
->stringval
, i
, l
);
9222 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
9224 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, ret
));
9227 xmlXPathReleaseObject(ctxt
->context
, str
);
9231 * xmlXPathSubstringBeforeFunction:
9232 * @ctxt: the XPath Parser context
9233 * @nargs: the number of arguments
9235 * Implement the substring-before() XPath function
9236 * string substring-before(string, string)
9237 * The substring-before function returns the substring of the first
9238 * argument string that precedes the first occurrence of the second
9239 * argument string in the first argument string, or the empty string
9240 * if the first argument string does not contain the second argument
9241 * string. For example, substring-before("1999/04/01","/") returns 1999.
9244 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9245 xmlXPathObjectPtr str
;
9246 xmlXPathObjectPtr find
;
9248 const xmlChar
*point
;
9253 find
= valuePop(ctxt
);
9255 str
= valuePop(ctxt
);
9257 target
= xmlBufCreate();
9259 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9261 offset
= (int)(point
- str
->stringval
);
9262 xmlBufAdd(target
, str
->stringval
, offset
);
9264 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9265 xmlBufContent(target
)));
9268 xmlXPathReleaseObject(ctxt
->context
, str
);
9269 xmlXPathReleaseObject(ctxt
->context
, find
);
9273 * xmlXPathSubstringAfterFunction:
9274 * @ctxt: the XPath Parser context
9275 * @nargs: the number of arguments
9277 * Implement the substring-after() XPath function
9278 * string substring-after(string, string)
9279 * The substring-after function returns the substring of the first
9280 * argument string that follows the first occurrence of the second
9281 * argument string in the first argument string, or the empty stringi
9282 * if the first argument string does not contain the second argument
9283 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9284 * and substring-after("1999/04/01","19") returns 99/04/01.
9287 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9288 xmlXPathObjectPtr str
;
9289 xmlXPathObjectPtr find
;
9291 const xmlChar
*point
;
9296 find
= valuePop(ctxt
);
9298 str
= valuePop(ctxt
);
9300 target
= xmlBufCreate();
9302 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9304 offset
= (int)(point
- str
->stringval
) + xmlStrlen(find
->stringval
);
9305 xmlBufAdd(target
, &str
->stringval
[offset
],
9306 xmlStrlen(str
->stringval
) - offset
);
9308 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9309 xmlBufContent(target
)));
9312 xmlXPathReleaseObject(ctxt
->context
, str
);
9313 xmlXPathReleaseObject(ctxt
->context
, find
);
9317 * xmlXPathNormalizeFunction:
9318 * @ctxt: the XPath Parser context
9319 * @nargs: the number of arguments
9321 * Implement the normalize-space() XPath function
9322 * string normalize-space(string?)
9323 * The normalize-space function returns the argument string with white
9324 * space normalized by stripping leading and trailing whitespace
9325 * and replacing sequences of whitespace characters by a single
9326 * space. Whitespace characters are the same allowed by the S production
9327 * in XML. If the argument is omitted, it defaults to the context
9328 * node converted to a string, in other words the value of the context node.
9331 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9332 xmlXPathObjectPtr obj
= NULL
;
9333 xmlChar
*source
= NULL
;
9337 if (ctxt
== NULL
) return;
9339 /* Use current context node */
9341 xmlXPathCacheWrapString(ctxt
->context
,
9342 xmlXPathCastNodeToString(ctxt
->context
->node
)));
9348 CHECK_TYPE(XPATH_STRING
);
9349 obj
= valuePop(ctxt
);
9350 source
= obj
->stringval
;
9352 target
= xmlBufCreate();
9353 if (target
&& source
) {
9355 /* Skip leading whitespaces */
9356 while (IS_BLANK_CH(*source
))
9359 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9362 if (IS_BLANK_CH(*source
)) {
9366 xmlBufAdd(target
, &blank
, 1);
9369 xmlBufAdd(target
, source
, 1);
9373 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9374 xmlBufContent(target
)));
9377 xmlXPathReleaseObject(ctxt
->context
, obj
);
9381 * xmlXPathTranslateFunction:
9382 * @ctxt: the XPath Parser context
9383 * @nargs: the number of arguments
9385 * Implement the translate() XPath function
9386 * string translate(string, string, string)
9387 * The translate function returns the first argument string with
9388 * occurrences of characters in the second argument string replaced
9389 * by the character at the corresponding position in the third argument
9390 * string. For example, translate("bar","abc","ABC") returns the string
9391 * BAr. If there is a character in the second argument string with no
9392 * character at a corresponding position in the third argument string
9393 * (because the second argument string is longer than the third argument
9394 * string), then occurrences of that character in the first argument
9395 * string are removed. For example, translate("--aaa--","abc-","ABC")
9396 * returns "AAA". If a character occurs more than once in second
9397 * argument string, then the first occurrence determines the replacement
9398 * character. If the third argument string is longer than the second
9399 * argument string, then excess characters are ignored.
9402 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9403 xmlXPathObjectPtr str
;
9404 xmlXPathObjectPtr from
;
9405 xmlXPathObjectPtr to
;
9409 const xmlChar
*point
;
9415 to
= valuePop(ctxt
);
9417 from
= valuePop(ctxt
);
9419 str
= valuePop(ctxt
);
9421 target
= xmlBufCreate();
9423 max
= xmlUTF8Strlen(to
->stringval
);
9424 for (cptr
= str
->stringval
; (ch
=*cptr
); ) {
9425 offset
= xmlUTF8Strloc(from
->stringval
, cptr
);
9428 point
= xmlUTF8Strpos(to
->stringval
, offset
);
9430 xmlBufAdd(target
, point
, xmlUTF8Strsize(point
, 1));
9433 xmlBufAdd(target
, cptr
, xmlUTF8Strsize(cptr
, 1));
9435 /* Step to next character in input */
9438 /* if not simple ascii, verify proper format */
9439 if ( (ch
& 0xc0) != 0xc0 ) {
9440 xmlGenericError(xmlGenericErrorContext
,
9441 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9442 /* not asserting an XPath error is probably better */
9445 /* then skip over remaining bytes for this char */
9446 while ( (ch
<<= 1) & 0x80 )
9447 if ( (*cptr
++ & 0xc0) != 0x80 ) {
9448 xmlGenericError(xmlGenericErrorContext
,
9449 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9450 /* not asserting an XPath error is probably better */
9453 if (ch
& 0x80) /* must have had error encountered */
9458 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9459 xmlBufContent(target
)));
9461 xmlXPathReleaseObject(ctxt
->context
, str
);
9462 xmlXPathReleaseObject(ctxt
->context
, from
);
9463 xmlXPathReleaseObject(ctxt
->context
, to
);
9467 * xmlXPathBooleanFunction:
9468 * @ctxt: the XPath Parser context
9469 * @nargs: the number of arguments
9471 * Implement the boolean() XPath function
9472 * boolean boolean(object)
9473 * The boolean function converts its argument to a boolean as follows:
9474 * - a number is true if and only if it is neither positive or
9475 * negative zero nor NaN
9476 * - a node-set is true if and only if it is non-empty
9477 * - a string is true if and only if its length is non-zero
9480 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9481 xmlXPathObjectPtr cur
;
9484 cur
= valuePop(ctxt
);
9485 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
9486 cur
= xmlXPathCacheConvertBoolean(ctxt
->context
, cur
);
9487 valuePush(ctxt
, cur
);
9491 * xmlXPathNotFunction:
9492 * @ctxt: the XPath Parser context
9493 * @nargs: the number of arguments
9495 * Implement the not() XPath function
9496 * boolean not(boolean)
9497 * The not function returns true if its argument is false,
9498 * and false otherwise.
9501 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9504 CHECK_TYPE(XPATH_BOOLEAN
);
9505 ctxt
->value
->boolval
= ! ctxt
->value
->boolval
;
9509 * xmlXPathTrueFunction:
9510 * @ctxt: the XPath Parser context
9511 * @nargs: the number of arguments
9513 * Implement the true() XPath function
9517 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9519 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9523 * xmlXPathFalseFunction:
9524 * @ctxt: the XPath Parser context
9525 * @nargs: the number of arguments
9527 * Implement the false() XPath function
9531 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9533 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9537 * xmlXPathLangFunction:
9538 * @ctxt: the XPath Parser context
9539 * @nargs: the number of arguments
9541 * Implement the lang() XPath function
9542 * boolean lang(string)
9543 * The lang function returns true or false depending on whether the
9544 * language of the context node as specified by xml:lang attributes
9545 * is the same as or is a sublanguage of the language specified by
9546 * the argument string. The language of the context node is determined
9547 * by the value of the xml:lang attribute on the context node, or, if
9548 * the context node has no xml:lang attribute, by the value of the
9549 * xml:lang attribute on the nearest ancestor of the context node that
9550 * has an xml:lang attribute. If there is no such attribute, then lang
9551 * returns false. If there is such an attribute, then lang returns
9552 * true if the attribute value is equal to the argument ignoring case,
9553 * or if there is some suffix starting with - such that the attribute
9554 * value is equal to the argument ignoring that suffix of the attribute
9555 * value and ignoring case.
9558 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9559 xmlXPathObjectPtr val
= NULL
;
9560 const xmlChar
*theLang
= NULL
;
9561 const xmlChar
*lang
;
9567 CHECK_TYPE(XPATH_STRING
);
9568 val
= valuePop(ctxt
);
9569 lang
= val
->stringval
;
9570 theLang
= xmlNodeGetLang(ctxt
->context
->node
);
9571 if ((theLang
!= NULL
) && (lang
!= NULL
)) {
9572 for (i
= 0;lang
[i
] != 0;i
++)
9573 if (toupper(lang
[i
]) != toupper(theLang
[i
]))
9575 if ((theLang
[i
] == 0) || (theLang
[i
] == '-'))
9579 if (theLang
!= NULL
)
9580 xmlFree((void *)theLang
);
9582 xmlXPathReleaseObject(ctxt
->context
, val
);
9583 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
9587 * xmlXPathNumberFunction:
9588 * @ctxt: the XPath Parser context
9589 * @nargs: the number of arguments
9591 * Implement the number() XPath function
9592 * number number(object?)
9595 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9596 xmlXPathObjectPtr cur
;
9599 if (ctxt
== NULL
) return;
9601 if (ctxt
->context
->node
== NULL
) {
9602 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0.0));
9604 xmlChar
* content
= xmlNodeGetContent(ctxt
->context
->node
);
9606 res
= xmlXPathStringEvalNumber(content
);
9607 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9614 cur
= valuePop(ctxt
);
9615 valuePush(ctxt
, xmlXPathCacheConvertNumber(ctxt
->context
, cur
));
9619 * xmlXPathSumFunction:
9620 * @ctxt: the XPath Parser context
9621 * @nargs: the number of arguments
9623 * Implement the sum() XPath function
9624 * number sum(node-set)
9625 * The sum function returns the sum of the values of the nodes in
9626 * the argument node-set.
9629 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9630 xmlXPathObjectPtr cur
;
9635 if ((ctxt
->value
== NULL
) ||
9636 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
9637 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
9638 XP_ERROR(XPATH_INVALID_TYPE
);
9639 cur
= valuePop(ctxt
);
9641 if ((cur
->nodesetval
!= NULL
) && (cur
->nodesetval
->nodeNr
!= 0)) {
9642 for (i
= 0; i
< cur
->nodesetval
->nodeNr
; i
++) {
9643 res
+= xmlXPathCastNodeToNumber(cur
->nodesetval
->nodeTab
[i
]);
9646 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9647 xmlXPathReleaseObject(ctxt
->context
, cur
);
9651 * xmlXPathFloorFunction:
9652 * @ctxt: the XPath Parser context
9653 * @nargs: the number of arguments
9655 * Implement the floor() XPath function
9656 * number floor(number)
9657 * The floor function returns the largest (closest to positive infinity)
9658 * number that is not greater than the argument and that is an integer.
9661 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9664 CHECK_TYPE(XPATH_NUMBER
);
9666 ctxt
->value
->floatval
= floor(ctxt
->value
->floatval
);
9670 * xmlXPathCeilingFunction:
9671 * @ctxt: the XPath Parser context
9672 * @nargs: the number of arguments
9674 * Implement the ceiling() XPath function
9675 * number ceiling(number)
9676 * The ceiling function returns the smallest (closest to negative infinity)
9677 * number that is not less than the argument and that is an integer.
9680 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9683 CHECK_TYPE(XPATH_NUMBER
);
9685 ctxt
->value
->floatval
= ceil(ctxt
->value
->floatval
);
9689 * xmlXPathRoundFunction:
9690 * @ctxt: the XPath Parser context
9691 * @nargs: the number of arguments
9693 * Implement the round() XPath function
9694 * number round(number)
9695 * The round function returns the number that is closest to the
9696 * argument and that is an integer. If there are two such numbers,
9697 * then the one that is closest to positive infinity is returned.
9700 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9705 CHECK_TYPE(XPATH_NUMBER
);
9707 f
= ctxt
->value
->floatval
;
9709 if ((f
>= -0.5) && (f
< 0.5)) {
9710 /* Handles negative zero. */
9711 ctxt
->value
->floatval
*= 0.0;
9714 double rounded
= floor(f
);
9715 if (f
- rounded
>= 0.5)
9717 ctxt
->value
->floatval
= rounded
;
9721 /************************************************************************
9725 ************************************************************************/
9728 * a few forward declarations since we use a recursive call based
9731 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
);
9732 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
);
9733 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
);
9734 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt
);
9735 static xmlChar
* xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
,
9739 * xmlXPathCurrentChar:
9740 * @ctxt: the XPath parser context
9741 * @cur: pointer to the beginning of the char
9742 * @len: pointer to the length of the char read
9744 * The current char value, if using UTF-8 this may actually span multiple
9745 * bytes in the input buffer.
9747 * Returns the current char value and its length
9751 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt
, int *len
) {
9761 * We are supposed to handle UTF8, check it's valid
9762 * From rfc2044: encoding of the Unicode values on UTF-8:
9764 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9765 * 0000 0000-0000 007F 0xxxxxxx
9766 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9767 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9769 * Check for the 0x110000 limit too
9773 if ((cur
[1] & 0xc0) != 0x80)
9774 goto encoding_error
;
9775 if ((c
& 0xe0) == 0xe0) {
9777 if ((cur
[2] & 0xc0) != 0x80)
9778 goto encoding_error
;
9779 if ((c
& 0xf0) == 0xf0) {
9780 if (((c
& 0xf8) != 0xf0) ||
9781 ((cur
[3] & 0xc0) != 0x80))
9782 goto encoding_error
;
9785 val
= (cur
[0] & 0x7) << 18;
9786 val
|= (cur
[1] & 0x3f) << 12;
9787 val
|= (cur
[2] & 0x3f) << 6;
9788 val
|= cur
[3] & 0x3f;
9792 val
= (cur
[0] & 0xf) << 12;
9793 val
|= (cur
[1] & 0x3f) << 6;
9794 val
|= cur
[2] & 0x3f;
9799 val
= (cur
[0] & 0x1f) << 6;
9800 val
|= cur
[1] & 0x3f;
9802 if (!IS_CHAR(val
)) {
9803 XP_ERROR0(XPATH_INVALID_CHAR_ERROR
);
9813 * If we detect an UTF8 error that probably means that the
9814 * input encoding didn't get properly advertised in the
9815 * declaration header. Report the error and switch the encoding
9816 * to ISO-Latin-1 (if you don't like this policy, just declare the
9820 XP_ERROR0(XPATH_ENCODING_ERROR
);
9824 * xmlXPathParseNCName:
9825 * @ctxt: the XPath Parser context
9827 * parse an XML namespace non qualified name.
9829 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9831 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9832 * CombiningChar | Extender
9834 * Returns the namespace name or NULL
9838 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt
) {
9843 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9845 * Accelerator for simple ASCII names
9848 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9849 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9852 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9853 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9854 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9855 (*in
== '_') || (*in
== '.') ||
9858 if ((*in
== ' ') || (*in
== '>') || (*in
== '/') ||
9859 (*in
== '[') || (*in
== ']') || (*in
== ':') ||
9860 (*in
== '@') || (*in
== '*')) {
9861 count
= in
- ctxt
->cur
;
9864 ret
= xmlStrndup(ctxt
->cur
, count
);
9869 return(xmlXPathParseNameComplex(ctxt
, 0));
9874 * xmlXPathParseQName:
9875 * @ctxt: the XPath Parser context
9876 * @prefix: a xmlChar **
9878 * parse an XML qualified name
9880 * [NS 5] QName ::= (Prefix ':')? LocalPart
9882 * [NS 6] Prefix ::= NCName
9884 * [NS 7] LocalPart ::= NCName
9886 * Returns the function returns the local part, and prefix is updated
9887 * to get the Prefix if any.
9891 xmlXPathParseQName(xmlXPathParserContextPtr ctxt
, xmlChar
**prefix
) {
9892 xmlChar
*ret
= NULL
;
9895 ret
= xmlXPathParseNCName(ctxt
);
9896 if (ret
&& CUR
== ':') {
9899 ret
= xmlXPathParseNCName(ctxt
);
9905 * xmlXPathParseName:
9906 * @ctxt: the XPath Parser context
9910 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9911 * CombiningChar | Extender
9913 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9915 * Returns the namespace name or NULL
9919 xmlXPathParseName(xmlXPathParserContextPtr ctxt
) {
9924 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9926 * Accelerator for simple ASCII names
9929 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9930 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9931 (*in
== '_') || (*in
== ':')) {
9933 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9934 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9935 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9936 (*in
== '_') || (*in
== '-') ||
9937 (*in
== ':') || (*in
== '.'))
9939 if ((*in
> 0) && (*in
< 0x80)) {
9940 count
= in
- ctxt
->cur
;
9941 if (count
> XML_MAX_NAME_LENGTH
) {
9943 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9945 ret
= xmlStrndup(ctxt
->cur
, count
);
9950 return(xmlXPathParseNameComplex(ctxt
, 1));
9954 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
, int qualified
) {
9955 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
9960 * Handler for more complex cases
9963 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
9964 (c
== '[') || (c
== ']') || (c
== '@') || /* accelerators */
9965 (c
== '*') || /* accelerators */
9966 (!IS_LETTER(c
) && (c
!= '_') &&
9967 ((!qualified
) || (c
!= ':')))) {
9971 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
9972 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
9973 (c
== '.') || (c
== '-') ||
9974 (c
== '_') || ((qualified
) && (c
== ':')) ||
9975 (IS_COMBINING(c
)) ||
9976 (IS_EXTENDER(c
)))) {
9977 COPY_BUF(l
,buf
,len
,c
);
9980 if (len
>= XML_MAX_NAMELEN
) {
9982 * Okay someone managed to make a huge name, so he's ready to pay
9983 * for the processing speed.
9988 if (len
> XML_MAX_NAME_LENGTH
) {
9989 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9991 buffer
= (xmlChar
*) xmlMallocAtomic(max
* sizeof(xmlChar
));
9992 if (buffer
== NULL
) {
9993 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
9995 memcpy(buffer
, buf
, len
);
9996 while ((IS_LETTER(c
)) || (IS_DIGIT(c
)) || /* test bigname.xml */
9997 (c
== '.') || (c
== '-') ||
9998 (c
== '_') || ((qualified
) && (c
== ':')) ||
9999 (IS_COMBINING(c
)) ||
10000 (IS_EXTENDER(c
))) {
10001 if (len
+ 10 > max
) {
10002 if (max
> XML_MAX_NAME_LENGTH
) {
10003 XP_ERRORNULL(XPATH_EXPR_ERROR
);
10006 buffer
= (xmlChar
*) xmlRealloc(buffer
,
10007 max
* sizeof(xmlChar
));
10008 if (buffer
== NULL
) {
10009 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
10012 COPY_BUF(l
,buffer
,len
,c
);
10022 return(xmlStrndup(buf
, len
));
10025 #define MAX_FRAC 20
10028 * xmlXPathStringEvalNumber:
10029 * @str: A string to scan
10031 * [30a] Float ::= Number ('e' Digits?)?
10033 * [30] Number ::= Digits ('.' Digits?)?
10035 * [31] Digits ::= [0-9]+
10037 * Compile a Number in the string
10038 * In complement of the Number expression, this function also handles
10039 * negative values : '-' Number.
10041 * Returns the double value.
10044 xmlXPathStringEvalNumber(const xmlChar
*str
) {
10045 const xmlChar
*cur
= str
;
10050 int is_exponent_negative
= 0;
10052 unsigned long tmp
= 0;
10055 if (cur
== NULL
) return(0);
10056 while (IS_BLANK_CH(*cur
)) cur
++;
10057 if ((*cur
!= '.') && ((*cur
< '0') || (*cur
> '9')) && (*cur
!= '-')) {
10067 * tmp/temp is a workaround against a gcc compiler bug
10068 * http://veillard.com/gcc.bug
10071 while ((*cur
>= '0') && (*cur
<= '9')) {
10073 tmp
= (*cur
- '0');
10076 temp
= (double) tmp
;
10081 while ((*cur
>= '0') && (*cur
<= '9')) {
10082 ret
= ret
* 10 + (*cur
- '0');
10089 int v
, frac
= 0, max
;
10090 double fraction
= 0;
10093 if (((*cur
< '0') || (*cur
> '9')) && (!ok
)) {
10096 while (*cur
== '0') {
10100 max
= frac
+ MAX_FRAC
;
10101 while (((*cur
>= '0') && (*cur
<= '9')) && (frac
< max
)) {
10103 fraction
= fraction
* 10 + v
;
10107 fraction
/= pow(10.0, frac
);
10108 ret
= ret
+ fraction
;
10109 while ((*cur
>= '0') && (*cur
<= '9'))
10112 if ((*cur
== 'e') || (*cur
== 'E')) {
10115 is_exponent_negative
= 1;
10117 } else if (*cur
== '+') {
10120 while ((*cur
>= '0') && (*cur
<= '9')) {
10121 if (exponent
< 1000000)
10122 exponent
= exponent
* 10 + (*cur
- '0');
10126 while (IS_BLANK_CH(*cur
)) cur
++;
10127 if (*cur
!= 0) return(NAN
);
10128 if (isneg
) ret
= -ret
;
10129 if (is_exponent_negative
) exponent
= -exponent
;
10130 ret
*= pow(10.0, (double)exponent
);
10135 * xmlXPathCompNumber:
10136 * @ctxt: the XPath Parser context
10138 * [30] Number ::= Digits ('.' Digits?)?
10140 * [31] Digits ::= [0-9]+
10142 * Compile a Number, then push it on the stack
10146 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt
)
10151 int is_exponent_negative
= 0;
10153 unsigned long tmp
= 0;
10158 if ((CUR
!= '.') && ((CUR
< '0') || (CUR
> '9'))) {
10159 XP_ERROR(XPATH_NUMBER_ERROR
);
10163 * tmp/temp is a workaround against a gcc compiler bug
10164 * http://veillard.com/gcc.bug
10167 while ((CUR
>= '0') && (CUR
<= '9')) {
10172 temp
= (double) tmp
;
10177 while ((CUR
>= '0') && (CUR
<= '9')) {
10178 ret
= ret
* 10 + (CUR
- '0');
10184 int v
, frac
= 0, max
;
10185 double fraction
= 0;
10188 if (((CUR
< '0') || (CUR
> '9')) && (!ok
)) {
10189 XP_ERROR(XPATH_NUMBER_ERROR
);
10191 while (CUR
== '0') {
10195 max
= frac
+ MAX_FRAC
;
10196 while ((CUR
>= '0') && (CUR
<= '9') && (frac
< max
)) {
10198 fraction
= fraction
* 10 + v
;
10202 fraction
/= pow(10.0, frac
);
10203 ret
= ret
+ fraction
;
10204 while ((CUR
>= '0') && (CUR
<= '9'))
10207 if ((CUR
== 'e') || (CUR
== 'E')) {
10210 is_exponent_negative
= 1;
10212 } else if (CUR
== '+') {
10215 while ((CUR
>= '0') && (CUR
<= '9')) {
10216 if (exponent
< 1000000)
10217 exponent
= exponent
* 10 + (CUR
- '0');
10220 if (is_exponent_negative
)
10221 exponent
= -exponent
;
10222 ret
*= pow(10.0, (double) exponent
);
10224 PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_NUMBER
, 0, 0,
10225 xmlXPathCacheNewFloat(ctxt
->context
, ret
), NULL
);
10229 * xmlXPathParseLiteral:
10230 * @ctxt: the XPath Parser context
10234 * [29] Literal ::= '"' [^"]* '"'
10237 * Returns the value found or NULL in case of error
10240 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt
) {
10242 xmlChar
*ret
= NULL
;
10247 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10249 if (!IS_CHAR_CH(CUR
)) {
10250 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10252 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10255 } else if (CUR
== '\'') {
10258 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10260 if (!IS_CHAR_CH(CUR
)) {
10261 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10263 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10267 XP_ERRORNULL(XPATH_START_LITERAL_ERROR
);
10273 * xmlXPathCompLiteral:
10274 * @ctxt: the XPath Parser context
10276 * Parse a Literal and push it on the stack.
10278 * [29] Literal ::= '"' [^"]* '"'
10281 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10284 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt
) {
10286 xmlChar
*ret
= NULL
;
10291 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10293 if (!IS_CHAR_CH(CUR
)) {
10294 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10296 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10299 } else if (CUR
== '\'') {
10302 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10304 if (!IS_CHAR_CH(CUR
)) {
10305 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10307 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10311 XP_ERROR(XPATH_START_LITERAL_ERROR
);
10313 if (ret
== NULL
) return;
10314 PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_STRING
, 0, 0,
10315 xmlXPathCacheNewString(ctxt
->context
, ret
), NULL
);
10320 * xmlXPathCompVariableReference:
10321 * @ctxt: the XPath Parser context
10323 * Parse a VariableReference, evaluate it and push it on the stack.
10325 * The variable bindings consist of a mapping from variable names
10326 * to variable values. The value of a variable is an object, which can be
10327 * of any of the types that are possible for the value of an expression,
10328 * and may also be of additional types not specified here.
10330 * Early evaluation is possible since:
10331 * The variable bindings [...] used to evaluate a subexpression are
10332 * always the same as those used to evaluate the containing expression.
10334 * [36] VariableReference ::= '$' QName
10337 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt
) {
10343 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10346 name
= xmlXPathParseQName(ctxt
, &prefix
);
10347 if (name
== NULL
) {
10349 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10351 ctxt
->comp
->last
= -1;
10352 PUSH_LONG_EXPR(XPATH_OP_VARIABLE
, 0, 0, 0,
10355 if ((ctxt
->context
!= NULL
) && (ctxt
->context
->flags
& XML_XPATH_NOVAR
)) {
10356 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR
);
10361 * xmlXPathIsNodeType:
10362 * @name: a name string
10364 * Is the name given a NodeType one.
10366 * [38] NodeType ::= 'comment'
10368 * | 'processing-instruction'
10371 * Returns 1 if true 0 otherwise
10374 xmlXPathIsNodeType(const xmlChar
*name
) {
10378 if (xmlStrEqual(name
, BAD_CAST
"node"))
10380 if (xmlStrEqual(name
, BAD_CAST
"text"))
10382 if (xmlStrEqual(name
, BAD_CAST
"comment"))
10384 if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
10390 * xmlXPathCompFunctionCall:
10391 * @ctxt: the XPath Parser context
10393 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10394 * [17] Argument ::= Expr
10396 * Compile a function call, the evaluation of all arguments are
10397 * pushed on the stack
10400 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt
) {
10406 name
= xmlXPathParseQName(ctxt
, &prefix
);
10407 if (name
== NULL
) {
10409 XP_ERROR(XPATH_EXPR_ERROR
);
10413 if (prefix
== NULL
)
10414 xmlGenericError(xmlGenericErrorContext
, "Calling function %s\n",
10417 xmlGenericError(xmlGenericErrorContext
, "Calling function %s:%s\n",
10424 XP_ERROR(XPATH_EXPR_ERROR
);
10430 * Optimization for count(): we don't need the node-set to be sorted.
10432 if ((prefix
== NULL
) && (name
[0] == 'c') &&
10433 xmlStrEqual(name
, BAD_CAST
"count"))
10437 ctxt
->comp
->last
= -1;
10440 int op1
= ctxt
->comp
->last
;
10441 ctxt
->comp
->last
= -1;
10442 xmlXPathCompileExpr(ctxt
, sort
);
10443 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
10448 PUSH_BINARY_EXPR(XPATH_OP_ARG
, op1
, ctxt
->comp
->last
, 0, 0);
10450 if (CUR
== ')') break;
10454 XP_ERROR(XPATH_EXPR_ERROR
);
10460 PUSH_LONG_EXPR(XPATH_OP_FUNCTION
, nbargs
, 0, 0,
10467 * xmlXPathCompPrimaryExpr:
10468 * @ctxt: the XPath Parser context
10470 * [15] PrimaryExpr ::= VariableReference
10476 * Compile a primary expression.
10479 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt
) {
10481 if (CUR
== '$') xmlXPathCompVariableReference(ctxt
);
10482 else if (CUR
== '(') {
10485 xmlXPathCompileExpr(ctxt
, 1);
10488 XP_ERROR(XPATH_EXPR_ERROR
);
10492 } else if (IS_ASCII_DIGIT(CUR
) || (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10493 xmlXPathCompNumber(ctxt
);
10494 } else if ((CUR
== '\'') || (CUR
== '"')) {
10495 xmlXPathCompLiteral(ctxt
);
10497 xmlXPathCompFunctionCall(ctxt
);
10503 * xmlXPathCompFilterExpr:
10504 * @ctxt: the XPath Parser context
10506 * [20] FilterExpr ::= PrimaryExpr
10507 * | FilterExpr Predicate
10509 * Compile a filter expression.
10510 * Square brackets are used to filter expressions in the same way that
10511 * they are used in location paths. It is an error if the expression to
10512 * be filtered does not evaluate to a node-set. The context node list
10513 * used for evaluating the expression in square brackets is the node-set
10514 * to be filtered listed in document order.
10518 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt
) {
10519 xmlXPathCompPrimaryExpr(ctxt
);
10523 while (CUR
== '[') {
10524 xmlXPathCompPredicate(ctxt
, 1);
10532 * xmlXPathScanName:
10533 * @ctxt: the XPath Parser context
10535 * Trickery: parse an XML name but without consuming the input flow
10536 * Needed to avoid insanity in the parser state.
10538 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10539 * CombiningChar | Extender
10541 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10543 * [6] Names ::= Name (S Name)*
10545 * Returns the Name parsed or NULL
10549 xmlXPathScanName(xmlXPathParserContextPtr ctxt
) {
10552 const xmlChar
*cur
;
10558 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
10559 (!IS_LETTER(c
) && (c
!= '_') &&
10564 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
10565 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
10566 (c
== '.') || (c
== '-') ||
10567 (c
== '_') || (c
== ':') ||
10568 (IS_COMBINING(c
)) ||
10569 (IS_EXTENDER(c
)))) {
10574 ret
= xmlStrndup(cur
, ctxt
->cur
- cur
);
10580 * xmlXPathCompPathExpr:
10581 * @ctxt: the XPath Parser context
10583 * [19] PathExpr ::= LocationPath
10585 * | FilterExpr '/' RelativeLocationPath
10586 * | FilterExpr '//' RelativeLocationPath
10588 * Compile a path expression.
10589 * The / operator and // operators combine an arbitrary expression
10590 * and a relative location path. It is an error if the expression
10591 * does not evaluate to a node-set.
10592 * The / operator does composition in the same way as when / is
10593 * used in a location path. As in location paths, // is short for
10594 * /descendant-or-self::node()/.
10598 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt
) {
10599 int lc
= 1; /* Should we branch to LocationPath ? */
10600 xmlChar
*name
= NULL
; /* we may have to preparse a name to find out */
10603 if ((CUR
== '$') || (CUR
== '(') ||
10604 (IS_ASCII_DIGIT(CUR
)) ||
10605 (CUR
== '\'') || (CUR
== '"') ||
10606 (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10608 } else if (CUR
== '*') {
10609 /* relative or absolute location path */
10611 } else if (CUR
== '/') {
10612 /* relative or absolute location path */
10614 } else if (CUR
== '@') {
10615 /* relative abbreviated attribute location path */
10617 } else if (CUR
== '.') {
10618 /* relative abbreviated attribute location path */
10622 * Problem is finding if we have a name here whether it's:
10624 * - a function call in which case it's followed by '('
10625 * - an axis in which case it's followed by ':'
10627 * We do an a priori analysis here rather than having to
10628 * maintain parsed token content through the recursive function
10629 * calls. This looks uglier but makes the code easier to
10630 * read/write/debug.
10633 name
= xmlXPathScanName(ctxt
);
10634 if ((name
!= NULL
) && (xmlStrstr(name
, (xmlChar
*) "::") != NULL
)) {
10636 xmlGenericError(xmlGenericErrorContext
,
10637 "PathExpr: Axis\n");
10641 } else if (name
!= NULL
) {
10642 int len
=xmlStrlen(name
);
10645 while (NXT(len
) != 0) {
10646 if (NXT(len
) == '/') {
10649 xmlGenericError(xmlGenericErrorContext
,
10650 "PathExpr: AbbrRelLocation\n");
10654 } else if (IS_BLANK_CH(NXT(len
))) {
10655 /* ignore blanks */
10657 } else if (NXT(len
) == ':') {
10659 xmlGenericError(xmlGenericErrorContext
,
10660 "PathExpr: AbbrRelLocation\n");
10664 } else if ((NXT(len
) == '(')) {
10665 /* Node Type or Function */
10666 if (xmlXPathIsNodeType(name
)) {
10668 xmlGenericError(xmlGenericErrorContext
,
10669 "PathExpr: Type search\n");
10672 #ifdef LIBXML_XPTR_ENABLED
10673 } else if (ctxt
->xptr
&&
10674 xmlStrEqual(name
, BAD_CAST
"range-to")) {
10679 xmlGenericError(xmlGenericErrorContext
,
10680 "PathExpr: function call\n");
10685 } else if ((NXT(len
) == '[')) {
10688 xmlGenericError(xmlGenericErrorContext
,
10689 "PathExpr: AbbrRelLocation\n");
10693 } else if ((NXT(len
) == '<') || (NXT(len
) == '>') ||
10694 (NXT(len
) == '=')) {
10703 if (NXT(len
) == 0) {
10705 xmlGenericError(xmlGenericErrorContext
,
10706 "PathExpr: AbbrRelLocation\n");
10713 /* make sure all cases are covered explicitly */
10714 XP_ERROR(XPATH_EXPR_ERROR
);
10720 PUSH_LEAVE_EXPR(XPATH_OP_ROOT
, 0, 0);
10722 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10724 xmlXPathCompLocationPath(ctxt
);
10726 xmlXPathCompFilterExpr(ctxt
);
10728 if ((CUR
== '/') && (NXT(1) == '/')) {
10732 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
10733 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
10735 xmlXPathCompRelativeLocationPath(ctxt
);
10736 } else if (CUR
== '/') {
10737 xmlXPathCompRelativeLocationPath(ctxt
);
10744 * xmlXPathCompUnionExpr:
10745 * @ctxt: the XPath Parser context
10747 * [18] UnionExpr ::= PathExpr
10748 * | UnionExpr '|' PathExpr
10750 * Compile an union expression.
10754 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt
) {
10755 xmlXPathCompPathExpr(ctxt
);
10758 while (CUR
== '|') {
10759 int op1
= ctxt
->comp
->last
;
10760 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10764 xmlXPathCompPathExpr(ctxt
);
10766 PUSH_BINARY_EXPR(XPATH_OP_UNION
, op1
, ctxt
->comp
->last
, 0, 0);
10773 * xmlXPathCompUnaryExpr:
10774 * @ctxt: the XPath Parser context
10776 * [27] UnaryExpr ::= UnionExpr
10779 * Compile an unary expression.
10783 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt
) {
10788 while (CUR
== '-') {
10795 xmlXPathCompUnionExpr(ctxt
);
10799 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 2, 0);
10801 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 3, 0);
10806 * xmlXPathCompMultiplicativeExpr:
10807 * @ctxt: the XPath Parser context
10809 * [26] MultiplicativeExpr ::= UnaryExpr
10810 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10811 * | MultiplicativeExpr 'div' UnaryExpr
10812 * | MultiplicativeExpr 'mod' UnaryExpr
10813 * [34] MultiplyOperator ::= '*'
10815 * Compile an Additive expression.
10819 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt
) {
10820 xmlXPathCompUnaryExpr(ctxt
);
10823 while ((CUR
== '*') ||
10824 ((CUR
== 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10825 ((CUR
== 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10827 int op1
= ctxt
->comp
->last
;
10832 } else if (CUR
== 'd') {
10835 } else if (CUR
== 'm') {
10840 xmlXPathCompUnaryExpr(ctxt
);
10842 PUSH_BINARY_EXPR(XPATH_OP_MULT
, op1
, ctxt
->comp
->last
, op
, 0);
10848 * xmlXPathCompAdditiveExpr:
10849 * @ctxt: the XPath Parser context
10851 * [25] AdditiveExpr ::= MultiplicativeExpr
10852 * | AdditiveExpr '+' MultiplicativeExpr
10853 * | AdditiveExpr '-' MultiplicativeExpr
10855 * Compile an Additive expression.
10859 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt
) {
10861 xmlXPathCompMultiplicativeExpr(ctxt
);
10864 while ((CUR
== '+') || (CUR
== '-')) {
10866 int op1
= ctxt
->comp
->last
;
10868 if (CUR
== '+') plus
= 1;
10872 xmlXPathCompMultiplicativeExpr(ctxt
);
10874 PUSH_BINARY_EXPR(XPATH_OP_PLUS
, op1
, ctxt
->comp
->last
, plus
, 0);
10880 * xmlXPathCompRelationalExpr:
10881 * @ctxt: the XPath Parser context
10883 * [24] RelationalExpr ::= AdditiveExpr
10884 * | RelationalExpr '<' AdditiveExpr
10885 * | RelationalExpr '>' AdditiveExpr
10886 * | RelationalExpr '<=' AdditiveExpr
10887 * | RelationalExpr '>=' AdditiveExpr
10889 * A <= B > C is allowed ? Answer from James, yes with
10890 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10891 * which is basically what got implemented.
10893 * Compile a Relational expression, then push the result
10898 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt
) {
10899 xmlXPathCompAdditiveExpr(ctxt
);
10902 while ((CUR
== '<') ||
10904 ((CUR
== '<') && (NXT(1) == '=')) ||
10905 ((CUR
== '>') && (NXT(1) == '='))) {
10907 int op1
= ctxt
->comp
->last
;
10909 if (CUR
== '<') inf
= 1;
10911 if (NXT(1) == '=') strict
= 0;
10916 xmlXPathCompAdditiveExpr(ctxt
);
10918 PUSH_BINARY_EXPR(XPATH_OP_CMP
, op1
, ctxt
->comp
->last
, inf
, strict
);
10924 * xmlXPathCompEqualityExpr:
10925 * @ctxt: the XPath Parser context
10927 * [23] EqualityExpr ::= RelationalExpr
10928 * | EqualityExpr '=' RelationalExpr
10929 * | EqualityExpr '!=' RelationalExpr
10931 * A != B != C is allowed ? Answer from James, yes with
10932 * (RelationalExpr = RelationalExpr) = RelationalExpr
10933 * (RelationalExpr != RelationalExpr) != RelationalExpr
10934 * which is basically what got implemented.
10936 * Compile an Equality expression.
10940 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt
) {
10941 xmlXPathCompRelationalExpr(ctxt
);
10944 while ((CUR
== '=') || ((CUR
== '!') && (NXT(1) == '='))) {
10946 int op1
= ctxt
->comp
->last
;
10948 if (CUR
== '=') eq
= 1;
10953 xmlXPathCompRelationalExpr(ctxt
);
10955 PUSH_BINARY_EXPR(XPATH_OP_EQUAL
, op1
, ctxt
->comp
->last
, eq
, 0);
10961 * xmlXPathCompAndExpr:
10962 * @ctxt: the XPath Parser context
10964 * [22] AndExpr ::= EqualityExpr
10965 * | AndExpr 'and' EqualityExpr
10967 * Compile an AND expression.
10971 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt
) {
10972 xmlXPathCompEqualityExpr(ctxt
);
10975 while ((CUR
== 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10976 int op1
= ctxt
->comp
->last
;
10979 xmlXPathCompEqualityExpr(ctxt
);
10981 PUSH_BINARY_EXPR(XPATH_OP_AND
, op1
, ctxt
->comp
->last
, 0, 0);
10987 * xmlXPathCompileExpr:
10988 * @ctxt: the XPath Parser context
10990 * [14] Expr ::= OrExpr
10991 * [21] OrExpr ::= AndExpr
10992 * | OrExpr 'or' AndExpr
10994 * Parse and compile an expression
10997 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
) {
10998 xmlXPathCompAndExpr(ctxt
);
11001 while ((CUR
== 'o') && (NXT(1) == 'r')) {
11002 int op1
= ctxt
->comp
->last
;
11005 xmlXPathCompAndExpr(ctxt
);
11007 PUSH_BINARY_EXPR(XPATH_OP_OR
, op1
, ctxt
->comp
->last
, 0, 0);
11010 if ((sort
) && (ctxt
->comp
->steps
[ctxt
->comp
->last
].op
!= XPATH_OP_VALUE
)) {
11011 /* more ops could be optimized too */
11013 * This is the main place to eliminate sorting for
11014 * operations which don't require a sorted node-set.
11017 PUSH_UNARY_EXPR(XPATH_OP_SORT
, ctxt
->comp
->last
, 0, 0);
11022 * xmlXPathCompPredicate:
11023 * @ctxt: the XPath Parser context
11024 * @filter: act as a filter
11026 * [8] Predicate ::= '[' PredicateExpr ']'
11027 * [9] PredicateExpr ::= Expr
11029 * Compile a predicate expression
11032 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
) {
11033 int op1
= ctxt
->comp
->last
;
11037 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11042 ctxt
->comp
->last
= -1;
11044 * This call to xmlXPathCompileExpr() will deactivate sorting
11045 * of the predicate result.
11046 * TODO: Sorting is still activated for filters, since I'm not
11047 * sure if needed. Normally sorting should not be needed, since
11048 * a filter can only diminish the number of items in a sequence,
11049 * but won't change its order; so if the initial sequence is sorted,
11050 * subsequent sorting is not needed.
11053 xmlXPathCompileExpr(ctxt
, 0);
11055 xmlXPathCompileExpr(ctxt
, 1);
11059 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11063 PUSH_BINARY_EXPR(XPATH_OP_FILTER
, op1
, ctxt
->comp
->last
, 0, 0);
11065 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE
, op1
, ctxt
->comp
->last
, 0, 0);
11072 * xmlXPathCompNodeTest:
11073 * @ctxt: the XPath Parser context
11074 * @test: pointer to a xmlXPathTestVal
11075 * @type: pointer to a xmlXPathTypeVal
11076 * @prefix: placeholder for a possible name prefix
11078 * [7] NodeTest ::= NameTest
11079 * | NodeType '(' ')'
11080 * | 'processing-instruction' '(' Literal ')'
11082 * [37] NameTest ::= '*'
11085 * [38] NodeType ::= 'comment'
11087 * | 'processing-instruction'
11090 * Returns the name found and updates @test, @type and @prefix appropriately
11093 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt
, xmlXPathTestVal
*test
,
11094 xmlXPathTypeVal
*type
, const xmlChar
**prefix
,
11098 if ((test
== NULL
) || (type
== NULL
) || (prefix
== NULL
)) {
11102 *type
= (xmlXPathTypeVal
) 0;
11103 *test
= (xmlXPathTestVal
) 0;
11107 if ((name
== NULL
) && (CUR
== '*')) {
11112 *test
= NODE_TEST_ALL
;
11117 name
= xmlXPathParseNCName(ctxt
);
11118 if (name
== NULL
) {
11119 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11122 blanks
= IS_BLANK_CH(CUR
);
11127 * NodeType or PI search
11129 if (xmlStrEqual(name
, BAD_CAST
"comment"))
11130 *type
= NODE_TYPE_COMMENT
;
11131 else if (xmlStrEqual(name
, BAD_CAST
"node"))
11132 *type
= NODE_TYPE_NODE
;
11133 else if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
11134 *type
= NODE_TYPE_PI
;
11135 else if (xmlStrEqual(name
, BAD_CAST
"text"))
11136 *type
= NODE_TYPE_TEXT
;
11140 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11143 *test
= NODE_TEST_TYPE
;
11146 if (*type
== NODE_TYPE_PI
) {
11148 * Specific case: search a PI by name.
11154 name
= xmlXPathParseLiteral(ctxt
);
11156 *test
= NODE_TEST_PI
;
11163 XP_ERRORNULL(XPATH_UNCLOSED_ERROR
);
11168 *test
= NODE_TEST_NAME
;
11169 if ((!blanks
) && (CUR
== ':')) {
11173 * Since currently the parser context don't have a
11174 * namespace list associated:
11175 * The namespace name for this prefix can be computed
11176 * only at evaluation time. The compilation is done
11177 * outside of any context.
11180 *prefix
= xmlXPathNsLookup(ctxt
->context
, name
);
11183 if (*prefix
== NULL
) {
11184 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
11195 *test
= NODE_TEST_ALL
;
11199 name
= xmlXPathParseNCName(ctxt
);
11200 if (name
== NULL
) {
11201 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11208 * xmlXPathIsAxisName:
11209 * @name: a preparsed name token
11211 * [6] AxisName ::= 'ancestor'
11212 * | 'ancestor-or-self'
11216 * | 'descendant-or-self'
11218 * | 'following-sibling'
11222 * | 'preceding-sibling'
11225 * Returns the axis or 0
11227 static xmlXPathAxisVal
11228 xmlXPathIsAxisName(const xmlChar
*name
) {
11229 xmlXPathAxisVal ret
= (xmlXPathAxisVal
) 0;
11232 if (xmlStrEqual(name
, BAD_CAST
"ancestor"))
11233 ret
= AXIS_ANCESTOR
;
11234 if (xmlStrEqual(name
, BAD_CAST
"ancestor-or-self"))
11235 ret
= AXIS_ANCESTOR_OR_SELF
;
11236 if (xmlStrEqual(name
, BAD_CAST
"attribute"))
11237 ret
= AXIS_ATTRIBUTE
;
11240 if (xmlStrEqual(name
, BAD_CAST
"child"))
11244 if (xmlStrEqual(name
, BAD_CAST
"descendant"))
11245 ret
= AXIS_DESCENDANT
;
11246 if (xmlStrEqual(name
, BAD_CAST
"descendant-or-self"))
11247 ret
= AXIS_DESCENDANT_OR_SELF
;
11250 if (xmlStrEqual(name
, BAD_CAST
"following"))
11251 ret
= AXIS_FOLLOWING
;
11252 if (xmlStrEqual(name
, BAD_CAST
"following-sibling"))
11253 ret
= AXIS_FOLLOWING_SIBLING
;
11256 if (xmlStrEqual(name
, BAD_CAST
"namespace"))
11257 ret
= AXIS_NAMESPACE
;
11260 if (xmlStrEqual(name
, BAD_CAST
"parent"))
11262 if (xmlStrEqual(name
, BAD_CAST
"preceding"))
11263 ret
= AXIS_PRECEDING
;
11264 if (xmlStrEqual(name
, BAD_CAST
"preceding-sibling"))
11265 ret
= AXIS_PRECEDING_SIBLING
;
11268 if (xmlStrEqual(name
, BAD_CAST
"self"))
11276 * xmlXPathCompStep:
11277 * @ctxt: the XPath Parser context
11279 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11280 * | AbbreviatedStep
11282 * [12] AbbreviatedStep ::= '.' | '..'
11284 * [5] AxisSpecifier ::= AxisName '::'
11285 * | AbbreviatedAxisSpecifier
11287 * [13] AbbreviatedAxisSpecifier ::= '@'?
11289 * Modified for XPtr range support as:
11291 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11292 * | AbbreviatedStep
11293 * | 'range-to' '(' Expr ')' Predicate*
11295 * Compile one step in a Location Path
11296 * A location step of . is short for self::node(). This is
11297 * particularly useful in conjunction with //. For example, the
11298 * location path .//para is short for
11299 * self::node()/descendant-or-self::node()/child::para
11300 * and so will select all para descendant elements of the context
11302 * Similarly, a location step of .. is short for parent::node().
11303 * For example, ../title is short for parent::node()/child::title
11304 * and so will select the title children of the parent of the context
11308 xmlXPathCompStep(xmlXPathParserContextPtr ctxt
) {
11309 #ifdef LIBXML_XPTR_ENABLED
11315 if ((CUR
== '.') && (NXT(1) == '.')) {
11318 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_PARENT
,
11319 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11320 } else if (CUR
== '.') {
11324 xmlChar
*name
= NULL
;
11325 const xmlChar
*prefix
= NULL
;
11326 xmlXPathTestVal test
= (xmlXPathTestVal
) 0;
11327 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) 0;
11328 xmlXPathTypeVal type
= (xmlXPathTypeVal
) 0;
11332 * The modification needed for XPointer change to the production
11334 #ifdef LIBXML_XPTR_ENABLED
11336 name
= xmlXPathParseNCName(ctxt
);
11337 if ((name
!= NULL
) && (xmlStrEqual(name
, BAD_CAST
"range-to"))) {
11338 op2
= ctxt
->comp
->last
;
11342 XP_ERROR(XPATH_EXPR_ERROR
);
11347 xmlXPathCompileExpr(ctxt
, 1);
11348 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11353 XP_ERROR(XPATH_EXPR_ERROR
);
11357 goto eval_predicates
;
11365 name
= xmlXPathParseNCName(ctxt
);
11366 if (name
!= NULL
) {
11367 axis
= xmlXPathIsAxisName(name
);
11370 if ((CUR
== ':') && (NXT(1) == ':')) {
11375 /* an element name can conflict with an axis one :-\ */
11381 } else if (CUR
== '@') {
11383 axis
= AXIS_ATTRIBUTE
;
11389 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
11394 name
= xmlXPathCompNodeTest(ctxt
, &test
, &type
, &prefix
, name
);
11398 if ((prefix
!= NULL
) && (ctxt
->context
!= NULL
) &&
11399 (ctxt
->context
->flags
& XML_XPATH_CHECKNS
)) {
11400 if (xmlXPathNsLookup(ctxt
->context
, prefix
) == NULL
) {
11401 xmlXPathErr(ctxt
, XPATH_UNDEF_PREFIX_ERROR
);
11405 xmlGenericError(xmlGenericErrorContext
,
11406 "Basis : computing new set\n");
11410 xmlGenericError(xmlGenericErrorContext
, "Basis : ");
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(stdout
, ctxt
->value
->nodesetval
);
11419 #ifdef LIBXML_XPTR_ENABLED
11422 op1
= ctxt
->comp
->last
;
11423 ctxt
->comp
->last
= -1;
11426 while (CUR
== '[') {
11427 xmlXPathCompPredicate(ctxt
, 0);
11430 #ifdef LIBXML_XPTR_ENABLED
11432 PUSH_BINARY_EXPR(XPATH_OP_RANGETO
, op2
, op1
, 0, 0);
11435 PUSH_FULL_EXPR(XPATH_OP_COLLECT
, op1
, ctxt
->comp
->last
, axis
,
11436 test
, type
, (void *)prefix
, (void *)name
);
11440 xmlGenericError(xmlGenericErrorContext
, "Step : ");
11441 if (ctxt
->value
== NULL
)
11442 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11443 else if (ctxt
->value
->nodesetval
== NULL
)
11444 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11446 xmlGenericErrorContextNodeSet(xmlGenericErrorContext
,
11447 ctxt
->value
->nodesetval
);
11452 * xmlXPathCompRelativeLocationPath:
11453 * @ctxt: the XPath Parser context
11455 * [3] RelativeLocationPath ::= Step
11456 * | RelativeLocationPath '/' Step
11457 * | AbbreviatedRelativeLocationPath
11458 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11460 * Compile a relative location path.
11463 xmlXPathCompRelativeLocationPath
11464 (xmlXPathParserContextPtr ctxt
) {
11466 if ((CUR
== '/') && (NXT(1) == '/')) {
11469 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11470 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11471 } else if (CUR
== '/') {
11475 xmlXPathCompStep(ctxt
);
11478 while (CUR
== '/') {
11479 if ((CUR
== '/') && (NXT(1) == '/')) {
11482 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11483 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11484 xmlXPathCompStep(ctxt
);
11485 } else if (CUR
== '/') {
11488 xmlXPathCompStep(ctxt
);
11495 * xmlXPathCompLocationPath:
11496 * @ctxt: the XPath Parser context
11498 * [1] LocationPath ::= RelativeLocationPath
11499 * | AbsoluteLocationPath
11500 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11501 * | AbbreviatedAbsoluteLocationPath
11502 * [10] AbbreviatedAbsoluteLocationPath ::=
11503 * '//' RelativeLocationPath
11505 * Compile a location path
11507 * // is short for /descendant-or-self::node()/. For example,
11508 * //para is short for /descendant-or-self::node()/child::para and
11509 * so will select any para element in the document (even a para element
11510 * that is a document element will be selected by //para since the
11511 * document element node is a child of the root node); div//para is
11512 * short for div/descendant-or-self::node()/child::para and so will
11513 * select all para descendants of div children.
11516 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
) {
11519 xmlXPathCompRelativeLocationPath(ctxt
);
11521 while (CUR
== '/') {
11522 if ((CUR
== '/') && (NXT(1) == '/')) {
11525 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11526 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11527 xmlXPathCompRelativeLocationPath(ctxt
);
11528 } else if (CUR
== '/') {
11532 ((IS_ASCII_LETTER(CUR
)) || (CUR
== '_') || (CUR
== '.') ||
11533 (CUR
== '@') || (CUR
== '*')))
11534 xmlXPathCompRelativeLocationPath(ctxt
);
11541 /************************************************************************
11543 * XPath precompiled expression evaluation *
11545 ************************************************************************/
11548 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
);
11552 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op
,
11555 xmlGenericError(xmlGenericErrorContext
, "new step : ");
11556 switch (op
->value
) {
11557 case AXIS_ANCESTOR
:
11558 xmlGenericError(xmlGenericErrorContext
, "axis 'ancestors' ");
11560 case AXIS_ANCESTOR_OR_SELF
:
11561 xmlGenericError(xmlGenericErrorContext
,
11562 "axis 'ancestors-or-self' ");
11564 case AXIS_ATTRIBUTE
:
11565 xmlGenericError(xmlGenericErrorContext
, "axis 'attributes' ");
11568 xmlGenericError(xmlGenericErrorContext
, "axis 'child' ");
11570 case AXIS_DESCENDANT
:
11571 xmlGenericError(xmlGenericErrorContext
, "axis 'descendant' ");
11573 case AXIS_DESCENDANT_OR_SELF
:
11574 xmlGenericError(xmlGenericErrorContext
,
11575 "axis 'descendant-or-self' ");
11577 case AXIS_FOLLOWING
:
11578 xmlGenericError(xmlGenericErrorContext
, "axis 'following' ");
11580 case AXIS_FOLLOWING_SIBLING
:
11581 xmlGenericError(xmlGenericErrorContext
,
11582 "axis 'following-siblings' ");
11584 case AXIS_NAMESPACE
:
11585 xmlGenericError(xmlGenericErrorContext
, "axis 'namespace' ");
11588 xmlGenericError(xmlGenericErrorContext
, "axis 'parent' ");
11590 case AXIS_PRECEDING
:
11591 xmlGenericError(xmlGenericErrorContext
, "axis 'preceding' ");
11593 case AXIS_PRECEDING_SIBLING
:
11594 xmlGenericError(xmlGenericErrorContext
,
11595 "axis 'preceding-sibling' ");
11598 xmlGenericError(xmlGenericErrorContext
, "axis 'self' ");
11601 xmlGenericError(xmlGenericErrorContext
,
11602 " context contains %d nodes\n", nbNodes
);
11603 switch (op
->value2
) {
11604 case NODE_TEST_NONE
:
11605 xmlGenericError(xmlGenericErrorContext
,
11606 " searching for none !!!\n");
11608 case NODE_TEST_TYPE
:
11609 xmlGenericError(xmlGenericErrorContext
,
11610 " searching for type %d\n", op
->value3
);
11613 xmlGenericError(xmlGenericErrorContext
,
11614 " searching for PI !!!\n");
11616 case NODE_TEST_ALL
:
11617 xmlGenericError(xmlGenericErrorContext
,
11618 " searching for *\n");
11621 xmlGenericError(xmlGenericErrorContext
,
11622 " searching for namespace %s\n",
11625 case NODE_TEST_NAME
:
11626 xmlGenericError(xmlGenericErrorContext
,
11627 " searching for name %s\n", op
->value5
);
11629 xmlGenericError(xmlGenericErrorContext
,
11630 " with namespace %s\n", op
->value4
);
11633 xmlGenericError(xmlGenericErrorContext
, "Testing : ");
11635 #endif /* DEBUG_STEP */
11638 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt
,
11639 xmlXPathStepOpPtr op
,
11644 if (op
->ch1
!= -1) {
11645 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11647 * Process inner predicates first.
11649 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11651 * TODO: raise an internal error.
11654 contextSize
= xmlXPathCompOpEvalPredicate(ctxt
,
11655 &comp
->steps
[op
->ch1
], set
, contextSize
, hasNsNodes
);
11657 if (contextSize
<= 0)
11660 if (op
->ch2
!= -1) {
11661 xmlXPathContextPtr xpctxt
= ctxt
->context
;
11662 xmlNodePtr contextNode
, oldContextNode
;
11663 xmlDocPtr oldContextDoc
;
11665 int i
, res
, contextPos
= 0, newContextSize
;
11666 xmlXPathStepOpPtr exprOp
;
11667 xmlXPathObjectPtr contextObj
= NULL
, exprRes
= NULL
;
11669 #ifdef LIBXML_XPTR_ENABLED
11671 * URGENT TODO: Check the following:
11672 * We don't expect location sets if evaluating prediates, right?
11673 * Only filters should expect location sets, right?
11678 * "For each node in the node-set to be filtered, the
11679 * PredicateExpr is evaluated with that node as the
11680 * context node, with the number of nodes in the
11681 * node-set as the context size, and with the proximity
11682 * position of the node in the node-set with respect to
11683 * the axis as the context position;"
11684 * @oldset is the node-set" to be filtered.
11687 * "only predicates change the context position and
11688 * context size (see [2.4 Predicates])."
11690 * node-set context pos
11694 * After applying predicate [position() > 1] :
11695 * node-set context pos
11699 oldContextNode
= xpctxt
->node
;
11700 oldContextDoc
= xpctxt
->doc
;
11701 oldcs
= xpctxt
->contextSize
;
11702 oldpp
= xpctxt
->proximityPosition
;
11704 * Get the expression of this predicate.
11706 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11707 newContextSize
= 0;
11708 for (i
= 0; i
< set
->nodeNr
; i
++) {
11709 if (set
->nodeTab
[i
] == NULL
)
11712 contextNode
= set
->nodeTab
[i
];
11713 xpctxt
->node
= contextNode
;
11714 xpctxt
->contextSize
= contextSize
;
11715 xpctxt
->proximityPosition
= ++contextPos
;
11718 * Also set the xpath document in case things like
11719 * key() are evaluated in the predicate.
11721 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11722 (contextNode
->doc
!= NULL
))
11723 xpctxt
->doc
= contextNode
->doc
;
11725 * Evaluate the predicate expression with 1 context node
11726 * at a time; this node is packaged into a node set; this
11727 * node set is handed over to the evaluation mechanism.
11729 if (contextObj
== NULL
)
11730 contextObj
= xmlXPathCacheNewNodeSet(xpctxt
, contextNode
);
11732 if (xmlXPathNodeSetAddUnique(contextObj
->nodesetval
,
11733 contextNode
) < 0) {
11734 ctxt
->error
= XPATH_MEMORY_ERROR
;
11735 goto evaluation_exit
;
11739 valuePush(ctxt
, contextObj
);
11741 res
= xmlXPathCompOpEvalToBoolean(ctxt
, exprOp
, 1);
11743 if ((ctxt
->error
!= XPATH_EXPRESSION_OK
) || (res
== -1)) {
11744 xmlXPathNodeSetClear(set
, hasNsNodes
);
11745 newContextSize
= 0;
11746 goto evaluation_exit
;
11753 * Remove the entry from the initial node set.
11755 set
->nodeTab
[i
] = NULL
;
11756 if (contextNode
->type
== XML_NAMESPACE_DECL
)
11757 xmlXPathNodeSetFreeNs((xmlNsPtr
) contextNode
);
11759 if (ctxt
->value
== contextObj
) {
11761 * Don't free the temporary XPath object holding the
11762 * context node, in order to avoid massive recreation
11763 * inside this loop.
11766 xmlXPathNodeSetClear(contextObj
->nodesetval
, hasNsNodes
);
11769 * TODO: The object was lost in the evaluation machinery.
11770 * Can this happen? Maybe in internal-error cases.
11776 if (contextObj
!= NULL
) {
11777 if (ctxt
->value
== contextObj
)
11779 xmlXPathReleaseObject(xpctxt
, contextObj
);
11782 if (exprRes
!= NULL
)
11783 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11785 * Reset/invalidate the context.
11787 xpctxt
->node
= oldContextNode
;
11788 xpctxt
->doc
= oldContextDoc
;
11789 xpctxt
->contextSize
= oldcs
;
11790 xpctxt
->proximityPosition
= oldpp
;
11791 return(newContextSize
);
11793 return(contextSize
);
11797 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt
,
11798 xmlXPathStepOpPtr op
,
11805 if (op
->ch1
!= -1) {
11806 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11807 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11809 * TODO: raise an internal error.
11812 contextSize
= xmlXPathCompOpEvalPredicate(ctxt
,
11813 &comp
->steps
[op
->ch1
], set
, contextSize
, hasNsNodes
);
11815 if (contextSize
<= 0)
11819 * Check if the node set contains a sufficient number of nodes for
11820 * the requested range.
11822 if (contextSize
< minPos
) {
11823 xmlXPathNodeSetClear(set
, hasNsNodes
);
11826 if (op
->ch2
== -1) {
11828 * TODO: Can this ever happen?
11830 return (contextSize
);
11832 xmlDocPtr oldContextDoc
;
11834 int i
, pos
= 0, newContextSize
= 0, contextPos
= 0, res
;
11835 xmlXPathStepOpPtr exprOp
;
11836 xmlXPathObjectPtr contextObj
= NULL
, exprRes
= NULL
;
11837 xmlNodePtr oldContextNode
, contextNode
= NULL
;
11838 xmlXPathContextPtr xpctxt
= ctxt
->context
;
11841 #ifdef LIBXML_XPTR_ENABLED
11843 * URGENT TODO: Check the following:
11844 * We don't expect location sets if evaluating prediates, right?
11845 * Only filters should expect location sets, right?
11847 #endif /* LIBXML_XPTR_ENABLED */
11850 * Save old context.
11852 oldContextNode
= xpctxt
->node
;
11853 oldContextDoc
= xpctxt
->doc
;
11854 oldcs
= xpctxt
->contextSize
;
11855 oldpp
= xpctxt
->proximityPosition
;
11857 * Get the expression of this predicate.
11859 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11860 for (i
= 0; i
< set
->nodeNr
; i
++) {
11861 xmlXPathObjectPtr tmp
;
11863 if (set
->nodeTab
[i
] == NULL
)
11866 contextNode
= set
->nodeTab
[i
];
11867 xpctxt
->node
= contextNode
;
11868 xpctxt
->contextSize
= contextSize
;
11869 xpctxt
->proximityPosition
= ++contextPos
;
11872 * Initialize the new set.
11873 * Also set the xpath document in case things like
11874 * key() evaluation are attempted on the predicate
11876 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11877 (contextNode
->doc
!= NULL
))
11878 xpctxt
->doc
= contextNode
->doc
;
11880 * Evaluate the predicate expression with 1 context node
11881 * at a time; this node is packaged into a node set; this
11882 * node set is handed over to the evaluation mechanism.
11884 if (contextObj
== NULL
)
11885 contextObj
= xmlXPathCacheNewNodeSet(xpctxt
, contextNode
);
11887 if (xmlXPathNodeSetAddUnique(contextObj
->nodesetval
,
11888 contextNode
) < 0) {
11889 ctxt
->error
= XPATH_MEMORY_ERROR
;
11890 goto evaluation_exit
;
11894 valuePush(ctxt
, contextObj
);
11895 frame
= xmlXPathSetFrame(ctxt
);
11896 res
= xmlXPathCompOpEvalToBoolean(ctxt
, exprOp
, 1);
11897 xmlXPathPopFrame(ctxt
, frame
);
11898 tmp
= valuePop(ctxt
);
11900 if ((ctxt
->error
!= XPATH_EXPRESSION_OK
) || (res
== -1)) {
11901 while (tmp
!= contextObj
) {
11903 * Free up the result
11904 * then pop off contextObj, which will be freed later
11906 xmlXPathReleaseObject(xpctxt
, tmp
);
11907 tmp
= valuePop(ctxt
);
11909 goto evaluation_error
;
11911 /* push the result back onto the stack */
11912 valuePush(ctxt
, tmp
);
11917 if (res
&& (pos
>= minPos
) && (pos
<= maxPos
)) {
11919 * Fits in the requested range.
11922 if (minPos
== maxPos
) {
11924 * Only 1 node was requested.
11926 if (contextNode
->type
== XML_NAMESPACE_DECL
) {
11928 * As always: take care of those nasty
11931 set
->nodeTab
[i
] = NULL
;
11933 xmlXPathNodeSetClear(set
, hasNsNodes
);
11935 set
->nodeTab
[0] = contextNode
;
11936 goto evaluation_exit
;
11938 if (pos
== maxPos
) {
11942 xmlXPathNodeSetClearFromPos(set
, i
+1, hasNsNodes
);
11943 goto evaluation_exit
;
11947 * Remove the entry from the initial node set.
11949 set
->nodeTab
[i
] = NULL
;
11950 if (contextNode
->type
== XML_NAMESPACE_DECL
)
11951 xmlXPathNodeSetFreeNs((xmlNsPtr
) contextNode
);
11953 if (exprRes
!= NULL
) {
11954 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11957 if (ctxt
->value
== contextObj
) {
11959 * Don't free the temporary XPath object holding the
11960 * context node, in order to avoid massive recreation
11961 * inside this loop.
11964 xmlXPathNodeSetClear(contextObj
->nodesetval
, hasNsNodes
);
11967 * The object was lost in the evaluation machinery.
11968 * Can this happen? Maybe in case of internal-errors.
11973 goto evaluation_exit
;
11976 xmlXPathNodeSetClear(set
, hasNsNodes
);
11977 newContextSize
= 0;
11980 if (contextObj
!= NULL
) {
11981 if (ctxt
->value
== contextObj
)
11983 xmlXPathReleaseObject(xpctxt
, contextObj
);
11985 if (exprRes
!= NULL
)
11986 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11988 * Reset/invalidate the context.
11990 xpctxt
->node
= oldContextNode
;
11991 xpctxt
->doc
= oldContextDoc
;
11992 xpctxt
->contextSize
= oldcs
;
11993 xpctxt
->proximityPosition
= oldpp
;
11994 return(newContextSize
);
11996 return(contextSize
);
12000 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt
,
12001 xmlXPathStepOpPtr op
,
12005 xmlXPathStepOpPtr exprOp
;
12008 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12012 * If not -1, then ch1 will point to:
12013 * 1) For predicates (XPATH_OP_PREDICATE):
12014 * - an inner predicate operator
12015 * 2) For filters (XPATH_OP_FILTER):
12016 * - an inner filter operater OR
12017 * - an expression selecting the node set.
12018 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12020 if ((op
->op
!= XPATH_OP_PREDICATE
) && (op
->op
!= XPATH_OP_FILTER
))
12023 if (op
->ch2
!= -1) {
12024 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
12028 if ((exprOp
!= NULL
) &&
12029 (exprOp
->op
== XPATH_OP_VALUE
) &&
12030 (exprOp
->value4
!= NULL
) &&
12031 (((xmlXPathObjectPtr
) exprOp
->value4
)->type
== XPATH_NUMBER
))
12033 double floatval
= ((xmlXPathObjectPtr
) exprOp
->value4
)->floatval
;
12036 * We have a "[n]" predicate here.
12037 * TODO: Unfortunately this simplistic test here is not
12038 * able to detect a position() predicate in compound
12039 * expressions like "[@attr = 'a" and position() = 1],
12040 * and even not the usage of position() in
12041 * "[position() = 1]"; thus - obviously - a position-range,
12042 * like it "[position() < 5]", is also not detected.
12043 * Maybe we could rewrite the AST to ease the optimization.
12046 if ((floatval
> INT_MIN
) && (floatval
< INT_MAX
)) {
12047 *maxPos
= (int) floatval
;
12048 if (floatval
== (double) *maxPos
)
12056 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt
,
12057 xmlXPathStepOpPtr op
,
12058 xmlNodePtr
* first
, xmlNodePtr
* last
,
12062 #define XP_TEST_HIT \
12063 if (hasAxisRange != 0) { \
12064 if (++pos == maxPos) { \
12065 if (addNode(seq, cur) < 0) \
12066 ctxt->error = XPATH_MEMORY_ERROR; \
12067 goto axis_range_end; } \
12069 if (addNode(seq, cur) < 0) \
12070 ctxt->error = XPATH_MEMORY_ERROR; \
12071 if (breakOnFirstHit) goto first_hit; }
12073 #define XP_TEST_HIT_NS \
12074 if (hasAxisRange != 0) { \
12075 if (++pos == maxPos) { \
12077 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12078 ctxt->error = XPATH_MEMORY_ERROR; \
12079 goto axis_range_end; } \
12082 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12083 ctxt->error = XPATH_MEMORY_ERROR; \
12084 if (breakOnFirstHit) goto first_hit; }
12086 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) op
->value
;
12087 xmlXPathTestVal test
= (xmlXPathTestVal
) op
->value2
;
12088 xmlXPathTypeVal type
= (xmlXPathTypeVal
) op
->value3
;
12089 const xmlChar
*prefix
= op
->value4
;
12090 const xmlChar
*name
= op
->value5
;
12091 const xmlChar
*URI
= NULL
;
12094 int nbMatches
= 0, prevMatches
= 0;
12096 int total
= 0, hasNsNodes
= 0;
12097 /* The popped object holding the context nodes */
12098 xmlXPathObjectPtr obj
;
12099 /* The set of context nodes for the node tests */
12100 xmlNodeSetPtr contextSeq
;
12102 xmlNodePtr contextNode
;
12103 /* The final resulting node set wrt to all context nodes */
12104 xmlNodeSetPtr outSeq
;
12106 * The temporary resulting node set wrt 1 context node.
12107 * Used to feed predicate evaluation.
12111 /* First predicate operator */
12112 xmlXPathStepOpPtr predOp
;
12113 int maxPos
; /* The requested position() (when a "[n]" predicate) */
12114 int hasPredicateRange
, hasAxisRange
, pos
, size
, newSize
;
12115 int breakOnFirstHit
;
12117 xmlXPathTraversalFunction next
= NULL
;
12118 int (*addNode
) (xmlNodeSetPtr
, xmlNodePtr
);
12119 xmlXPathNodeSetMergeFunction mergeAndClear
;
12120 xmlNodePtr oldContextNode
;
12121 xmlXPathContextPtr xpctxt
= ctxt
->context
;
12124 CHECK_TYPE0(XPATH_NODESET
);
12125 obj
= valuePop(ctxt
);
12127 * Setup namespaces.
12129 if (prefix
!= NULL
) {
12130 URI
= xmlXPathNsLookup(xpctxt
, prefix
);
12132 xmlXPathReleaseObject(xpctxt
, obj
);
12133 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
12139 * MAYBE FUTURE TODO: merging optimizations:
12140 * - If the nodes to be traversed wrt to the initial nodes and
12141 * the current axis cannot overlap, then we could avoid searching
12142 * for duplicates during the merge.
12143 * But the question is how/when to evaluate if they cannot overlap.
12144 * Example: if we know that for two initial nodes, the one is
12145 * not in the ancestor-or-self axis of the other, then we could safely
12146 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12147 * the descendant-or-self axis.
12149 mergeAndClear
= xmlXPathNodeSetMergeAndClear
;
12151 case AXIS_ANCESTOR
:
12153 next
= xmlXPathNextAncestor
;
12155 case AXIS_ANCESTOR_OR_SELF
:
12157 next
= xmlXPathNextAncestorOrSelf
;
12159 case AXIS_ATTRIBUTE
:
12162 next
= xmlXPathNextAttribute
;
12163 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12167 if (((test
== NODE_TEST_NAME
) || (test
== NODE_TEST_ALL
)) &&
12168 (type
== NODE_TYPE_NODE
))
12171 * Optimization if an element node type is 'element'.
12173 next
= xmlXPathNextChildElement
;
12175 next
= xmlXPathNextChild
;
12176 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12178 case AXIS_DESCENDANT
:
12180 next
= xmlXPathNextDescendant
;
12182 case AXIS_DESCENDANT_OR_SELF
:
12184 next
= xmlXPathNextDescendantOrSelf
;
12186 case AXIS_FOLLOWING
:
12188 next
= xmlXPathNextFollowing
;
12190 case AXIS_FOLLOWING_SIBLING
:
12192 next
= xmlXPathNextFollowingSibling
;
12194 case AXIS_NAMESPACE
:
12197 next
= (xmlXPathTraversalFunction
) xmlXPathNextNamespace
;
12198 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12202 next
= xmlXPathNextParent
;
12204 case AXIS_PRECEDING
:
12206 next
= xmlXPathNextPrecedingInternal
;
12208 case AXIS_PRECEDING_SIBLING
:
12210 next
= xmlXPathNextPrecedingSibling
;
12215 next
= xmlXPathNextSelf
;
12216 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12221 xmlXPathDebugDumpStepAxis(op
,
12222 (obj
->nodesetval
!= NULL
) ? obj
->nodesetval
->nodeNr
: 0);
12225 if (next
== NULL
) {
12226 xmlXPathReleaseObject(xpctxt
, obj
);
12229 contextSeq
= obj
->nodesetval
;
12230 if ((contextSeq
== NULL
) || (contextSeq
->nodeNr
<= 0)) {
12231 xmlXPathReleaseObject(xpctxt
, obj
);
12232 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, NULL
));
12236 * Predicate optimization ---------------------------------------------
12237 * If this step has a last predicate, which contains a position(),
12238 * then we'll optimize (although not exactly "position()", but only
12239 * the short-hand form, i.e., "[n]".
12241 * Example - expression "/foo[parent::bar][1]":
12243 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12245 * PREDICATE -- op->ch2 (predOp)
12246 * PREDICATE -- predOp->ch1 = [parent::bar]
12248 * COLLECT 'parent' 'name' 'node' bar
12250 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12255 hasPredicateRange
= 0;
12257 if (op
->ch2
!= -1) {
12259 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12261 predOp
= &ctxt
->comp
->steps
[op
->ch2
];
12262 if (xmlXPathIsPositionalPredicate(ctxt
, predOp
, &maxPos
)) {
12263 if (predOp
->ch1
!= -1) {
12265 * Use the next inner predicate operator.
12267 predOp
= &ctxt
->comp
->steps
[predOp
->ch1
];
12268 hasPredicateRange
= 1;
12271 * There's no other predicate than the [n] predicate.
12278 breakOnFirstHit
= ((toBool
) && (predOp
== NULL
)) ? 1 : 0;
12280 * Axis traversal -----------------------------------------------------
12284 * - For the attribute axis, the principal node type is attribute.
12285 * - For the namespace axis, the principal node type is namespace.
12286 * - For other axes, the principal node type is element.
12288 * A node test * is true for any node of the
12289 * principal node type. For example, child::* will
12290 * select all element children of the context node
12292 oldContextNode
= xpctxt
->node
;
12293 addNode
= xmlXPathNodeSetAddUnique
;
12296 contextNode
= NULL
;
12300 while (((contextIdx
< contextSeq
->nodeNr
) || (contextNode
!= NULL
)) &&
12301 (ctxt
->error
== XPATH_EXPRESSION_OK
)) {
12302 xpctxt
->node
= contextSeq
->nodeTab
[contextIdx
++];
12305 seq
= xmlXPathNodeSetCreate(NULL
);
12312 * Traverse the axis and test the nodes.
12318 cur
= next(ctxt
, cur
);
12323 * QUESTION TODO: What does the "first" and "last" stuff do?
12325 if ((first
!= NULL
) && (*first
!= NULL
)) {
12328 if (((total
% 256) == 0) &&
12329 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12330 (xmlXPathCmpNodesExt(*first
, cur
) >= 0))
12332 (xmlXPathCmpNodes(*first
, cur
) >= 0))
12338 if ((last
!= NULL
) && (*last
!= NULL
)) {
12341 if (((total
% 256) == 0) &&
12342 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12343 (xmlXPathCmpNodesExt(cur
, *last
) >= 0))
12345 (xmlXPathCmpNodes(cur
, *last
) >= 0))
12355 xmlGenericError(xmlGenericErrorContext
, " %s", cur
->name
);
12359 case NODE_TEST_NONE
:
12363 case NODE_TEST_TYPE
:
12364 if (type
== NODE_TYPE_NODE
) {
12365 switch (cur
->type
) {
12366 case XML_DOCUMENT_NODE
:
12367 case XML_HTML_DOCUMENT_NODE
:
12368 #ifdef LIBXML_DOCB_ENABLED
12369 case XML_DOCB_DOCUMENT_NODE
:
12371 case XML_ELEMENT_NODE
:
12372 case XML_ATTRIBUTE_NODE
:
12374 case XML_COMMENT_NODE
:
12375 case XML_CDATA_SECTION_NODE
:
12376 case XML_TEXT_NODE
:
12379 case XML_NAMESPACE_DECL
: {
12380 if (axis
== AXIS_NAMESPACE
) {
12391 } else if (cur
->type
== (xmlElementType
) type
) {
12392 if (cur
->type
== XML_NAMESPACE_DECL
)
12396 } else if ((type
== NODE_TYPE_TEXT
) &&
12397 (cur
->type
== XML_CDATA_SECTION_NODE
))
12403 if ((cur
->type
== XML_PI_NODE
) &&
12404 ((name
== NULL
) || xmlStrEqual(name
, cur
->name
)))
12409 case NODE_TEST_ALL
:
12410 if (axis
== AXIS_ATTRIBUTE
) {
12411 if (cur
->type
== XML_ATTRIBUTE_NODE
)
12413 if (prefix
== NULL
)
12416 } else if ((cur
->ns
!= NULL
) &&
12417 (xmlStrEqual(URI
, cur
->ns
->href
)))
12422 } else if (axis
== AXIS_NAMESPACE
) {
12423 if (cur
->type
== XML_NAMESPACE_DECL
)
12428 if (cur
->type
== XML_ELEMENT_NODE
) {
12429 if (prefix
== NULL
)
12433 } else if ((cur
->ns
!= NULL
) &&
12434 (xmlStrEqual(URI
, cur
->ns
->href
)))
12441 case NODE_TEST_NS
:{
12445 case NODE_TEST_NAME
:
12446 if (axis
== AXIS_ATTRIBUTE
) {
12447 if (cur
->type
!= XML_ATTRIBUTE_NODE
)
12449 } else if (axis
== AXIS_NAMESPACE
) {
12450 if (cur
->type
!= XML_NAMESPACE_DECL
)
12453 if (cur
->type
!= XML_ELEMENT_NODE
)
12456 switch (cur
->type
) {
12457 case XML_ELEMENT_NODE
:
12458 if (xmlStrEqual(name
, cur
->name
)) {
12459 if (prefix
== NULL
) {
12460 if (cur
->ns
== NULL
)
12465 if ((cur
->ns
!= NULL
) &&
12466 (xmlStrEqual(URI
, cur
->ns
->href
)))
12473 case XML_ATTRIBUTE_NODE
:{
12474 xmlAttrPtr attr
= (xmlAttrPtr
) cur
;
12476 if (xmlStrEqual(name
, attr
->name
)) {
12477 if (prefix
== NULL
) {
12478 if ((attr
->ns
== NULL
) ||
12479 (attr
->ns
->prefix
== NULL
))
12484 if ((attr
->ns
!= NULL
) &&
12494 case XML_NAMESPACE_DECL
:
12495 if (cur
->type
== XML_NAMESPACE_DECL
) {
12496 xmlNsPtr ns
= (xmlNsPtr
) cur
;
12498 if ((ns
->prefix
!= NULL
) && (name
!= NULL
)
12499 && (xmlStrEqual(ns
->prefix
, name
)))
12509 } /* switch(test) */
12510 } while ((cur
!= NULL
) && (ctxt
->error
== XPATH_EXPRESSION_OK
));
12512 goto apply_predicates
;
12514 axis_range_end
: /* ----------------------------------------------------- */
12516 * We have a "/foo[n]", and position() = n was reached.
12517 * Note that we can have as well "/foo/::parent::foo[1]", so
12518 * a duplicate-aware merge is still needed.
12519 * Merge with the result.
12521 if (outSeq
== NULL
) {
12525 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12527 * Break if only a true/false result was requested.
12533 first_hit
: /* ---------------------------------------------------------- */
12535 * Break if only a true/false result was requested and
12536 * no predicates existed and a node test succeeded.
12538 if (outSeq
== NULL
) {
12542 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12547 nbMatches
+= seq
->nodeNr
;
12550 apply_predicates
: /* --------------------------------------------------- */
12551 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
12555 * Apply predicates.
12557 if ((predOp
!= NULL
) && (seq
->nodeNr
> 0)) {
12559 * E.g. when we have a "/foo[some expression][n]".
12562 * QUESTION TODO: The old predicate evaluation took into
12563 * account location-sets.
12564 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12565 * Do we expect such a set here?
12566 * All what I learned now from the evaluation semantics
12567 * does not indicate that a location-set will be processed
12568 * here, so this looks OK.
12571 * Iterate over all predicates, starting with the outermost
12573 * TODO: Problem: we cannot execute the inner predicates first
12574 * since we cannot go back *up* the operator tree!
12576 * 1) Use of recursive functions (like is it currently done
12577 * via xmlXPathCompOpEval())
12578 * 2) Add a predicate evaluation information stack to the
12580 * 3) Change the way the operators are linked; we need a
12581 * "parent" field on xmlXPathStepOp
12583 * For the moment, I'll try to solve this with a recursive
12584 * function: xmlXPathCompOpEvalPredicate().
12586 size
= seq
->nodeNr
;
12587 if (hasPredicateRange
!= 0)
12588 newSize
= xmlXPathCompOpEvalPositionalPredicate(ctxt
,
12589 predOp
, seq
, size
, maxPos
, maxPos
, hasNsNodes
);
12591 newSize
= xmlXPathCompOpEvalPredicate(ctxt
,
12592 predOp
, seq
, size
, hasNsNodes
);
12594 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
12599 * Add the filtered set of nodes to the result node set.
12601 if (newSize
== 0) {
12603 * The predicates filtered all nodes out.
12605 xmlXPathNodeSetClear(seq
, hasNsNodes
);
12606 } else if (seq
->nodeNr
> 0) {
12608 * Add to result set.
12610 if (outSeq
== NULL
) {
12611 if (size
!= newSize
) {
12613 * We need to merge and clear here, since
12614 * the sequence will contained NULLed entries.
12616 outSeq
= mergeAndClear(NULL
, seq
, 1);
12622 outSeq
= mergeAndClear(outSeq
, seq
,
12623 (size
!= newSize
) ? 1: 0);
12625 * Break if only a true/false result was requested.
12630 } else if (seq
->nodeNr
> 0) {
12632 * Add to result set.
12634 if (outSeq
== NULL
) {
12638 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12644 if ((obj
->boolval
) && (obj
->user
!= NULL
)) {
12646 * QUESTION TODO: What does this do and why?
12647 * TODO: Do we have to do this also for the "error"
12648 * cleanup further down?
12650 ctxt
->value
->boolval
= 1;
12651 ctxt
->value
->user
= obj
->user
;
12655 xmlXPathReleaseObject(xpctxt
, obj
);
12658 * Ensure we return at least an emtpy set.
12660 if (outSeq
== NULL
) {
12661 if ((seq
!= NULL
) && (seq
->nodeNr
== 0))
12664 outSeq
= xmlXPathNodeSetCreate(NULL
);
12665 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12667 if ((seq
!= NULL
) && (seq
!= outSeq
)) {
12668 xmlXPathFreeNodeSet(seq
);
12671 * Hand over the result. Better to push the set also in
12674 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, outSeq
));
12676 * Reset the context node.
12678 xpctxt
->node
= oldContextNode
;
12680 * When traversing the namespace axis in "toBool" mode, it's
12681 * possible that tmpNsList wasn't freed.
12683 if (xpctxt
->tmpNsList
!= NULL
) {
12684 xmlFree(xpctxt
->tmpNsList
);
12685 xpctxt
->tmpNsList
= NULL
;
12689 xmlGenericError(xmlGenericErrorContext
,
12690 "\nExamined %d nodes, found %d nodes at that step\n",
12698 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12699 xmlXPathStepOpPtr op
, xmlNodePtr
* first
);
12702 * xmlXPathCompOpEvalFirst:
12703 * @ctxt: the XPath parser context with the compiled expression
12704 * @op: an XPath compiled operation
12705 * @first: the first elem found so far
12707 * Evaluate the Precompiled XPath operation searching only the first
12708 * element in document order
12710 * Returns the number of examined objects.
12713 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
12714 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12716 int total
= 0, cur
;
12717 xmlXPathCompExprPtr comp
;
12718 xmlXPathObjectPtr arg1
, arg2
;
12725 case XPATH_OP_UNION
:
12727 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12730 if ((ctxt
->value
!= NULL
)
12731 && (ctxt
->value
->type
== XPATH_NODESET
)
12732 && (ctxt
->value
->nodesetval
!= NULL
)
12733 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12735 * limit tree traversing to first node in the result
12738 * OPTIMIZE TODO: This implicitely sorts
12739 * the result, even if not needed. E.g. if the argument
12740 * of the count() function, no sorting is needed.
12741 * OPTIMIZE TODO: How do we know if the node-list wasn't
12744 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12745 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12746 *first
= ctxt
->value
->nodesetval
->nodeTab
[0];
12749 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch2
],
12753 arg2
= valuePop(ctxt
);
12754 arg1
= valuePop(ctxt
);
12755 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12756 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12757 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12758 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12759 XP_ERROR0(XPATH_INVALID_TYPE
);
12762 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12764 valuePush(ctxt
, arg1
);
12765 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12768 xmlXPathCompSwap(op
);
12769 return (total
+ cur
);
12770 case XPATH_OP_ROOT
:
12771 xmlXPathRoot(ctxt
);
12773 case XPATH_OP_NODE
:
12775 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12778 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12780 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12781 ctxt
->context
->node
));
12783 case XPATH_OP_COLLECT
:{
12787 total
= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12790 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, first
, NULL
, 0);
12793 case XPATH_OP_VALUE
:
12795 xmlXPathCacheObjectCopy(ctxt
->context
,
12796 (xmlXPathObjectPtr
) op
->value4
));
12798 case XPATH_OP_SORT
:
12801 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12804 if ((ctxt
->value
!= NULL
)
12805 && (ctxt
->value
->type
== XPATH_NODESET
)
12806 && (ctxt
->value
->nodesetval
!= NULL
)
12807 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12808 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12810 #ifdef XP_OPTIMIZED_FILTER_FIRST
12811 case XPATH_OP_FILTER
:
12812 total
+= xmlXPathCompOpEvalFilterFirst(ctxt
, op
, first
);
12816 return (xmlXPathCompOpEval(ctxt
, op
));
12821 * xmlXPathCompOpEvalLast:
12822 * @ctxt: the XPath parser context with the compiled expression
12823 * @op: an XPath compiled operation
12824 * @last: the last elem found so far
12826 * Evaluate the Precompiled XPath operation searching only the last
12827 * element in document order
12829 * Returns the number of nodes traversed
12832 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
,
12835 int total
= 0, cur
;
12836 xmlXPathCompExprPtr comp
;
12837 xmlXPathObjectPtr arg1
, arg2
;
12844 case XPATH_OP_UNION
:
12846 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
], last
);
12848 if ((ctxt
->value
!= NULL
)
12849 && (ctxt
->value
->type
== XPATH_NODESET
)
12850 && (ctxt
->value
->nodesetval
!= NULL
)
12851 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12853 * limit tree traversing to first node in the result
12855 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12856 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12858 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->value
->
12859 nodesetval
->nodeNr
-
12863 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch2
], last
);
12865 if ((ctxt
->value
!= NULL
)
12866 && (ctxt
->value
->type
== XPATH_NODESET
)
12867 && (ctxt
->value
->nodesetval
!= NULL
)
12868 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) { /* TODO: NOP ? */
12871 arg2
= valuePop(ctxt
);
12872 arg1
= valuePop(ctxt
);
12873 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12874 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12875 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12876 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12877 XP_ERROR0(XPATH_INVALID_TYPE
);
12880 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12882 valuePush(ctxt
, arg1
);
12883 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12886 xmlXPathCompSwap(op
);
12887 return (total
+ cur
);
12888 case XPATH_OP_ROOT
:
12889 xmlXPathRoot(ctxt
);
12891 case XPATH_OP_NODE
:
12893 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12896 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12898 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12899 ctxt
->context
->node
));
12901 case XPATH_OP_COLLECT
:{
12905 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12908 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, last
, 0);
12911 case XPATH_OP_VALUE
:
12913 xmlXPathCacheObjectCopy(ctxt
->context
,
12914 (xmlXPathObjectPtr
) op
->value4
));
12916 case XPATH_OP_SORT
:
12919 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
],
12922 if ((ctxt
->value
!= NULL
)
12923 && (ctxt
->value
->type
== XPATH_NODESET
)
12924 && (ctxt
->value
->nodesetval
!= NULL
)
12925 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12926 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12929 return (xmlXPathCompOpEval(ctxt
, op
));
12933 #ifdef XP_OPTIMIZED_FILTER_FIRST
12935 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12936 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12939 xmlXPathCompExprPtr comp
;
12940 xmlXPathObjectPtr res
;
12941 xmlXPathObjectPtr obj
;
12942 xmlNodeSetPtr oldset
;
12943 xmlNodePtr oldnode
;
12951 * Optimization for ()[last()] selection i.e. the last elem
12953 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
12954 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
12955 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
12956 int f
= comp
->steps
[op
->ch2
].ch1
;
12959 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
12960 (comp
->steps
[f
].value5
== NULL
) &&
12961 (comp
->steps
[f
].value
== 0) &&
12962 (comp
->steps
[f
].value4
!= NULL
) &&
12964 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
12965 xmlNodePtr last
= NULL
;
12968 xmlXPathCompOpEvalLast(ctxt
,
12969 &comp
->steps
[op
->ch1
],
12973 * The nodeset should be in document order,
12974 * Keep only the last value
12976 if ((ctxt
->value
!= NULL
) &&
12977 (ctxt
->value
->type
== XPATH_NODESET
) &&
12978 (ctxt
->value
->nodesetval
!= NULL
) &&
12979 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
12980 (ctxt
->value
->nodesetval
->nodeNr
> 1)) {
12981 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
12982 *first
= *(ctxt
->value
->nodesetval
->nodeTab
);
12989 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12993 if (ctxt
->value
== NULL
)
12996 #ifdef LIBXML_XPTR_ENABLED
12998 * Hum are we filtering the result of an XPointer expression
13000 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13001 xmlXPathObjectPtr tmp
= NULL
;
13002 xmlLocationSetPtr newlocset
= NULL
;
13003 xmlLocationSetPtr oldlocset
;
13006 * Extract the old locset, and then evaluate the result of the
13007 * expression for all the element in the locset. use it to grow
13010 CHECK_TYPE0(XPATH_LOCATIONSET
);
13012 if ((ctxt
->value
->user
== NULL
) ||
13013 (((xmlLocationSetPtr
) ctxt
->value
->user
)->locNr
== 0))
13016 obj
= valuePop(ctxt
);
13017 oldlocset
= obj
->user
;
13018 oldnode
= ctxt
->context
->node
;
13019 oldcs
= ctxt
->context
->contextSize
;
13020 oldpp
= ctxt
->context
->proximityPosition
;
13022 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13024 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13026 * Run the evaluation with a node list made of a
13027 * single item in the nodelocset.
13029 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13030 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13031 ctxt
->context
->proximityPosition
= i
+ 1;
13033 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13034 ctxt
->context
->node
);
13036 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13037 ctxt
->context
->node
) < 0) {
13038 ctxt
->error
= XPATH_MEMORY_ERROR
;
13041 valuePush(ctxt
, tmp
);
13043 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13044 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13045 xmlXPtrFreeLocationSet(newlocset
);
13049 * The result of the evaluation need to be tested to
13050 * decided whether the filter succeeded or not
13052 res
= valuePop(ctxt
);
13053 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13054 xmlXPtrLocationSetAdd(newlocset
,
13055 xmlXPathCacheObjectCopy(ctxt
->context
,
13056 oldlocset
->locTab
[i
]));
13062 xmlXPathReleaseObject(ctxt
->context
, res
);
13064 if (ctxt
->value
== tmp
) {
13066 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13068 * REVISIT TODO: Don't create a temporary nodeset
13069 * for everly iteration.
13071 /* OLD: xmlXPathFreeObject(res); */
13075 * Only put the first node in the result, then leave.
13077 if (newlocset
->locNr
> 0) {
13078 *first
= (xmlNodePtr
) oldlocset
->locTab
[i
]->user
;
13083 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13086 * The result is used as the new evaluation locset.
13088 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13090 xmlXPathReleaseObject(ctxt
->context
, obj
);
13091 ctxt
->context
->node
= oldnode
;
13092 ctxt
->context
->contextSize
= oldcs
;
13093 ctxt
->context
->proximityPosition
= oldpp
;
13096 #endif /* LIBXML_XPTR_ENABLED */
13099 * Extract the old set, and then evaluate the result of the
13100 * expression for all the element in the set. use it to grow
13103 CHECK_TYPE0(XPATH_NODESET
);
13105 if ((ctxt
->value
->nodesetval
!= NULL
) &&
13106 (ctxt
->value
->nodesetval
->nodeNr
!= 0)) {
13107 xmlNodeSetPtr newset
;
13108 xmlXPathObjectPtr tmp
= NULL
;
13110 obj
= valuePop(ctxt
);
13111 oldset
= obj
->nodesetval
;
13112 oldnode
= ctxt
->context
->node
;
13113 oldDoc
= ctxt
->context
->doc
;
13114 oldcs
= ctxt
->context
->contextSize
;
13115 oldpp
= ctxt
->context
->proximityPosition
;
13118 * Initialize the new set.
13119 * Also set the xpath document in case things like
13120 * key() evaluation are attempted on the predicate
13122 newset
= xmlXPathNodeSetCreate(NULL
);
13123 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13125 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13127 * Run the evaluation with a node list made of
13128 * a single item in the nodeset.
13130 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13131 if ((oldset
->nodeTab
[i
]->type
!= XML_NAMESPACE_DECL
) &&
13132 (oldset
->nodeTab
[i
]->doc
!= NULL
))
13133 ctxt
->context
->doc
= oldset
->nodeTab
[i
]->doc
;
13135 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13136 ctxt
->context
->node
);
13138 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13139 ctxt
->context
->node
) < 0) {
13140 ctxt
->error
= XPATH_MEMORY_ERROR
;
13143 valuePush(ctxt
, tmp
);
13144 ctxt
->context
->contextSize
= oldset
->nodeNr
;
13145 ctxt
->context
->proximityPosition
= i
+ 1;
13147 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13148 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13149 xmlXPathFreeNodeSet(newset
);
13153 * The result of the evaluation needs to be tested to
13154 * decide whether the filter succeeded or not
13156 res
= valuePop(ctxt
);
13157 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13158 if (xmlXPathNodeSetAdd(newset
, oldset
->nodeTab
[i
]) < 0)
13159 ctxt
->error
= XPATH_MEMORY_ERROR
;
13165 xmlXPathReleaseObject(ctxt
->context
, res
);
13167 if (ctxt
->value
== tmp
) {
13170 * Don't free the temporary nodeset
13171 * in order to avoid massive recreation inside this
13174 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13178 * Only put the first node in the result, then leave.
13180 if (newset
->nodeNr
> 0) {
13181 *first
= *(newset
->nodeTab
);
13186 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13189 * The result is used as the new evaluation set.
13191 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, newset
));
13193 xmlXPathReleaseObject(ctxt
->context
, obj
);
13194 ctxt
->context
->node
= oldnode
;
13195 ctxt
->context
->doc
= oldDoc
;
13196 ctxt
->context
->contextSize
= oldcs
;
13197 ctxt
->context
->proximityPosition
= oldpp
;
13201 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13204 * xmlXPathCompOpEval:
13205 * @ctxt: the XPath parser context with the compiled expression
13206 * @op: an XPath compiled operation
13208 * Evaluate the Precompiled XPath operation
13209 * Returns the number of nodes traversed
13212 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
)
13216 xmlXPathCompExprPtr comp
;
13217 xmlXPathObjectPtr arg1
, arg2
;
13225 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13227 xmlXPathBooleanFunction(ctxt
, 1);
13228 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 0))
13230 arg2
= valuePop(ctxt
);
13231 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13233 xmlXPathFreeObject(arg2
);
13236 xmlXPathBooleanFunction(ctxt
, 1);
13237 if (ctxt
->value
!= NULL
)
13238 ctxt
->value
->boolval
&= arg2
->boolval
;
13239 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13242 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13244 xmlXPathBooleanFunction(ctxt
, 1);
13245 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 1))
13247 arg2
= valuePop(ctxt
);
13248 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13250 xmlXPathFreeObject(arg2
);
13253 xmlXPathBooleanFunction(ctxt
, 1);
13254 if (ctxt
->value
!= NULL
)
13255 ctxt
->value
->boolval
|= arg2
->boolval
;
13256 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13258 case XPATH_OP_EQUAL
:
13259 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13261 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13264 equal
= xmlXPathEqualValues(ctxt
);
13266 equal
= xmlXPathNotEqualValues(ctxt
);
13267 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, equal
));
13270 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13272 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13274 ret
= xmlXPathCompareValues(ctxt
, op
->value
, op
->value2
);
13275 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
13277 case XPATH_OP_PLUS
:
13278 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13280 if (op
->ch2
!= -1) {
13281 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13284 if (op
->value
== 0)
13285 xmlXPathSubValues(ctxt
);
13286 else if (op
->value
== 1)
13287 xmlXPathAddValues(ctxt
);
13288 else if (op
->value
== 2)
13289 xmlXPathValueFlipSign(ctxt
);
13290 else if (op
->value
== 3) {
13292 CHECK_TYPE0(XPATH_NUMBER
);
13295 case XPATH_OP_MULT
:
13296 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13298 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13300 if (op
->value
== 0)
13301 xmlXPathMultValues(ctxt
);
13302 else if (op
->value
== 1)
13303 xmlXPathDivValues(ctxt
);
13304 else if (op
->value
== 2)
13305 xmlXPathModValues(ctxt
);
13307 case XPATH_OP_UNION
:
13308 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13310 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13313 arg2
= valuePop(ctxt
);
13314 arg1
= valuePop(ctxt
);
13315 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
13316 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
13317 xmlXPathReleaseObject(ctxt
->context
, arg1
);
13318 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13319 XP_ERROR0(XPATH_INVALID_TYPE
);
13322 if ((arg1
->nodesetval
== NULL
) ||
13323 ((arg2
->nodesetval
!= NULL
) &&
13324 (arg2
->nodesetval
->nodeNr
!= 0)))
13326 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
13330 valuePush(ctxt
, arg1
);
13331 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13333 case XPATH_OP_ROOT
:
13334 xmlXPathRoot(ctxt
);
13336 case XPATH_OP_NODE
:
13338 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13341 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13343 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
13344 ctxt
->context
->node
));
13346 case XPATH_OP_COLLECT
:{
13350 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13353 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 0);
13356 case XPATH_OP_VALUE
:
13358 xmlXPathCacheObjectCopy(ctxt
->context
,
13359 (xmlXPathObjectPtr
) op
->value4
));
13361 case XPATH_OP_VARIABLE
:{
13362 xmlXPathObjectPtr val
;
13366 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13367 if (op
->value5
== NULL
) {
13368 val
= xmlXPathVariableLookup(ctxt
->context
, op
->value4
);
13370 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13371 valuePush(ctxt
, val
);
13373 const xmlChar
*URI
;
13375 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13377 xmlGenericError(xmlGenericErrorContext
,
13378 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13379 (char *) op
->value4
, (char *)op
->value5
);
13380 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13383 val
= xmlXPathVariableLookupNS(ctxt
->context
,
13386 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13387 valuePush(ctxt
, val
);
13391 case XPATH_OP_FUNCTION
:{
13392 xmlXPathFunction func
;
13393 const xmlChar
*oldFunc
, *oldFuncURI
;
13397 frame
= xmlXPathSetFrame(ctxt
);
13398 if (op
->ch1
!= -1) {
13400 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13401 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13402 xmlXPathPopFrame(ctxt
, frame
);
13406 if (ctxt
->valueNr
< ctxt
->valueFrame
+ op
->value
) {
13407 xmlGenericError(xmlGenericErrorContext
,
13408 "xmlXPathCompOpEval: parameter error\n");
13409 ctxt
->error
= XPATH_INVALID_OPERAND
;
13410 xmlXPathPopFrame(ctxt
, frame
);
13413 for (i
= 0; i
< op
->value
; i
++) {
13414 if (ctxt
->valueTab
[(ctxt
->valueNr
- 1) - i
] == NULL
) {
13415 xmlGenericError(xmlGenericErrorContext
,
13416 "xmlXPathCompOpEval: parameter error\n");
13417 ctxt
->error
= XPATH_INVALID_OPERAND
;
13418 xmlXPathPopFrame(ctxt
, frame
);
13422 if (op
->cache
!= NULL
)
13425 const xmlChar
*URI
= NULL
;
13427 if (op
->value5
== NULL
)
13429 xmlXPathFunctionLookup(ctxt
->context
,
13432 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13434 xmlGenericError(xmlGenericErrorContext
,
13435 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13436 (char *)op
->value4
, (char *)op
->value5
);
13437 xmlXPathPopFrame(ctxt
, frame
);
13438 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13441 func
= xmlXPathFunctionLookupNS(ctxt
->context
,
13444 if (func
== NULL
) {
13445 xmlGenericError(xmlGenericErrorContext
,
13446 "xmlXPathCompOpEval: function %s not found\n",
13447 (char *)op
->value4
);
13448 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR
);
13451 op
->cacheURI
= (void *) URI
;
13453 oldFunc
= ctxt
->context
->function
;
13454 oldFuncURI
= ctxt
->context
->functionURI
;
13455 ctxt
->context
->function
= op
->value4
;
13456 ctxt
->context
->functionURI
= op
->cacheURI
;
13457 func(ctxt
, op
->value
);
13458 ctxt
->context
->function
= oldFunc
;
13459 ctxt
->context
->functionURI
= oldFuncURI
;
13460 xmlXPathPopFrame(ctxt
, frame
);
13464 if (op
->ch1
!= -1) {
13465 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13468 if (op
->ch2
!= -1) {
13469 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13473 case XPATH_OP_PREDICATE
:
13474 case XPATH_OP_FILTER
:{
13475 xmlXPathObjectPtr res
;
13476 xmlXPathObjectPtr obj
, tmp
;
13477 xmlNodeSetPtr newset
= NULL
;
13478 xmlNodeSetPtr oldset
;
13479 xmlNodePtr oldnode
;
13485 * Optimization for ()[1] selection i.e. the first elem
13487 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13488 #ifdef XP_OPTIMIZED_FILTER_FIRST
13490 * FILTER TODO: Can we assume that the inner processing
13491 * will result in an ordered list if we have an
13493 * What about an additional field or flag on
13494 * xmlXPathObject like @sorted ? This way we wouln'd need
13495 * to assume anything, so it would be more robust and
13496 * easier to optimize.
13498 ((comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) || /* 18 */
13499 (comp
->steps
[op
->ch1
].op
== XPATH_OP_FILTER
)) && /* 17 */
13501 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13503 (comp
->steps
[op
->ch2
].op
== XPATH_OP_VALUE
)) { /* 12 */
13504 xmlXPathObjectPtr val
;
13506 val
= comp
->steps
[op
->ch2
].value4
;
13507 if ((val
!= NULL
) && (val
->type
== XPATH_NUMBER
) &&
13508 (val
->floatval
== 1.0)) {
13509 xmlNodePtr first
= NULL
;
13512 xmlXPathCompOpEvalFirst(ctxt
,
13513 &comp
->steps
[op
->ch1
],
13517 * The nodeset should be in document order,
13518 * Keep only the first value
13520 if ((ctxt
->value
!= NULL
) &&
13521 (ctxt
->value
->type
== XPATH_NODESET
) &&
13522 (ctxt
->value
->nodesetval
!= NULL
) &&
13523 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13524 xmlXPathNodeSetClearFromPos(ctxt
->value
->nodesetval
,
13530 * Optimization for ()[last()] selection i.e. the last elem
13532 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13533 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13534 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
13535 int f
= comp
->steps
[op
->ch2
].ch1
;
13538 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
13539 (comp
->steps
[f
].value5
== NULL
) &&
13540 (comp
->steps
[f
].value
== 0) &&
13541 (comp
->steps
[f
].value4
!= NULL
) &&
13543 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
13544 xmlNodePtr last
= NULL
;
13547 xmlXPathCompOpEvalLast(ctxt
,
13548 &comp
->steps
[op
->ch1
],
13552 * The nodeset should be in document order,
13553 * Keep only the last value
13555 if ((ctxt
->value
!= NULL
) &&
13556 (ctxt
->value
->type
== XPATH_NODESET
) &&
13557 (ctxt
->value
->nodesetval
!= NULL
) &&
13558 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
13559 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13560 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
13565 * Process inner predicates first.
13566 * Example "index[parent::book][1]":
13568 * PREDICATE <-- we are here "[1]"
13569 * PREDICATE <-- process "[parent::book]" first
13571 * COLLECT 'parent' 'name' 'node' book
13573 * ELEM Object is a number : 1
13577 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13581 if (ctxt
->value
== NULL
)
13584 #ifdef LIBXML_XPTR_ENABLED
13586 * Hum are we filtering the result of an XPointer expression
13588 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13589 xmlLocationSetPtr newlocset
= NULL
;
13590 xmlLocationSetPtr oldlocset
;
13593 * Extract the old locset, and then evaluate the result of the
13594 * expression for all the element in the locset. use it to grow
13597 CHECK_TYPE0(XPATH_LOCATIONSET
);
13599 if ((ctxt
->value
->user
== NULL
) ||
13600 (((xmlLocationSetPtr
) ctxt
->value
->user
)->locNr
== 0))
13603 obj
= valuePop(ctxt
);
13604 oldlocset
= obj
->user
;
13605 oldnode
= ctxt
->context
->node
;
13606 oldcs
= ctxt
->context
->contextSize
;
13607 oldpp
= ctxt
->context
->proximityPosition
;
13609 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13611 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13613 * Run the evaluation with a node list made of a
13614 * single item in the nodelocset.
13616 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13617 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13618 ctxt
->context
->proximityPosition
= i
+ 1;
13619 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13620 ctxt
->context
->node
);
13621 valuePush(ctxt
, tmp
);
13625 xmlXPathCompOpEval(ctxt
,
13626 &comp
->steps
[op
->ch2
]);
13627 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13628 xmlXPtrFreeLocationSet(newlocset
);
13629 goto filter_xptr_error
;
13633 * The result of the evaluation need to be tested to
13634 * decided whether the filter succeeded or not
13636 res
= valuePop(ctxt
);
13637 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13638 xmlXPtrLocationSetAdd(newlocset
,
13640 (oldlocset
->locTab
[i
]));
13647 xmlXPathReleaseObject(ctxt
->context
, res
);
13649 if (ctxt
->value
== tmp
) {
13650 res
= valuePop(ctxt
);
13651 xmlXPathReleaseObject(ctxt
->context
, res
);
13656 * The result is used as the new evaluation locset.
13658 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13660 xmlXPathReleaseObject(ctxt
->context
, obj
);
13661 ctxt
->context
->node
= oldnode
;
13662 ctxt
->context
->contextSize
= oldcs
;
13663 ctxt
->context
->proximityPosition
= oldpp
;
13666 #endif /* LIBXML_XPTR_ENABLED */
13669 * Extract the old set, and then evaluate the result of the
13670 * expression for all the element in the set. use it to grow
13673 CHECK_TYPE0(XPATH_NODESET
);
13675 if ((ctxt
->value
->nodesetval
!= NULL
) &&
13676 (ctxt
->value
->nodesetval
->nodeNr
!= 0)) {
13677 obj
= valuePop(ctxt
);
13678 oldset
= obj
->nodesetval
;
13679 oldnode
= ctxt
->context
->node
;
13680 oldDoc
= ctxt
->context
->doc
;
13681 oldcs
= ctxt
->context
->contextSize
;
13682 oldpp
= ctxt
->context
->proximityPosition
;
13685 * Initialize the new set.
13686 * Also set the xpath document in case things like
13687 * key() evaluation are attempted on the predicate
13689 newset
= xmlXPathNodeSetCreate(NULL
);
13692 * "For each node in the node-set to be filtered, the
13693 * PredicateExpr is evaluated with that node as the
13694 * context node, with the number of nodes in the
13695 * node-set as the context size, and with the proximity
13696 * position of the node in the node-set with respect to
13697 * the axis as the context position;"
13698 * @oldset is the node-set" to be filtered.
13701 * "only predicates change the context position and
13702 * context size (see [2.4 Predicates])."
13704 * node-set context pos
13708 * After applying predicate [position() > 1] :
13709 * node-set context pos
13713 * removed the first node in the node-set, then
13714 * the context position of the
13716 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13718 * Run the evaluation with a node list made of
13719 * a single item in the nodeset.
13721 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13722 if ((oldset
->nodeTab
[i
]->type
!= XML_NAMESPACE_DECL
) &&
13723 (oldset
->nodeTab
[i
]->doc
!= NULL
))
13724 ctxt
->context
->doc
= oldset
->nodeTab
[i
]->doc
;
13726 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13727 ctxt
->context
->node
);
13729 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13730 ctxt
->context
->node
) < 0) {
13731 ctxt
->error
= XPATH_MEMORY_ERROR
;
13734 valuePush(ctxt
, tmp
);
13735 ctxt
->context
->contextSize
= oldset
->nodeNr
;
13736 ctxt
->context
->proximityPosition
= i
+ 1;
13738 * Evaluate the predicate against the context node.
13739 * Can/should we optimize position() predicates
13740 * here (e.g. "[1]")?
13744 xmlXPathCompOpEval(ctxt
,
13745 &comp
->steps
[op
->ch2
]);
13746 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13747 xmlXPathFreeNodeSet(newset
);
13752 * The result of the evaluation needs to be tested to
13753 * decide whether the filter succeeded or not
13756 * OPTIMIZE TODO: Can we use
13757 * xmlXPathNodeSetAdd*Unique()* instead?
13759 res
= valuePop(ctxt
);
13760 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13761 if (xmlXPathNodeSetAdd(newset
, oldset
->nodeTab
[i
])
13763 ctxt
->error
= XPATH_MEMORY_ERROR
;
13770 xmlXPathReleaseObject(ctxt
->context
, res
);
13772 if (ctxt
->value
== tmp
) {
13774 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13776 * Don't free the temporary nodeset
13777 * in order to avoid massive recreation inside this
13784 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13786 * The result is used as the new evaluation set.
13789 xmlXPathCacheWrapNodeSet(ctxt
->context
, newset
));
13791 xmlXPathReleaseObject(ctxt
->context
, obj
);
13792 ctxt
->context
->node
= oldnode
;
13793 ctxt
->context
->doc
= oldDoc
;
13794 ctxt
->context
->contextSize
= oldcs
;
13795 ctxt
->context
->proximityPosition
= oldpp
;
13799 case XPATH_OP_SORT
:
13801 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13803 if ((ctxt
->value
!= NULL
) &&
13804 (ctxt
->value
->type
== XPATH_NODESET
) &&
13805 (ctxt
->value
->nodesetval
!= NULL
) &&
13806 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13808 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
13811 #ifdef LIBXML_XPTR_ENABLED
13812 case XPATH_OP_RANGETO
:{
13813 xmlXPathObjectPtr range
;
13814 xmlXPathObjectPtr res
, obj
;
13815 xmlXPathObjectPtr tmp
;
13816 xmlLocationSetPtr newlocset
= NULL
;
13817 xmlLocationSetPtr oldlocset
;
13818 xmlNodeSetPtr oldset
;
13819 xmlNodePtr oldnode
= ctxt
->context
->node
;
13820 int oldcs
= ctxt
->context
->contextSize
;
13821 int oldpp
= ctxt
->context
->proximityPosition
;
13824 if (op
->ch1
!= -1) {
13826 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13829 if (ctxt
->value
== NULL
) {
13830 XP_ERROR0(XPATH_INVALID_OPERAND
);
13835 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13837 * Extract the old locset, and then evaluate the result of the
13838 * expression for all the element in the locset. use it to grow
13841 CHECK_TYPE0(XPATH_LOCATIONSET
);
13843 if ((ctxt
->value
->user
== NULL
) ||
13844 (((xmlLocationSetPtr
) ctxt
->value
->user
)->locNr
== 0))
13847 obj
= valuePop(ctxt
);
13848 oldlocset
= obj
->user
;
13850 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13852 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13854 * Run the evaluation with a node list made of a
13855 * single item in the nodelocset.
13857 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13858 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13859 ctxt
->context
->proximityPosition
= i
+ 1;
13860 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13861 ctxt
->context
->node
);
13862 valuePush(ctxt
, tmp
);
13866 xmlXPathCompOpEval(ctxt
,
13867 &comp
->steps
[op
->ch2
]);
13868 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13869 xmlXPtrFreeLocationSet(newlocset
);
13870 goto rangeto_error
;
13873 res
= valuePop(ctxt
);
13874 if (res
->type
== XPATH_LOCATIONSET
) {
13875 xmlLocationSetPtr rloc
=
13876 (xmlLocationSetPtr
)res
->user
;
13877 for (j
=0; j
<rloc
->locNr
; j
++) {
13878 range
= xmlXPtrNewRange(
13879 oldlocset
->locTab
[i
]->user
,
13880 oldlocset
->locTab
[i
]->index
,
13881 rloc
->locTab
[j
]->user2
,
13882 rloc
->locTab
[j
]->index2
);
13883 if (range
!= NULL
) {
13884 xmlXPtrLocationSetAdd(newlocset
, range
);
13888 range
= xmlXPtrNewRangeNodeObject(
13889 (xmlNodePtr
)oldlocset
->locTab
[i
]->user
, res
);
13890 if (range
!= NULL
) {
13891 xmlXPtrLocationSetAdd(newlocset
,range
);
13899 xmlXPathReleaseObject(ctxt
->context
, res
);
13901 if (ctxt
->value
== tmp
) {
13902 res
= valuePop(ctxt
);
13903 xmlXPathReleaseObject(ctxt
->context
, res
);
13906 } else { /* Not a location set */
13907 CHECK_TYPE0(XPATH_NODESET
);
13908 obj
= valuePop(ctxt
);
13909 oldset
= obj
->nodesetval
;
13911 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13913 if (oldset
!= NULL
) {
13914 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13916 * Run the evaluation with a node list made of a single item
13919 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13921 * OPTIMIZE TODO: Avoid recreation for every iteration.
13923 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13924 ctxt
->context
->node
);
13925 valuePush(ctxt
, tmp
);
13929 xmlXPathCompOpEval(ctxt
,
13930 &comp
->steps
[op
->ch2
]);
13931 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13932 xmlXPtrFreeLocationSet(newlocset
);
13933 goto rangeto_error
;
13936 res
= valuePop(ctxt
);
13938 xmlXPtrNewRangeNodeObject(oldset
->nodeTab
[i
],
13940 if (range
!= NULL
) {
13941 xmlXPtrLocationSetAdd(newlocset
, range
);
13948 xmlXPathReleaseObject(ctxt
->context
, res
);
13950 if (ctxt
->value
== tmp
) {
13951 res
= valuePop(ctxt
);
13952 xmlXPathReleaseObject(ctxt
->context
, res
);
13959 * The result is used as the new evaluation set.
13961 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13963 xmlXPathReleaseObject(ctxt
->context
, obj
);
13964 ctxt
->context
->node
= oldnode
;
13965 ctxt
->context
->contextSize
= oldcs
;
13966 ctxt
->context
->proximityPosition
= oldpp
;
13969 #endif /* LIBXML_XPTR_ENABLED */
13971 xmlGenericError(xmlGenericErrorContext
,
13972 "XPath: unknown precompiled operation %d\n", op
->op
);
13973 ctxt
->error
= XPATH_INVALID_OPERAND
;
13978 * xmlXPathCompOpEvalToBoolean:
13979 * @ctxt: the XPath parser context
13981 * Evaluates if the expression evaluates to true.
13983 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13986 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
13987 xmlXPathStepOpPtr op
,
13990 xmlXPathObjectPtr resObj
= NULL
;
13993 /* comp = ctxt->comp; */
13997 case XPATH_OP_VALUE
:
13998 resObj
= (xmlXPathObjectPtr
) op
->value4
;
14000 return(xmlXPathEvaluatePredicateResult(ctxt
, resObj
));
14001 return(xmlXPathCastToBoolean(resObj
));
14002 case XPATH_OP_SORT
:
14004 * We don't need sorting for boolean results. Skip this one.
14006 if (op
->ch1
!= -1) {
14007 op
= &ctxt
->comp
->steps
[op
->ch1
];
14011 case XPATH_OP_COLLECT
:
14015 xmlXPathCompOpEval(ctxt
, &ctxt
->comp
->steps
[op
->ch1
]);
14016 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14019 xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 1);
14020 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14023 resObj
= valuePop(ctxt
);
14024 if (resObj
== NULL
)
14029 * Fallback to call xmlXPathCompOpEval().
14031 xmlXPathCompOpEval(ctxt
, op
);
14032 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14035 resObj
= valuePop(ctxt
);
14036 if (resObj
== NULL
)
14044 if (resObj
->type
== XPATH_BOOLEAN
) {
14045 res
= resObj
->boolval
;
14046 } else if (isPredicate
) {
14048 * For predicates a result of type "number" is handled
14051 * "If the result is a number, the result will be converted
14052 * to true if the number is equal to the context position
14053 * and will be converted to false otherwise;"
14055 res
= xmlXPathEvaluatePredicateResult(ctxt
, resObj
);
14057 res
= xmlXPathCastToBoolean(resObj
);
14059 xmlXPathReleaseObject(ctxt
->context
, resObj
);
14066 #ifdef XPATH_STREAMING
14068 * xmlXPathRunStreamEval:
14069 * @ctxt: the XPath parser context with the compiled expression
14071 * Evaluate the Precompiled Streamable XPath expression in the given context.
14074 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt
, xmlPatternPtr comp
,
14075 xmlXPathObjectPtr
*resultSeq
, int toBool
)
14077 int max_depth
, min_depth
;
14080 int eval_all_nodes
;
14081 xmlNodePtr cur
= NULL
, limit
= NULL
;
14082 xmlStreamCtxtPtr patstream
= NULL
;
14086 if ((ctxt
== NULL
) || (comp
== NULL
))
14088 max_depth
= xmlPatternMaxDepth(comp
);
14089 if (max_depth
== -1)
14091 if (max_depth
== -2)
14093 min_depth
= xmlPatternMinDepth(comp
);
14094 if (min_depth
== -1)
14096 from_root
= xmlPatternFromRoot(comp
);
14100 printf("stream eval: depth %d from root %d\n", max_depth
, from_root
);
14104 if (resultSeq
== NULL
)
14106 *resultSeq
= xmlXPathCacheNewNodeSet(ctxt
, NULL
);
14107 if (*resultSeq
== NULL
)
14112 * handle the special cases of "/" amd "." being matched
14114 if (min_depth
== 0) {
14119 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
,
14120 (xmlNodePtr
) ctxt
->doc
);
14122 /* Select "self::node()" */
14125 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, ctxt
->node
);
14128 if (max_depth
== 0) {
14133 cur
= (xmlNodePtr
)ctxt
->doc
;
14134 } else if (ctxt
->node
!= NULL
) {
14135 switch (ctxt
->node
->type
) {
14136 case XML_ELEMENT_NODE
:
14137 case XML_DOCUMENT_NODE
:
14138 case XML_DOCUMENT_FRAG_NODE
:
14139 case XML_HTML_DOCUMENT_NODE
:
14140 #ifdef LIBXML_DOCB_ENABLED
14141 case XML_DOCB_DOCUMENT_NODE
:
14145 case XML_ATTRIBUTE_NODE
:
14146 case XML_TEXT_NODE
:
14147 case XML_CDATA_SECTION_NODE
:
14148 case XML_ENTITY_REF_NODE
:
14149 case XML_ENTITY_NODE
:
14151 case XML_COMMENT_NODE
:
14152 case XML_NOTATION_NODE
:
14154 case XML_DOCUMENT_TYPE_NODE
:
14155 case XML_ELEMENT_DECL
:
14156 case XML_ATTRIBUTE_DECL
:
14157 case XML_ENTITY_DECL
:
14158 case XML_NAMESPACE_DECL
:
14159 case XML_XINCLUDE_START
:
14160 case XML_XINCLUDE_END
:
14169 patstream
= xmlPatternGetStreamCtxt(comp
);
14170 if (patstream
== NULL
) {
14172 * QUESTION TODO: Is this an error?
14177 eval_all_nodes
= xmlStreamWantsAnyNode(patstream
);
14180 ret
= xmlStreamPush(patstream
, NULL
, NULL
);
14182 } else if (ret
== 1) {
14185 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
);
14189 goto scan_children
;
14194 switch (cur
->type
) {
14195 case XML_ELEMENT_NODE
:
14196 case XML_TEXT_NODE
:
14197 case XML_CDATA_SECTION_NODE
:
14198 case XML_COMMENT_NODE
:
14200 if (cur
->type
== XML_ELEMENT_NODE
) {
14201 ret
= xmlStreamPush(patstream
, cur
->name
,
14202 (cur
->ns
? cur
->ns
->href
: NULL
));
14203 } else if (eval_all_nodes
)
14204 ret
= xmlStreamPushNode(patstream
, NULL
, NULL
, cur
->type
);
14210 } else if (ret
== 1) {
14213 if (xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
)
14215 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
14216 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
14219 if ((cur
->children
== NULL
) || (depth
>= max_depth
)) {
14220 ret
= xmlStreamPop(patstream
);
14221 while (cur
->next
!= NULL
) {
14223 if ((cur
->type
!= XML_ENTITY_DECL
) &&
14224 (cur
->type
!= XML_DTD_NODE
))
14233 if (cur
->type
== XML_NAMESPACE_DECL
) break;
14234 if ((cur
->children
!= NULL
) && (depth
< max_depth
)) {
14236 * Do not descend on entities declarations
14238 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
14239 cur
= cur
->children
;
14244 if (cur
->type
!= XML_DTD_NODE
)
14252 while (cur
->next
!= NULL
) {
14254 if ((cur
->type
!= XML_ENTITY_DECL
) &&
14255 (cur
->type
!= XML_DTD_NODE
))
14262 if ((cur
== NULL
) || (cur
== limit
))
14264 if (cur
->type
== XML_ELEMENT_NODE
) {
14265 ret
= xmlStreamPop(patstream
);
14266 } else if ((eval_all_nodes
) &&
14267 ((cur
->type
== XML_TEXT_NODE
) ||
14268 (cur
->type
== XML_CDATA_SECTION_NODE
) ||
14269 (cur
->type
== XML_COMMENT_NODE
) ||
14270 (cur
->type
== XML_PI_NODE
)))
14272 ret
= xmlStreamPop(patstream
);
14274 if (cur
->next
!= NULL
) {
14278 } while (cur
!= NULL
);
14280 } while ((cur
!= NULL
) && (depth
>= 0));
14285 printf("stream eval: checked %d nodes selected %d\n",
14286 nb_nodes
, retObj
->nodesetval
->nodeNr
);
14290 xmlFreeStreamCtxt(patstream
);
14295 xmlFreeStreamCtxt(patstream
);
14298 #endif /* XPATH_STREAMING */
14302 * @ctxt: the XPath parser context with the compiled expression
14303 * @toBool: evaluate to a boolean result
14305 * Evaluate the Precompiled XPath expression in the given context.
14308 xmlXPathRunEval(xmlXPathParserContextPtr ctxt
, int toBool
)
14310 xmlXPathCompExprPtr comp
;
14312 if ((ctxt
== NULL
) || (ctxt
->comp
== NULL
))
14315 if (ctxt
->valueTab
== NULL
) {
14316 /* Allocate the value stack */
14317 ctxt
->valueTab
= (xmlXPathObjectPtr
*)
14318 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
14319 if (ctxt
->valueTab
== NULL
) {
14320 xmlXPathPErrMemory(ctxt
, "creating evaluation context\n");
14324 ctxt
->valueMax
= 10;
14325 ctxt
->value
= NULL
;
14326 ctxt
->valueFrame
= 0;
14328 #ifdef XPATH_STREAMING
14329 if (ctxt
->comp
->stream
) {
14334 * Evaluation to boolean result.
14336 res
= xmlXPathRunStreamEval(ctxt
->context
,
14337 ctxt
->comp
->stream
, NULL
, 1);
14341 xmlXPathObjectPtr resObj
= NULL
;
14344 * Evaluation to a sequence.
14346 res
= xmlXPathRunStreamEval(ctxt
->context
,
14347 ctxt
->comp
->stream
, &resObj
, 0);
14349 if ((res
!= -1) && (resObj
!= NULL
)) {
14350 valuePush(ctxt
, resObj
);
14353 if (resObj
!= NULL
)
14354 xmlXPathReleaseObject(ctxt
->context
, resObj
);
14357 * QUESTION TODO: This falls back to normal XPath evaluation
14358 * if res == -1. Is this intended?
14363 if (comp
->last
< 0) {
14364 xmlGenericError(xmlGenericErrorContext
,
14365 "xmlXPathRunEval: last is less than zero\n");
14369 return(xmlXPathCompOpEvalToBoolean(ctxt
,
14370 &comp
->steps
[comp
->last
], 0));
14372 xmlXPathCompOpEval(ctxt
, &comp
->steps
[comp
->last
]);
14377 /************************************************************************
14379 * Public interfaces *
14381 ************************************************************************/
14384 * xmlXPathEvalPredicate:
14385 * @ctxt: the XPath context
14386 * @res: the Predicate Expression evaluation result
14388 * Evaluate a predicate result for the current node.
14389 * A PredicateExpr is evaluated by evaluating the Expr and converting
14390 * the result to a boolean. If the result is a number, the result will
14391 * be converted to true if the number is equal to the position of the
14392 * context node in the context node list (as returned by the position
14393 * function) and will be converted to false otherwise; if the result
14394 * is not a number, then the result will be converted as if by a call
14395 * to the boolean function.
14397 * Returns 1 if predicate is true, 0 otherwise
14400 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr res
) {
14401 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14402 switch (res
->type
) {
14403 case XPATH_BOOLEAN
:
14404 return(res
->boolval
);
14406 return(res
->floatval
== ctxt
->proximityPosition
);
14407 case XPATH_NODESET
:
14408 case XPATH_XSLT_TREE
:
14409 if (res
->nodesetval
== NULL
)
14411 return(res
->nodesetval
->nodeNr
!= 0);
14413 return((res
->stringval
!= NULL
) &&
14414 (xmlStrlen(res
->stringval
) != 0));
14422 * xmlXPathEvaluatePredicateResult:
14423 * @ctxt: the XPath Parser context
14424 * @res: the Predicate Expression evaluation result
14426 * Evaluate a predicate result for the current node.
14427 * A PredicateExpr is evaluated by evaluating the Expr and converting
14428 * the result to a boolean. If the result is a number, the result will
14429 * be converted to true if the number is equal to the position of the
14430 * context node in the context node list (as returned by the position
14431 * function) and will be converted to false otherwise; if the result
14432 * is not a number, then the result will be converted as if by a call
14433 * to the boolean function.
14435 * Returns 1 if predicate is true, 0 otherwise
14438 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt
,
14439 xmlXPathObjectPtr res
) {
14440 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14441 switch (res
->type
) {
14442 case XPATH_BOOLEAN
:
14443 return(res
->boolval
);
14445 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14446 return((res
->floatval
== ctxt
->context
->proximityPosition
) &&
14447 (!xmlXPathIsNaN(res
->floatval
))); /* MSC pbm Mark Vakoc !*/
14449 return(res
->floatval
== ctxt
->context
->proximityPosition
);
14451 case XPATH_NODESET
:
14452 case XPATH_XSLT_TREE
:
14453 if (res
->nodesetval
== NULL
)
14455 return(res
->nodesetval
->nodeNr
!= 0);
14457 return((res
->stringval
!= NULL
) && (res
->stringval
[0] != 0));
14458 #ifdef LIBXML_XPTR_ENABLED
14459 case XPATH_LOCATIONSET
:{
14460 xmlLocationSetPtr ptr
= res
->user
;
14463 return (ptr
->locNr
!= 0);
14472 #ifdef XPATH_STREAMING
14474 * xmlXPathTryStreamCompile:
14475 * @ctxt: an XPath context
14476 * @str: the XPath expression
14478 * Try to compile the XPath expression as a streamable subset.
14480 * Returns the compiled expression or NULL if failed to compile.
14482 static xmlXPathCompExprPtr
14483 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14485 * Optimization: use streaming patterns when the XPath expression can
14486 * be compiled to a stream lookup
14488 xmlPatternPtr stream
;
14489 xmlXPathCompExprPtr comp
;
14490 xmlDictPtr dict
= NULL
;
14491 const xmlChar
**namespaces
= NULL
;
14495 if ((!xmlStrchr(str
, '[')) && (!xmlStrchr(str
, '(')) &&
14496 (!xmlStrchr(str
, '@'))) {
14497 const xmlChar
*tmp
;
14500 * We don't try to handle expressions using the verbose axis
14501 * specifiers ("::"), just the simplied form at this point.
14502 * Additionally, if there is no list of namespaces available and
14503 * there's a ":" in the expression, indicating a prefixed QName,
14504 * then we won't try to compile either. xmlPatterncompile() needs
14505 * to have a list of namespaces at compilation time in order to
14506 * compile prefixed name tests.
14508 tmp
= xmlStrchr(str
, ':');
14509 if ((tmp
!= NULL
) &&
14510 ((ctxt
== NULL
) || (ctxt
->nsNr
== 0) || (tmp
[1] == ':')))
14513 if (ctxt
!= NULL
) {
14515 if (ctxt
->nsNr
> 0) {
14516 namespaces
= xmlMalloc(2 * (ctxt
->nsNr
+ 1) * sizeof(xmlChar
*));
14517 if (namespaces
== NULL
) {
14518 xmlXPathErrMemory(ctxt
, "allocating namespaces array\n");
14521 for (i
= 0, j
= 0; (j
< ctxt
->nsNr
); j
++) {
14522 ns
= ctxt
->namespaces
[j
];
14523 namespaces
[i
++] = ns
->href
;
14524 namespaces
[i
++] = ns
->prefix
;
14526 namespaces
[i
++] = NULL
;
14527 namespaces
[i
] = NULL
;
14531 stream
= xmlPatterncompile(str
, dict
, XML_PATTERN_XPATH
,
14533 if (namespaces
!= NULL
) {
14534 xmlFree((xmlChar
**)namespaces
);
14536 if ((stream
!= NULL
) && (xmlPatternStreamable(stream
) == 1)) {
14537 comp
= xmlXPathNewCompExpr();
14538 if (comp
== NULL
) {
14539 xmlXPathErrMemory(ctxt
, "allocating streamable expression\n");
14542 comp
->stream
= stream
;
14545 xmlDictReference(comp
->dict
);
14548 xmlFreePattern(stream
);
14552 #endif /* XPATH_STREAMING */
14555 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp
, xmlXPathStepOpPtr op
)
14558 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14559 * internal representation.
14562 if ((op
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14564 (op
->ch2
== -1 /* no predicate */))
14566 xmlXPathStepOpPtr prevop
= &comp
->steps
[op
->ch1
];
14568 if ((prevop
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14569 ((xmlXPathAxisVal
) prevop
->value
==
14570 AXIS_DESCENDANT_OR_SELF
) &&
14571 (prevop
->ch2
== -1) &&
14572 ((xmlXPathTestVal
) prevop
->value2
== NODE_TEST_TYPE
) &&
14573 ((xmlXPathTypeVal
) prevop
->value3
== NODE_TYPE_NODE
))
14576 * This is a "descendant-or-self::node()" without predicates.
14577 * Try to eliminate it.
14580 switch ((xmlXPathAxisVal
) op
->value
) {
14582 case AXIS_DESCENDANT
:
14584 * Convert "descendant-or-self::node()/child::" or
14585 * "descendant-or-self::node()/descendant::" to
14588 op
->ch1
= prevop
->ch1
;
14589 op
->value
= AXIS_DESCENDANT
;
14592 case AXIS_DESCENDANT_OR_SELF
:
14594 * Convert "descendant-or-self::node()/self::" or
14595 * "descendant-or-self::node()/descendant-or-self::" to
14596 * to "descendant-or-self::"
14598 op
->ch1
= prevop
->ch1
;
14599 op
->value
= AXIS_DESCENDANT_OR_SELF
;
14607 /* OP_VALUE has invalid ch1. */
14608 if (op
->op
== XPATH_OP_VALUE
)
14613 xmlXPathOptimizeExpression(comp
, &comp
->steps
[op
->ch1
]);
14615 xmlXPathOptimizeExpression(comp
, &comp
->steps
[op
->ch2
]);
14619 * xmlXPathCtxtCompile:
14620 * @ctxt: an XPath context
14621 * @str: the XPath expression
14623 * Compile an XPath expression
14625 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14626 * the caller has to free the object.
14628 xmlXPathCompExprPtr
14629 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14630 xmlXPathParserContextPtr pctxt
;
14631 xmlXPathCompExprPtr comp
;
14633 #ifdef XPATH_STREAMING
14634 comp
= xmlXPathTryStreamCompile(ctxt
, str
);
14641 pctxt
= xmlXPathNewParserContext(str
, ctxt
);
14644 xmlXPathCompileExpr(pctxt
, 1);
14646 if( pctxt
->error
!= XPATH_EXPRESSION_OK
)
14648 xmlXPathFreeParserContext(pctxt
);
14652 if (*pctxt
->cur
!= 0) {
14654 * aleksey: in some cases this line prints *second* error message
14655 * (see bug #78858) and probably this should be fixed.
14656 * However, we are not sure that all error messages are printed
14657 * out in other places. It's not critical so we leave it as-is for now
14659 xmlXPatherror(pctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
14662 comp
= pctxt
->comp
;
14663 pctxt
->comp
= NULL
;
14665 xmlXPathFreeParserContext(pctxt
);
14667 if (comp
!= NULL
) {
14668 comp
->expr
= xmlStrdup(str
);
14669 #ifdef DEBUG_EVAL_COUNTS
14670 comp
->string
= xmlStrdup(str
);
14673 if ((comp
->nbStep
> 1) && (comp
->last
>= 0)) {
14674 xmlXPathOptimizeExpression(comp
, &comp
->steps
[comp
->last
]);
14682 * @str: the XPath expression
14684 * Compile an XPath expression
14686 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14687 * the caller has to free the object.
14689 xmlXPathCompExprPtr
14690 xmlXPathCompile(const xmlChar
*str
) {
14691 return(xmlXPathCtxtCompile(NULL
, str
));
14695 * xmlXPathCompiledEvalInternal:
14696 * @comp: the compiled XPath expression
14697 * @ctxt: the XPath context
14698 * @resObj: the resulting XPath object or NULL
14699 * @toBool: 1 if only a boolean result is requested
14701 * Evaluate the Precompiled XPath expression in the given context.
14702 * The caller has to free @resObj.
14704 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14705 * the caller has to free the object.
14708 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp
,
14709 xmlXPathContextPtr ctxt
,
14710 xmlXPathObjectPtr
*resObjPtr
,
14713 xmlXPathParserContextPtr pctxt
;
14714 xmlXPathObjectPtr resObj
;
14715 #ifndef LIBXML_THREAD_ENABLED
14716 static int reentance
= 0;
14720 CHECK_CTXT_NEG(ctxt
)
14726 #ifndef LIBXML_THREAD_ENABLED
14729 xmlXPathDisableOptimizer
= 1;
14732 #ifdef DEBUG_EVAL_COUNTS
14734 if ((comp
->string
!= NULL
) && (comp
->nb
> 100)) {
14735 fprintf(stderr
, "100 x %s\n", comp
->string
);
14739 pctxt
= xmlXPathCompParserContext(comp
, ctxt
);
14740 res
= xmlXPathRunEval(pctxt
, toBool
);
14742 if (pctxt
->error
!= XPATH_EXPRESSION_OK
) {
14745 resObj
= valuePop(pctxt
);
14746 if (resObj
== NULL
) {
14748 xmlGenericError(xmlGenericErrorContext
,
14749 "xmlXPathCompiledEval: No result on the stack.\n");
14750 } else if (pctxt
->valueNr
> 0) {
14751 xmlGenericError(xmlGenericErrorContext
,
14752 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14758 *resObjPtr
= resObj
;
14760 xmlXPathReleaseObject(ctxt
, resObj
);
14762 pctxt
->comp
= NULL
;
14763 xmlXPathFreeParserContext(pctxt
);
14764 #ifndef LIBXML_THREAD_ENABLED
14772 * xmlXPathCompiledEval:
14773 * @comp: the compiled XPath expression
14774 * @ctx: the XPath context
14776 * Evaluate the Precompiled XPath expression in the given context.
14778 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14779 * the caller has to free the object.
14782 xmlXPathCompiledEval(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctx
)
14784 xmlXPathObjectPtr res
= NULL
;
14786 xmlXPathCompiledEvalInternal(comp
, ctx
, &res
, 0);
14791 * xmlXPathCompiledEvalToBoolean:
14792 * @comp: the compiled XPath expression
14793 * @ctxt: the XPath context
14795 * Applies the XPath boolean() function on the result of the given
14796 * compiled expression.
14798 * Returns 1 if the expression evaluated to true, 0 if to false and
14799 * -1 in API and internal errors.
14802 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp
,
14803 xmlXPathContextPtr ctxt
)
14805 return(xmlXPathCompiledEvalInternal(comp
, ctxt
, NULL
, 1));
14809 * xmlXPathEvalExpr:
14810 * @ctxt: the XPath Parser context
14812 * Parse and evaluate an XPath expression in the given context,
14813 * then push the result on the context stack
14816 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt
) {
14817 #ifdef XPATH_STREAMING
14818 xmlXPathCompExprPtr comp
;
14821 if (ctxt
== NULL
) return;
14823 #ifdef XPATH_STREAMING
14824 comp
= xmlXPathTryStreamCompile(ctxt
->context
, ctxt
->base
);
14825 if (comp
!= NULL
) {
14826 if (ctxt
->comp
!= NULL
)
14827 xmlXPathFreeCompExpr(ctxt
->comp
);
14832 xmlXPathCompileExpr(ctxt
, 1);
14835 /* Check for trailing characters. */
14836 if (*ctxt
->cur
!= 0)
14837 XP_ERROR(XPATH_EXPR_ERROR
);
14839 if ((ctxt
->comp
->nbStep
> 1) && (ctxt
->comp
->last
>= 0))
14840 xmlXPathOptimizeExpression(ctxt
->comp
,
14841 &ctxt
->comp
->steps
[ctxt
->comp
->last
]);
14844 xmlXPathRunEval(ctxt
, 0);
14849 * @str: the XPath expression
14850 * @ctx: the XPath context
14852 * Evaluate the XPath Location Path in the given context.
14854 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14855 * the caller has to free the object.
14858 xmlXPathEval(const xmlChar
*str
, xmlXPathContextPtr ctx
) {
14859 xmlXPathParserContextPtr ctxt
;
14860 xmlXPathObjectPtr res
;
14866 ctxt
= xmlXPathNewParserContext(str
, ctx
);
14869 xmlXPathEvalExpr(ctxt
);
14871 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14874 res
= valuePop(ctxt
);
14876 xmlGenericError(xmlGenericErrorContext
,
14877 "xmlXPathCompiledEval: No result on the stack.\n");
14878 } else if (ctxt
->valueNr
> 0) {
14879 xmlGenericError(xmlGenericErrorContext
,
14880 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14885 xmlXPathFreeParserContext(ctxt
);
14890 * xmlXPathSetContextNode:
14891 * @node: the node to to use as the context node
14892 * @ctx: the XPath context
14894 * Sets 'node' as the context node. The node must be in the same
14895 * document as that associated with the context.
14897 * Returns -1 in case of error or 0 if successful
14900 xmlXPathSetContextNode(xmlNodePtr node
, xmlXPathContextPtr ctx
) {
14901 if ((node
== NULL
) || (ctx
== NULL
))
14904 if (node
->doc
== ctx
->doc
) {
14912 * xmlXPathNodeEval:
14913 * @node: the node to to use as the context node
14914 * @str: the XPath expression
14915 * @ctx: the XPath context
14917 * Evaluate the XPath Location Path in the given context. The node 'node'
14918 * is set as the context node. The context node is not restored.
14920 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14921 * the caller has to free the object.
14924 xmlXPathNodeEval(xmlNodePtr node
, const xmlChar
*str
, xmlXPathContextPtr ctx
) {
14927 if (xmlXPathSetContextNode(node
, ctx
) < 0)
14929 return(xmlXPathEval(str
, ctx
));
14933 * xmlXPathEvalExpression:
14934 * @str: the XPath expression
14935 * @ctxt: the XPath context
14937 * Alias for xmlXPathEval().
14939 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14940 * the caller has to free the object.
14943 xmlXPathEvalExpression(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
14944 return(xmlXPathEval(str
, ctxt
));
14947 /************************************************************************
14949 * Extra functions not pertaining to the XPath spec *
14951 ************************************************************************/
14953 * xmlXPathEscapeUriFunction:
14954 * @ctxt: the XPath Parser context
14955 * @nargs: the number of arguments
14957 * Implement the escape-uri() XPath function
14958 * string escape-uri(string $str, bool $escape-reserved)
14960 * This function applies the URI escaping rules defined in section 2 of [RFC
14961 * 2396] to the string supplied as $uri-part, which typically represents all
14962 * or part of a URI. The effect of the function is to replace any special
14963 * character in the string by an escape sequence of the form %xx%yy...,
14964 * where xxyy... is the hexadecimal representation of the octets used to
14965 * represent the character in UTF-8.
14967 * The set of characters that are escaped depends on the setting of the
14968 * boolean argument $escape-reserved.
14970 * If $escape-reserved is true, all characters are escaped other than lower
14971 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14972 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14973 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14974 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14977 * If $escape-reserved is false, the behavior differs in that characters
14978 * referred to in [RFC 2396] as reserved characters are not escaped. These
14979 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14981 * [RFC 2396] does not define whether escaped URIs should use lower case or
14982 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14983 * compared using string comparison functions, this function must always use
14984 * the upper-case letters A-F.
14986 * Generally, $escape-reserved should be set to true when escaping a string
14987 * that is to form a single part of a URI, and to false when escaping an
14988 * entire URI or URI reference.
14990 * In the case of non-ascii characters, the string is encoded according to
14991 * utf-8 and then converted according to RFC 2396.
14994 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14995 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14996 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14997 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15001 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
15002 xmlXPathObjectPtr str
;
15003 int escape_reserved
;
15010 escape_reserved
= xmlXPathPopBoolean(ctxt
);
15013 str
= valuePop(ctxt
);
15015 target
= xmlBufCreate();
15021 for (cptr
= str
->stringval
; *cptr
; cptr
++) {
15022 if ((*cptr
>= 'A' && *cptr
<= 'Z') ||
15023 (*cptr
>= 'a' && *cptr
<= 'z') ||
15024 (*cptr
>= '0' && *cptr
<= '9') ||
15025 *cptr
== '-' || *cptr
== '_' || *cptr
== '.' ||
15026 *cptr
== '!' || *cptr
== '~' || *cptr
== '*' ||
15027 *cptr
== '\''|| *cptr
== '(' || *cptr
== ')' ||
15029 ((cptr
[1] >= 'A' && cptr
[1] <= 'F') ||
15030 (cptr
[1] >= 'a' && cptr
[1] <= 'f') ||
15031 (cptr
[1] >= '0' && cptr
[1] <= '9')) &&
15032 ((cptr
[2] >= 'A' && cptr
[2] <= 'F') ||
15033 (cptr
[2] >= 'a' && cptr
[2] <= 'f') ||
15034 (cptr
[2] >= '0' && cptr
[2] <= '9'))) ||
15035 (!escape_reserved
&&
15036 (*cptr
== ';' || *cptr
== '/' || *cptr
== '?' ||
15037 *cptr
== ':' || *cptr
== '@' || *cptr
== '&' ||
15038 *cptr
== '=' || *cptr
== '+' || *cptr
== '$' ||
15040 xmlBufAdd(target
, cptr
, 1);
15042 if ((*cptr
>> 4) < 10)
15043 escape
[1] = '0' + (*cptr
>> 4);
15045 escape
[1] = 'A' - 10 + (*cptr
>> 4);
15046 if ((*cptr
& 0xF) < 10)
15047 escape
[2] = '0' + (*cptr
& 0xF);
15049 escape
[2] = 'A' - 10 + (*cptr
& 0xF);
15051 xmlBufAdd(target
, &escape
[0], 3);
15055 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
15056 xmlBufContent(target
)));
15057 xmlBufFree(target
);
15058 xmlXPathReleaseObject(ctxt
->context
, str
);
15062 * xmlXPathRegisterAllFunctions:
15063 * @ctxt: the XPath context
15065 * Registers all default XPath functions in this context
15068 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt
)
15070 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"boolean",
15071 xmlXPathBooleanFunction
);
15072 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"ceiling",
15073 xmlXPathCeilingFunction
);
15074 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"count",
15075 xmlXPathCountFunction
);
15076 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"concat",
15077 xmlXPathConcatFunction
);
15078 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"contains",
15079 xmlXPathContainsFunction
);
15080 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"id",
15081 xmlXPathIdFunction
);
15082 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"false",
15083 xmlXPathFalseFunction
);
15084 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"floor",
15085 xmlXPathFloorFunction
);
15086 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"last",
15087 xmlXPathLastFunction
);
15088 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"lang",
15089 xmlXPathLangFunction
);
15090 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"local-name",
15091 xmlXPathLocalNameFunction
);
15092 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"not",
15093 xmlXPathNotFunction
);
15094 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"name",
15095 xmlXPathNameFunction
);
15096 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"namespace-uri",
15097 xmlXPathNamespaceURIFunction
);
15098 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"normalize-space",
15099 xmlXPathNormalizeFunction
);
15100 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"number",
15101 xmlXPathNumberFunction
);
15102 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"position",
15103 xmlXPathPositionFunction
);
15104 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"round",
15105 xmlXPathRoundFunction
);
15106 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string",
15107 xmlXPathStringFunction
);
15108 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string-length",
15109 xmlXPathStringLengthFunction
);
15110 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"starts-with",
15111 xmlXPathStartsWithFunction
);
15112 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring",
15113 xmlXPathSubstringFunction
);
15114 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-before",
15115 xmlXPathSubstringBeforeFunction
);
15116 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-after",
15117 xmlXPathSubstringAfterFunction
);
15118 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"sum",
15119 xmlXPathSumFunction
);
15120 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"true",
15121 xmlXPathTrueFunction
);
15122 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"translate",
15123 xmlXPathTranslateFunction
);
15125 xmlXPathRegisterFuncNS(ctxt
, (const xmlChar
*)"escape-uri",
15126 (const xmlChar
*)"http://www.w3.org/2002/08/xquery-functions",
15127 xmlXPathEscapeUriFunction
);
15130 #endif /* LIBXML_XPATH_ENABLED */
15131 #define bottom_xpath
15132 #include "elfgcchack.h"