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 NAN (0.0 / 0.0)
485 #define INFINITY HUGE_VAL
488 double xmlXPathNAN
= NAN
;
489 double xmlXPathPINF
= INFINITY
;
490 double xmlXPathNINF
= -INFINITY
;
495 * Initialize the XPath environment
497 * Does nothing but must be kept as public function.
505 * @val: a double value
507 * Returns 1 if the value is a NaN, 0 otherwise
510 xmlXPathIsNaN(double val
) {
514 return !(val
== val
);
520 * @val: a double value
522 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
525 xmlXPathIsInf(double val
) {
527 return isinf(val
) ? (val
> 0 ? 1 : -1) : 0;
531 if (val
<= -HUGE_VAL
)
537 #endif /* SCHEMAS or XPATH */
539 #ifdef LIBXML_XPATH_ENABLED
542 * TODO: when compatibility allows remove all "fake node libxslt" strings
543 * the test should just be name[0] = ' '
545 #ifdef DEBUG_XPATH_EXPRESSION
548 #define DEBUG_EVAL_COUNTS
551 static xmlNs xmlXPathXMLNamespaceStruct
= {
559 static xmlNsPtr xmlXPathXMLNamespace
= &xmlXPathXMLNamespaceStruct
;
560 #ifndef LIBXML_THREAD_ENABLED
562 * Optimizer is disabled only when threaded apps are detected while
563 * the library ain't compiled for thread safety.
565 static int xmlXPathDisableOptimizer
= 0;
568 /************************************************************************
570 * Error handling routines *
572 ************************************************************************/
578 * Macro to raise an XPath error and return NULL.
580 #define XP_ERRORNULL(X) \
581 { xmlXPathErr(ctxt, X); return(NULL); }
584 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
586 static const char *xmlXPathErrorMessages
[] = {
589 "Unfinished literal\n",
590 "Start of literal\n",
591 "Expected $ for variable reference\n",
592 "Undefined variable\n",
593 "Invalid predicate\n",
594 "Invalid expression\n",
595 "Missing closing curly brace\n",
596 "Unregistered function\n",
599 "Invalid number of arguments\n",
600 "Invalid context size\n",
601 "Invalid context position\n",
602 "Memory allocation error\n",
605 "Sub resource error\n",
606 "Undefined namespace prefix\n",
608 "Char out of XML range\n",
609 "Invalid or incomplete context\n",
610 "Stack usage error\n",
611 "Forbidden variable\n",
612 "?? Unknown error ??\n" /* Must be last in the list! */
614 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
615 sizeof(xmlXPathErrorMessages[0])) - 1)
618 * @ctxt: an XPath context
619 * @extra: extra informations
621 * Handle a redefinition of attribute error
624 xmlXPathErrMemory(xmlXPathContextPtr ctxt
, const char *extra
)
630 xmlStrPrintf(buf
, 200,
631 "Memory allocation failed : %s\n",
633 ctxt
->lastError
.message
= (char *) xmlStrdup(buf
);
635 ctxt
->lastError
.message
= (char *)
636 xmlStrdup(BAD_CAST
"Memory allocation failed\n");
638 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
639 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
640 if (ctxt
->error
!= NULL
)
641 ctxt
->error(ctxt
->userData
, &ctxt
->lastError
);
644 __xmlRaiseError(NULL
, NULL
, NULL
,
645 NULL
, NULL
, XML_FROM_XPATH
,
646 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
647 extra
, NULL
, NULL
, 0, 0,
648 "Memory allocation failed : %s\n", extra
);
650 __xmlRaiseError(NULL
, NULL
, NULL
,
651 NULL
, NULL
, XML_FROM_XPATH
,
652 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
653 NULL
, NULL
, NULL
, 0, 0,
654 "Memory allocation failed\n");
659 * xmlXPathPErrMemory:
660 * @ctxt: an XPath parser context
661 * @extra: extra informations
663 * Handle a redefinition of attribute error
666 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt
, const char *extra
)
669 xmlXPathErrMemory(NULL
, extra
);
671 ctxt
->error
= XPATH_MEMORY_ERROR
;
672 xmlXPathErrMemory(ctxt
->context
, extra
);
678 * @ctxt: a XPath parser context
679 * @error: the error code
681 * Handle an XPath error
684 xmlXPathErr(xmlXPathParserContextPtr ctxt
, int error
)
686 if ((error
< 0) || (error
> MAXERRNO
))
689 __xmlRaiseError(NULL
, NULL
, NULL
,
690 NULL
, NULL
, XML_FROM_XPATH
,
691 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
692 XML_ERR_ERROR
, NULL
, 0,
693 NULL
, NULL
, NULL
, 0, 0,
694 "%s", xmlXPathErrorMessages
[error
]);
698 if (ctxt
->context
== NULL
) {
699 __xmlRaiseError(NULL
, NULL
, NULL
,
700 NULL
, NULL
, XML_FROM_XPATH
,
701 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
702 XML_ERR_ERROR
, NULL
, 0,
703 (const char *) ctxt
->base
, NULL
, NULL
,
704 ctxt
->cur
- ctxt
->base
, 0,
705 "%s", xmlXPathErrorMessages
[error
]);
709 /* cleanup current last error */
710 xmlResetError(&ctxt
->context
->lastError
);
712 ctxt
->context
->lastError
.domain
= XML_FROM_XPATH
;
713 ctxt
->context
->lastError
.code
= error
+ XML_XPATH_EXPRESSION_OK
-
715 ctxt
->context
->lastError
.level
= XML_ERR_ERROR
;
716 ctxt
->context
->lastError
.str1
= (char *) xmlStrdup(ctxt
->base
);
717 ctxt
->context
->lastError
.int1
= ctxt
->cur
- ctxt
->base
;
718 ctxt
->context
->lastError
.node
= ctxt
->context
->debugNode
;
719 if (ctxt
->context
->error
!= NULL
) {
720 ctxt
->context
->error(ctxt
->context
->userData
,
721 &ctxt
->context
->lastError
);
723 __xmlRaiseError(NULL
, NULL
, NULL
,
724 NULL
, ctxt
->context
->debugNode
, XML_FROM_XPATH
,
725 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
726 XML_ERR_ERROR
, NULL
, 0,
727 (const char *) ctxt
->base
, NULL
, NULL
,
728 ctxt
->cur
- ctxt
->base
, 0,
729 "%s", xmlXPathErrorMessages
[error
]);
736 * @ctxt: the XPath Parser context
737 * @file: the file name
738 * @line: the line number
739 * @no: the error number
741 * Formats an error message.
744 xmlXPatherror(xmlXPathParserContextPtr ctxt
, const char *file ATTRIBUTE_UNUSED
,
745 int line ATTRIBUTE_UNUSED
, int no
) {
746 xmlXPathErr(ctxt
, no
);
749 /************************************************************************
753 ************************************************************************/
758 * Pointer-list for various purposes.
760 typedef struct _xmlPointerList xmlPointerList
;
761 typedef xmlPointerList
*xmlPointerListPtr
;
762 struct _xmlPointerList
{
768 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
769 * and here, we should make the functions public.
772 xmlPointerListAddSize(xmlPointerListPtr list
,
776 if (list
->items
== NULL
) {
777 if (initialSize
<= 0)
779 list
->items
= (void **) xmlMalloc(initialSize
* sizeof(void *));
780 if (list
->items
== NULL
) {
781 xmlXPathErrMemory(NULL
,
782 "xmlPointerListCreate: allocating item\n");
786 list
->size
= initialSize
;
787 } else if (list
->size
<= list
->number
) {
788 if (list
->size
> 50000000) {
789 xmlXPathErrMemory(NULL
,
790 "xmlPointerListAddSize: re-allocating item\n");
794 list
->items
= (void **) xmlRealloc(list
->items
,
795 list
->size
* sizeof(void *));
796 if (list
->items
== NULL
) {
797 xmlXPathErrMemory(NULL
,
798 "xmlPointerListAddSize: re-allocating item\n");
803 list
->items
[list
->number
++] = item
;
808 * xsltPointerListCreate:
810 * Creates an xsltPointerList structure.
812 * Returns a xsltPointerList structure or NULL in case of an error.
814 static xmlPointerListPtr
815 xmlPointerListCreate(int initialSize
)
817 xmlPointerListPtr ret
;
819 ret
= xmlMalloc(sizeof(xmlPointerList
));
821 xmlXPathErrMemory(NULL
,
822 "xmlPointerListCreate: allocating item\n");
825 memset(ret
, 0, sizeof(xmlPointerList
));
826 if (initialSize
> 0) {
827 xmlPointerListAddSize(ret
, NULL
, initialSize
);
834 * xsltPointerListFree:
836 * Frees the xsltPointerList structure. This does not free
837 * the content of the list.
840 xmlPointerListFree(xmlPointerListPtr list
)
844 if (list
->items
!= NULL
)
845 xmlFree(list
->items
);
849 /************************************************************************
853 ************************************************************************/
870 XPATH_OP_RESET
, /* 10 */
872 XPATH_OP_VALUE
, /* 12 */
877 XPATH_OP_FILTER
, /* 17 */
878 XPATH_OP_SORT
/* 18 */
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;
1528 case XPATH_OP_RESET
:
1529 fprintf(output
, "RESET"); break;
1531 fprintf(output
, "SORT"); break;
1532 case XPATH_OP_COLLECT
: {
1533 xmlXPathAxisVal axis
= (xmlXPathAxisVal
)op
->value
;
1534 xmlXPathTestVal test
= (xmlXPathTestVal
)op
->value2
;
1535 xmlXPathTypeVal type
= (xmlXPathTypeVal
)op
->value3
;
1536 const xmlChar
*prefix
= op
->value4
;
1537 const xmlChar
*name
= op
->value5
;
1539 fprintf(output
, "COLLECT ");
1542 fprintf(output
, " 'ancestors' "); break;
1543 case AXIS_ANCESTOR_OR_SELF
:
1544 fprintf(output
, " 'ancestors-or-self' "); break;
1545 case AXIS_ATTRIBUTE
:
1546 fprintf(output
, " 'attributes' "); break;
1548 fprintf(output
, " 'child' "); break;
1549 case AXIS_DESCENDANT
:
1550 fprintf(output
, " 'descendant' "); break;
1551 case AXIS_DESCENDANT_OR_SELF
:
1552 fprintf(output
, " 'descendant-or-self' "); break;
1553 case AXIS_FOLLOWING
:
1554 fprintf(output
, " 'following' "); break;
1555 case AXIS_FOLLOWING_SIBLING
:
1556 fprintf(output
, " 'following-siblings' "); break;
1557 case AXIS_NAMESPACE
:
1558 fprintf(output
, " 'namespace' "); break;
1560 fprintf(output
, " 'parent' "); break;
1561 case AXIS_PRECEDING
:
1562 fprintf(output
, " 'preceding' "); break;
1563 case AXIS_PRECEDING_SIBLING
:
1564 fprintf(output
, " 'preceding-sibling' "); break;
1566 fprintf(output
, " 'self' "); break;
1569 case NODE_TEST_NONE
:
1570 fprintf(output
, "'none' "); break;
1571 case NODE_TEST_TYPE
:
1572 fprintf(output
, "'type' "); break;
1574 fprintf(output
, "'PI' "); break;
1576 fprintf(output
, "'all' "); break;
1578 fprintf(output
, "'namespace' "); break;
1579 case NODE_TEST_NAME
:
1580 fprintf(output
, "'name' "); break;
1583 case NODE_TYPE_NODE
:
1584 fprintf(output
, "'node' "); break;
1585 case NODE_TYPE_COMMENT
:
1586 fprintf(output
, "'comment' "); break;
1587 case NODE_TYPE_TEXT
:
1588 fprintf(output
, "'text' "); break;
1590 fprintf(output
, "'PI' "); break;
1593 fprintf(output
, "%s:", prefix
);
1595 fprintf(output
, "%s", (const char *) name
);
1599 case XPATH_OP_VALUE
: {
1600 xmlXPathObjectPtr object
= (xmlXPathObjectPtr
) op
->value4
;
1602 fprintf(output
, "ELEM ");
1603 xmlXPathDebugDumpObject(output
, object
, 0);
1606 case XPATH_OP_VARIABLE
: {
1607 const xmlChar
*prefix
= op
->value5
;
1608 const xmlChar
*name
= op
->value4
;
1611 fprintf(output
, "VARIABLE %s:%s", prefix
, name
);
1613 fprintf(output
, "VARIABLE %s", name
);
1616 case XPATH_OP_FUNCTION
: {
1617 int nbargs
= op
->value
;
1618 const xmlChar
*prefix
= op
->value5
;
1619 const xmlChar
*name
= op
->value4
;
1622 fprintf(output
, "FUNCTION %s:%s(%d args)",
1623 prefix
, name
, nbargs
);
1625 fprintf(output
, "FUNCTION %s(%d args)", name
, nbargs
);
1628 case XPATH_OP_ARG
: fprintf(output
, "ARG"); break;
1629 case XPATH_OP_PREDICATE
: fprintf(output
, "PREDICATE"); break;
1630 case XPATH_OP_FILTER
: fprintf(output
, "FILTER"); break;
1631 #ifdef LIBXML_XPTR_ENABLED
1632 case XPATH_OP_RANGETO
: fprintf(output
, "RANGETO"); break;
1635 fprintf(output
, "UNKNOWN %d\n", op
->op
); return;
1637 fprintf(output
, "\n");
1640 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch1
], depth
+ 1);
1642 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch2
], depth
+ 1);
1646 * xmlXPathDebugDumpCompExpr:
1647 * @output: the FILE * for the output
1648 * @comp: the precompiled XPath expression
1649 * @depth: the indentation level.
1651 * Dumps the tree of the compiled XPath expression.
1654 xmlXPathDebugDumpCompExpr(FILE *output
, xmlXPathCompExprPtr comp
,
1659 if ((output
== NULL
) || (comp
== NULL
)) return;
1661 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1662 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1663 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1665 fprintf(output
, "%s", shift
);
1667 #ifdef XPATH_STREAMING
1669 fprintf(output
, "Streaming Expression\n");
1673 fprintf(output
, "Compiled Expression : %d elements\n",
1676 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[i
], depth
+ 1);
1680 #ifdef XP_DEBUG_OBJ_USAGE
1683 * XPath object usage related debugging variables.
1685 static int xmlXPathDebugObjCounterUndefined
= 0;
1686 static int xmlXPathDebugObjCounterNodeset
= 0;
1687 static int xmlXPathDebugObjCounterBool
= 0;
1688 static int xmlXPathDebugObjCounterNumber
= 0;
1689 static int xmlXPathDebugObjCounterString
= 0;
1690 static int xmlXPathDebugObjCounterPoint
= 0;
1691 static int xmlXPathDebugObjCounterRange
= 0;
1692 static int xmlXPathDebugObjCounterLocset
= 0;
1693 static int xmlXPathDebugObjCounterUsers
= 0;
1694 static int xmlXPathDebugObjCounterXSLTTree
= 0;
1695 static int xmlXPathDebugObjCounterAll
= 0;
1697 static int xmlXPathDebugObjTotalUndefined
= 0;
1698 static int xmlXPathDebugObjTotalNodeset
= 0;
1699 static int xmlXPathDebugObjTotalBool
= 0;
1700 static int xmlXPathDebugObjTotalNumber
= 0;
1701 static int xmlXPathDebugObjTotalString
= 0;
1702 static int xmlXPathDebugObjTotalPoint
= 0;
1703 static int xmlXPathDebugObjTotalRange
= 0;
1704 static int xmlXPathDebugObjTotalLocset
= 0;
1705 static int xmlXPathDebugObjTotalUsers
= 0;
1706 static int xmlXPathDebugObjTotalXSLTTree
= 0;
1707 static int xmlXPathDebugObjTotalAll
= 0;
1709 static int xmlXPathDebugObjMaxUndefined
= 0;
1710 static int xmlXPathDebugObjMaxNodeset
= 0;
1711 static int xmlXPathDebugObjMaxBool
= 0;
1712 static int xmlXPathDebugObjMaxNumber
= 0;
1713 static int xmlXPathDebugObjMaxString
= 0;
1714 static int xmlXPathDebugObjMaxPoint
= 0;
1715 static int xmlXPathDebugObjMaxRange
= 0;
1716 static int xmlXPathDebugObjMaxLocset
= 0;
1717 static int xmlXPathDebugObjMaxUsers
= 0;
1718 static int xmlXPathDebugObjMaxXSLTTree
= 0;
1719 static int xmlXPathDebugObjMaxAll
= 0;
1721 /* REVISIT TODO: Make this static when committing */
1723 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt
)
1726 if (ctxt
->cache
!= NULL
) {
1727 xmlXPathContextCachePtr cache
=
1728 (xmlXPathContextCachePtr
) ctxt
->cache
;
1730 cache
->dbgCachedAll
= 0;
1731 cache
->dbgCachedNodeset
= 0;
1732 cache
->dbgCachedString
= 0;
1733 cache
->dbgCachedBool
= 0;
1734 cache
->dbgCachedNumber
= 0;
1735 cache
->dbgCachedPoint
= 0;
1736 cache
->dbgCachedRange
= 0;
1737 cache
->dbgCachedLocset
= 0;
1738 cache
->dbgCachedUsers
= 0;
1739 cache
->dbgCachedXSLTTree
= 0;
1740 cache
->dbgCachedUndefined
= 0;
1742 cache
->dbgReusedAll
= 0;
1743 cache
->dbgReusedNodeset
= 0;
1744 cache
->dbgReusedString
= 0;
1745 cache
->dbgReusedBool
= 0;
1746 cache
->dbgReusedNumber
= 0;
1747 cache
->dbgReusedPoint
= 0;
1748 cache
->dbgReusedRange
= 0;
1749 cache
->dbgReusedLocset
= 0;
1750 cache
->dbgReusedUsers
= 0;
1751 cache
->dbgReusedXSLTTree
= 0;
1752 cache
->dbgReusedUndefined
= 0;
1756 xmlXPathDebugObjCounterUndefined
= 0;
1757 xmlXPathDebugObjCounterNodeset
= 0;
1758 xmlXPathDebugObjCounterBool
= 0;
1759 xmlXPathDebugObjCounterNumber
= 0;
1760 xmlXPathDebugObjCounterString
= 0;
1761 xmlXPathDebugObjCounterPoint
= 0;
1762 xmlXPathDebugObjCounterRange
= 0;
1763 xmlXPathDebugObjCounterLocset
= 0;
1764 xmlXPathDebugObjCounterUsers
= 0;
1765 xmlXPathDebugObjCounterXSLTTree
= 0;
1766 xmlXPathDebugObjCounterAll
= 0;
1768 xmlXPathDebugObjTotalUndefined
= 0;
1769 xmlXPathDebugObjTotalNodeset
= 0;
1770 xmlXPathDebugObjTotalBool
= 0;
1771 xmlXPathDebugObjTotalNumber
= 0;
1772 xmlXPathDebugObjTotalString
= 0;
1773 xmlXPathDebugObjTotalPoint
= 0;
1774 xmlXPathDebugObjTotalRange
= 0;
1775 xmlXPathDebugObjTotalLocset
= 0;
1776 xmlXPathDebugObjTotalUsers
= 0;
1777 xmlXPathDebugObjTotalXSLTTree
= 0;
1778 xmlXPathDebugObjTotalAll
= 0;
1780 xmlXPathDebugObjMaxUndefined
= 0;
1781 xmlXPathDebugObjMaxNodeset
= 0;
1782 xmlXPathDebugObjMaxBool
= 0;
1783 xmlXPathDebugObjMaxNumber
= 0;
1784 xmlXPathDebugObjMaxString
= 0;
1785 xmlXPathDebugObjMaxPoint
= 0;
1786 xmlXPathDebugObjMaxRange
= 0;
1787 xmlXPathDebugObjMaxLocset
= 0;
1788 xmlXPathDebugObjMaxUsers
= 0;
1789 xmlXPathDebugObjMaxXSLTTree
= 0;
1790 xmlXPathDebugObjMaxAll
= 0;
1795 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt
,
1796 xmlXPathObjectType objType
)
1801 if (ctxt
->cache
!= NULL
) {
1802 xmlXPathContextCachePtr cache
=
1803 (xmlXPathContextCachePtr
) ctxt
->cache
;
1807 cache
->dbgReusedAll
++;
1809 case XPATH_UNDEFINED
:
1810 cache
->dbgReusedUndefined
++;
1813 cache
->dbgReusedNodeset
++;
1816 cache
->dbgReusedBool
++;
1819 cache
->dbgReusedNumber
++;
1822 cache
->dbgReusedString
++;
1825 cache
->dbgReusedPoint
++;
1828 cache
->dbgReusedRange
++;
1830 case XPATH_LOCATIONSET
:
1831 cache
->dbgReusedLocset
++;
1834 cache
->dbgReusedUsers
++;
1836 case XPATH_XSLT_TREE
:
1837 cache
->dbgReusedXSLTTree
++;
1846 case XPATH_UNDEFINED
:
1848 xmlXPathDebugObjTotalUndefined
++;
1849 xmlXPathDebugObjCounterUndefined
++;
1850 if (xmlXPathDebugObjCounterUndefined
>
1851 xmlXPathDebugObjMaxUndefined
)
1852 xmlXPathDebugObjMaxUndefined
=
1853 xmlXPathDebugObjCounterUndefined
;
1857 xmlXPathDebugObjTotalNodeset
++;
1858 xmlXPathDebugObjCounterNodeset
++;
1859 if (xmlXPathDebugObjCounterNodeset
>
1860 xmlXPathDebugObjMaxNodeset
)
1861 xmlXPathDebugObjMaxNodeset
=
1862 xmlXPathDebugObjCounterNodeset
;
1866 xmlXPathDebugObjTotalBool
++;
1867 xmlXPathDebugObjCounterBool
++;
1868 if (xmlXPathDebugObjCounterBool
>
1869 xmlXPathDebugObjMaxBool
)
1870 xmlXPathDebugObjMaxBool
=
1871 xmlXPathDebugObjCounterBool
;
1875 xmlXPathDebugObjTotalNumber
++;
1876 xmlXPathDebugObjCounterNumber
++;
1877 if (xmlXPathDebugObjCounterNumber
>
1878 xmlXPathDebugObjMaxNumber
)
1879 xmlXPathDebugObjMaxNumber
=
1880 xmlXPathDebugObjCounterNumber
;
1884 xmlXPathDebugObjTotalString
++;
1885 xmlXPathDebugObjCounterString
++;
1886 if (xmlXPathDebugObjCounterString
>
1887 xmlXPathDebugObjMaxString
)
1888 xmlXPathDebugObjMaxString
=
1889 xmlXPathDebugObjCounterString
;
1893 xmlXPathDebugObjTotalPoint
++;
1894 xmlXPathDebugObjCounterPoint
++;
1895 if (xmlXPathDebugObjCounterPoint
>
1896 xmlXPathDebugObjMaxPoint
)
1897 xmlXPathDebugObjMaxPoint
=
1898 xmlXPathDebugObjCounterPoint
;
1902 xmlXPathDebugObjTotalRange
++;
1903 xmlXPathDebugObjCounterRange
++;
1904 if (xmlXPathDebugObjCounterRange
>
1905 xmlXPathDebugObjMaxRange
)
1906 xmlXPathDebugObjMaxRange
=
1907 xmlXPathDebugObjCounterRange
;
1909 case XPATH_LOCATIONSET
:
1911 xmlXPathDebugObjTotalLocset
++;
1912 xmlXPathDebugObjCounterLocset
++;
1913 if (xmlXPathDebugObjCounterLocset
>
1914 xmlXPathDebugObjMaxLocset
)
1915 xmlXPathDebugObjMaxLocset
=
1916 xmlXPathDebugObjCounterLocset
;
1920 xmlXPathDebugObjTotalUsers
++;
1921 xmlXPathDebugObjCounterUsers
++;
1922 if (xmlXPathDebugObjCounterUsers
>
1923 xmlXPathDebugObjMaxUsers
)
1924 xmlXPathDebugObjMaxUsers
=
1925 xmlXPathDebugObjCounterUsers
;
1927 case XPATH_XSLT_TREE
:
1929 xmlXPathDebugObjTotalXSLTTree
++;
1930 xmlXPathDebugObjCounterXSLTTree
++;
1931 if (xmlXPathDebugObjCounterXSLTTree
>
1932 xmlXPathDebugObjMaxXSLTTree
)
1933 xmlXPathDebugObjMaxXSLTTree
=
1934 xmlXPathDebugObjCounterXSLTTree
;
1940 xmlXPathDebugObjTotalAll
++;
1941 xmlXPathDebugObjCounterAll
++;
1942 if (xmlXPathDebugObjCounterAll
>
1943 xmlXPathDebugObjMaxAll
)
1944 xmlXPathDebugObjMaxAll
=
1945 xmlXPathDebugObjCounterAll
;
1949 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt
,
1950 xmlXPathObjectType objType
)
1955 if (ctxt
->cache
!= NULL
) {
1956 xmlXPathContextCachePtr cache
=
1957 (xmlXPathContextCachePtr
) ctxt
->cache
;
1961 cache
->dbgCachedAll
++;
1963 case XPATH_UNDEFINED
:
1964 cache
->dbgCachedUndefined
++;
1967 cache
->dbgCachedNodeset
++;
1970 cache
->dbgCachedBool
++;
1973 cache
->dbgCachedNumber
++;
1976 cache
->dbgCachedString
++;
1979 cache
->dbgCachedPoint
++;
1982 cache
->dbgCachedRange
++;
1984 case XPATH_LOCATIONSET
:
1985 cache
->dbgCachedLocset
++;
1988 cache
->dbgCachedUsers
++;
1990 case XPATH_XSLT_TREE
:
1991 cache
->dbgCachedXSLTTree
++;
2000 case XPATH_UNDEFINED
:
2001 xmlXPathDebugObjCounterUndefined
--;
2004 xmlXPathDebugObjCounterNodeset
--;
2007 xmlXPathDebugObjCounterBool
--;
2010 xmlXPathDebugObjCounterNumber
--;
2013 xmlXPathDebugObjCounterString
--;
2016 xmlXPathDebugObjCounterPoint
--;
2019 xmlXPathDebugObjCounterRange
--;
2021 case XPATH_LOCATIONSET
:
2022 xmlXPathDebugObjCounterLocset
--;
2025 xmlXPathDebugObjCounterUsers
--;
2027 case XPATH_XSLT_TREE
:
2028 xmlXPathDebugObjCounterXSLTTree
--;
2033 xmlXPathDebugObjCounterAll
--;
2036 /* REVISIT TODO: Make this static when committing */
2038 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt
)
2040 int reqAll
, reqNodeset
, reqString
, reqBool
, reqNumber
,
2041 reqXSLTTree
, reqUndefined
;
2042 int caAll
= 0, caNodeset
= 0, caString
= 0, caBool
= 0,
2043 caNumber
= 0, caXSLTTree
= 0, caUndefined
= 0;
2044 int reAll
= 0, reNodeset
= 0, reString
= 0, reBool
= 0,
2045 reNumber
= 0, reXSLTTree
= 0, reUndefined
= 0;
2046 int leftObjs
= xmlXPathDebugObjCounterAll
;
2048 reqAll
= xmlXPathDebugObjTotalAll
;
2049 reqNodeset
= xmlXPathDebugObjTotalNodeset
;
2050 reqString
= xmlXPathDebugObjTotalString
;
2051 reqBool
= xmlXPathDebugObjTotalBool
;
2052 reqNumber
= xmlXPathDebugObjTotalNumber
;
2053 reqXSLTTree
= xmlXPathDebugObjTotalXSLTTree
;
2054 reqUndefined
= xmlXPathDebugObjTotalUndefined
;
2056 printf("# XPath object usage:\n");
2059 if (ctxt
->cache
!= NULL
) {
2060 xmlXPathContextCachePtr cache
=
2061 (xmlXPathContextCachePtr
) ctxt
->cache
;
2063 reAll
= cache
->dbgReusedAll
;
2065 reNodeset
= cache
->dbgReusedNodeset
;
2066 reqNodeset
+= reNodeset
;
2067 reString
= cache
->dbgReusedString
;
2068 reqString
+= reString
;
2069 reBool
= cache
->dbgReusedBool
;
2071 reNumber
= cache
->dbgReusedNumber
;
2072 reqNumber
+= reNumber
;
2073 reXSLTTree
= cache
->dbgReusedXSLTTree
;
2074 reqXSLTTree
+= reXSLTTree
;
2075 reUndefined
= cache
->dbgReusedUndefined
;
2076 reqUndefined
+= reUndefined
;
2078 caAll
= cache
->dbgCachedAll
;
2079 caBool
= cache
->dbgCachedBool
;
2080 caNodeset
= cache
->dbgCachedNodeset
;
2081 caString
= cache
->dbgCachedString
;
2082 caNumber
= cache
->dbgCachedNumber
;
2083 caXSLTTree
= cache
->dbgCachedXSLTTree
;
2084 caUndefined
= cache
->dbgCachedUndefined
;
2086 if (cache
->nodesetObjs
)
2087 leftObjs
-= cache
->nodesetObjs
->number
;
2088 if (cache
->stringObjs
)
2089 leftObjs
-= cache
->stringObjs
->number
;
2090 if (cache
->booleanObjs
)
2091 leftObjs
-= cache
->booleanObjs
->number
;
2092 if (cache
->numberObjs
)
2093 leftObjs
-= cache
->numberObjs
->number
;
2094 if (cache
->miscObjs
)
2095 leftObjs
-= cache
->miscObjs
->number
;
2100 printf("# total : %d\n", reqAll
);
2101 printf("# left : %d\n", leftObjs
);
2102 printf("# created: %d\n", xmlXPathDebugObjTotalAll
);
2103 printf("# reused : %d\n", reAll
);
2104 printf("# max : %d\n", xmlXPathDebugObjMaxAll
);
2106 printf("# node-sets\n");
2107 printf("# total : %d\n", reqNodeset
);
2108 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset
);
2109 printf("# reused : %d\n", reNodeset
);
2110 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset
);
2112 printf("# strings\n");
2113 printf("# total : %d\n", reqString
);
2114 printf("# created: %d\n", xmlXPathDebugObjTotalString
);
2115 printf("# reused : %d\n", reString
);
2116 printf("# max : %d\n", xmlXPathDebugObjMaxString
);
2118 printf("# booleans\n");
2119 printf("# total : %d\n", reqBool
);
2120 printf("# created: %d\n", xmlXPathDebugObjTotalBool
);
2121 printf("# reused : %d\n", reBool
);
2122 printf("# max : %d\n", xmlXPathDebugObjMaxBool
);
2124 printf("# numbers\n");
2125 printf("# total : %d\n", reqNumber
);
2126 printf("# created: %d\n", xmlXPathDebugObjTotalNumber
);
2127 printf("# reused : %d\n", reNumber
);
2128 printf("# max : %d\n", xmlXPathDebugObjMaxNumber
);
2130 printf("# XSLT result tree fragments\n");
2131 printf("# total : %d\n", reqXSLTTree
);
2132 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree
);
2133 printf("# reused : %d\n", reXSLTTree
);
2134 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree
);
2136 printf("# undefined\n");
2137 printf("# total : %d\n", reqUndefined
);
2138 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined
);
2139 printf("# reused : %d\n", reUndefined
);
2140 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined
);
2144 #endif /* XP_DEBUG_OBJ_USAGE */
2146 #endif /* LIBXML_DEBUG_ENABLED */
2148 /************************************************************************
2150 * XPath object caching *
2152 ************************************************************************/
2157 * Create a new object cache
2159 * Returns the xmlXPathCache just allocated.
2161 static xmlXPathContextCachePtr
2162 xmlXPathNewCache(void)
2164 xmlXPathContextCachePtr ret
;
2166 ret
= (xmlXPathContextCachePtr
) xmlMalloc(sizeof(xmlXPathContextCache
));
2168 xmlXPathErrMemory(NULL
, "creating object cache\n");
2171 memset(ret
, 0 , (size_t) sizeof(xmlXPathContextCache
));
2172 ret
->maxNodeset
= 100;
2173 ret
->maxString
= 100;
2174 ret
->maxBoolean
= 100;
2175 ret
->maxNumber
= 100;
2181 xmlXPathCacheFreeObjectList(xmlPointerListPtr list
)
2184 xmlXPathObjectPtr obj
;
2189 for (i
= 0; i
< list
->number
; i
++) {
2190 obj
= list
->items
[i
];
2192 * Note that it is already assured that we don't need to
2193 * look out for namespace nodes in the node-set.
2195 if (obj
->nodesetval
!= NULL
) {
2196 if (obj
->nodesetval
->nodeTab
!= NULL
)
2197 xmlFree(obj
->nodesetval
->nodeTab
);
2198 xmlFree(obj
->nodesetval
);
2201 #ifdef XP_DEBUG_OBJ_USAGE
2202 xmlXPathDebugObjCounterAll
--;
2205 xmlPointerListFree(list
);
2209 xmlXPathFreeCache(xmlXPathContextCachePtr cache
)
2213 if (cache
->nodesetObjs
)
2214 xmlXPathCacheFreeObjectList(cache
->nodesetObjs
);
2215 if (cache
->stringObjs
)
2216 xmlXPathCacheFreeObjectList(cache
->stringObjs
);
2217 if (cache
->booleanObjs
)
2218 xmlXPathCacheFreeObjectList(cache
->booleanObjs
);
2219 if (cache
->numberObjs
)
2220 xmlXPathCacheFreeObjectList(cache
->numberObjs
);
2221 if (cache
->miscObjs
)
2222 xmlXPathCacheFreeObjectList(cache
->miscObjs
);
2227 * xmlXPathContextSetCache:
2229 * @ctxt: the XPath context
2230 * @active: enables/disables (creates/frees) the cache
2231 * @value: a value with semantics dependant on @options
2232 * @options: options (currently only the value 0 is used)
2234 * Creates/frees an object cache on the XPath context.
2235 * If activates XPath objects (xmlXPathObject) will be cached internally
2238 * 0: This will set the XPath object caching:
2240 * This will set the maximum number of XPath objects
2241 * to be cached per slot
2242 * There are 5 slots for: node-set, string, number, boolean, and
2243 * misc objects. Use <0 for the default number (100).
2244 * Other values for @options have currently no effect.
2246 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2249 xmlXPathContextSetCache(xmlXPathContextPtr ctxt
,
2257 xmlXPathContextCachePtr cache
;
2259 if (ctxt
->cache
== NULL
) {
2260 ctxt
->cache
= xmlXPathNewCache();
2261 if (ctxt
->cache
== NULL
)
2264 cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2268 cache
->maxNodeset
= value
;
2269 cache
->maxString
= value
;
2270 cache
->maxNumber
= value
;
2271 cache
->maxBoolean
= value
;
2272 cache
->maxMisc
= value
;
2274 } else if (ctxt
->cache
!= NULL
) {
2275 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
2282 * xmlXPathCacheWrapNodeSet:
2283 * @ctxt: the XPath context
2284 * @val: the NodePtr value
2286 * This is the cached version of xmlXPathWrapNodeSet().
2287 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2289 * Returns the created or reused object.
2291 static xmlXPathObjectPtr
2292 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt
, xmlNodeSetPtr val
)
2294 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2295 xmlXPathContextCachePtr cache
=
2296 (xmlXPathContextCachePtr
) ctxt
->cache
;
2298 if ((cache
->miscObjs
!= NULL
) &&
2299 (cache
->miscObjs
->number
!= 0))
2301 xmlXPathObjectPtr ret
;
2303 ret
= (xmlXPathObjectPtr
)
2304 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2305 ret
->type
= XPATH_NODESET
;
2306 ret
->nodesetval
= val
;
2307 #ifdef XP_DEBUG_OBJ_USAGE
2308 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2314 return(xmlXPathWrapNodeSet(val
));
2319 * xmlXPathCacheWrapString:
2320 * @ctxt: the XPath context
2321 * @val: the xmlChar * value
2323 * This is the cached version of xmlXPathWrapString().
2324 * Wraps the @val string into an XPath object.
2326 * Returns the created or reused object.
2328 static xmlXPathObjectPtr
2329 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt
, xmlChar
*val
)
2331 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2332 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2334 if ((cache
->stringObjs
!= NULL
) &&
2335 (cache
->stringObjs
->number
!= 0))
2338 xmlXPathObjectPtr ret
;
2340 ret
= (xmlXPathObjectPtr
)
2341 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2342 ret
->type
= XPATH_STRING
;
2343 ret
->stringval
= val
;
2344 #ifdef XP_DEBUG_OBJ_USAGE
2345 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2348 } else if ((cache
->miscObjs
!= NULL
) &&
2349 (cache
->miscObjs
->number
!= 0))
2351 xmlXPathObjectPtr ret
;
2353 * Fallback to misc-cache.
2355 ret
= (xmlXPathObjectPtr
)
2356 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2358 ret
->type
= XPATH_STRING
;
2359 ret
->stringval
= val
;
2360 #ifdef XP_DEBUG_OBJ_USAGE
2361 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2366 return(xmlXPathWrapString(val
));
2370 * xmlXPathCacheNewNodeSet:
2371 * @ctxt: the XPath context
2372 * @val: the NodePtr value
2374 * This is the cached version of xmlXPathNewNodeSet().
2375 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2376 * it with the single Node @val
2378 * Returns the created or reused object.
2380 static xmlXPathObjectPtr
2381 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt
, xmlNodePtr val
)
2383 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2384 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2386 if ((cache
->nodesetObjs
!= NULL
) &&
2387 (cache
->nodesetObjs
->number
!= 0))
2389 xmlXPathObjectPtr ret
;
2391 * Use the nodset-cache.
2393 ret
= (xmlXPathObjectPtr
)
2394 cache
->nodesetObjs
->items
[--cache
->nodesetObjs
->number
];
2395 ret
->type
= XPATH_NODESET
;
2398 if ((ret
->nodesetval
->nodeMax
== 0) ||
2399 (val
->type
== XML_NAMESPACE_DECL
))
2401 xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
);
2403 ret
->nodesetval
->nodeTab
[0] = val
;
2404 ret
->nodesetval
->nodeNr
= 1;
2407 #ifdef XP_DEBUG_OBJ_USAGE
2408 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2411 } else if ((cache
->miscObjs
!= NULL
) &&
2412 (cache
->miscObjs
->number
!= 0))
2414 xmlXPathObjectPtr ret
;
2416 * Fallback to misc-cache.
2419 ret
= (xmlXPathObjectPtr
)
2420 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2422 ret
->type
= XPATH_NODESET
;
2424 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
2425 if (ret
->nodesetval
== NULL
) {
2426 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
2427 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
2430 #ifdef XP_DEBUG_OBJ_USAGE
2431 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2436 return(xmlXPathNewNodeSet(val
));
2440 * xmlXPathCacheNewCString:
2441 * @ctxt: the XPath context
2442 * @val: the char * value
2444 * This is the cached version of xmlXPathNewCString().
2445 * Acquire an xmlXPathObjectPtr of type string and of value @val
2447 * Returns the created or reused object.
2449 static xmlXPathObjectPtr
2450 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt
, const char *val
)
2452 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2453 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2455 if ((cache
->stringObjs
!= NULL
) &&
2456 (cache
->stringObjs
->number
!= 0))
2458 xmlXPathObjectPtr ret
;
2460 ret
= (xmlXPathObjectPtr
)
2461 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2463 ret
->type
= XPATH_STRING
;
2464 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2465 #ifdef XP_DEBUG_OBJ_USAGE
2466 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2469 } else if ((cache
->miscObjs
!= NULL
) &&
2470 (cache
->miscObjs
->number
!= 0))
2472 xmlXPathObjectPtr ret
;
2474 ret
= (xmlXPathObjectPtr
)
2475 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2477 ret
->type
= XPATH_STRING
;
2478 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2479 #ifdef XP_DEBUG_OBJ_USAGE
2480 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2485 return(xmlXPathNewCString(val
));
2489 * xmlXPathCacheNewString:
2490 * @ctxt: the XPath context
2491 * @val: the xmlChar * value
2493 * This is the cached version of xmlXPathNewString().
2494 * Acquire an xmlXPathObjectPtr of type string and of value @val
2496 * Returns the created or reused object.
2498 static xmlXPathObjectPtr
2499 xmlXPathCacheNewString(xmlXPathContextPtr ctxt
, const xmlChar
*val
)
2501 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2502 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2504 if ((cache
->stringObjs
!= NULL
) &&
2505 (cache
->stringObjs
->number
!= 0))
2507 xmlXPathObjectPtr ret
;
2509 ret
= (xmlXPathObjectPtr
)
2510 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2511 ret
->type
= XPATH_STRING
;
2513 ret
->stringval
= xmlStrdup(val
);
2515 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2516 #ifdef XP_DEBUG_OBJ_USAGE
2517 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2520 } else if ((cache
->miscObjs
!= NULL
) &&
2521 (cache
->miscObjs
->number
!= 0))
2523 xmlXPathObjectPtr ret
;
2525 ret
= (xmlXPathObjectPtr
)
2526 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2528 ret
->type
= XPATH_STRING
;
2530 ret
->stringval
= xmlStrdup(val
);
2532 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2533 #ifdef XP_DEBUG_OBJ_USAGE
2534 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2539 return(xmlXPathNewString(val
));
2543 * xmlXPathCacheNewBoolean:
2544 * @ctxt: the XPath context
2545 * @val: the boolean value
2547 * This is the cached version of xmlXPathNewBoolean().
2548 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2550 * Returns the created or reused object.
2552 static xmlXPathObjectPtr
2553 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt
, int val
)
2555 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2556 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2558 if ((cache
->booleanObjs
!= NULL
) &&
2559 (cache
->booleanObjs
->number
!= 0))
2561 xmlXPathObjectPtr ret
;
2563 ret
= (xmlXPathObjectPtr
)
2564 cache
->booleanObjs
->items
[--cache
->booleanObjs
->number
];
2565 ret
->type
= XPATH_BOOLEAN
;
2566 ret
->boolval
= (val
!= 0);
2567 #ifdef XP_DEBUG_OBJ_USAGE
2568 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2571 } else if ((cache
->miscObjs
!= NULL
) &&
2572 (cache
->miscObjs
->number
!= 0))
2574 xmlXPathObjectPtr ret
;
2576 ret
= (xmlXPathObjectPtr
)
2577 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2579 ret
->type
= XPATH_BOOLEAN
;
2580 ret
->boolval
= (val
!= 0);
2581 #ifdef XP_DEBUG_OBJ_USAGE
2582 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2587 return(xmlXPathNewBoolean(val
));
2591 * xmlXPathCacheNewFloat:
2592 * @ctxt: the XPath context
2593 * @val: the double value
2595 * This is the cached version of xmlXPathNewFloat().
2596 * Acquires an xmlXPathObjectPtr of type double and of value @val
2598 * Returns the created or reused object.
2600 static xmlXPathObjectPtr
2601 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt
, double val
)
2603 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2604 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2606 if ((cache
->numberObjs
!= NULL
) &&
2607 (cache
->numberObjs
->number
!= 0))
2609 xmlXPathObjectPtr ret
;
2611 ret
= (xmlXPathObjectPtr
)
2612 cache
->numberObjs
->items
[--cache
->numberObjs
->number
];
2613 ret
->type
= XPATH_NUMBER
;
2614 ret
->floatval
= val
;
2615 #ifdef XP_DEBUG_OBJ_USAGE
2616 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2619 } else if ((cache
->miscObjs
!= NULL
) &&
2620 (cache
->miscObjs
->number
!= 0))
2622 xmlXPathObjectPtr ret
;
2624 ret
= (xmlXPathObjectPtr
)
2625 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2627 ret
->type
= XPATH_NUMBER
;
2628 ret
->floatval
= val
;
2629 #ifdef XP_DEBUG_OBJ_USAGE
2630 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2635 return(xmlXPathNewFloat(val
));
2639 * xmlXPathCacheConvertString:
2640 * @ctxt: the XPath context
2641 * @val: an XPath object
2643 * This is the cached version of xmlXPathConvertString().
2644 * Converts an existing object to its string() equivalent
2646 * Returns a created or reused object, the old one is freed (cached)
2647 * (or the operation is done directly on @val)
2650 static xmlXPathObjectPtr
2651 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2652 xmlChar
*res
= NULL
;
2655 return(xmlXPathCacheNewCString(ctxt
, ""));
2657 switch (val
->type
) {
2658 case XPATH_UNDEFINED
:
2660 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
2664 case XPATH_XSLT_TREE
:
2665 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
2670 res
= xmlXPathCastBooleanToString(val
->boolval
);
2673 res
= xmlXPathCastNumberToString(val
->floatval
);
2678 case XPATH_LOCATIONSET
:
2682 xmlXPathReleaseObject(ctxt
, val
);
2684 return(xmlXPathCacheNewCString(ctxt
, ""));
2685 return(xmlXPathCacheWrapString(ctxt
, res
));
2689 * xmlXPathCacheObjectCopy:
2690 * @ctxt: the XPath context
2691 * @val: the original object
2693 * This is the cached version of xmlXPathObjectCopy().
2694 * Acquire a copy of a given object
2696 * Returns a created or reused created object.
2698 static xmlXPathObjectPtr
2699 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
)
2704 if (XP_HAS_CACHE(ctxt
)) {
2705 switch (val
->type
) {
2707 return(xmlXPathCacheWrapNodeSet(ctxt
,
2708 xmlXPathNodeSetMerge(NULL
, val
->nodesetval
)));
2710 return(xmlXPathCacheNewString(ctxt
, val
->stringval
));
2712 return(xmlXPathCacheNewBoolean(ctxt
, val
->boolval
));
2714 return(xmlXPathCacheNewFloat(ctxt
, val
->floatval
));
2719 return(xmlXPathObjectCopy(val
));
2723 * xmlXPathCacheConvertBoolean:
2724 * @ctxt: the XPath context
2725 * @val: an XPath object
2727 * This is the cached version of xmlXPathConvertBoolean().
2728 * Converts an existing object to its boolean() equivalent
2730 * Returns a created or reused object, the old one is freed (or the operation
2731 * is done directly on @val)
2733 static xmlXPathObjectPtr
2734 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2735 xmlXPathObjectPtr ret
;
2738 return(xmlXPathCacheNewBoolean(ctxt
, 0));
2739 if (val
->type
== XPATH_BOOLEAN
)
2741 ret
= xmlXPathCacheNewBoolean(ctxt
, xmlXPathCastToBoolean(val
));
2742 xmlXPathReleaseObject(ctxt
, val
);
2747 * xmlXPathCacheConvertNumber:
2748 * @ctxt: the XPath context
2749 * @val: an XPath object
2751 * This is the cached version of xmlXPathConvertNumber().
2752 * Converts an existing object to its number() equivalent
2754 * Returns a created or reused object, the old one is freed (or the operation
2755 * is done directly on @val)
2757 static xmlXPathObjectPtr
2758 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2759 xmlXPathObjectPtr ret
;
2762 return(xmlXPathCacheNewFloat(ctxt
, 0.0));
2763 if (val
->type
== XPATH_NUMBER
)
2765 ret
= xmlXPathCacheNewFloat(ctxt
, xmlXPathCastToNumber(val
));
2766 xmlXPathReleaseObject(ctxt
, val
);
2770 /************************************************************************
2772 * Parser stacks related functions and macros *
2774 ************************************************************************/
2778 * @ctxt: an XPath parser context
2780 * Set the callee evaluation frame
2782 * Returns the previous frame value to be restored once done
2785 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt
) {
2790 ret
= ctxt
->valueFrame
;
2791 ctxt
->valueFrame
= ctxt
->valueNr
;
2797 * @ctxt: an XPath parser context
2798 * @frame: the previous frame value
2800 * Remove the callee evaluation frame
2803 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt
, int frame
) {
2806 if (ctxt
->valueNr
< ctxt
->valueFrame
) {
2807 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2809 ctxt
->valueFrame
= frame
;
2814 * @ctxt: an XPath evaluation context
2816 * Pops the top XPath object from the value stack
2818 * Returns the XPath object just removed
2821 valuePop(xmlXPathParserContextPtr ctxt
)
2823 xmlXPathObjectPtr ret
;
2825 if ((ctxt
== NULL
) || (ctxt
->valueNr
<= 0))
2828 if (ctxt
->valueNr
<= ctxt
->valueFrame
) {
2829 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2834 if (ctxt
->valueNr
> 0)
2835 ctxt
->value
= ctxt
->valueTab
[ctxt
->valueNr
- 1];
2838 ret
= ctxt
->valueTab
[ctxt
->valueNr
];
2839 ctxt
->valueTab
[ctxt
->valueNr
] = NULL
;
2844 * @ctxt: an XPath evaluation context
2845 * @value: the XPath object
2847 * Pushes a new XPath object on top of the value stack
2849 * returns the number of items on the value stack
2852 valuePush(xmlXPathParserContextPtr ctxt
, xmlXPathObjectPtr value
)
2854 if ((ctxt
== NULL
) || (value
== NULL
)) return(-1);
2855 if (ctxt
->valueNr
>= ctxt
->valueMax
) {
2856 xmlXPathObjectPtr
*tmp
;
2858 if (ctxt
->valueMax
>= XPATH_MAX_STACK_DEPTH
) {
2859 xmlXPathErrMemory(NULL
, "XPath stack depth limit reached\n");
2860 ctxt
->error
= XPATH_MEMORY_ERROR
;
2863 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(ctxt
->valueTab
,
2864 2 * ctxt
->valueMax
*
2865 sizeof(ctxt
->valueTab
[0]));
2867 xmlXPathErrMemory(NULL
, "pushing value\n");
2868 ctxt
->error
= XPATH_MEMORY_ERROR
;
2871 ctxt
->valueMax
*= 2;
2872 ctxt
->valueTab
= tmp
;
2874 ctxt
->valueTab
[ctxt
->valueNr
] = value
;
2875 ctxt
->value
= value
;
2876 return (ctxt
->valueNr
++);
2880 * xmlXPathPopBoolean:
2881 * @ctxt: an XPath parser context
2883 * Pops a boolean from the stack, handling conversion if needed.
2884 * Check error with #xmlXPathCheckError.
2886 * Returns the boolean
2889 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt
) {
2890 xmlXPathObjectPtr obj
;
2893 obj
= valuePop(ctxt
);
2895 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2898 if (obj
->type
!= XPATH_BOOLEAN
)
2899 ret
= xmlXPathCastToBoolean(obj
);
2902 xmlXPathReleaseObject(ctxt
->context
, obj
);
2907 * xmlXPathPopNumber:
2908 * @ctxt: an XPath parser context
2910 * Pops a number from the stack, handling conversion if needed.
2911 * Check error with #xmlXPathCheckError.
2913 * Returns the number
2916 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt
) {
2917 xmlXPathObjectPtr obj
;
2920 obj
= valuePop(ctxt
);
2922 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2925 if (obj
->type
!= XPATH_NUMBER
)
2926 ret
= xmlXPathCastToNumber(obj
);
2928 ret
= obj
->floatval
;
2929 xmlXPathReleaseObject(ctxt
->context
, obj
);
2934 * xmlXPathPopString:
2935 * @ctxt: an XPath parser context
2937 * Pops a string from the stack, handling conversion if needed.
2938 * Check error with #xmlXPathCheckError.
2940 * Returns the string
2943 xmlXPathPopString (xmlXPathParserContextPtr ctxt
) {
2944 xmlXPathObjectPtr obj
;
2947 obj
= valuePop(ctxt
);
2949 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2952 ret
= xmlXPathCastToString(obj
); /* this does required strdup */
2953 /* TODO: needs refactoring somewhere else */
2954 if (obj
->stringval
== ret
)
2955 obj
->stringval
= NULL
;
2956 xmlXPathReleaseObject(ctxt
->context
, obj
);
2961 * xmlXPathPopNodeSet:
2962 * @ctxt: an XPath parser context
2964 * Pops a node-set from the stack, handling conversion if needed.
2965 * Check error with #xmlXPathCheckError.
2967 * Returns the node-set
2970 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt
) {
2971 xmlXPathObjectPtr obj
;
2974 if (ctxt
== NULL
) return(NULL
);
2975 if (ctxt
->value
== NULL
) {
2976 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2979 if (!xmlXPathStackIsNodeSet(ctxt
)) {
2980 xmlXPathSetTypeError(ctxt
);
2983 obj
= valuePop(ctxt
);
2984 ret
= obj
->nodesetval
;
2986 /* to fix memory leak of not clearing obj->user */
2987 if (obj
->boolval
&& obj
->user
!= NULL
)
2988 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
2990 obj
->nodesetval
= NULL
;
2991 xmlXPathReleaseObject(ctxt
->context
, obj
);
2996 * xmlXPathPopExternal:
2997 * @ctxt: an XPath parser context
2999 * Pops an external object from the stack, handling conversion if needed.
3000 * Check error with #xmlXPathCheckError.
3002 * Returns the object
3005 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt
) {
3006 xmlXPathObjectPtr obj
;
3009 if ((ctxt
== NULL
) || (ctxt
->value
== NULL
)) {
3010 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
3013 if (ctxt
->value
->type
!= XPATH_USERS
) {
3014 xmlXPathSetTypeError(ctxt
);
3017 obj
= valuePop(ctxt
);
3020 xmlXPathReleaseObject(ctxt
->context
, obj
);
3025 * Macros for accessing the content. Those should be used only by the parser,
3028 * Dirty macros, i.e. one need to make assumption on the context to use them
3030 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3031 * CUR returns the current xmlChar value, i.e. a 8 bit value
3032 * in ISO-Latin or UTF-8.
3033 * This should be used internally by the parser
3034 * only to compare to ASCII values otherwise it would break when
3035 * running with UTF-8 encoding.
3036 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3037 * to compare on ASCII based substring.
3038 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3039 * strings within the parser.
3040 * CURRENT Returns the current char value, with the full decoding of
3041 * UTF-8 if we are using this mode. It returns an int.
3042 * NEXT Skip to the next character, this does the proper decoding
3043 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3044 * It returns the pointer to the current xmlChar.
3047 #define CUR (*ctxt->cur)
3048 #define SKIP(val) ctxt->cur += (val)
3049 #define NXT(val) ctxt->cur[(val)]
3050 #define CUR_PTR ctxt->cur
3051 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3053 #define COPY_BUF(l,b,i,v) \
3054 if (l == 1) b[i++] = (xmlChar) v; \
3055 else i += xmlCopyChar(l,&b[i],v)
3057 #define NEXTL(l) ctxt->cur += l
3059 #define SKIP_BLANKS \
3060 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3062 #define CURRENT (*ctxt->cur)
3063 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3070 #define DBL_EPSILON 1E-9
3073 #define UPPER_DOUBLE 1E9
3074 #define LOWER_DOUBLE 1E-5
3075 #define LOWER_DOUBLE_EXP 5
3077 #define INTEGER_DIGITS DBL_DIG
3078 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3079 #define EXPONENT_DIGITS (3 + 2)
3082 * xmlXPathFormatNumber:
3083 * @number: number to format
3084 * @buffer: output buffer
3085 * @buffersize: size of output buffer
3087 * Convert the number into a string representation.
3090 xmlXPathFormatNumber(double number
, char buffer
[], int buffersize
)
3092 switch (xmlXPathIsInf(number
)) {
3094 if (buffersize
> (int)sizeof("Infinity"))
3095 snprintf(buffer
, buffersize
, "Infinity");
3098 if (buffersize
> (int)sizeof("-Infinity"))
3099 snprintf(buffer
, buffersize
, "-Infinity");
3102 if (xmlXPathIsNaN(number
)) {
3103 if (buffersize
> (int)sizeof("NaN"))
3104 snprintf(buffer
, buffersize
, "NaN");
3105 } else if (number
== 0) {
3106 /* Omit sign for negative zero. */
3107 snprintf(buffer
, buffersize
, "0");
3108 } else if ((number
> INT_MIN
) && (number
< INT_MAX
) &&
3109 (number
== (int) number
)) {
3112 int value
= (int) number
;
3118 snprintf(work
, 29, "%d", value
);
3120 while ((*cur
) && (ptr
- buffer
< buffersize
)) {
3124 if (ptr
- buffer
< buffersize
) {
3126 } else if (buffersize
> 0) {
3132 For the dimension of work,
3133 DBL_DIG is number of significant digits
3134 EXPONENT is only needed for "scientific notation"
3135 3 is sign, decimal point, and terminating zero
3136 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3137 Note that this dimension is slightly (a few characters)
3138 larger than actually necessary.
3140 char work
[DBL_DIG
+ EXPONENT_DIGITS
+ 3 + LOWER_DOUBLE_EXP
];
3141 int integer_place
, fraction_place
;
3143 char *after_fraction
;
3144 double absolute_value
;
3147 absolute_value
= fabs(number
);
3150 * First choose format - scientific or regular floating point.
3151 * In either case, result is in work, and after_fraction points
3152 * just past the fractional part.
3154 if ( ((absolute_value
> UPPER_DOUBLE
) ||
3155 (absolute_value
< LOWER_DOUBLE
)) &&
3156 (absolute_value
!= 0.0) ) {
3157 /* Use scientific notation */
3158 integer_place
= DBL_DIG
+ EXPONENT_DIGITS
+ 1;
3159 fraction_place
= DBL_DIG
- 1;
3160 size
= snprintf(work
, sizeof(work
),"%*.*e",
3161 integer_place
, fraction_place
, number
);
3162 while ((size
> 0) && (work
[size
] != 'e')) size
--;
3166 /* Use regular notation */
3167 if (absolute_value
> 0.0) {
3168 integer_place
= (int)log10(absolute_value
);
3169 if (integer_place
> 0)
3170 fraction_place
= DBL_DIG
- integer_place
- 1;
3172 fraction_place
= DBL_DIG
- integer_place
;
3176 size
= snprintf(work
, sizeof(work
), "%0.*f",
3177 fraction_place
, number
);
3180 /* Remove leading spaces sometimes inserted by snprintf */
3181 while (work
[0] == ' ') {
3182 for (ptr
= &work
[0];(ptr
[0] = ptr
[1]);ptr
++);
3186 /* Remove fractional trailing zeroes */
3187 after_fraction
= work
+ size
;
3188 ptr
= after_fraction
;
3189 while (*(--ptr
) == '0')
3193 while ((*ptr
++ = *after_fraction
++) != 0);
3195 /* Finally copy result back to caller */
3196 size
= strlen(work
) + 1;
3197 if (size
> buffersize
) {
3198 work
[buffersize
- 1] = 0;
3201 memmove(buffer
, work
, size
);
3208 /************************************************************************
3210 * Routines to handle NodeSets *
3212 ************************************************************************/
3215 * xmlXPathOrderDocElems:
3216 * @doc: an input document
3218 * Call this routine to speed up XPath computation on static documents.
3219 * This stamps all the element nodes with the document order
3220 * Like for line information, the order is kept in the element->content
3221 * field, the value stored is actually - the node number (starting at -1)
3222 * to be able to differentiate from line numbers.
3224 * Returns the number of elements found in the document or -1 in case
3228 xmlXPathOrderDocElems(xmlDocPtr doc
) {
3229 ptrdiff_t count
= 0;
3234 cur
= doc
->children
;
3235 while (cur
!= NULL
) {
3236 if (cur
->type
== XML_ELEMENT_NODE
) {
3237 cur
->content
= (void *) (-(++count
));
3238 if (cur
->children
!= NULL
) {
3239 cur
= cur
->children
;
3243 if (cur
->next
!= NULL
) {
3251 if (cur
== (xmlNodePtr
) doc
) {
3255 if (cur
->next
!= NULL
) {
3259 } while (cur
!= NULL
);
3261 return((long) count
);
3266 * @node1: the first node
3267 * @node2: the second node
3269 * Compare two nodes w.r.t document order
3271 * Returns -2 in case of error 1 if first point < second point, 0 if
3272 * it's the same node, -1 otherwise
3275 xmlXPathCmpNodes(xmlNodePtr node1
, xmlNodePtr node2
) {
3277 int attr1
= 0, attr2
= 0;
3278 xmlNodePtr attrNode1
= NULL
, attrNode2
= NULL
;
3279 xmlNodePtr cur
, root
;
3281 if ((node1
== NULL
) || (node2
== NULL
))
3284 * a couple of optimizations which will avoid computations in most cases
3286 if (node1
== node2
) /* trivial case */
3288 if (node1
->type
== XML_ATTRIBUTE_NODE
) {
3291 node1
= node1
->parent
;
3293 if (node2
->type
== XML_ATTRIBUTE_NODE
) {
3296 node2
= node2
->parent
;
3298 if (node1
== node2
) {
3299 if (attr1
== attr2
) {
3300 /* not required, but we keep attributes in order */
3302 cur
= attrNode2
->prev
;
3303 while (cur
!= NULL
) {
3304 if (cur
== attrNode1
)
3316 if ((node1
->type
== XML_NAMESPACE_DECL
) ||
3317 (node2
->type
== XML_NAMESPACE_DECL
))
3319 if (node1
== node2
->prev
)
3321 if (node1
== node2
->next
)
3325 * Speedup using document order if availble.
3327 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3328 (node2
->type
== XML_ELEMENT_NODE
) &&
3329 (0 > (ptrdiff_t) node1
->content
) &&
3330 (0 > (ptrdiff_t) node2
->content
) &&
3331 (node1
->doc
== node2
->doc
)) {
3334 l1
= -((ptrdiff_t) node1
->content
);
3335 l2
= -((ptrdiff_t) node2
->content
);
3343 * compute depth to root
3345 for (depth2
= 0, cur
= node2
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3346 if (cur
->parent
== node1
)
3351 for (depth1
= 0, cur
= node1
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3352 if (cur
->parent
== node2
)
3357 * Distinct document (or distinct entities :-( ) case.
3363 * get the nearest common ancestor.
3365 while (depth1
> depth2
) {
3367 node1
= node1
->parent
;
3369 while (depth2
> depth1
) {
3371 node2
= node2
->parent
;
3373 while (node1
->parent
!= node2
->parent
) {
3374 node1
= node1
->parent
;
3375 node2
= node2
->parent
;
3376 /* should not happen but just in case ... */
3377 if ((node1
== NULL
) || (node2
== NULL
))
3383 if (node1
== node2
->prev
)
3385 if (node1
== node2
->next
)
3388 * Speedup using document order if availble.
3390 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3391 (node2
->type
== XML_ELEMENT_NODE
) &&
3392 (0 > (ptrdiff_t) node1
->content
) &&
3393 (0 > (ptrdiff_t) node2
->content
) &&
3394 (node1
->doc
== node2
->doc
)) {
3397 l1
= -((ptrdiff_t) node1
->content
);
3398 l2
= -((ptrdiff_t) node2
->content
);
3405 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
3408 return(-1); /* assume there is no sibling list corruption */
3412 * xmlXPathNodeSetSort:
3413 * @set: the node set
3415 * Sort the node set in document order
3418 xmlXPathNodeSetSort(xmlNodeSetPtr set
) {
3419 #ifndef WITH_TIM_SORT
3420 int i
, j
, incr
, len
;
3427 #ifndef WITH_TIM_SORT
3429 * Use the old Shell's sort implementation to sort the node-set
3430 * Timsort ought to be quite faster
3433 for (incr
= len
/ 2; incr
> 0; incr
/= 2) {
3434 for (i
= incr
; i
< len
; i
++) {
3437 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3438 if (xmlXPathCmpNodesExt(set
->nodeTab
[j
],
3439 set
->nodeTab
[j
+ incr
]) == -1)
3441 if (xmlXPathCmpNodes(set
->nodeTab
[j
],
3442 set
->nodeTab
[j
+ incr
]) == -1)
3445 tmp
= set
->nodeTab
[j
];
3446 set
->nodeTab
[j
] = set
->nodeTab
[j
+ incr
];
3447 set
->nodeTab
[j
+ incr
] = tmp
;
3454 #else /* WITH_TIM_SORT */
3455 libxml_domnode_tim_sort(set
->nodeTab
, set
->nodeNr
);
3456 #endif /* WITH_TIM_SORT */
3459 #define XML_NODESET_DEFAULT 10
3461 * xmlXPathNodeSetDupNs:
3462 * @node: the parent node of the namespace XPath node
3463 * @ns: the libxml namespace declaration node.
3465 * Namespace node in libxml don't match the XPath semantic. In a node set
3466 * the namespace nodes are duplicated and the next pointer is set to the
3467 * parent node in the XPath semantic.
3469 * Returns the newly created object.
3472 xmlXPathNodeSetDupNs(xmlNodePtr node
, xmlNsPtr ns
) {
3475 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3477 if ((node
== NULL
) || (node
->type
== XML_NAMESPACE_DECL
))
3478 return((xmlNodePtr
) ns
);
3481 * Allocate a new Namespace and fill the fields.
3483 cur
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
3485 xmlXPathErrMemory(NULL
, "duplicating namespace\n");
3488 memset(cur
, 0, sizeof(xmlNs
));
3489 cur
->type
= XML_NAMESPACE_DECL
;
3490 if (ns
->href
!= NULL
)
3491 cur
->href
= xmlStrdup(ns
->href
);
3492 if (ns
->prefix
!= NULL
)
3493 cur
->prefix
= xmlStrdup(ns
->prefix
);
3494 cur
->next
= (xmlNsPtr
) node
;
3495 return((xmlNodePtr
) cur
);
3499 * xmlXPathNodeSetFreeNs:
3500 * @ns: the XPath namespace node found in a nodeset.
3502 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3503 * the namespace nodes are duplicated and the next pointer is set to the
3504 * parent node in the XPath semantic. Check if such a node needs to be freed
3507 xmlXPathNodeSetFreeNs(xmlNsPtr ns
) {
3508 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3511 if ((ns
->next
!= NULL
) && (ns
->next
->type
!= XML_NAMESPACE_DECL
)) {
3512 if (ns
->href
!= NULL
)
3513 xmlFree((xmlChar
*)ns
->href
);
3514 if (ns
->prefix
!= NULL
)
3515 xmlFree((xmlChar
*)ns
->prefix
);
3521 * xmlXPathNodeSetCreate:
3522 * @val: an initial xmlNodePtr, or NULL
3524 * Create a new xmlNodeSetPtr of type double and of value @val
3526 * Returns the newly created object.
3529 xmlXPathNodeSetCreate(xmlNodePtr val
) {
3532 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3534 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3537 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3539 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3540 sizeof(xmlNodePtr
));
3541 if (ret
->nodeTab
== NULL
) {
3542 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3546 memset(ret
->nodeTab
, 0 ,
3547 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3548 ret
->nodeMax
= XML_NODESET_DEFAULT
;
3549 if (val
->type
== XML_NAMESPACE_DECL
) {
3550 xmlNsPtr ns
= (xmlNsPtr
) val
;
3552 ret
->nodeTab
[ret
->nodeNr
++] =
3553 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3555 ret
->nodeTab
[ret
->nodeNr
++] = val
;
3561 * xmlXPathNodeSetCreateSize:
3562 * @size: the initial size of the set
3564 * Create a new xmlNodeSetPtr of type double and of value @val
3566 * Returns the newly created object.
3568 static xmlNodeSetPtr
3569 xmlXPathNodeSetCreateSize(int size
) {
3572 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3574 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3577 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3578 if (size
< XML_NODESET_DEFAULT
)
3579 size
= XML_NODESET_DEFAULT
;
3580 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(size
* sizeof(xmlNodePtr
));
3581 if (ret
->nodeTab
== NULL
) {
3582 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3586 memset(ret
->nodeTab
, 0 , size
* (size_t) sizeof(xmlNodePtr
));
3587 ret
->nodeMax
= size
;
3592 * xmlXPathNodeSetContains:
3593 * @cur: the node-set
3596 * checks whether @cur contains @val
3598 * Returns true (1) if @cur contains @val, false (0) otherwise
3601 xmlXPathNodeSetContains (xmlNodeSetPtr cur
, xmlNodePtr val
) {
3604 if ((cur
== NULL
) || (val
== NULL
)) return(0);
3605 if (val
->type
== XML_NAMESPACE_DECL
) {
3606 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3607 if (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
3610 ns1
= (xmlNsPtr
) val
;
3611 ns2
= (xmlNsPtr
) cur
->nodeTab
[i
];
3614 if ((ns1
->next
!= NULL
) && (ns2
->next
== ns1
->next
) &&
3615 (xmlStrEqual(ns1
->prefix
, ns2
->prefix
)))
3620 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3621 if (cur
->nodeTab
[i
] == val
)
3629 * xmlXPathNodeSetAddNs:
3630 * @cur: the initial node set
3631 * @node: the hosting node
3632 * @ns: a the namespace node
3634 * add a new namespace node to an existing NodeSet
3636 * Returns 0 in case of success and -1 in case of error
3639 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur
, xmlNodePtr node
, xmlNsPtr ns
) {
3643 if ((cur
== NULL
) || (ns
== NULL
) || (node
== NULL
) ||
3644 (ns
->type
!= XML_NAMESPACE_DECL
) ||
3645 (node
->type
!= XML_ELEMENT_NODE
))
3648 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3650 * prevent duplicates
3652 for (i
= 0;i
< cur
->nodeNr
;i
++) {
3653 if ((cur
->nodeTab
[i
] != NULL
) &&
3654 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) &&
3655 (((xmlNsPtr
)cur
->nodeTab
[i
])->next
== (xmlNsPtr
) node
) &&
3656 (xmlStrEqual(ns
->prefix
, ((xmlNsPtr
)cur
->nodeTab
[i
])->prefix
)))
3661 * grow the nodeTab if needed
3663 if (cur
->nodeMax
== 0) {
3664 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3665 sizeof(xmlNodePtr
));
3666 if (cur
->nodeTab
== NULL
) {
3667 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3670 memset(cur
->nodeTab
, 0 ,
3671 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3672 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3673 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3676 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3677 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3680 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3681 sizeof(xmlNodePtr
));
3683 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3687 cur
->nodeTab
= temp
;
3689 cur
->nodeTab
[cur
->nodeNr
++] = xmlXPathNodeSetDupNs(node
, ns
);
3694 * xmlXPathNodeSetAdd:
3695 * @cur: the initial node set
3696 * @val: a new xmlNodePtr
3698 * add a new xmlNodePtr to an existing NodeSet
3700 * Returns 0 in case of success, and -1 in case of error
3703 xmlXPathNodeSetAdd(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3706 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3708 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3710 * prevent duplicates
3712 for (i
= 0;i
< cur
->nodeNr
;i
++)
3713 if (cur
->nodeTab
[i
] == val
) return(0);
3716 * grow the nodeTab if needed
3718 if (cur
->nodeMax
== 0) {
3719 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3720 sizeof(xmlNodePtr
));
3721 if (cur
->nodeTab
== NULL
) {
3722 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3725 memset(cur
->nodeTab
, 0 ,
3726 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3727 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3728 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3731 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3732 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3735 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3736 sizeof(xmlNodePtr
));
3738 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3742 cur
->nodeTab
= temp
;
3744 if (val
->type
== XML_NAMESPACE_DECL
) {
3745 xmlNsPtr ns
= (xmlNsPtr
) val
;
3747 cur
->nodeTab
[cur
->nodeNr
++] =
3748 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3750 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3755 * xmlXPathNodeSetAddUnique:
3756 * @cur: the initial node set
3757 * @val: a new xmlNodePtr
3759 * add a new xmlNodePtr to an existing NodeSet, optimized version
3760 * when we are sure the node is not already in the set.
3762 * Returns 0 in case of success and -1 in case of failure
3765 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3766 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3768 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3770 * grow the nodeTab if needed
3772 if (cur
->nodeMax
== 0) {
3773 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3774 sizeof(xmlNodePtr
));
3775 if (cur
->nodeTab
== NULL
) {
3776 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3779 memset(cur
->nodeTab
, 0 ,
3780 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3781 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3782 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3785 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3786 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3789 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3790 sizeof(xmlNodePtr
));
3792 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3795 cur
->nodeTab
= temp
;
3798 if (val
->type
== XML_NAMESPACE_DECL
) {
3799 xmlNsPtr ns
= (xmlNsPtr
) val
;
3801 cur
->nodeTab
[cur
->nodeNr
++] =
3802 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3804 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3809 * xmlXPathNodeSetMerge:
3810 * @val1: the first NodeSet or NULL
3811 * @val2: the second NodeSet
3813 * Merges two nodesets, all nodes from @val2 are added to @val1
3814 * if @val1 is NULL, a new set is created and copied from @val2
3816 * Returns @val1 once extended or NULL in case of error.
3819 xmlXPathNodeSetMerge(xmlNodeSetPtr val1
, xmlNodeSetPtr val2
) {
3820 int i
, j
, initNr
, skip
;
3823 if (val2
== NULL
) return(val1
);
3825 val1
= xmlXPathNodeSetCreate(NULL
);
3830 * TODO: The optimization won't work in every case, since
3831 * those nasty namespace nodes need to be added with
3832 * xmlXPathNodeSetDupNs() to the set; thus a pure
3833 * memcpy is not possible.
3834 * If there was a flag on the nodesetval, indicating that
3835 * some temporary nodes are in, that would be helpfull.
3838 * Optimization: Create an equally sized node-set
3839 * and memcpy the content.
3841 val1
= xmlXPathNodeSetCreateSize(val2
->nodeNr
);
3844 if (val2
->nodeNr
!= 0) {
3845 if (val2
->nodeNr
== 1)
3846 *(val1
->nodeTab
) = *(val2
->nodeTab
);
3848 memcpy(val1
->nodeTab
, val2
->nodeTab
,
3849 val2
->nodeNr
* sizeof(xmlNodePtr
));
3851 val1
->nodeNr
= val2
->nodeNr
;
3857 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3858 initNr
= val1
->nodeNr
;
3860 for (i
= 0;i
< val2
->nodeNr
;i
++) {
3861 n2
= val2
->nodeTab
[i
];
3863 * check against duplicates
3866 for (j
= 0; j
< initNr
; j
++) {
3867 n1
= val1
->nodeTab
[j
];
3871 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3872 (n2
->type
== XML_NAMESPACE_DECL
)) {
3873 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3874 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3875 ((xmlNsPtr
) n2
)->prefix
)))
3886 * grow the nodeTab if needed
3888 if (val1
->nodeMax
== 0) {
3889 val1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3890 sizeof(xmlNodePtr
));
3891 if (val1
->nodeTab
== NULL
) {
3892 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3895 memset(val1
->nodeTab
, 0 ,
3896 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3897 val1
->nodeMax
= XML_NODESET_DEFAULT
;
3898 } else if (val1
->nodeNr
== val1
->nodeMax
) {
3901 if (val1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3902 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
3905 temp
= (xmlNodePtr
*) xmlRealloc(val1
->nodeTab
, val1
->nodeMax
* 2 *
3906 sizeof(xmlNodePtr
));
3908 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3911 val1
->nodeTab
= temp
;
3914 if (n2
->type
== XML_NAMESPACE_DECL
) {
3915 xmlNsPtr ns
= (xmlNsPtr
) n2
;
3917 val1
->nodeTab
[val1
->nodeNr
++] =
3918 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3920 val1
->nodeTab
[val1
->nodeNr
++] = n2
;
3928 * xmlXPathNodeSetMergeAndClear:
3929 * @set1: the first NodeSet or NULL
3930 * @set2: the second NodeSet
3931 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3933 * Merges two nodesets, all nodes from @set2 are added to @set1
3934 * if @set1 is NULL, a new set is created and copied from @set2.
3935 * Checks for duplicate nodes. Clears set2.
3937 * Returns @set1 once extended or NULL in case of error.
3939 static xmlNodeSetPtr
3940 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
,
3943 if ((set1
== NULL
) && (hasNullEntries
== 0)) {
3945 * Note that doing a memcpy of the list, namespace nodes are
3946 * just assigned to set1, since set2 is cleared anyway.
3948 set1
= xmlXPathNodeSetCreateSize(set2
->nodeNr
);
3951 if (set2
->nodeNr
!= 0) {
3952 memcpy(set1
->nodeTab
, set2
->nodeTab
,
3953 set2
->nodeNr
* sizeof(xmlNodePtr
));
3954 set1
->nodeNr
= set2
->nodeNr
;
3957 int i
, j
, initNbSet1
;
3961 set1
= xmlXPathNodeSetCreate(NULL
);
3965 initNbSet1
= set1
->nodeNr
;
3966 for (i
= 0;i
< set2
->nodeNr
;i
++) {
3967 n2
= set2
->nodeTab
[i
];
3969 * Skip NULLed entries.
3976 for (j
= 0; j
< initNbSet1
; j
++) {
3977 n1
= set1
->nodeTab
[j
];
3980 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3981 (n2
->type
== XML_NAMESPACE_DECL
))
3983 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3984 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3985 ((xmlNsPtr
) n2
)->prefix
)))
3988 * Free the namespace node.
3990 set2
->nodeTab
[i
] = NULL
;
3991 xmlXPathNodeSetFreeNs((xmlNsPtr
) n2
);
3997 * grow the nodeTab if needed
3999 if (set1
->nodeMax
== 0) {
4000 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
4001 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4002 if (set1
->nodeTab
== NULL
) {
4003 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4006 memset(set1
->nodeTab
, 0,
4007 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4008 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4009 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4012 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4013 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4016 temp
= (xmlNodePtr
*) xmlRealloc(
4017 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4019 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4022 set1
->nodeTab
= temp
;
4025 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4035 * xmlXPathNodeSetMergeAndClearNoDupls:
4036 * @set1: the first NodeSet or NULL
4037 * @set2: the second NodeSet
4038 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4040 * Merges two nodesets, all nodes from @set2 are added to @set1
4041 * if @set1 is NULL, a new set is created and copied from @set2.
4042 * Doesn't chack for duplicate nodes. Clears set2.
4044 * Returns @set1 once extended or NULL in case of error.
4046 static xmlNodeSetPtr
4047 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
,
4052 if ((set1
== NULL
) && (hasNullEntries
== 0)) {
4054 * Note that doing a memcpy of the list, namespace nodes are
4055 * just assigned to set1, since set2 is cleared anyway.
4057 set1
= xmlXPathNodeSetCreateSize(set2
->nodeNr
);
4060 if (set2
->nodeNr
!= 0) {
4061 memcpy(set1
->nodeTab
, set2
->nodeTab
,
4062 set2
->nodeNr
* sizeof(xmlNodePtr
));
4063 set1
->nodeNr
= set2
->nodeNr
;
4070 set1
= xmlXPathNodeSetCreate(NULL
);
4074 for (i
= 0;i
< set2
->nodeNr
;i
++) {
4075 n2
= set2
->nodeTab
[i
];
4077 * Skip NULLed entries.
4081 if (set1
->nodeMax
== 0) {
4082 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
4083 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4084 if (set1
->nodeTab
== NULL
) {
4085 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4088 memset(set1
->nodeTab
, 0,
4089 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4090 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4091 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4094 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4095 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4098 temp
= (xmlNodePtr
*) xmlRealloc(
4099 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4101 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4104 set1
->nodeTab
= temp
;
4107 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4115 * xmlXPathNodeSetDel:
4116 * @cur: the initial node set
4117 * @val: an xmlNodePtr
4119 * Removes an xmlNodePtr from an existing NodeSet
4122 xmlXPathNodeSetDel(xmlNodeSetPtr cur
, xmlNodePtr val
) {
4125 if (cur
== NULL
) return;
4126 if (val
== NULL
) return;
4129 * find node in nodeTab
4131 for (i
= 0;i
< cur
->nodeNr
;i
++)
4132 if (cur
->nodeTab
[i
] == val
) break;
4134 if (i
>= cur
->nodeNr
) { /* not found */
4136 xmlGenericError(xmlGenericErrorContext
,
4137 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4142 if ((cur
->nodeTab
[i
] != NULL
) &&
4143 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4144 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[i
]);
4146 for (;i
< cur
->nodeNr
;i
++)
4147 cur
->nodeTab
[i
] = cur
->nodeTab
[i
+ 1];
4148 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4152 * xmlXPathNodeSetRemove:
4153 * @cur: the initial node set
4154 * @val: the index to remove
4156 * Removes an entry from an existing NodeSet list.
4159 xmlXPathNodeSetRemove(xmlNodeSetPtr cur
, int val
) {
4160 if (cur
== NULL
) return;
4161 if (val
>= cur
->nodeNr
) return;
4162 if ((cur
->nodeTab
[val
] != NULL
) &&
4163 (cur
->nodeTab
[val
]->type
== XML_NAMESPACE_DECL
))
4164 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[val
]);
4166 for (;val
< cur
->nodeNr
;val
++)
4167 cur
->nodeTab
[val
] = cur
->nodeTab
[val
+ 1];
4168 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4172 * xmlXPathFreeNodeSet:
4173 * @obj: the xmlNodeSetPtr to free
4175 * Free the NodeSet compound (not the actual nodes !).
4178 xmlXPathFreeNodeSet(xmlNodeSetPtr obj
) {
4179 if (obj
== NULL
) return;
4180 if (obj
->nodeTab
!= NULL
) {
4183 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4184 for (i
= 0;i
< obj
->nodeNr
;i
++)
4185 if ((obj
->nodeTab
[i
] != NULL
) &&
4186 (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4187 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4188 xmlFree(obj
->nodeTab
);
4194 * xmlXPathNodeSetClearFromPos:
4195 * @set: the node set to be cleared
4196 * @pos: the start position to clear from
4198 * Clears the list from temporary XPath objects (e.g. namespace nodes
4199 * are feed) starting with the entry at @pos, but does *not* free the list
4200 * itself. Sets the length of the list to @pos.
4203 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set
, int pos
, int hasNsNodes
)
4205 if ((set
== NULL
) || (pos
>= set
->nodeNr
))
4207 else if ((hasNsNodes
)) {
4211 for (i
= pos
; i
< set
->nodeNr
; i
++) {
4212 node
= set
->nodeTab
[i
];
4213 if ((node
!= NULL
) &&
4214 (node
->type
== XML_NAMESPACE_DECL
))
4215 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4222 * xmlXPathNodeSetClear:
4223 * @set: the node set to clear
4225 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4226 * are feed), but does *not* free the list itself. Sets the length of the
4230 xmlXPathNodeSetClear(xmlNodeSetPtr set
, int hasNsNodes
)
4232 xmlXPathNodeSetClearFromPos(set
, 0, hasNsNodes
);
4236 * xmlXPathNodeSetKeepLast:
4237 * @set: the node set to be cleared
4239 * Move the last node to the first position and clear temporary XPath objects
4240 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4244 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set
)
4249 if ((set
== NULL
) || (set
->nodeNr
<= 1))
4251 for (i
= 0; i
< set
->nodeNr
- 1; i
++) {
4252 node
= set
->nodeTab
[i
];
4253 if ((node
!= NULL
) &&
4254 (node
->type
== XML_NAMESPACE_DECL
))
4255 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4257 set
->nodeTab
[0] = set
->nodeTab
[set
->nodeNr
-1];
4262 * xmlXPathFreeValueTree:
4263 * @obj: the xmlNodeSetPtr to free
4265 * Free the NodeSet compound and the actual tree, this is different
4266 * from xmlXPathFreeNodeSet()
4269 xmlXPathFreeValueTree(xmlNodeSetPtr obj
) {
4272 if (obj
== NULL
) return;
4274 if (obj
->nodeTab
!= NULL
) {
4275 for (i
= 0;i
< obj
->nodeNr
;i
++) {
4276 if (obj
->nodeTab
[i
] != NULL
) {
4277 if (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
4278 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4280 xmlFreeNodeList(obj
->nodeTab
[i
]);
4284 xmlFree(obj
->nodeTab
);
4289 #if defined(DEBUG) || defined(DEBUG_STEP)
4291 * xmlGenericErrorContextNodeSet:
4292 * @output: a FILE * for the output
4293 * @obj: the xmlNodeSetPtr to display
4295 * Quick display of a NodeSet
4298 xmlGenericErrorContextNodeSet(FILE *output
, xmlNodeSetPtr obj
) {
4301 if (output
== NULL
) output
= xmlGenericErrorContext
;
4303 fprintf(output
, "NodeSet == NULL !\n");
4306 if (obj
->nodeNr
== 0) {
4307 fprintf(output
, "NodeSet is empty\n");
4310 if (obj
->nodeTab
== NULL
) {
4311 fprintf(output
, " nodeTab == NULL !\n");
4314 for (i
= 0; i
< obj
->nodeNr
; i
++) {
4315 if (obj
->nodeTab
[i
] == NULL
) {
4316 fprintf(output
, " NULL !\n");
4319 if ((obj
->nodeTab
[i
]->type
== XML_DOCUMENT_NODE
) ||
4320 (obj
->nodeTab
[i
]->type
== XML_HTML_DOCUMENT_NODE
))
4321 fprintf(output
, " /");
4322 else if (obj
->nodeTab
[i
]->name
== NULL
)
4323 fprintf(output
, " noname!");
4324 else fprintf(output
, " %s", obj
->nodeTab
[i
]->name
);
4326 fprintf(output
, "\n");
4331 * xmlXPathNewNodeSet:
4332 * @val: the NodePtr value
4334 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4335 * it with the single Node @val
4337 * Returns the newly created object.
4340 xmlXPathNewNodeSet(xmlNodePtr val
) {
4341 xmlXPathObjectPtr ret
;
4343 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4345 xmlXPathErrMemory(NULL
, "creating nodeset\n");
4348 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4349 ret
->type
= XPATH_NODESET
;
4351 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4352 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4353 #ifdef XP_DEBUG_OBJ_USAGE
4354 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4360 * xmlXPathNewValueTree:
4361 * @val: the NodePtr value
4363 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4364 * it with the tree root @val
4366 * Returns the newly created object.
4369 xmlXPathNewValueTree(xmlNodePtr val
) {
4370 xmlXPathObjectPtr ret
;
4372 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4374 xmlXPathErrMemory(NULL
, "creating result value tree\n");
4377 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4378 ret
->type
= XPATH_XSLT_TREE
;
4380 ret
->user
= (void *) val
;
4381 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4382 #ifdef XP_DEBUG_OBJ_USAGE
4383 xmlXPathDebugObjUsageRequested(NULL
, XPATH_XSLT_TREE
);
4389 * xmlXPathNewNodeSetList:
4390 * @val: an existing NodeSet
4392 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4393 * it with the Nodeset @val
4395 * Returns the newly created object.
4398 xmlXPathNewNodeSetList(xmlNodeSetPtr val
)
4400 xmlXPathObjectPtr ret
;
4405 else if (val
->nodeTab
== NULL
)
4406 ret
= xmlXPathNewNodeSet(NULL
);
4408 ret
= xmlXPathNewNodeSet(val
->nodeTab
[0]);
4410 for (i
= 1; i
< val
->nodeNr
; ++i
) {
4411 if (xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
->nodeTab
[i
])
4421 * xmlXPathWrapNodeSet:
4422 * @val: the NodePtr value
4424 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4426 * Returns the newly created object.
4429 xmlXPathWrapNodeSet(xmlNodeSetPtr val
) {
4430 xmlXPathObjectPtr ret
;
4432 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4434 xmlXPathErrMemory(NULL
, "creating node set object\n");
4437 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4438 ret
->type
= XPATH_NODESET
;
4439 ret
->nodesetval
= val
;
4440 #ifdef XP_DEBUG_OBJ_USAGE
4441 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4447 * xmlXPathFreeNodeSetList:
4448 * @obj: an existing NodeSetList object
4450 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4451 * the list contrary to xmlXPathFreeObject().
4454 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj
) {
4455 if (obj
== NULL
) return;
4456 #ifdef XP_DEBUG_OBJ_USAGE
4457 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
4463 * xmlXPathDifference:
4464 * @nodes1: a node-set
4465 * @nodes2: a node-set
4467 * Implements the EXSLT - Sets difference() function:
4468 * node-set set:difference (node-set, node-set)
4470 * Returns the difference between the two node sets, or nodes1 if
4474 xmlXPathDifference (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4479 if (xmlXPathNodeSetIsEmpty(nodes2
))
4482 ret
= xmlXPathNodeSetCreate(NULL
);
4483 if (xmlXPathNodeSetIsEmpty(nodes1
))
4486 l1
= xmlXPathNodeSetGetLength(nodes1
);
4488 for (i
= 0; i
< l1
; i
++) {
4489 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4490 if (!xmlXPathNodeSetContains(nodes2
, cur
)) {
4491 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4499 * xmlXPathIntersection:
4500 * @nodes1: a node-set
4501 * @nodes2: a node-set
4503 * Implements the EXSLT - Sets intersection() function:
4504 * node-set set:intersection (node-set, node-set)
4506 * Returns a node set comprising the nodes that are within both the
4507 * node sets passed as arguments
4510 xmlXPathIntersection (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4511 xmlNodeSetPtr ret
= xmlXPathNodeSetCreate(NULL
);
4517 if (xmlXPathNodeSetIsEmpty(nodes1
))
4519 if (xmlXPathNodeSetIsEmpty(nodes2
))
4522 l1
= xmlXPathNodeSetGetLength(nodes1
);
4524 for (i
= 0; i
< l1
; i
++) {
4525 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4526 if (xmlXPathNodeSetContains(nodes2
, cur
)) {
4527 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4535 * xmlXPathDistinctSorted:
4536 * @nodes: a node-set, sorted by document order
4538 * Implements the EXSLT - Sets distinct() function:
4539 * node-set set:distinct (node-set)
4541 * Returns a subset of the nodes contained in @nodes, or @nodes if
4545 xmlXPathDistinctSorted (xmlNodeSetPtr nodes
) {
4547 xmlHashTablePtr hash
;
4552 if (xmlXPathNodeSetIsEmpty(nodes
))
4555 ret
= xmlXPathNodeSetCreate(NULL
);
4558 l
= xmlXPathNodeSetGetLength(nodes
);
4559 hash
= xmlHashCreate (l
);
4560 for (i
= 0; i
< l
; i
++) {
4561 cur
= xmlXPathNodeSetItem(nodes
, i
);
4562 strval
= xmlXPathCastNodeToString(cur
);
4563 if (xmlHashLookup(hash
, strval
) == NULL
) {
4564 xmlHashAddEntry(hash
, strval
, strval
);
4565 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4571 xmlHashFree(hash
, xmlHashDefaultDeallocator
);
4577 * @nodes: a node-set
4579 * Implements the EXSLT - Sets distinct() function:
4580 * node-set set:distinct (node-set)
4581 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4582 * is called with the sorted node-set
4584 * Returns a subset of the nodes contained in @nodes, or @nodes if
4588 xmlXPathDistinct (xmlNodeSetPtr nodes
) {
4589 if (xmlXPathNodeSetIsEmpty(nodes
))
4592 xmlXPathNodeSetSort(nodes
);
4593 return(xmlXPathDistinctSorted(nodes
));
4597 * xmlXPathHasSameNodes:
4598 * @nodes1: a node-set
4599 * @nodes2: a node-set
4601 * Implements the EXSLT - Sets has-same-nodes function:
4602 * boolean set:has-same-node(node-set, node-set)
4604 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4608 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4612 if (xmlXPathNodeSetIsEmpty(nodes1
) ||
4613 xmlXPathNodeSetIsEmpty(nodes2
))
4616 l
= xmlXPathNodeSetGetLength(nodes1
);
4617 for (i
= 0; i
< l
; i
++) {
4618 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4619 if (xmlXPathNodeSetContains(nodes2
, cur
))
4626 * xmlXPathNodeLeadingSorted:
4627 * @nodes: a node-set, sorted by document order
4630 * Implements the EXSLT - Sets leading() function:
4631 * node-set set:leading (node-set, node-set)
4633 * Returns the nodes in @nodes that precede @node in document order,
4634 * @nodes if @node is NULL or an empty node-set if @nodes
4635 * doesn't contain @node
4638 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4646 ret
= xmlXPathNodeSetCreate(NULL
);
4649 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4650 (!xmlXPathNodeSetContains(nodes
, node
)))
4653 l
= xmlXPathNodeSetGetLength(nodes
);
4654 for (i
= 0; i
< l
; i
++) {
4655 cur
= xmlXPathNodeSetItem(nodes
, i
);
4658 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4665 * xmlXPathNodeLeading:
4666 * @nodes: a node-set
4669 * Implements the EXSLT - Sets leading() function:
4670 * node-set set:leading (node-set, node-set)
4671 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4674 * Returns the nodes in @nodes that precede @node in document order,
4675 * @nodes if @node is NULL or an empty node-set if @nodes
4676 * doesn't contain @node
4679 xmlXPathNodeLeading (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4680 xmlXPathNodeSetSort(nodes
);
4681 return(xmlXPathNodeLeadingSorted(nodes
, node
));
4685 * xmlXPathLeadingSorted:
4686 * @nodes1: a node-set, sorted by document order
4687 * @nodes2: a node-set, sorted by document order
4689 * Implements the EXSLT - Sets leading() function:
4690 * node-set set:leading (node-set, node-set)
4692 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4693 * in document order, @nodes1 if @nodes2 is NULL or empty or
4694 * an empty node-set if @nodes1 doesn't contain @nodes2
4697 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4698 if (xmlXPathNodeSetIsEmpty(nodes2
))
4700 return(xmlXPathNodeLeadingSorted(nodes1
,
4701 xmlXPathNodeSetItem(nodes2
, 1)));
4706 * @nodes1: a node-set
4707 * @nodes2: a node-set
4709 * Implements the EXSLT - Sets leading() function:
4710 * node-set set:leading (node-set, node-set)
4711 * @nodes1 and @nodes2 are sorted by document order, then
4712 * #exslSetsLeadingSorted is called.
4714 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4715 * in document order, @nodes1 if @nodes2 is NULL or empty or
4716 * an empty node-set if @nodes1 doesn't contain @nodes2
4719 xmlXPathLeading (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4720 if (xmlXPathNodeSetIsEmpty(nodes2
))
4722 if (xmlXPathNodeSetIsEmpty(nodes1
))
4723 return(xmlXPathNodeSetCreate(NULL
));
4724 xmlXPathNodeSetSort(nodes1
);
4725 xmlXPathNodeSetSort(nodes2
);
4726 return(xmlXPathNodeLeadingSorted(nodes1
,
4727 xmlXPathNodeSetItem(nodes2
, 1)));
4731 * xmlXPathNodeTrailingSorted:
4732 * @nodes: a node-set, sorted by document order
4735 * Implements the EXSLT - Sets trailing() function:
4736 * node-set set:trailing (node-set, node-set)
4738 * Returns the nodes in @nodes that follow @node in document order,
4739 * @nodes if @node is NULL or an empty node-set if @nodes
4740 * doesn't contain @node
4743 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4751 ret
= xmlXPathNodeSetCreate(NULL
);
4754 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4755 (!xmlXPathNodeSetContains(nodes
, node
)))
4758 l
= xmlXPathNodeSetGetLength(nodes
);
4759 for (i
= l
- 1; i
>= 0; i
--) {
4760 cur
= xmlXPathNodeSetItem(nodes
, i
);
4763 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4766 xmlXPathNodeSetSort(ret
); /* bug 413451 */
4771 * xmlXPathNodeTrailing:
4772 * @nodes: a node-set
4775 * Implements the EXSLT - Sets trailing() function:
4776 * node-set set:trailing (node-set, node-set)
4777 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4780 * Returns the nodes in @nodes that follow @node in document order,
4781 * @nodes if @node is NULL or an empty node-set if @nodes
4782 * doesn't contain @node
4785 xmlXPathNodeTrailing (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4786 xmlXPathNodeSetSort(nodes
);
4787 return(xmlXPathNodeTrailingSorted(nodes
, node
));
4791 * xmlXPathTrailingSorted:
4792 * @nodes1: a node-set, sorted by document order
4793 * @nodes2: a node-set, sorted by document order
4795 * Implements the EXSLT - Sets trailing() function:
4796 * node-set set:trailing (node-set, node-set)
4798 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4799 * in document order, @nodes1 if @nodes2 is NULL or empty or
4800 * an empty node-set if @nodes1 doesn't contain @nodes2
4803 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4804 if (xmlXPathNodeSetIsEmpty(nodes2
))
4806 return(xmlXPathNodeTrailingSorted(nodes1
,
4807 xmlXPathNodeSetItem(nodes2
, 0)));
4812 * @nodes1: a node-set
4813 * @nodes2: a node-set
4815 * Implements the EXSLT - Sets trailing() function:
4816 * node-set set:trailing (node-set, node-set)
4817 * @nodes1 and @nodes2 are sorted by document order, then
4818 * #xmlXPathTrailingSorted is called.
4820 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4821 * in document order, @nodes1 if @nodes2 is NULL or empty or
4822 * an empty node-set if @nodes1 doesn't contain @nodes2
4825 xmlXPathTrailing (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4826 if (xmlXPathNodeSetIsEmpty(nodes2
))
4828 if (xmlXPathNodeSetIsEmpty(nodes1
))
4829 return(xmlXPathNodeSetCreate(NULL
));
4830 xmlXPathNodeSetSort(nodes1
);
4831 xmlXPathNodeSetSort(nodes2
);
4832 return(xmlXPathNodeTrailingSorted(nodes1
,
4833 xmlXPathNodeSetItem(nodes2
, 0)));
4836 /************************************************************************
4838 * Routines to handle extra functions *
4840 ************************************************************************/
4843 * xmlXPathRegisterFunc:
4844 * @ctxt: the XPath context
4845 * @name: the function name
4846 * @f: the function implementation or NULL
4848 * Register a new function. If @f is NULL it unregisters the function
4850 * Returns 0 in case of success, -1 in case of error
4853 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4854 xmlXPathFunction f
) {
4855 return(xmlXPathRegisterFuncNS(ctxt
, name
, NULL
, f
));
4859 * xmlXPathRegisterFuncNS:
4860 * @ctxt: the XPath context
4861 * @name: the function name
4862 * @ns_uri: the function namespace URI
4863 * @f: the function implementation or NULL
4865 * Register a new function. If @f is NULL it unregisters the function
4867 * Returns 0 in case of success, -1 in case of error
4870 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4871 const xmlChar
*ns_uri
, xmlXPathFunction f
) {
4877 if (ctxt
->funcHash
== NULL
)
4878 ctxt
->funcHash
= xmlHashCreate(0);
4879 if (ctxt
->funcHash
== NULL
)
4882 return(xmlHashRemoveEntry2(ctxt
->funcHash
, name
, ns_uri
, NULL
));
4883 XML_IGNORE_PEDANTIC_WARNINGS
4884 return(xmlHashAddEntry2(ctxt
->funcHash
, name
, ns_uri
, (void *) f
));
4889 * xmlXPathRegisterFuncLookup:
4890 * @ctxt: the XPath context
4891 * @f: the lookup function
4892 * @funcCtxt: the lookup data
4894 * Registers an external mechanism to do function lookup.
4897 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt
,
4898 xmlXPathFuncLookupFunc f
,
4902 ctxt
->funcLookupFunc
= f
;
4903 ctxt
->funcLookupData
= funcCtxt
;
4907 * xmlXPathFunctionLookup:
4908 * @ctxt: the XPath context
4909 * @name: the function name
4911 * Search in the Function array of the context for the given
4914 * Returns the xmlXPathFunction or NULL if not found
4917 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
4921 if (ctxt
->funcLookupFunc
!= NULL
) {
4922 xmlXPathFunction ret
;
4923 xmlXPathFuncLookupFunc f
;
4925 f
= ctxt
->funcLookupFunc
;
4926 ret
= f(ctxt
->funcLookupData
, name
, NULL
);
4930 return(xmlXPathFunctionLookupNS(ctxt
, name
, NULL
));
4934 * xmlXPathFunctionLookupNS:
4935 * @ctxt: the XPath context
4936 * @name: the function name
4937 * @ns_uri: the function namespace URI
4939 * Search in the Function array of the context for the given
4942 * Returns the xmlXPathFunction or NULL if not found
4945 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4946 const xmlChar
*ns_uri
) {
4947 xmlXPathFunction ret
;
4954 if (ctxt
->funcLookupFunc
!= NULL
) {
4955 xmlXPathFuncLookupFunc f
;
4957 f
= ctxt
->funcLookupFunc
;
4958 ret
= f(ctxt
->funcLookupData
, name
, ns_uri
);
4963 if (ctxt
->funcHash
== NULL
)
4966 XML_IGNORE_PEDANTIC_WARNINGS
4967 ret
= (xmlXPathFunction
) xmlHashLookup2(ctxt
->funcHash
, name
, ns_uri
);
4973 * xmlXPathRegisteredFuncsCleanup:
4974 * @ctxt: the XPath context
4976 * Cleanup the XPath context data associated to registered functions
4979 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt
) {
4983 xmlHashFree(ctxt
->funcHash
, NULL
);
4984 ctxt
->funcHash
= NULL
;
4987 /************************************************************************
4989 * Routines to handle Variables *
4991 ************************************************************************/
4994 * xmlXPathRegisterVariable:
4995 * @ctxt: the XPath context
4996 * @name: the variable name
4997 * @value: the variable value or NULL
4999 * Register a new variable value. If @value is NULL it unregisters
5002 * Returns 0 in case of success, -1 in case of error
5005 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5006 xmlXPathObjectPtr value
) {
5007 return(xmlXPathRegisterVariableNS(ctxt
, name
, NULL
, value
));
5011 * xmlXPathRegisterVariableNS:
5012 * @ctxt: the XPath context
5013 * @name: the variable name
5014 * @ns_uri: the variable namespace URI
5015 * @value: the variable value or NULL
5017 * Register a new variable value. If @value is NULL it unregisters
5020 * Returns 0 in case of success, -1 in case of error
5023 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5024 const xmlChar
*ns_uri
,
5025 xmlXPathObjectPtr value
) {
5031 if (ctxt
->varHash
== NULL
)
5032 ctxt
->varHash
= xmlHashCreate(0);
5033 if (ctxt
->varHash
== NULL
)
5036 return(xmlHashRemoveEntry2(ctxt
->varHash
, name
, ns_uri
,
5037 xmlXPathFreeObjectEntry
));
5038 return(xmlHashUpdateEntry2(ctxt
->varHash
, name
, ns_uri
,
5039 (void *) value
, xmlXPathFreeObjectEntry
));
5043 * xmlXPathRegisterVariableLookup:
5044 * @ctxt: the XPath context
5045 * @f: the lookup function
5046 * @data: the lookup data
5048 * register an external mechanism to do variable lookup
5051 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt
,
5052 xmlXPathVariableLookupFunc f
, void *data
) {
5055 ctxt
->varLookupFunc
= f
;
5056 ctxt
->varLookupData
= data
;
5060 * xmlXPathVariableLookup:
5061 * @ctxt: the XPath context
5062 * @name: the variable name
5064 * Search in the Variable array of the context for the given
5067 * Returns a copy of the value or NULL if not found
5070 xmlXPathVariableLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
5074 if (ctxt
->varLookupFunc
!= NULL
) {
5075 xmlXPathObjectPtr ret
;
5077 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5078 (ctxt
->varLookupData
, name
, NULL
);
5081 return(xmlXPathVariableLookupNS(ctxt
, name
, NULL
));
5085 * xmlXPathVariableLookupNS:
5086 * @ctxt: the XPath context
5087 * @name: the variable name
5088 * @ns_uri: the variable namespace URI
5090 * Search in the Variable array of the context for the given
5093 * Returns the a copy of the value or NULL if not found
5096 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5097 const xmlChar
*ns_uri
) {
5101 if (ctxt
->varLookupFunc
!= NULL
) {
5102 xmlXPathObjectPtr ret
;
5104 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5105 (ctxt
->varLookupData
, name
, ns_uri
);
5106 if (ret
!= NULL
) return(ret
);
5109 if (ctxt
->varHash
== NULL
)
5114 return(xmlXPathCacheObjectCopy(ctxt
, (xmlXPathObjectPtr
)
5115 xmlHashLookup2(ctxt
->varHash
, name
, ns_uri
)));
5119 * xmlXPathRegisteredVariablesCleanup:
5120 * @ctxt: the XPath context
5122 * Cleanup the XPath context data associated to registered variables
5125 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt
) {
5129 xmlHashFree(ctxt
->varHash
, xmlXPathFreeObjectEntry
);
5130 ctxt
->varHash
= NULL
;
5134 * xmlXPathRegisterNs:
5135 * @ctxt: the XPath context
5136 * @prefix: the namespace prefix cannot be NULL or empty string
5137 * @ns_uri: the namespace name
5139 * Register a new namespace. If @ns_uri is NULL it unregisters
5142 * Returns 0 in case of success, -1 in case of error
5145 xmlXPathRegisterNs(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
,
5146 const xmlChar
*ns_uri
) {
5154 if (ctxt
->nsHash
== NULL
)
5155 ctxt
->nsHash
= xmlHashCreate(10);
5156 if (ctxt
->nsHash
== NULL
)
5159 return(xmlHashRemoveEntry(ctxt
->nsHash
, prefix
,
5160 xmlHashDefaultDeallocator
));
5161 return(xmlHashUpdateEntry(ctxt
->nsHash
, prefix
, (void *) xmlStrdup(ns_uri
),
5162 xmlHashDefaultDeallocator
));
5167 * @ctxt: the XPath context
5168 * @prefix: the namespace prefix value
5170 * Search in the namespace declaration array of the context for the given
5171 * namespace name associated to the given prefix
5173 * Returns the value or NULL if not found
5176 xmlXPathNsLookup(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
) {
5182 #ifdef XML_XML_NAMESPACE
5183 if (xmlStrEqual(prefix
, (const xmlChar
*) "xml"))
5184 return(XML_XML_NAMESPACE
);
5187 if (ctxt
->namespaces
!= NULL
) {
5190 for (i
= 0;i
< ctxt
->nsNr
;i
++) {
5191 if ((ctxt
->namespaces
[i
] != NULL
) &&
5192 (xmlStrEqual(ctxt
->namespaces
[i
]->prefix
, prefix
)))
5193 return(ctxt
->namespaces
[i
]->href
);
5197 return((const xmlChar
*) xmlHashLookup(ctxt
->nsHash
, prefix
));
5201 * xmlXPathRegisteredNsCleanup:
5202 * @ctxt: the XPath context
5204 * Cleanup the XPath context data associated to registered variables
5207 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt
) {
5211 xmlHashFree(ctxt
->nsHash
, xmlHashDefaultDeallocator
);
5212 ctxt
->nsHash
= NULL
;
5215 /************************************************************************
5217 * Routines to handle Values *
5219 ************************************************************************/
5221 /* Allocations are terrible, one needs to optimize all this !!! */
5225 * @val: the double value
5227 * Create a new xmlXPathObjectPtr of type double and of value @val
5229 * Returns the newly created object.
5232 xmlXPathNewFloat(double val
) {
5233 xmlXPathObjectPtr ret
;
5235 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5237 xmlXPathErrMemory(NULL
, "creating float object\n");
5240 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5241 ret
->type
= XPATH_NUMBER
;
5242 ret
->floatval
= val
;
5243 #ifdef XP_DEBUG_OBJ_USAGE
5244 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NUMBER
);
5250 * xmlXPathNewBoolean:
5251 * @val: the boolean value
5253 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5255 * Returns the newly created object.
5258 xmlXPathNewBoolean(int val
) {
5259 xmlXPathObjectPtr ret
;
5261 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5263 xmlXPathErrMemory(NULL
, "creating boolean object\n");
5266 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5267 ret
->type
= XPATH_BOOLEAN
;
5268 ret
->boolval
= (val
!= 0);
5269 #ifdef XP_DEBUG_OBJ_USAGE
5270 xmlXPathDebugObjUsageRequested(NULL
, XPATH_BOOLEAN
);
5276 * xmlXPathNewString:
5277 * @val: the xmlChar * value
5279 * Create a new xmlXPathObjectPtr of type string and of value @val
5281 * Returns the newly created object.
5284 xmlXPathNewString(const xmlChar
*val
) {
5285 xmlXPathObjectPtr ret
;
5287 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5289 xmlXPathErrMemory(NULL
, "creating string object\n");
5292 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5293 ret
->type
= XPATH_STRING
;
5295 ret
->stringval
= xmlStrdup(val
);
5297 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
5298 #ifdef XP_DEBUG_OBJ_USAGE
5299 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5305 * xmlXPathWrapString:
5306 * @val: the xmlChar * value
5308 * Wraps the @val string into an XPath object.
5310 * Returns the newly created object.
5313 xmlXPathWrapString (xmlChar
*val
) {
5314 xmlXPathObjectPtr ret
;
5316 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5318 xmlXPathErrMemory(NULL
, "creating string object\n");
5321 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5322 ret
->type
= XPATH_STRING
;
5323 ret
->stringval
= val
;
5324 #ifdef XP_DEBUG_OBJ_USAGE
5325 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5331 * xmlXPathNewCString:
5332 * @val: the char * value
5334 * Create a new xmlXPathObjectPtr of type string and of value @val
5336 * Returns the newly created object.
5339 xmlXPathNewCString(const char *val
) {
5340 xmlXPathObjectPtr ret
;
5342 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5344 xmlXPathErrMemory(NULL
, "creating string object\n");
5347 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5348 ret
->type
= XPATH_STRING
;
5349 ret
->stringval
= xmlStrdup(BAD_CAST val
);
5350 #ifdef XP_DEBUG_OBJ_USAGE
5351 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5357 * xmlXPathWrapCString:
5358 * @val: the char * value
5360 * Wraps a string into an XPath object.
5362 * Returns the newly created object.
5365 xmlXPathWrapCString (char * val
) {
5366 return(xmlXPathWrapString((xmlChar
*)(val
)));
5370 * xmlXPathWrapExternal:
5371 * @val: the user data
5373 * Wraps the @val data into an XPath object.
5375 * Returns the newly created object.
5378 xmlXPathWrapExternal (void *val
) {
5379 xmlXPathObjectPtr ret
;
5381 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5383 xmlXPathErrMemory(NULL
, "creating user object\n");
5386 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5387 ret
->type
= XPATH_USERS
;
5389 #ifdef XP_DEBUG_OBJ_USAGE
5390 xmlXPathDebugObjUsageRequested(NULL
, XPATH_USERS
);
5396 * xmlXPathObjectCopy:
5397 * @val: the original object
5399 * allocate a new copy of a given object
5401 * Returns the newly created object.
5404 xmlXPathObjectCopy(xmlXPathObjectPtr val
) {
5405 xmlXPathObjectPtr ret
;
5410 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5412 xmlXPathErrMemory(NULL
, "copying object\n");
5415 memcpy(ret
, val
, (size_t) sizeof(xmlXPathObject
));
5416 #ifdef XP_DEBUG_OBJ_USAGE
5417 xmlXPathDebugObjUsageRequested(NULL
, val
->type
);
5419 switch (val
->type
) {
5426 ret
->stringval
= xmlStrdup(val
->stringval
);
5428 case XPATH_XSLT_TREE
:
5431 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5432 this previous handling is no longer correct, and can cause some serious
5433 problems (ref. bug 145547)
5435 if ((val
->nodesetval
!= NULL
) &&
5436 (val
->nodesetval
->nodeTab
!= NULL
)) {
5437 xmlNodePtr cur
, tmp
;
5441 top
= xmlNewDoc(NULL
);
5442 top
->name
= (char *)
5443 xmlStrdup(val
->nodesetval
->nodeTab
[0]->name
);
5447 cur
= val
->nodesetval
->nodeTab
[0]->children
;
5448 while (cur
!= NULL
) {
5449 tmp
= xmlDocCopyNode(cur
, top
, 1);
5450 xmlAddChild((xmlNodePtr
) top
, tmp
);
5455 ret
->nodesetval
= xmlXPathNodeSetCreate((xmlNodePtr
) top
);
5457 ret
->nodesetval
= xmlXPathNodeSetCreate(NULL
);
5458 /* Deallocate the copied tree value */
5462 ret
->nodesetval
= xmlXPathNodeSetMerge(NULL
, val
->nodesetval
);
5463 /* Do not deallocate the copied tree value */
5466 case XPATH_LOCATIONSET
:
5467 #ifdef LIBXML_XPTR_ENABLED
5469 xmlLocationSetPtr loc
= val
->user
;
5470 ret
->user
= (void *) xmlXPtrLocationSetMerge(NULL
, loc
);
5475 ret
->user
= val
->user
;
5477 case XPATH_UNDEFINED
:
5478 xmlGenericError(xmlGenericErrorContext
,
5479 "xmlXPathObjectCopy: unsupported type %d\n",
5487 * xmlXPathFreeObject:
5488 * @obj: the object to free
5490 * Free up an xmlXPathObjectPtr object.
5493 xmlXPathFreeObject(xmlXPathObjectPtr obj
) {
5494 if (obj
== NULL
) return;
5495 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
5498 if (obj
->user
!= NULL
) {
5499 xmlXPathFreeNodeSet(obj
->nodesetval
);
5500 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
5503 obj
->type
= XPATH_XSLT_TREE
; /* TODO: Just for debugging. */
5504 if (obj
->nodesetval
!= NULL
)
5505 xmlXPathFreeValueTree(obj
->nodesetval
);
5507 if (obj
->nodesetval
!= NULL
)
5508 xmlXPathFreeNodeSet(obj
->nodesetval
);
5510 #ifdef LIBXML_XPTR_ENABLED
5511 } else if (obj
->type
== XPATH_LOCATIONSET
) {
5512 if (obj
->user
!= NULL
)
5513 xmlXPtrFreeLocationSet(obj
->user
);
5515 } else if (obj
->type
== XPATH_STRING
) {
5516 if (obj
->stringval
!= NULL
)
5517 xmlFree(obj
->stringval
);
5519 #ifdef XP_DEBUG_OBJ_USAGE
5520 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5526 xmlXPathFreeObjectEntry(void *obj
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
5527 xmlXPathFreeObject((xmlXPathObjectPtr
) obj
);
5531 * xmlXPathReleaseObject:
5532 * @obj: the xmlXPathObjectPtr to free or to cache
5534 * Depending on the state of the cache this frees the given
5535 * XPath object or stores it in the cache.
5538 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
)
5540 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5541 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5542 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5544 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5548 if ((ctxt
== NULL
) || (ctxt
->cache
== NULL
)) {
5549 xmlXPathFreeObject(obj
);
5551 xmlXPathContextCachePtr cache
=
5552 (xmlXPathContextCachePtr
) ctxt
->cache
;
5554 switch (obj
->type
) {
5556 case XPATH_XSLT_TREE
:
5557 if (obj
->nodesetval
!= NULL
) {
5560 * It looks like the @boolval is used for
5561 * evaluation if this an XSLT Result Tree Fragment.
5562 * TODO: Check if this assumption is correct.
5564 obj
->type
= XPATH_XSLT_TREE
; /* just for debugging */
5565 xmlXPathFreeValueTree(obj
->nodesetval
);
5566 obj
->nodesetval
= NULL
;
5567 } else if ((obj
->nodesetval
->nodeMax
<= 40) &&
5568 (XP_CACHE_WANTS(cache
->nodesetObjs
,
5569 cache
->maxNodeset
)))
5571 XP_CACHE_ADD(cache
->nodesetObjs
, obj
);
5574 xmlXPathFreeNodeSet(obj
->nodesetval
);
5575 obj
->nodesetval
= NULL
;
5580 if (obj
->stringval
!= NULL
)
5581 xmlFree(obj
->stringval
);
5583 if (XP_CACHE_WANTS(cache
->stringObjs
, cache
->maxString
)) {
5584 XP_CACHE_ADD(cache
->stringObjs
, obj
);
5589 if (XP_CACHE_WANTS(cache
->booleanObjs
, cache
->maxBoolean
)) {
5590 XP_CACHE_ADD(cache
->booleanObjs
, obj
);
5595 if (XP_CACHE_WANTS(cache
->numberObjs
, cache
->maxNumber
)) {
5596 XP_CACHE_ADD(cache
->numberObjs
, obj
);
5600 #ifdef LIBXML_XPTR_ENABLED
5601 case XPATH_LOCATIONSET
:
5602 if (obj
->user
!= NULL
) {
5603 xmlXPtrFreeLocationSet(obj
->user
);
5612 * Fallback to adding to the misc-objects slot.
5614 if (XP_CACHE_WANTS(cache
->miscObjs
, cache
->maxMisc
)) {
5615 XP_CACHE_ADD(cache
->miscObjs
, obj
);
5621 #ifdef XP_DEBUG_OBJ_USAGE
5622 xmlXPathDebugObjUsageReleased(ctxt
, obj
->type
);
5625 if (obj
->nodesetval
!= NULL
) {
5626 xmlNodeSetPtr tmpset
= obj
->nodesetval
;
5629 * TODO: Due to those nasty ns-nodes, we need to traverse
5630 * the list and free the ns-nodes.
5631 * URGENT TODO: Check if it's actually slowing things down.
5632 * Maybe we shouldn't try to preserve the list.
5634 if (tmpset
->nodeNr
> 1) {
5638 for (i
= 0; i
< tmpset
->nodeNr
; i
++) {
5639 node
= tmpset
->nodeTab
[i
];
5640 if ((node
!= NULL
) &&
5641 (node
->type
== XML_NAMESPACE_DECL
))
5643 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
5646 } else if (tmpset
->nodeNr
== 1) {
5647 if ((tmpset
->nodeTab
[0] != NULL
) &&
5648 (tmpset
->nodeTab
[0]->type
== XML_NAMESPACE_DECL
))
5649 xmlXPathNodeSetFreeNs((xmlNsPtr
) tmpset
->nodeTab
[0]);
5652 memset(obj
, 0, sizeof(xmlXPathObject
));
5653 obj
->nodesetval
= tmpset
;
5655 memset(obj
, 0, sizeof(xmlXPathObject
));
5661 * Cache is full; free the object.
5663 if (obj
->nodesetval
!= NULL
)
5664 xmlXPathFreeNodeSet(obj
->nodesetval
);
5665 #ifdef XP_DEBUG_OBJ_USAGE
5666 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5674 /************************************************************************
5676 * Type Casting Routines *
5678 ************************************************************************/
5681 * xmlXPathCastBooleanToString:
5684 * Converts a boolean to its string value.
5686 * Returns a newly allocated string.
5689 xmlXPathCastBooleanToString (int val
) {
5692 ret
= xmlStrdup((const xmlChar
*) "true");
5694 ret
= xmlStrdup((const xmlChar
*) "false");
5699 * xmlXPathCastNumberToString:
5702 * Converts a number to its string value.
5704 * Returns a newly allocated string.
5707 xmlXPathCastNumberToString (double val
) {
5709 switch (xmlXPathIsInf(val
)) {
5711 ret
= xmlStrdup((const xmlChar
*) "Infinity");
5714 ret
= xmlStrdup((const xmlChar
*) "-Infinity");
5717 if (xmlXPathIsNaN(val
)) {
5718 ret
= xmlStrdup((const xmlChar
*) "NaN");
5719 } else if (val
== 0) {
5720 /* Omit sign for negative zero. */
5721 ret
= xmlStrdup((const xmlChar
*) "0");
5723 /* could be improved */
5725 xmlXPathFormatNumber(val
, buf
, 99);
5727 ret
= xmlStrdup((const xmlChar
*) buf
);
5734 * xmlXPathCastNodeToString:
5737 * Converts a node to its string value.
5739 * Returns a newly allocated string.
5742 xmlXPathCastNodeToString (xmlNodePtr node
) {
5744 if ((ret
= xmlNodeGetContent(node
)) == NULL
)
5745 ret
= xmlStrdup((const xmlChar
*) "");
5750 * xmlXPathCastNodeSetToString:
5753 * Converts a node-set to its string value.
5755 * Returns a newly allocated string.
5758 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns
) {
5759 if ((ns
== NULL
) || (ns
->nodeNr
== 0) || (ns
->nodeTab
== NULL
))
5760 return(xmlStrdup((const xmlChar
*) ""));
5763 xmlXPathNodeSetSort(ns
);
5764 return(xmlXPathCastNodeToString(ns
->nodeTab
[0]));
5768 * xmlXPathCastToString:
5769 * @val: an XPath object
5771 * Converts an existing object to its string() equivalent
5773 * Returns the allocated string value of the object, NULL in case of error.
5774 * It's up to the caller to free the string memory with xmlFree().
5777 xmlXPathCastToString(xmlXPathObjectPtr val
) {
5778 xmlChar
*ret
= NULL
;
5781 return(xmlStrdup((const xmlChar
*) ""));
5782 switch (val
->type
) {
5783 case XPATH_UNDEFINED
:
5785 xmlGenericError(xmlGenericErrorContext
, "String: undefined\n");
5787 ret
= xmlStrdup((const xmlChar
*) "");
5790 case XPATH_XSLT_TREE
:
5791 ret
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5794 return(xmlStrdup(val
->stringval
));
5796 ret
= xmlXPathCastBooleanToString(val
->boolval
);
5798 case XPATH_NUMBER
: {
5799 ret
= xmlXPathCastNumberToString(val
->floatval
);
5805 case XPATH_LOCATIONSET
:
5807 ret
= xmlStrdup((const xmlChar
*) "");
5814 * xmlXPathConvertString:
5815 * @val: an XPath object
5817 * Converts an existing object to its string() equivalent
5819 * Returns the new object, the old one is freed (or the operation
5820 * is done directly on @val)
5823 xmlXPathConvertString(xmlXPathObjectPtr val
) {
5824 xmlChar
*res
= NULL
;
5827 return(xmlXPathNewCString(""));
5829 switch (val
->type
) {
5830 case XPATH_UNDEFINED
:
5832 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
5836 case XPATH_XSLT_TREE
:
5837 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5842 res
= xmlXPathCastBooleanToString(val
->boolval
);
5845 res
= xmlXPathCastNumberToString(val
->floatval
);
5850 case XPATH_LOCATIONSET
:
5854 xmlXPathFreeObject(val
);
5856 return(xmlXPathNewCString(""));
5857 return(xmlXPathWrapString(res
));
5861 * xmlXPathCastBooleanToNumber:
5864 * Converts a boolean to its number value
5866 * Returns the number value
5869 xmlXPathCastBooleanToNumber(int val
) {
5876 * xmlXPathCastStringToNumber:
5879 * Converts a string to its number value
5881 * Returns the number value
5884 xmlXPathCastStringToNumber(const xmlChar
* val
) {
5885 return(xmlXPathStringEvalNumber(val
));
5889 * xmlXPathCastNodeToNumber:
5892 * Converts a node to its number value
5894 * Returns the number value
5897 xmlXPathCastNodeToNumber (xmlNodePtr node
) {
5903 strval
= xmlXPathCastNodeToString(node
);
5906 ret
= xmlXPathCastStringToNumber(strval
);
5913 * xmlXPathCastNodeSetToNumber:
5916 * Converts a node-set to its number value
5918 * Returns the number value
5921 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns
) {
5927 str
= xmlXPathCastNodeSetToString(ns
);
5928 ret
= xmlXPathCastStringToNumber(str
);
5934 * xmlXPathCastToNumber:
5935 * @val: an XPath object
5937 * Converts an XPath object to its number value
5939 * Returns the number value
5942 xmlXPathCastToNumber(xmlXPathObjectPtr val
) {
5947 switch (val
->type
) {
5948 case XPATH_UNDEFINED
:
5950 xmlGenericError(xmlGenericErrorContext
, "NUMBER: undefined\n");
5955 case XPATH_XSLT_TREE
:
5956 ret
= xmlXPathCastNodeSetToNumber(val
->nodesetval
);
5959 ret
= xmlXPathCastStringToNumber(val
->stringval
);
5962 ret
= val
->floatval
;
5965 ret
= xmlXPathCastBooleanToNumber(val
->boolval
);
5970 case XPATH_LOCATIONSET
:
5979 * xmlXPathConvertNumber:
5980 * @val: an XPath object
5982 * Converts an existing object to its number() equivalent
5984 * Returns the new object, the old one is freed (or the operation
5985 * is done directly on @val)
5988 xmlXPathConvertNumber(xmlXPathObjectPtr val
) {
5989 xmlXPathObjectPtr ret
;
5992 return(xmlXPathNewFloat(0.0));
5993 if (val
->type
== XPATH_NUMBER
)
5995 ret
= xmlXPathNewFloat(xmlXPathCastToNumber(val
));
5996 xmlXPathFreeObject(val
);
6001 * xmlXPathCastNumberToBoolean:
6004 * Converts a number to its boolean value
6006 * Returns the boolean value
6009 xmlXPathCastNumberToBoolean (double val
) {
6010 if (xmlXPathIsNaN(val
) || (val
== 0.0))
6016 * xmlXPathCastStringToBoolean:
6019 * Converts a string to its boolean value
6021 * Returns the boolean value
6024 xmlXPathCastStringToBoolean (const xmlChar
*val
) {
6025 if ((val
== NULL
) || (xmlStrlen(val
) == 0))
6031 * xmlXPathCastNodeSetToBoolean:
6034 * Converts a node-set to its boolean value
6036 * Returns the boolean value
6039 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns
) {
6040 if ((ns
== NULL
) || (ns
->nodeNr
== 0))
6046 * xmlXPathCastToBoolean:
6047 * @val: an XPath object
6049 * Converts an XPath object to its boolean value
6051 * Returns the boolean value
6054 xmlXPathCastToBoolean (xmlXPathObjectPtr val
) {
6059 switch (val
->type
) {
6060 case XPATH_UNDEFINED
:
6062 xmlGenericError(xmlGenericErrorContext
, "BOOLEAN: undefined\n");
6067 case XPATH_XSLT_TREE
:
6068 ret
= xmlXPathCastNodeSetToBoolean(val
->nodesetval
);
6071 ret
= xmlXPathCastStringToBoolean(val
->stringval
);
6074 ret
= xmlXPathCastNumberToBoolean(val
->floatval
);
6082 case XPATH_LOCATIONSET
:
6092 * xmlXPathConvertBoolean:
6093 * @val: an XPath object
6095 * Converts an existing object to its boolean() equivalent
6097 * Returns the new object, the old one is freed (or the operation
6098 * is done directly on @val)
6101 xmlXPathConvertBoolean(xmlXPathObjectPtr val
) {
6102 xmlXPathObjectPtr ret
;
6105 return(xmlXPathNewBoolean(0));
6106 if (val
->type
== XPATH_BOOLEAN
)
6108 ret
= xmlXPathNewBoolean(xmlXPathCastToBoolean(val
));
6109 xmlXPathFreeObject(val
);
6113 /************************************************************************
6115 * Routines to handle XPath contexts *
6117 ************************************************************************/
6120 * xmlXPathNewContext:
6121 * @doc: the XML document
6123 * Create a new xmlXPathContext
6125 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6128 xmlXPathNewContext(xmlDocPtr doc
) {
6129 xmlXPathContextPtr ret
;
6131 ret
= (xmlXPathContextPtr
) xmlMalloc(sizeof(xmlXPathContext
));
6133 xmlXPathErrMemory(NULL
, "creating context\n");
6136 memset(ret
, 0 , (size_t) sizeof(xmlXPathContext
));
6140 ret
->varHash
= NULL
;
6146 ret
->funcHash
= xmlHashCreate(0);
6155 ret
->contextSize
= -1;
6156 ret
->proximityPosition
= -1;
6158 #ifdef XP_DEFAULT_CACHE_ON
6159 if (xmlXPathContextSetCache(ret
, 1, -1, 0) == -1) {
6160 xmlXPathFreeContext(ret
);
6165 xmlXPathRegisterAllFunctions(ret
);
6171 * xmlXPathFreeContext:
6172 * @ctxt: the context to free
6174 * Free up an xmlXPathContext
6177 xmlXPathFreeContext(xmlXPathContextPtr ctxt
) {
6178 if (ctxt
== NULL
) return;
6180 if (ctxt
->cache
!= NULL
)
6181 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
6182 xmlXPathRegisteredNsCleanup(ctxt
);
6183 xmlXPathRegisteredFuncsCleanup(ctxt
);
6184 xmlXPathRegisteredVariablesCleanup(ctxt
);
6185 xmlResetError(&ctxt
->lastError
);
6189 /************************************************************************
6191 * Routines to handle XPath parser contexts *
6193 ************************************************************************/
6195 #define CHECK_CTXT(ctxt) \
6196 if (ctxt == NULL) { \
6197 __xmlRaiseError(NULL, NULL, NULL, \
6198 NULL, NULL, XML_FROM_XPATH, \
6199 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6200 __FILE__, __LINE__, \
6201 NULL, NULL, NULL, 0, 0, \
6202 "NULL context pointer\n"); \
6206 #define CHECK_CTXT_NEG(ctxt) \
6207 if (ctxt == NULL) { \
6208 __xmlRaiseError(NULL, NULL, NULL, \
6209 NULL, NULL, XML_FROM_XPATH, \
6210 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6211 __FILE__, __LINE__, \
6212 NULL, NULL, NULL, 0, 0, \
6213 "NULL context pointer\n"); \
6218 #define CHECK_CONTEXT(ctxt) \
6219 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6220 (ctxt->doc->children == NULL)) { \
6221 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6227 * xmlXPathNewParserContext:
6228 * @str: the XPath expression
6229 * @ctxt: the XPath context
6231 * Create a new xmlXPathParserContext
6233 * Returns the xmlXPathParserContext just allocated.
6235 xmlXPathParserContextPtr
6236 xmlXPathNewParserContext(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
6237 xmlXPathParserContextPtr ret
;
6239 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6241 xmlXPathErrMemory(ctxt
, "creating parser context\n");
6244 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6245 ret
->cur
= ret
->base
= str
;
6246 ret
->context
= ctxt
;
6248 ret
->comp
= xmlXPathNewCompExpr();
6249 if (ret
->comp
== NULL
) {
6250 xmlFree(ret
->valueTab
);
6254 if ((ctxt
!= NULL
) && (ctxt
->dict
!= NULL
)) {
6255 ret
->comp
->dict
= ctxt
->dict
;
6256 xmlDictReference(ret
->comp
->dict
);
6263 * xmlXPathCompParserContext:
6264 * @comp: the XPath compiled expression
6265 * @ctxt: the XPath context
6267 * Create a new xmlXPathParserContext when processing a compiled expression
6269 * Returns the xmlXPathParserContext just allocated.
6271 static xmlXPathParserContextPtr
6272 xmlXPathCompParserContext(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctxt
) {
6273 xmlXPathParserContextPtr ret
;
6275 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6277 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6280 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6282 /* Allocate the value stack */
6283 ret
->valueTab
= (xmlXPathObjectPtr
*)
6284 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
6285 if (ret
->valueTab
== NULL
) {
6287 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6293 ret
->valueFrame
= 0;
6295 ret
->context
= ctxt
;
6302 * xmlXPathFreeParserContext:
6303 * @ctxt: the context to free
6305 * Free up an xmlXPathParserContext
6308 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt
) {
6311 if (ctxt
->valueTab
!= NULL
) {
6312 for (i
= 0; i
< ctxt
->valueNr
; i
++) {
6314 xmlXPathReleaseObject(ctxt
->context
, ctxt
->valueTab
[i
]);
6316 xmlXPathFreeObject(ctxt
->valueTab
[i
]);
6318 xmlFree(ctxt
->valueTab
);
6320 if (ctxt
->comp
!= NULL
) {
6321 #ifdef XPATH_STREAMING
6322 if (ctxt
->comp
->stream
!= NULL
) {
6323 xmlFreePatternList(ctxt
->comp
->stream
);
6324 ctxt
->comp
->stream
= NULL
;
6327 xmlXPathFreeCompExpr(ctxt
->comp
);
6332 /************************************************************************
6334 * The implicit core function library *
6336 ************************************************************************/
6339 * xmlXPathNodeValHash:
6340 * @node: a node pointer
6342 * Function computing the beginning of the string value of the node,
6343 * used to speed up comparisons
6345 * Returns an int usable as a hash
6348 xmlXPathNodeValHash(xmlNodePtr node
) {
6350 const xmlChar
* string
= NULL
;
6351 xmlNodePtr tmp
= NULL
;
6352 unsigned int ret
= 0;
6357 if (node
->type
== XML_DOCUMENT_NODE
) {
6358 tmp
= xmlDocGetRootElement((xmlDocPtr
) node
);
6360 node
= node
->children
;
6368 switch (node
->type
) {
6369 case XML_COMMENT_NODE
:
6371 case XML_CDATA_SECTION_NODE
:
6373 string
= node
->content
;
6378 return(((unsigned int) string
[0]) +
6379 (((unsigned int) string
[1]) << 8));
6380 case XML_NAMESPACE_DECL
:
6381 string
= ((xmlNsPtr
)node
)->href
;
6386 return(((unsigned int) string
[0]) +
6387 (((unsigned int) string
[1]) << 8));
6388 case XML_ATTRIBUTE_NODE
:
6389 tmp
= ((xmlAttrPtr
) node
)->children
;
6391 case XML_ELEMENT_NODE
:
6392 tmp
= node
->children
;
6397 while (tmp
!= NULL
) {
6398 switch (tmp
->type
) {
6399 case XML_CDATA_SECTION_NODE
:
6401 string
= tmp
->content
;
6407 if ((string
!= NULL
) && (string
[0] != 0)) {
6409 return(ret
+ (((unsigned int) string
[0]) << 8));
6411 if (string
[1] == 0) {
6413 ret
= (unsigned int) string
[0];
6415 return(((unsigned int) string
[0]) +
6416 (((unsigned int) string
[1]) << 8));
6422 if ((tmp
->children
!= NULL
) && (tmp
->type
!= XML_DTD_NODE
)) {
6423 if (tmp
->children
->type
!= XML_ENTITY_DECL
) {
6424 tmp
= tmp
->children
;
6431 if (tmp
->next
!= NULL
) {
6444 if (tmp
->next
!= NULL
) {
6448 } while (tmp
!= NULL
);
6454 * xmlXPathStringHash:
6457 * Function computing the beginning of the string value of the node,
6458 * used to speed up comparisons
6460 * Returns an int usable as a hash
6463 xmlXPathStringHash(const xmlChar
* string
) {
6465 return((unsigned int) 0);
6468 return(((unsigned int) string
[0]) +
6469 (((unsigned int) string
[1]) << 8));
6473 * xmlXPathCompareNodeSetFloat:
6474 * @ctxt: the XPath Parser context
6475 * @inf: less than (1) or greater than (0)
6476 * @strict: is the comparison strict
6477 * @arg: the node set
6480 * Implement the compare operation between a nodeset and a number
6481 * @ns < @val (1, 1, ...
6482 * @ns <= @val (1, 0, ...
6483 * @ns > @val (0, 1, ...
6484 * @ns >= @val (0, 0, ...
6486 * If one object to be compared is a node-set and the other is a number,
6487 * then the comparison will be true if and only if there is a node in the
6488 * node-set such that the result of performing the comparison on the number
6489 * to be compared and on the result of converting the string-value of that
6490 * node to a number using the number function is true.
6492 * Returns 0 or 1 depending on the results of the test.
6495 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6496 xmlXPathObjectPtr arg
, xmlXPathObjectPtr f
) {
6501 if ((f
== NULL
) || (arg
== NULL
) ||
6502 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6503 xmlXPathReleaseObject(ctxt
->context
, arg
);
6504 xmlXPathReleaseObject(ctxt
->context
, f
);
6507 ns
= arg
->nodesetval
;
6509 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6510 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6513 xmlXPathCacheNewString(ctxt
->context
, str2
));
6515 xmlXPathNumberFunction(ctxt
, 1);
6516 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, f
));
6517 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6523 xmlXPathReleaseObject(ctxt
->context
, arg
);
6524 xmlXPathReleaseObject(ctxt
->context
, f
);
6529 * xmlXPathCompareNodeSetString:
6530 * @ctxt: the XPath Parser context
6531 * @inf: less than (1) or greater than (0)
6532 * @strict: is the comparison strict
6533 * @arg: the node set
6536 * Implement the compare operation between a nodeset and a string
6537 * @ns < @val (1, 1, ...
6538 * @ns <= @val (1, 0, ...
6539 * @ns > @val (0, 1, ...
6540 * @ns >= @val (0, 0, ...
6542 * If one object to be compared is a node-set and the other is a string,
6543 * then the comparison will be true if and only if there is a node in
6544 * the node-set such that the result of performing the comparison on the
6545 * string-value of the node and the other string is true.
6547 * Returns 0 or 1 depending on the results of the test.
6550 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6551 xmlXPathObjectPtr arg
, xmlXPathObjectPtr s
) {
6556 if ((s
== NULL
) || (arg
== NULL
) ||
6557 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6558 xmlXPathReleaseObject(ctxt
->context
, arg
);
6559 xmlXPathReleaseObject(ctxt
->context
, s
);
6562 ns
= arg
->nodesetval
;
6564 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6565 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6568 xmlXPathCacheNewString(ctxt
->context
, str2
));
6570 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, s
));
6571 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6577 xmlXPathReleaseObject(ctxt
->context
, arg
);
6578 xmlXPathReleaseObject(ctxt
->context
, s
);
6583 * xmlXPathCompareNodeSets:
6584 * @inf: less than (1) or greater than (0)
6585 * @strict: is the comparison strict
6586 * @arg1: the first node set object
6587 * @arg2: the second node set object
6589 * Implement the compare operation on nodesets:
6591 * If both objects to be compared are node-sets, then the comparison
6592 * will be true if and only if there is a node in the first node-set
6593 * and a node in the second node-set such that the result of performing
6594 * the comparison on the string-values of the two nodes is true.
6596 * When neither object to be compared is a node-set and the operator
6597 * is <=, <, >= or >, then the objects are compared by converting both
6598 * objects to numbers and comparing the numbers according to IEEE 754.
6600 * The number function converts its argument to a number as follows:
6601 * - a string that consists of optional whitespace followed by an
6602 * optional minus sign followed by a Number followed by whitespace
6603 * is converted to the IEEE 754 number that is nearest (according
6604 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6605 * represented by the string; any other string is converted to NaN
6607 * Conclusion all nodes need to be converted first to their string value
6608 * and then the comparison must be done when possible
6611 xmlXPathCompareNodeSets(int inf
, int strict
,
6612 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6620 if ((arg1
== NULL
) ||
6621 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
))) {
6622 xmlXPathFreeObject(arg2
);
6625 if ((arg2
== NULL
) ||
6626 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
))) {
6627 xmlXPathFreeObject(arg1
);
6628 xmlXPathFreeObject(arg2
);
6632 ns1
= arg1
->nodesetval
;
6633 ns2
= arg2
->nodesetval
;
6635 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0)) {
6636 xmlXPathFreeObject(arg1
);
6637 xmlXPathFreeObject(arg2
);
6640 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0)) {
6641 xmlXPathFreeObject(arg1
);
6642 xmlXPathFreeObject(arg2
);
6646 values2
= (double *) xmlMalloc(ns2
->nodeNr
* sizeof(double));
6647 if (values2
== NULL
) {
6648 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6649 xmlXPathFreeObject(arg1
);
6650 xmlXPathFreeObject(arg2
);
6653 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6654 val1
= xmlXPathCastNodeToNumber(ns1
->nodeTab
[i
]);
6655 if (xmlXPathIsNaN(val1
))
6657 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6659 values2
[j
] = xmlXPathCastNodeToNumber(ns2
->nodeTab
[j
]);
6661 if (xmlXPathIsNaN(values2
[j
]))
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
]);
6669 else if (!inf
&& !strict
)
6670 ret
= (val1
>= values2
[j
]);
6679 xmlXPathFreeObject(arg1
);
6680 xmlXPathFreeObject(arg2
);
6685 * xmlXPathCompareNodeSetValue:
6686 * @ctxt: the XPath Parser context
6687 * @inf: less than (1) or greater than (0)
6688 * @strict: is the comparison strict
6689 * @arg: the node set
6692 * Implement the compare operation between a nodeset and a value
6693 * @ns < @val (1, 1, ...
6694 * @ns <= @val (1, 0, ...
6695 * @ns > @val (0, 1, ...
6696 * @ns >= @val (0, 0, ...
6698 * If one object to be compared is a node-set and the other is a boolean,
6699 * then the comparison will be true if and only if the result of performing
6700 * the comparison on the boolean and on the result of converting
6701 * the node-set to a boolean using the boolean function is true.
6703 * Returns 0 or 1 depending on the results of the test.
6706 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6707 xmlXPathObjectPtr arg
, xmlXPathObjectPtr val
) {
6708 if ((val
== NULL
) || (arg
== NULL
) ||
6709 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6714 return(xmlXPathCompareNodeSetFloat(ctxt
, inf
, strict
, arg
, val
));
6716 case XPATH_XSLT_TREE
:
6717 return(xmlXPathCompareNodeSets(inf
, strict
, arg
, val
));
6719 return(xmlXPathCompareNodeSetString(ctxt
, inf
, strict
, arg
, val
));
6721 valuePush(ctxt
, arg
);
6722 xmlXPathBooleanFunction(ctxt
, 1);
6723 valuePush(ctxt
, val
);
6724 return(xmlXPathCompareValues(ctxt
, inf
, strict
));
6726 xmlGenericError(xmlGenericErrorContext
,
6727 "xmlXPathCompareNodeSetValue: Can't compare node set "
6728 "and object of type %d\n",
6730 xmlXPathReleaseObject(ctxt
->context
, arg
);
6731 xmlXPathReleaseObject(ctxt
->context
, val
);
6732 XP_ERROR0(XPATH_INVALID_TYPE
);
6738 * xmlXPathEqualNodeSetString:
6739 * @arg: the nodeset object argument
6740 * @str: the string to compare to.
6741 * @neq: flag to show whether for '=' (0) or '!=' (1)
6743 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6744 * If one object to be compared is a node-set and the other is a string,
6745 * then the comparison will be true if and only if there is a node in
6746 * the node-set such that the result of performing the comparison on the
6747 * string-value of the node and the other string is true.
6749 * Returns 0 or 1 depending on the results of the test.
6752 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg
, const xmlChar
* str
, int neq
)
6759 if ((str
== NULL
) || (arg
== NULL
) ||
6760 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6762 ns
= arg
->nodesetval
;
6764 * A NULL nodeset compared with a string is always false
6765 * (since there is no node equal, and no node not equal)
6767 if ((ns
== NULL
) || (ns
->nodeNr
<= 0) )
6769 hash
= xmlXPathStringHash(str
);
6770 for (i
= 0; i
< ns
->nodeNr
; i
++) {
6771 if (xmlXPathNodeValHash(ns
->nodeTab
[i
]) == hash
) {
6772 str2
= xmlNodeGetContent(ns
->nodeTab
[i
]);
6773 if ((str2
!= NULL
) && (xmlStrEqual(str
, str2
))) {
6778 } else if ((str2
== NULL
) && (xmlStrEqual(str
, BAD_CAST
""))) {
6796 * xmlXPathEqualNodeSetFloat:
6797 * @arg: the nodeset object argument
6798 * @f: the float to compare to
6799 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6801 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6802 * If one object to be compared is a node-set and the other is a number,
6803 * then the comparison will be true if and only if there is a node in
6804 * the node-set such that the result of performing the comparison on the
6805 * number to be compared and on the result of converting the string-value
6806 * of that node to a number using the number function is true.
6808 * Returns 0 or 1 depending on the results of the test.
6811 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt
,
6812 xmlXPathObjectPtr arg
, double f
, int neq
) {
6816 xmlXPathObjectPtr val
;
6819 if ((arg
== NULL
) ||
6820 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6823 ns
= arg
->nodesetval
;
6825 for (i
=0;i
<ns
->nodeNr
;i
++) {
6826 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6828 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, str2
));
6830 xmlXPathNumberFunction(ctxt
, 1);
6831 val
= valuePop(ctxt
);
6833 xmlXPathReleaseObject(ctxt
->context
, val
);
6834 if (!xmlXPathIsNaN(v
)) {
6835 if ((!neq
) && (v
==f
)) {
6838 } else if ((neq
) && (v
!=f
)) {
6842 } else { /* NaN is unequal to any value */
6855 * xmlXPathEqualNodeSets:
6856 * @arg1: first nodeset object argument
6857 * @arg2: second nodeset object argument
6858 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6860 * Implement the equal / not equal operation on XPath nodesets:
6861 * @arg1 == @arg2 or @arg1 != @arg2
6862 * If both objects to be compared are node-sets, then the comparison
6863 * will be true if and only if there is a node in the first node-set and
6864 * a node in the second node-set such that the result of performing the
6865 * comparison on the string-values of the two nodes is true.
6867 * (needless to say, this is a costly operation)
6869 * Returns 0 or 1 depending on the results of the test.
6872 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
, int neq
) {
6874 unsigned int *hashs1
;
6875 unsigned int *hashs2
;
6882 if ((arg1
== NULL
) ||
6883 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)))
6885 if ((arg2
== NULL
) ||
6886 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
)))
6889 ns1
= arg1
->nodesetval
;
6890 ns2
= arg2
->nodesetval
;
6892 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0))
6894 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0))
6898 * for equal, check if there is a node pertaining to both sets
6901 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6902 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6903 if (ns1
->nodeTab
[i
] == ns2
->nodeTab
[j
])
6906 values1
= (xmlChar
**) xmlMalloc(ns1
->nodeNr
* sizeof(xmlChar
*));
6907 if (values1
== NULL
) {
6908 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6911 hashs1
= (unsigned int *) xmlMalloc(ns1
->nodeNr
* sizeof(unsigned int));
6912 if (hashs1
== NULL
) {
6913 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6917 memset(values1
, 0, ns1
->nodeNr
* sizeof(xmlChar
*));
6918 values2
= (xmlChar
**) xmlMalloc(ns2
->nodeNr
* sizeof(xmlChar
*));
6919 if (values2
== NULL
) {
6920 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6925 hashs2
= (unsigned int *) xmlMalloc(ns2
->nodeNr
* sizeof(unsigned int));
6926 if (hashs2
== NULL
) {
6927 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6933 memset(values2
, 0, ns2
->nodeNr
* sizeof(xmlChar
*));
6934 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6935 hashs1
[i
] = xmlXPathNodeValHash(ns1
->nodeTab
[i
]);
6936 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6938 hashs2
[j
] = xmlXPathNodeValHash(ns2
->nodeTab
[j
]);
6939 if (hashs1
[i
] != hashs2
[j
]) {
6946 if (values1
[i
] == NULL
)
6947 values1
[i
] = xmlNodeGetContent(ns1
->nodeTab
[i
]);
6948 if (values2
[j
] == NULL
)
6949 values2
[j
] = xmlNodeGetContent(ns2
->nodeTab
[j
]);
6950 ret
= xmlStrEqual(values1
[i
], values2
[j
]) ^ neq
;
6958 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6959 if (values1
[i
] != NULL
)
6960 xmlFree(values1
[i
]);
6961 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6962 if (values2
[j
] != NULL
)
6963 xmlFree(values2
[j
]);
6972 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt
,
6973 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6976 *At this point we are assured neither arg1 nor arg2
6977 *is a nodeset, so we can just pick the appropriate routine.
6979 switch (arg1
->type
) {
6980 case XPATH_UNDEFINED
:
6982 xmlGenericError(xmlGenericErrorContext
,
6983 "Equal: undefined\n");
6987 switch (arg2
->type
) {
6988 case XPATH_UNDEFINED
:
6990 xmlGenericError(xmlGenericErrorContext
,
6991 "Equal: undefined\n");
6996 xmlGenericError(xmlGenericErrorContext
,
6997 "Equal: %d boolean %d \n",
6998 arg1
->boolval
, arg2
->boolval
);
7000 ret
= (arg1
->boolval
== arg2
->boolval
);
7003 ret
= (arg1
->boolval
==
7004 xmlXPathCastNumberToBoolean(arg2
->floatval
));
7007 if ((arg2
->stringval
== NULL
) ||
7008 (arg2
->stringval
[0] == 0)) ret
= 0;
7011 ret
= (arg1
->boolval
== ret
);
7016 case XPATH_LOCATIONSET
:
7020 case XPATH_XSLT_TREE
:
7025 switch (arg2
->type
) {
7026 case XPATH_UNDEFINED
:
7028 xmlGenericError(xmlGenericErrorContext
,
7029 "Equal: undefined\n");
7033 ret
= (arg2
->boolval
==
7034 xmlXPathCastNumberToBoolean(arg1
->floatval
));
7037 valuePush(ctxt
, arg2
);
7038 xmlXPathNumberFunction(ctxt
, 1);
7039 arg2
= valuePop(ctxt
);
7040 /* Falls through. */
7042 /* Hand check NaN and Infinity equalities */
7043 if (xmlXPathIsNaN(arg1
->floatval
) ||
7044 xmlXPathIsNaN(arg2
->floatval
)) {
7046 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7047 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7051 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7052 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7056 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7057 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7061 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7062 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7067 ret
= (arg1
->floatval
== arg2
->floatval
);
7073 case XPATH_LOCATIONSET
:
7077 case XPATH_XSLT_TREE
:
7082 switch (arg2
->type
) {
7083 case XPATH_UNDEFINED
:
7085 xmlGenericError(xmlGenericErrorContext
,
7086 "Equal: undefined\n");
7090 if ((arg1
->stringval
== NULL
) ||
7091 (arg1
->stringval
[0] == 0)) ret
= 0;
7094 ret
= (arg2
->boolval
== ret
);
7097 ret
= xmlStrEqual(arg1
->stringval
, arg2
->stringval
);
7100 valuePush(ctxt
, arg1
);
7101 xmlXPathNumberFunction(ctxt
, 1);
7102 arg1
= valuePop(ctxt
);
7103 /* Hand check NaN and Infinity equalities */
7104 if (xmlXPathIsNaN(arg1
->floatval
) ||
7105 xmlXPathIsNaN(arg2
->floatval
)) {
7107 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7108 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7112 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7113 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7117 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7118 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7122 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7123 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7128 ret
= (arg1
->floatval
== arg2
->floatval
);
7134 case XPATH_LOCATIONSET
:
7138 case XPATH_XSLT_TREE
:
7145 case XPATH_LOCATIONSET
:
7149 case XPATH_XSLT_TREE
:
7152 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7153 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7158 * xmlXPathEqualValues:
7159 * @ctxt: the XPath Parser context
7161 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7163 * Returns 0 or 1 depending on the results of the test.
7166 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt
) {
7167 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7170 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7171 arg2
= valuePop(ctxt
);
7172 arg1
= valuePop(ctxt
);
7173 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7175 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7177 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7178 XP_ERROR0(XPATH_INVALID_OPERAND
);
7183 xmlGenericError(xmlGenericErrorContext
,
7184 "Equal: by pointer\n");
7186 xmlXPathFreeObject(arg1
);
7191 *If either argument is a nodeset, it's a 'special case'
7193 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7194 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7196 *Hack it to assure arg1 is the nodeset
7198 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7203 switch (arg2
->type
) {
7204 case XPATH_UNDEFINED
:
7206 xmlGenericError(xmlGenericErrorContext
,
7207 "Equal: undefined\n");
7211 case XPATH_XSLT_TREE
:
7212 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 0);
7215 if ((arg1
->nodesetval
== NULL
) ||
7216 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7219 ret
= (ret
== arg2
->boolval
);
7222 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 0);
7225 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
, 0);
7230 case XPATH_LOCATIONSET
:
7234 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7235 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7239 return (xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7243 * xmlXPathNotEqualValues:
7244 * @ctxt: the XPath Parser context
7246 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7248 * Returns 0 or 1 depending on the results of the test.
7251 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt
) {
7252 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7255 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7256 arg2
= valuePop(ctxt
);
7257 arg1
= valuePop(ctxt
);
7258 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7260 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7262 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7263 XP_ERROR0(XPATH_INVALID_OPERAND
);
7268 xmlGenericError(xmlGenericErrorContext
,
7269 "NotEqual: by pointer\n");
7271 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7276 *If either argument is a nodeset, it's a 'special case'
7278 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7279 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7281 *Hack it to assure arg1 is the nodeset
7283 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7288 switch (arg2
->type
) {
7289 case XPATH_UNDEFINED
:
7291 xmlGenericError(xmlGenericErrorContext
,
7292 "NotEqual: undefined\n");
7296 case XPATH_XSLT_TREE
:
7297 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 1);
7300 if ((arg1
->nodesetval
== NULL
) ||
7301 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7304 ret
= (ret
!= arg2
->boolval
);
7307 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 1);
7310 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
,1);
7315 case XPATH_LOCATIONSET
:
7319 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7320 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7324 return (!xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7328 * xmlXPathCompareValues:
7329 * @ctxt: the XPath Parser context
7330 * @inf: less than (1) or greater than (0)
7331 * @strict: is the comparison strict
7333 * Implement the compare operation on XPath objects:
7334 * @arg1 < @arg2 (1, 1, ...
7335 * @arg1 <= @arg2 (1, 0, ...
7336 * @arg1 > @arg2 (0, 1, ...
7337 * @arg1 >= @arg2 (0, 0, ...
7339 * When neither object to be compared is a node-set and the operator is
7340 * <=, <, >=, >, then the objects are compared by converted both objects
7341 * to numbers and comparing the numbers according to IEEE 754. The <
7342 * comparison will be true if and only if the first number is less than the
7343 * second number. The <= comparison will be true if and only if the first
7344 * number is less than or equal to the second number. The > comparison
7345 * will be true if and only if the first number is greater than the second
7346 * number. The >= comparison will be true if and only if the first number
7347 * is greater than or equal to the second number.
7349 * Returns 1 if the comparison succeeded, 0 if it failed
7352 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt
, int inf
, int strict
) {
7353 int ret
= 0, arg1i
= 0, arg2i
= 0;
7354 xmlXPathObjectPtr arg1
, arg2
;
7356 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7357 arg2
= valuePop(ctxt
);
7358 arg1
= valuePop(ctxt
);
7359 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7361 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7363 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7364 XP_ERROR0(XPATH_INVALID_OPERAND
);
7367 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7368 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7370 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7371 * are not freed from within this routine; they will be freed from the
7372 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7374 if (((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
)) &&
7375 ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
))){
7376 ret
= xmlXPathCompareNodeSets(inf
, strict
, arg1
, arg2
);
7378 if ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7379 ret
= xmlXPathCompareNodeSetValue(ctxt
, inf
, strict
,
7382 ret
= xmlXPathCompareNodeSetValue(ctxt
, !inf
, strict
,
7389 if (arg1
->type
!= XPATH_NUMBER
) {
7390 valuePush(ctxt
, arg1
);
7391 xmlXPathNumberFunction(ctxt
, 1);
7392 arg1
= valuePop(ctxt
);
7394 if (arg1
->type
!= XPATH_NUMBER
) {
7395 xmlXPathFreeObject(arg1
);
7396 xmlXPathFreeObject(arg2
);
7397 XP_ERROR0(XPATH_INVALID_OPERAND
);
7399 if (arg2
->type
!= XPATH_NUMBER
) {
7400 valuePush(ctxt
, arg2
);
7401 xmlXPathNumberFunction(ctxt
, 1);
7402 arg2
= valuePop(ctxt
);
7404 if (arg2
->type
!= XPATH_NUMBER
) {
7405 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7406 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7407 XP_ERROR0(XPATH_INVALID_OPERAND
);
7410 * Add tests for infinity and nan
7411 * => feedback on 3.4 for Inf and NaN
7413 /* Hand check NaN and Infinity comparisons */
7414 if (xmlXPathIsNaN(arg1
->floatval
) || xmlXPathIsNaN(arg2
->floatval
)) {
7417 arg1i
=xmlXPathIsInf(arg1
->floatval
);
7418 arg2i
=xmlXPathIsInf(arg2
->floatval
);
7419 if (inf
&& strict
) {
7420 if ((arg1i
== -1 && arg2i
!= -1) ||
7421 (arg2i
== 1 && arg1i
!= 1)) {
7423 } else if (arg1i
== 0 && arg2i
== 0) {
7424 ret
= (arg1
->floatval
< arg2
->floatval
);
7429 else if (inf
&& !strict
) {
7430 if (arg1i
== -1 || arg2i
== 1) {
7432 } else if (arg1i
== 0 && arg2i
== 0) {
7433 ret
= (arg1
->floatval
<= arg2
->floatval
);
7438 else if (!inf
&& strict
) {
7439 if ((arg1i
== 1 && arg2i
!= 1) ||
7440 (arg2i
== -1 && arg1i
!= -1)) {
7442 } else if (arg1i
== 0 && arg2i
== 0) {
7443 ret
= (arg1
->floatval
> arg2
->floatval
);
7448 else if (!inf
&& !strict
) {
7449 if (arg1i
== 1 || arg2i
== -1) {
7451 } else if (arg1i
== 0 && arg2i
== 0) {
7452 ret
= (arg1
->floatval
>= arg2
->floatval
);
7458 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7459 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7464 * xmlXPathValueFlipSign:
7465 * @ctxt: the XPath Parser context
7467 * Implement the unary - operation on an XPath object
7468 * The numeric operators convert their operands to numbers as if
7469 * by calling the number function.
7472 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt
) {
7473 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return;
7475 CHECK_TYPE(XPATH_NUMBER
);
7476 ctxt
->value
->floatval
= -ctxt
->value
->floatval
;
7480 * xmlXPathAddValues:
7481 * @ctxt: the XPath Parser context
7483 * Implement the add operation on XPath objects:
7484 * The numeric operators convert their operands to numbers as if
7485 * by calling the number function.
7488 xmlXPathAddValues(xmlXPathParserContextPtr ctxt
) {
7489 xmlXPathObjectPtr arg
;
7492 arg
= valuePop(ctxt
);
7494 XP_ERROR(XPATH_INVALID_OPERAND
);
7495 val
= xmlXPathCastToNumber(arg
);
7496 xmlXPathReleaseObject(ctxt
->context
, arg
);
7498 CHECK_TYPE(XPATH_NUMBER
);
7499 ctxt
->value
->floatval
+= val
;
7503 * xmlXPathSubValues:
7504 * @ctxt: the XPath Parser context
7506 * Implement the subtraction operation on XPath objects:
7507 * The numeric operators convert their operands to numbers as if
7508 * by calling the number function.
7511 xmlXPathSubValues(xmlXPathParserContextPtr ctxt
) {
7512 xmlXPathObjectPtr arg
;
7515 arg
= valuePop(ctxt
);
7517 XP_ERROR(XPATH_INVALID_OPERAND
);
7518 val
= xmlXPathCastToNumber(arg
);
7519 xmlXPathReleaseObject(ctxt
->context
, arg
);
7521 CHECK_TYPE(XPATH_NUMBER
);
7522 ctxt
->value
->floatval
-= val
;
7526 * xmlXPathMultValues:
7527 * @ctxt: the XPath Parser context
7529 * Implement the multiply operation on XPath objects:
7530 * The numeric operators convert their operands to numbers as if
7531 * by calling the number function.
7534 xmlXPathMultValues(xmlXPathParserContextPtr ctxt
) {
7535 xmlXPathObjectPtr arg
;
7538 arg
= valuePop(ctxt
);
7540 XP_ERROR(XPATH_INVALID_OPERAND
);
7541 val
= xmlXPathCastToNumber(arg
);
7542 xmlXPathReleaseObject(ctxt
->context
, arg
);
7544 CHECK_TYPE(XPATH_NUMBER
);
7545 ctxt
->value
->floatval
*= val
;
7549 * xmlXPathDivValues:
7550 * @ctxt: the XPath Parser context
7552 * Implement the div operation on XPath objects @arg1 / @arg2:
7553 * The numeric operators convert their operands to numbers as if
7554 * by calling the number function.
7557 xmlXPathDivValues(xmlXPathParserContextPtr ctxt
) {
7558 xmlXPathObjectPtr arg
;
7561 arg
= valuePop(ctxt
);
7563 XP_ERROR(XPATH_INVALID_OPERAND
);
7564 val
= xmlXPathCastToNumber(arg
);
7565 xmlXPathReleaseObject(ctxt
->context
, arg
);
7567 CHECK_TYPE(XPATH_NUMBER
);
7568 ctxt
->value
->floatval
/= val
;
7572 * xmlXPathModValues:
7573 * @ctxt: the XPath Parser context
7575 * Implement the mod operation on XPath objects: @arg1 / @arg2
7576 * The numeric operators convert their operands to numbers as if
7577 * by calling the number function.
7580 xmlXPathModValues(xmlXPathParserContextPtr ctxt
) {
7581 xmlXPathObjectPtr arg
;
7584 arg
= valuePop(ctxt
);
7586 XP_ERROR(XPATH_INVALID_OPERAND
);
7587 arg2
= xmlXPathCastToNumber(arg
);
7588 xmlXPathReleaseObject(ctxt
->context
, arg
);
7590 CHECK_TYPE(XPATH_NUMBER
);
7591 arg1
= ctxt
->value
->floatval
;
7593 ctxt
->value
->floatval
= NAN
;
7595 ctxt
->value
->floatval
= fmod(arg1
, arg2
);
7599 /************************************************************************
7601 * The traversal functions *
7603 ************************************************************************/
7606 * A traversal function enumerates nodes along an axis.
7607 * Initially it must be called with NULL, and it indicates
7608 * termination on the axis by returning NULL.
7610 typedef xmlNodePtr (*xmlXPathTraversalFunction
)
7611 (xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
);
7614 * xmlXPathTraversalFunctionExt:
7615 * A traversal function enumerates nodes along an axis.
7616 * Initially it must be called with NULL, and it indicates
7617 * termination on the axis by returning NULL.
7618 * The context node of the traversal is specified via @contextNode.
7620 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt
)
7621 (xmlNodePtr cur
, xmlNodePtr contextNode
);
7624 * xmlXPathNodeSetMergeFunction:
7625 * Used for merging node sets in xmlXPathCollectAndTest().
7627 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction
)
7628 (xmlNodeSetPtr
, xmlNodeSetPtr
, int);
7633 * @ctxt: the XPath Parser context
7634 * @cur: the current node in the traversal
7636 * Traversal function for the "self" direction
7637 * The self axis contains just the context node itself
7639 * Returns the next element following that axis
7642 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7643 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7645 return(ctxt
->context
->node
);
7650 * xmlXPathNextChild:
7651 * @ctxt: the XPath Parser context
7652 * @cur: the current node in the traversal
7654 * Traversal function for the "child" direction
7655 * The child axis contains the children of the context node in document order.
7657 * Returns the next element following that axis
7660 xmlXPathNextChild(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7661 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7663 if (ctxt
->context
->node
== NULL
) return(NULL
);
7664 switch (ctxt
->context
->node
->type
) {
7665 case XML_ELEMENT_NODE
:
7667 case XML_CDATA_SECTION_NODE
:
7668 case XML_ENTITY_REF_NODE
:
7669 case XML_ENTITY_NODE
:
7671 case XML_COMMENT_NODE
:
7672 case XML_NOTATION_NODE
:
7674 return(ctxt
->context
->node
->children
);
7675 case XML_DOCUMENT_NODE
:
7676 case XML_DOCUMENT_TYPE_NODE
:
7677 case XML_DOCUMENT_FRAG_NODE
:
7678 case XML_HTML_DOCUMENT_NODE
:
7679 #ifdef LIBXML_DOCB_ENABLED
7680 case XML_DOCB_DOCUMENT_NODE
:
7682 return(((xmlDocPtr
) ctxt
->context
->node
)->children
);
7683 case XML_ELEMENT_DECL
:
7684 case XML_ATTRIBUTE_DECL
:
7685 case XML_ENTITY_DECL
:
7686 case XML_ATTRIBUTE_NODE
:
7687 case XML_NAMESPACE_DECL
:
7688 case XML_XINCLUDE_START
:
7689 case XML_XINCLUDE_END
:
7694 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
7695 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
7701 * xmlXPathNextChildElement:
7702 * @ctxt: the XPath Parser context
7703 * @cur: the current node in the traversal
7705 * Traversal function for the "child" direction and nodes of type element.
7706 * The child axis contains the children of the context node in document order.
7708 * Returns the next element following that axis
7711 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7712 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7714 cur
= ctxt
->context
->node
;
7715 if (cur
== NULL
) return(NULL
);
7717 * Get the first element child.
7719 switch (cur
->type
) {
7720 case XML_ELEMENT_NODE
:
7721 case XML_DOCUMENT_FRAG_NODE
:
7722 case XML_ENTITY_REF_NODE
: /* URGENT TODO: entify-refs as well? */
7723 case XML_ENTITY_NODE
:
7724 cur
= cur
->children
;
7726 if (cur
->type
== XML_ELEMENT_NODE
)
7730 } while ((cur
!= NULL
) &&
7731 (cur
->type
!= XML_ELEMENT_NODE
));
7735 case XML_DOCUMENT_NODE
:
7736 case XML_HTML_DOCUMENT_NODE
:
7737 #ifdef LIBXML_DOCB_ENABLED
7738 case XML_DOCB_DOCUMENT_NODE
:
7740 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7747 * Get the next sibling element node.
7749 switch (cur
->type
) {
7750 case XML_ELEMENT_NODE
:
7752 case XML_ENTITY_REF_NODE
:
7753 case XML_ENTITY_NODE
:
7754 case XML_CDATA_SECTION_NODE
:
7756 case XML_COMMENT_NODE
:
7757 case XML_XINCLUDE_END
:
7759 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7763 if (cur
->next
!= NULL
) {
7764 if (cur
->next
->type
== XML_ELEMENT_NODE
)
7769 } while ((cur
!= NULL
) && (cur
->type
!= XML_ELEMENT_NODE
));
7777 * xmlXPathNextDescendantOrSelfElemParent:
7778 * @ctxt: the XPath Parser context
7779 * @cur: the current node in the traversal
7781 * Traversal function for the "descendant-or-self" axis.
7782 * Additionally it returns only nodes which can be parents of
7786 * Returns the next element following that axis
7789 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur
,
7790 xmlNodePtr contextNode
)
7793 if (contextNode
== NULL
)
7795 switch (contextNode
->type
) {
7796 case XML_ELEMENT_NODE
:
7797 case XML_XINCLUDE_START
:
7798 case XML_DOCUMENT_FRAG_NODE
:
7799 case XML_DOCUMENT_NODE
:
7800 #ifdef LIBXML_DOCB_ENABLED
7801 case XML_DOCB_DOCUMENT_NODE
:
7803 case XML_HTML_DOCUMENT_NODE
:
7804 return(contextNode
);
7810 xmlNodePtr start
= cur
;
7812 while (cur
!= NULL
) {
7813 switch (cur
->type
) {
7814 case XML_ELEMENT_NODE
:
7815 /* TODO: OK to have XInclude here? */
7816 case XML_XINCLUDE_START
:
7817 case XML_DOCUMENT_FRAG_NODE
:
7820 if (cur
->children
!= NULL
) {
7821 cur
= cur
->children
;
7825 /* Not sure if we need those here. */
7826 case XML_DOCUMENT_NODE
:
7827 #ifdef LIBXML_DOCB_ENABLED
7828 case XML_DOCB_DOCUMENT_NODE
:
7830 case XML_HTML_DOCUMENT_NODE
:
7833 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7839 if ((cur
== NULL
) || (cur
== contextNode
))
7841 if (cur
->next
!= NULL
) {
7854 * xmlXPathNextDescendant:
7855 * @ctxt: the XPath Parser context
7856 * @cur: the current node in the traversal
7858 * Traversal function for the "descendant" direction
7859 * the descendant axis contains the descendants of the context node in document
7860 * order; a descendant is a child or a child of a child and so on.
7862 * Returns the next element following that axis
7865 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7866 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7868 if (ctxt
->context
->node
== NULL
)
7870 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7871 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7874 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
7875 return(ctxt
->context
->doc
->children
);
7876 return(ctxt
->context
->node
->children
);
7879 if (cur
->type
== XML_NAMESPACE_DECL
)
7881 if (cur
->children
!= NULL
) {
7883 * Do not descend on entities declarations
7885 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
7886 cur
= cur
->children
;
7890 if (cur
->type
!= XML_DTD_NODE
)
7895 if (cur
== ctxt
->context
->node
) return(NULL
);
7897 while (cur
->next
!= NULL
) {
7899 if ((cur
->type
!= XML_ENTITY_DECL
) &&
7900 (cur
->type
!= XML_DTD_NODE
))
7906 if (cur
== NULL
) break;
7907 if (cur
== ctxt
->context
->node
) return(NULL
);
7908 if (cur
->next
!= NULL
) {
7912 } while (cur
!= NULL
);
7917 * xmlXPathNextDescendantOrSelf:
7918 * @ctxt: the XPath Parser context
7919 * @cur: the current node in the traversal
7921 * Traversal function for the "descendant-or-self" direction
7922 * the descendant-or-self axis contains the context node and the descendants
7923 * of the context node in document order; thus the context node is the first
7924 * node on the axis, and the first child of the context node is the second node
7927 * Returns the next element following that axis
7930 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7931 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7933 return(ctxt
->context
->node
);
7935 if (ctxt
->context
->node
== NULL
)
7937 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7938 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7941 return(xmlXPathNextDescendant(ctxt
, cur
));
7945 * xmlXPathNextParent:
7946 * @ctxt: the XPath Parser context
7947 * @cur: the current node in the traversal
7949 * Traversal function for the "parent" direction
7950 * The parent axis contains the parent of the context node, if there is one.
7952 * Returns the next element following that axis
7955 xmlXPathNextParent(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7956 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7958 * the parent of an attribute or namespace node is the element
7959 * to which the attribute or namespace node is attached
7960 * Namespace handling !!!
7963 if (ctxt
->context
->node
== NULL
) return(NULL
);
7964 switch (ctxt
->context
->node
->type
) {
7965 case XML_ELEMENT_NODE
:
7967 case XML_CDATA_SECTION_NODE
:
7968 case XML_ENTITY_REF_NODE
:
7969 case XML_ENTITY_NODE
:
7971 case XML_COMMENT_NODE
:
7972 case XML_NOTATION_NODE
:
7974 case XML_ELEMENT_DECL
:
7975 case XML_ATTRIBUTE_DECL
:
7976 case XML_XINCLUDE_START
:
7977 case XML_XINCLUDE_END
:
7978 case XML_ENTITY_DECL
:
7979 if (ctxt
->context
->node
->parent
== NULL
)
7980 return((xmlNodePtr
) ctxt
->context
->doc
);
7981 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
7982 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
7983 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
7984 BAD_CAST
"fake node libxslt"))))
7986 return(ctxt
->context
->node
->parent
);
7987 case XML_ATTRIBUTE_NODE
: {
7988 xmlAttrPtr att
= (xmlAttrPtr
) ctxt
->context
->node
;
7990 return(att
->parent
);
7992 case XML_DOCUMENT_NODE
:
7993 case XML_DOCUMENT_TYPE_NODE
:
7994 case XML_DOCUMENT_FRAG_NODE
:
7995 case XML_HTML_DOCUMENT_NODE
:
7996 #ifdef LIBXML_DOCB_ENABLED
7997 case XML_DOCB_DOCUMENT_NODE
:
8000 case XML_NAMESPACE_DECL
: {
8001 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8003 if ((ns
->next
!= NULL
) &&
8004 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8005 return((xmlNodePtr
) ns
->next
);
8014 * xmlXPathNextAncestor:
8015 * @ctxt: the XPath Parser context
8016 * @cur: the current node in the traversal
8018 * Traversal function for the "ancestor" direction
8019 * the ancestor axis contains the ancestors of the context node; the ancestors
8020 * of the context node consist of the parent of context node and the parent's
8021 * parent and so on; the nodes are ordered in reverse document order; thus the
8022 * parent is the first node on the axis, and the parent's parent is the second
8025 * Returns the next element following that axis
8028 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8029 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8031 * the parent of an attribute or namespace node is the element
8032 * to which the attribute or namespace node is attached
8036 if (ctxt
->context
->node
== NULL
) return(NULL
);
8037 switch (ctxt
->context
->node
->type
) {
8038 case XML_ELEMENT_NODE
:
8040 case XML_CDATA_SECTION_NODE
:
8041 case XML_ENTITY_REF_NODE
:
8042 case XML_ENTITY_NODE
:
8044 case XML_COMMENT_NODE
:
8046 case XML_ELEMENT_DECL
:
8047 case XML_ATTRIBUTE_DECL
:
8048 case XML_ENTITY_DECL
:
8049 case XML_NOTATION_NODE
:
8050 case XML_XINCLUDE_START
:
8051 case XML_XINCLUDE_END
:
8052 if (ctxt
->context
->node
->parent
== NULL
)
8053 return((xmlNodePtr
) ctxt
->context
->doc
);
8054 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
8055 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
8056 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
8057 BAD_CAST
"fake node libxslt"))))
8059 return(ctxt
->context
->node
->parent
);
8060 case XML_ATTRIBUTE_NODE
: {
8061 xmlAttrPtr tmp
= (xmlAttrPtr
) ctxt
->context
->node
;
8063 return(tmp
->parent
);
8065 case XML_DOCUMENT_NODE
:
8066 case XML_DOCUMENT_TYPE_NODE
:
8067 case XML_DOCUMENT_FRAG_NODE
:
8068 case XML_HTML_DOCUMENT_NODE
:
8069 #ifdef LIBXML_DOCB_ENABLED
8070 case XML_DOCB_DOCUMENT_NODE
:
8073 case XML_NAMESPACE_DECL
: {
8074 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8076 if ((ns
->next
!= NULL
) &&
8077 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8078 return((xmlNodePtr
) ns
->next
);
8079 /* Bad, how did that namespace end up here ? */
8085 if (cur
== ctxt
->context
->doc
->children
)
8086 return((xmlNodePtr
) ctxt
->context
->doc
);
8087 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8089 switch (cur
->type
) {
8090 case XML_ELEMENT_NODE
:
8092 case XML_CDATA_SECTION_NODE
:
8093 case XML_ENTITY_REF_NODE
:
8094 case XML_ENTITY_NODE
:
8096 case XML_COMMENT_NODE
:
8097 case XML_NOTATION_NODE
:
8099 case XML_ELEMENT_DECL
:
8100 case XML_ATTRIBUTE_DECL
:
8101 case XML_ENTITY_DECL
:
8102 case XML_XINCLUDE_START
:
8103 case XML_XINCLUDE_END
:
8104 if (cur
->parent
== NULL
)
8106 if ((cur
->parent
->type
== XML_ELEMENT_NODE
) &&
8107 ((cur
->parent
->name
[0] == ' ') ||
8108 (xmlStrEqual(cur
->parent
->name
,
8109 BAD_CAST
"fake node libxslt"))))
8111 return(cur
->parent
);
8112 case XML_ATTRIBUTE_NODE
: {
8113 xmlAttrPtr att
= (xmlAttrPtr
) cur
;
8115 return(att
->parent
);
8117 case XML_NAMESPACE_DECL
: {
8118 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8120 if ((ns
->next
!= NULL
) &&
8121 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8122 return((xmlNodePtr
) ns
->next
);
8123 /* Bad, how did that namespace end up here ? */
8126 case XML_DOCUMENT_NODE
:
8127 case XML_DOCUMENT_TYPE_NODE
:
8128 case XML_DOCUMENT_FRAG_NODE
:
8129 case XML_HTML_DOCUMENT_NODE
:
8130 #ifdef LIBXML_DOCB_ENABLED
8131 case XML_DOCB_DOCUMENT_NODE
:
8139 * xmlXPathNextAncestorOrSelf:
8140 * @ctxt: the XPath Parser context
8141 * @cur: the current node in the traversal
8143 * Traversal function for the "ancestor-or-self" direction
8144 * he ancestor-or-self axis contains the context node and ancestors of
8145 * the context node in reverse document order; thus the context node is
8146 * the first node on the axis, and the context node's parent the second;
8147 * parent here is defined the same as with the parent axis.
8149 * Returns the next element following that axis
8152 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8153 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8155 return(ctxt
->context
->node
);
8156 return(xmlXPathNextAncestor(ctxt
, cur
));
8160 * xmlXPathNextFollowingSibling:
8161 * @ctxt: the XPath Parser context
8162 * @cur: the current node in the traversal
8164 * Traversal function for the "following-sibling" direction
8165 * The following-sibling axis contains the following siblings of the context
8166 * node in document order.
8168 * Returns the next element following that axis
8171 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8172 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8173 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8174 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8176 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8179 return(ctxt
->context
->node
->next
);
8184 * xmlXPathNextPrecedingSibling:
8185 * @ctxt: the XPath Parser context
8186 * @cur: the current node in the traversal
8188 * Traversal function for the "preceding-sibling" direction
8189 * The preceding-sibling axis contains the preceding siblings of the context
8190 * node in reverse document order; the first preceding sibling is first on the
8191 * axis; the sibling preceding that node is the second on the axis and so on.
8193 * Returns the next element following that axis
8196 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8197 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8198 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8199 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8201 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8204 return(ctxt
->context
->node
->prev
);
8205 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
)) {
8208 return(ctxt
->context
->node
->prev
);
8214 * xmlXPathNextFollowing:
8215 * @ctxt: the XPath Parser context
8216 * @cur: the current node in the traversal
8218 * Traversal function for the "following" direction
8219 * The following axis contains all nodes in the same document as the context
8220 * node that are after the context node in document order, excluding any
8221 * descendants and excluding attribute nodes and namespace nodes; the nodes
8222 * are ordered in document order
8224 * Returns the next element following that axis
8227 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8228 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8229 if ((cur
!= NULL
) && (cur
->type
!= XML_ATTRIBUTE_NODE
) &&
8230 (cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->children
!= NULL
))
8231 return(cur
->children
);
8234 cur
= ctxt
->context
->node
;
8235 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8237 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8238 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8240 if ((ns
->next
== NULL
) ||
8241 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8243 cur
= (xmlNodePtr
) ns
->next
;
8246 if (cur
== NULL
) return(NULL
) ; /* ERROR */
8247 if (cur
->next
!= NULL
) return(cur
->next
) ;
8250 if (cur
== NULL
) break;
8251 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
) return(NULL
);
8252 if (cur
->next
!= NULL
) return(cur
->next
);
8253 } while (cur
!= NULL
);
8258 * xmlXPathIsAncestor:
8259 * @ancestor: the ancestor node
8260 * @node: the current node
8262 * Check that @ancestor is a @node's ancestor
8264 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8267 xmlXPathIsAncestor(xmlNodePtr ancestor
, xmlNodePtr node
) {
8268 if ((ancestor
== NULL
) || (node
== NULL
)) return(0);
8269 if (node
->type
== XML_NAMESPACE_DECL
)
8271 if (ancestor
->type
== XML_NAMESPACE_DECL
)
8273 /* nodes need to be in the same document */
8274 if (ancestor
->doc
!= node
->doc
) return(0);
8275 /* avoid searching if ancestor or node is the root node */
8276 if (ancestor
== (xmlNodePtr
) node
->doc
) return(1);
8277 if (node
== (xmlNodePtr
) ancestor
->doc
) return(0);
8278 while (node
->parent
!= NULL
) {
8279 if (node
->parent
== ancestor
)
8281 node
= node
->parent
;
8287 * xmlXPathNextPreceding:
8288 * @ctxt: the XPath Parser context
8289 * @cur: the current node in the traversal
8291 * Traversal function for the "preceding" direction
8292 * the preceding axis contains all nodes in the same document as the context
8293 * node that are before the context node in document order, excluding any
8294 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8295 * ordered in reverse document order
8297 * Returns the next element following that axis
8300 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
)
8302 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8304 cur
= ctxt
->context
->node
;
8305 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8307 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8308 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8310 if ((ns
->next
== NULL
) ||
8311 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8313 cur
= (xmlNodePtr
) ns
->next
;
8316 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
8318 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8321 if (cur
->prev
!= NULL
) {
8322 for (cur
= cur
->prev
; cur
->last
!= NULL
; cur
= cur
->last
) ;
8329 if (cur
== ctxt
->context
->doc
->children
)
8331 } while (xmlXPathIsAncestor(cur
, ctxt
->context
->node
));
8336 * xmlXPathNextPrecedingInternal:
8337 * @ctxt: the XPath Parser context
8338 * @cur: the current node in the traversal
8340 * Traversal function for the "preceding" direction
8341 * the preceding axis contains all nodes in the same document as the context
8342 * node that are before the context node in document order, excluding any
8343 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8344 * ordered in reverse document order
8345 * This is a faster implementation but internal only since it requires a
8346 * state kept in the parser context: ctxt->ancestor.
8348 * Returns the next element following that axis
8351 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt
,
8354 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8356 cur
= ctxt
->context
->node
;
8359 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8361 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8362 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8364 if ((ns
->next
== NULL
) ||
8365 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8367 cur
= (xmlNodePtr
) ns
->next
;
8369 ctxt
->ancestor
= cur
->parent
;
8371 if (cur
->type
== XML_NAMESPACE_DECL
)
8373 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8375 while (cur
->prev
== NULL
) {
8379 if (cur
== ctxt
->context
->doc
->children
)
8381 if (cur
!= ctxt
->ancestor
)
8383 ctxt
->ancestor
= cur
->parent
;
8386 while (cur
->last
!= NULL
)
8392 * xmlXPathNextNamespace:
8393 * @ctxt: the XPath Parser context
8394 * @cur: the current attribute in the traversal
8396 * Traversal function for the "namespace" direction
8397 * the namespace axis contains the namespace nodes of the context node;
8398 * the order of nodes on this axis is implementation-defined; the axis will
8399 * be empty unless the context node is an element
8401 * We keep the XML namespace node at the end of the list.
8403 * Returns the next element following that axis
8406 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8407 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8408 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
) return(NULL
);
8410 if (ctxt
->context
->tmpNsList
!= NULL
)
8411 xmlFree(ctxt
->context
->tmpNsList
);
8412 ctxt
->context
->tmpNsList
=
8413 xmlGetNsList(ctxt
->context
->doc
, ctxt
->context
->node
);
8414 ctxt
->context
->tmpNsNr
= 0;
8415 if (ctxt
->context
->tmpNsList
!= NULL
) {
8416 while (ctxt
->context
->tmpNsList
[ctxt
->context
->tmpNsNr
] != NULL
) {
8417 ctxt
->context
->tmpNsNr
++;
8420 return((xmlNodePtr
) xmlXPathXMLNamespace
);
8422 if (ctxt
->context
->tmpNsNr
> 0) {
8423 return (xmlNodePtr
)ctxt
->context
->tmpNsList
[--ctxt
->context
->tmpNsNr
];
8425 if (ctxt
->context
->tmpNsList
!= NULL
)
8426 xmlFree(ctxt
->context
->tmpNsList
);
8427 ctxt
->context
->tmpNsList
= NULL
;
8433 * xmlXPathNextAttribute:
8434 * @ctxt: the XPath Parser context
8435 * @cur: the current attribute in the traversal
8437 * Traversal function for the "attribute" direction
8438 * TODO: support DTD inherited default attributes
8440 * Returns the next element following that axis
8443 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8444 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8445 if (ctxt
->context
->node
== NULL
)
8447 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
)
8450 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
8452 return((xmlNodePtr
)ctxt
->context
->node
->properties
);
8454 return((xmlNodePtr
)cur
->next
);
8457 /************************************************************************
8459 * NodeTest Functions *
8461 ************************************************************************/
8463 #define IS_FUNCTION 200
8466 /************************************************************************
8468 * Implicit tree core function library *
8470 ************************************************************************/
8474 * @ctxt: the XPath Parser context
8476 * Initialize the context to the root of the document
8479 xmlXPathRoot(xmlXPathParserContextPtr ctxt
) {
8480 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8482 ctxt
->context
->node
= (xmlNodePtr
) ctxt
->context
->doc
;
8483 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8484 ctxt
->context
->node
));
8487 /************************************************************************
8489 * The explicit core function library *
8490 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8492 ************************************************************************/
8496 * xmlXPathLastFunction:
8497 * @ctxt: the XPath Parser context
8498 * @nargs: the number of arguments
8500 * Implement the last() XPath function
8502 * The last function returns the number of nodes in the context node list.
8505 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8507 if (ctxt
->context
->contextSize
>= 0) {
8509 xmlXPathCacheNewFloat(ctxt
->context
,
8510 (double) ctxt
->context
->contextSize
));
8512 xmlGenericError(xmlGenericErrorContext
,
8513 "last() : %d\n", ctxt
->context
->contextSize
);
8516 XP_ERROR(XPATH_INVALID_CTXT_SIZE
);
8521 * xmlXPathPositionFunction:
8522 * @ctxt: the XPath Parser context
8523 * @nargs: the number of arguments
8525 * Implement the position() XPath function
8527 * The position function returns the position of the context node in the
8528 * context node list. The first position is 1, and so the last position
8529 * will be equal to last().
8532 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8534 if (ctxt
->context
->proximityPosition
>= 0) {
8536 xmlXPathCacheNewFloat(ctxt
->context
,
8537 (double) ctxt
->context
->proximityPosition
));
8539 xmlGenericError(xmlGenericErrorContext
, "position() : %d\n",
8540 ctxt
->context
->proximityPosition
);
8543 XP_ERROR(XPATH_INVALID_CTXT_POSITION
);
8548 * xmlXPathCountFunction:
8549 * @ctxt: the XPath Parser context
8550 * @nargs: the number of arguments
8552 * Implement the count() XPath function
8553 * number count(node-set)
8556 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8557 xmlXPathObjectPtr cur
;
8560 if ((ctxt
->value
== NULL
) ||
8561 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8562 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8563 XP_ERROR(XPATH_INVALID_TYPE
);
8564 cur
= valuePop(ctxt
);
8566 if ((cur
== NULL
) || (cur
->nodesetval
== NULL
))
8567 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8568 else if ((cur
->type
== XPATH_NODESET
) || (cur
->type
== XPATH_XSLT_TREE
)) {
8569 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8570 (double) cur
->nodesetval
->nodeNr
));
8572 if ((cur
->nodesetval
->nodeNr
!= 1) ||
8573 (cur
->nodesetval
->nodeTab
== NULL
)) {
8574 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8579 tmp
= cur
->nodesetval
->nodeTab
[0];
8580 if ((tmp
!= NULL
) && (tmp
->type
!= XML_NAMESPACE_DECL
)) {
8581 tmp
= tmp
->children
;
8582 while (tmp
!= NULL
) {
8587 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) i
));
8590 xmlXPathReleaseObject(ctxt
->context
, cur
);
8594 * xmlXPathGetElementsByIds:
8595 * @doc: the document
8596 * @ids: a whitespace separated list of IDs
8598 * Selects elements by their unique ID.
8600 * Returns a node-set of selected elements.
8602 static xmlNodeSetPtr
8603 xmlXPathGetElementsByIds (xmlDocPtr doc
, const xmlChar
*ids
) {
8605 const xmlChar
*cur
= ids
;
8608 xmlNodePtr elem
= NULL
;
8610 if (ids
== NULL
) return(NULL
);
8612 ret
= xmlXPathNodeSetCreate(NULL
);
8616 while (IS_BLANK_CH(*cur
)) cur
++;
8618 while ((!IS_BLANK_CH(*cur
)) && (*cur
!= 0))
8621 ID
= xmlStrndup(ids
, cur
- ids
);
8624 * We used to check the fact that the value passed
8625 * was an NCName, but this generated much troubles for
8626 * me and Aleksey Sanin, people blatantly violated that
8627 * constaint, like Visa3D spec.
8628 * if (xmlValidateNCName(ID, 1) == 0)
8630 attr
= xmlGetID(doc
, ID
);
8632 if (attr
->type
== XML_ATTRIBUTE_NODE
)
8633 elem
= attr
->parent
;
8634 else if (attr
->type
== XML_ELEMENT_NODE
)
8635 elem
= (xmlNodePtr
) attr
;
8639 xmlXPathNodeSetAdd(ret
, elem
);
8644 while (IS_BLANK_CH(*cur
)) cur
++;
8651 * xmlXPathIdFunction:
8652 * @ctxt: the XPath Parser context
8653 * @nargs: the number of arguments
8655 * Implement the id() XPath function
8656 * node-set id(object)
8657 * The id function selects elements by their unique ID
8658 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8659 * then the result is the union of the result of applying id to the
8660 * string value of each of the nodes in the argument node-set. When the
8661 * argument to id is of any other type, the argument is converted to a
8662 * string as if by a call to the string function; the string is split
8663 * into a whitespace-separated list of tokens (whitespace is any sequence
8664 * of characters matching the production S); the result is a node-set
8665 * containing the elements in the same document as the context node that
8666 * have a unique ID equal to any of the tokens in the list.
8669 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8672 xmlXPathObjectPtr obj
;
8675 obj
= valuePop(ctxt
);
8676 if (obj
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8677 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
8681 ret
= xmlXPathNodeSetCreate(NULL
);
8683 * FIXME -- in an out-of-memory condition this will behave badly.
8684 * The solution is not clear -- we already popped an item from
8685 * ctxt, so the object is in a corrupt state.
8688 if (obj
->nodesetval
!= NULL
) {
8689 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
8691 xmlXPathCastNodeToString(obj
->nodesetval
->nodeTab
[i
]);
8692 ns
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, tokens
);
8693 ret
= xmlXPathNodeSetMerge(ret
, ns
);
8694 xmlXPathFreeNodeSet(ns
);
8699 xmlXPathReleaseObject(ctxt
->context
, obj
);
8700 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8703 obj
= xmlXPathCacheConvertString(ctxt
->context
, obj
);
8704 ret
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, obj
->stringval
);
8705 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8706 xmlXPathReleaseObject(ctxt
->context
, obj
);
8711 * xmlXPathLocalNameFunction:
8712 * @ctxt: the XPath Parser context
8713 * @nargs: the number of arguments
8715 * Implement the local-name() XPath function
8716 * string local-name(node-set?)
8717 * The local-name function returns a string containing the local part
8718 * of the name of the node in the argument node-set that is first in
8719 * document order. If the node-set is empty or the first node has no
8720 * name, an empty string is returned. If the argument is omitted it
8721 * defaults to the context node.
8724 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8725 xmlXPathObjectPtr cur
;
8727 if (ctxt
== NULL
) return;
8730 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8731 ctxt
->context
->node
));
8736 if ((ctxt
->value
== NULL
) ||
8737 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8738 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8739 XP_ERROR(XPATH_INVALID_TYPE
);
8740 cur
= valuePop(ctxt
);
8742 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8743 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8745 int i
= 0; /* Should be first in document order !!!!! */
8746 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8747 case XML_ELEMENT_NODE
:
8748 case XML_ATTRIBUTE_NODE
:
8750 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8751 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8754 xmlXPathCacheNewString(ctxt
->context
,
8755 cur
->nodesetval
->nodeTab
[i
]->name
));
8757 case XML_NAMESPACE_DECL
:
8758 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8759 ((xmlNsPtr
)cur
->nodesetval
->nodeTab
[i
])->prefix
));
8762 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8765 xmlXPathReleaseObject(ctxt
->context
, cur
);
8769 * xmlXPathNamespaceURIFunction:
8770 * @ctxt: the XPath Parser context
8771 * @nargs: the number of arguments
8773 * Implement the namespace-uri() XPath function
8774 * string namespace-uri(node-set?)
8775 * The namespace-uri function returns a string containing the
8776 * namespace URI of the expanded name of the node in the argument
8777 * node-set that is first in document order. If the node-set is empty,
8778 * the first node has no name, or the expanded name has no namespace
8779 * URI, an empty string is returned. If the argument is omitted it
8780 * defaults to the context node.
8783 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8784 xmlXPathObjectPtr cur
;
8786 if (ctxt
== NULL
) return;
8789 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8790 ctxt
->context
->node
));
8794 if ((ctxt
->value
== NULL
) ||
8795 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8796 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8797 XP_ERROR(XPATH_INVALID_TYPE
);
8798 cur
= valuePop(ctxt
);
8800 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8801 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8803 int i
= 0; /* Should be first in document order !!!!! */
8804 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8805 case XML_ELEMENT_NODE
:
8806 case XML_ATTRIBUTE_NODE
:
8807 if (cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
)
8808 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8810 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8811 cur
->nodesetval
->nodeTab
[i
]->ns
->href
));
8814 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8817 xmlXPathReleaseObject(ctxt
->context
, cur
);
8821 * xmlXPathNameFunction:
8822 * @ctxt: the XPath Parser context
8823 * @nargs: the number of arguments
8825 * Implement the name() XPath function
8826 * string name(node-set?)
8827 * The name function returns a string containing a QName representing
8828 * the name of the node in the argument node-set that is first in document
8829 * order. The QName must represent the name with respect to the namespace
8830 * declarations in effect on the node whose name is being represented.
8831 * Typically, this will be the form in which the name occurred in the XML
8832 * source. This need not be the case if there are namespace declarations
8833 * in effect on the node that associate multiple prefixes with the same
8834 * namespace. However, an implementation may include information about
8835 * the original prefix in its representation of nodes; in this case, an
8836 * implementation can ensure that the returned string is always the same
8837 * as the QName used in the XML source. If the argument it omitted it
8838 * defaults to the context node.
8839 * Libxml keep the original prefix so the "real qualified name" used is
8843 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
8845 xmlXPathObjectPtr cur
;
8848 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8849 ctxt
->context
->node
));
8854 if ((ctxt
->value
== NULL
) ||
8855 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8856 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8857 XP_ERROR(XPATH_INVALID_TYPE
);
8858 cur
= valuePop(ctxt
);
8860 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8861 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8863 int i
= 0; /* Should be first in document order !!!!! */
8865 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8866 case XML_ELEMENT_NODE
:
8867 case XML_ATTRIBUTE_NODE
:
8868 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8870 xmlXPathCacheNewCString(ctxt
->context
, ""));
8871 else if ((cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
) ||
8872 (cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
== NULL
)) {
8874 xmlXPathCacheNewString(ctxt
->context
,
8875 cur
->nodesetval
->nodeTab
[i
]->name
));
8879 fullname
= xmlBuildQName(cur
->nodesetval
->nodeTab
[i
]->name
,
8880 cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
,
8882 if (fullname
== cur
->nodesetval
->nodeTab
[i
]->name
)
8883 fullname
= xmlStrdup(cur
->nodesetval
->nodeTab
[i
]->name
);
8884 if (fullname
== NULL
) {
8885 XP_ERROR(XPATH_MEMORY_ERROR
);
8887 valuePush(ctxt
, xmlXPathCacheWrapString(
8888 ctxt
->context
, fullname
));
8892 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8893 cur
->nodesetval
->nodeTab
[i
]));
8894 xmlXPathLocalNameFunction(ctxt
, 1);
8897 xmlXPathReleaseObject(ctxt
->context
, cur
);
8902 * xmlXPathStringFunction:
8903 * @ctxt: the XPath Parser context
8904 * @nargs: the number of arguments
8906 * Implement the string() XPath function
8907 * string string(object?)
8908 * The string function converts an object to a string as follows:
8909 * - A node-set is converted to a string by returning the value of
8910 * the node in the node-set that is first in document order.
8911 * If the node-set is empty, an empty string is returned.
8912 * - A number is converted to a string as follows
8913 * + NaN is converted to the string NaN
8914 * + positive zero is converted to the string 0
8915 * + negative zero is converted to the string 0
8916 * + positive infinity is converted to the string Infinity
8917 * + negative infinity is converted to the string -Infinity
8918 * + if the number is an integer, the number is represented in
8919 * decimal form as a Number with no decimal point and no leading
8920 * zeros, preceded by a minus sign (-) if the number is negative
8921 * + otherwise, the number is represented in decimal form as a
8922 * Number including a decimal point with at least one digit
8923 * before the decimal point and at least one digit after the
8924 * decimal point, preceded by a minus sign (-) if the number
8925 * is negative; there must be no leading zeros before the decimal
8926 * point apart possibly from the one required digit immediately
8927 * before the decimal point; beyond the one required digit
8928 * after the decimal point there must be as many, but only as
8929 * many, more digits as are needed to uniquely distinguish the
8930 * number from all other IEEE 754 numeric values.
8931 * - The boolean false value is converted to the string false.
8932 * The boolean true value is converted to the string true.
8934 * If the argument is omitted, it defaults to a node-set with the
8935 * context node as its only member.
8938 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8939 xmlXPathObjectPtr cur
;
8941 if (ctxt
== NULL
) return;
8944 xmlXPathCacheWrapString(ctxt
->context
,
8945 xmlXPathCastNodeToString(ctxt
->context
->node
)));
8950 cur
= valuePop(ctxt
);
8951 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8952 valuePush(ctxt
, xmlXPathCacheConvertString(ctxt
->context
, cur
));
8956 * xmlXPathStringLengthFunction:
8957 * @ctxt: the XPath Parser context
8958 * @nargs: the number of arguments
8960 * Implement the string-length() XPath function
8961 * number string-length(string?)
8962 * The string-length returns the number of characters in the string
8963 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8964 * the context node converted to a string, in other words the value
8965 * of the context node.
8968 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8969 xmlXPathObjectPtr cur
;
8972 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8974 if (ctxt
->context
->node
== NULL
) {
8975 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0));
8979 content
= xmlXPathCastNodeToString(ctxt
->context
->node
);
8980 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8981 xmlUTF8Strlen(content
)));
8988 CHECK_TYPE(XPATH_STRING
);
8989 cur
= valuePop(ctxt
);
8990 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8991 xmlUTF8Strlen(cur
->stringval
)));
8992 xmlXPathReleaseObject(ctxt
->context
, cur
);
8996 * xmlXPathConcatFunction:
8997 * @ctxt: the XPath Parser context
8998 * @nargs: the number of arguments
9000 * Implement the concat() XPath function
9001 * string concat(string, string, string*)
9002 * The concat function returns the concatenation of its arguments.
9005 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9006 xmlXPathObjectPtr cur
, newobj
;
9009 if (ctxt
== NULL
) return;
9015 cur
= valuePop(ctxt
);
9016 if ((cur
== NULL
) || (cur
->type
!= XPATH_STRING
)) {
9017 xmlXPathReleaseObject(ctxt
->context
, cur
);
9024 newobj
= valuePop(ctxt
);
9025 if ((newobj
== NULL
) || (newobj
->type
!= XPATH_STRING
)) {
9026 xmlXPathReleaseObject(ctxt
->context
, newobj
);
9027 xmlXPathReleaseObject(ctxt
->context
, cur
);
9028 XP_ERROR(XPATH_INVALID_TYPE
);
9030 tmp
= xmlStrcat(newobj
->stringval
, cur
->stringval
);
9031 newobj
->stringval
= cur
->stringval
;
9032 cur
->stringval
= tmp
;
9033 xmlXPathReleaseObject(ctxt
->context
, newobj
);
9036 valuePush(ctxt
, cur
);
9040 * xmlXPathContainsFunction:
9041 * @ctxt: the XPath Parser context
9042 * @nargs: the number of arguments
9044 * Implement the contains() XPath function
9045 * boolean contains(string, string)
9046 * The contains function returns true if the first argument string
9047 * contains the second argument string, and otherwise returns false.
9050 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9051 xmlXPathObjectPtr hay
, needle
;
9055 CHECK_TYPE(XPATH_STRING
);
9056 needle
= valuePop(ctxt
);
9058 hay
= valuePop(ctxt
);
9060 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9061 xmlXPathReleaseObject(ctxt
->context
, hay
);
9062 xmlXPathReleaseObject(ctxt
->context
, needle
);
9063 XP_ERROR(XPATH_INVALID_TYPE
);
9065 if (xmlStrstr(hay
->stringval
, needle
->stringval
))
9066 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9068 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9069 xmlXPathReleaseObject(ctxt
->context
, hay
);
9070 xmlXPathReleaseObject(ctxt
->context
, needle
);
9074 * xmlXPathStartsWithFunction:
9075 * @ctxt: the XPath Parser context
9076 * @nargs: the number of arguments
9078 * Implement the starts-with() XPath function
9079 * boolean starts-with(string, string)
9080 * The starts-with function returns true if the first argument string
9081 * starts with the second argument string, and otherwise returns false.
9084 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9085 xmlXPathObjectPtr hay
, needle
;
9090 CHECK_TYPE(XPATH_STRING
);
9091 needle
= valuePop(ctxt
);
9093 hay
= valuePop(ctxt
);
9095 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9096 xmlXPathReleaseObject(ctxt
->context
, hay
);
9097 xmlXPathReleaseObject(ctxt
->context
, needle
);
9098 XP_ERROR(XPATH_INVALID_TYPE
);
9100 n
= xmlStrlen(needle
->stringval
);
9101 if (xmlStrncmp(hay
->stringval
, needle
->stringval
, n
))
9102 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9104 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9105 xmlXPathReleaseObject(ctxt
->context
, hay
);
9106 xmlXPathReleaseObject(ctxt
->context
, needle
);
9110 * xmlXPathSubstringFunction:
9111 * @ctxt: the XPath Parser context
9112 * @nargs: the number of arguments
9114 * Implement the substring() XPath function
9115 * string substring(string, number, number?)
9116 * The substring function returns the substring of the first argument
9117 * starting at the position specified in the second argument with
9118 * length specified in the third argument. For example,
9119 * substring("12345",2,3) returns "234". If the third argument is not
9120 * specified, it returns the substring starting at the position specified
9121 * in the second argument and continuing to the end of the string. For
9122 * example, substring("12345",2) returns "2345". More precisely, each
9123 * character in the string (see [3.6 Strings]) is considered to have a
9124 * numeric position: the position of the first character is 1, the position
9125 * of the second character is 2 and so on. The returned substring contains
9126 * those characters for which the position of the character is greater than
9127 * or equal to the second argument and, if the third argument is specified,
9128 * less than the sum of the second and third arguments; the comparisons
9129 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9130 * - substring("12345", 1.5, 2.6) returns "234"
9131 * - substring("12345", 0, 3) returns "12"
9132 * - substring("12345", 0 div 0, 3) returns ""
9133 * - substring("12345", 1, 0 div 0) returns ""
9134 * - substring("12345", -42, 1 div 0) returns "12345"
9135 * - substring("12345", -1 div 0, 1 div 0) returns ""
9138 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9139 xmlXPathObjectPtr str
, start
, len
;
9151 * take care of possible last (position) argument
9155 CHECK_TYPE(XPATH_NUMBER
);
9156 len
= valuePop(ctxt
);
9158 xmlXPathReleaseObject(ctxt
->context
, len
);
9162 CHECK_TYPE(XPATH_NUMBER
);
9163 start
= valuePop(ctxt
);
9164 in
= start
->floatval
;
9165 xmlXPathReleaseObject(ctxt
->context
, start
);
9167 CHECK_TYPE(XPATH_STRING
);
9168 str
= valuePop(ctxt
);
9169 m
= xmlUTF8Strlen((const unsigned char *)str
->stringval
);
9172 * If last pos not present, calculate last position
9180 /* Need to check for the special cases where either
9181 * the index is NaN, the length is NaN, or both
9182 * arguments are infinity (relying on Inf + -Inf = NaN)
9184 if (!xmlXPathIsInf(in
) && !xmlXPathIsNaN(in
+ le
)) {
9186 * To meet the requirements of the spec, the arguments
9187 * must be converted to integer format before
9188 * initial index calculations are done
9190 * First we go to integer form, rounding up
9191 * and checking for special cases
9194 if (((double)i
)+0.5 <= in
) i
++;
9196 if (xmlXPathIsInf(le
) == 1) {
9201 else if (xmlXPathIsInf(le
) == -1 || le
< 0.0)
9205 if (((double)l
)+0.5 <= le
) l
++;
9208 /* Now we normalize inidices */
9216 /* number of chars to copy */
9219 ret
= xmlUTF8Strsub(str
->stringval
, i
, l
);
9225 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
9227 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, ret
));
9230 xmlXPathReleaseObject(ctxt
->context
, str
);
9234 * xmlXPathSubstringBeforeFunction:
9235 * @ctxt: the XPath Parser context
9236 * @nargs: the number of arguments
9238 * Implement the substring-before() XPath function
9239 * string substring-before(string, string)
9240 * The substring-before function returns the substring of the first
9241 * argument string that precedes the first occurrence of the second
9242 * argument string in the first argument string, or the empty string
9243 * if the first argument string does not contain the second argument
9244 * string. For example, substring-before("1999/04/01","/") returns 1999.
9247 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9248 xmlXPathObjectPtr str
;
9249 xmlXPathObjectPtr find
;
9251 const xmlChar
*point
;
9256 find
= valuePop(ctxt
);
9258 str
= valuePop(ctxt
);
9260 target
= xmlBufCreate();
9262 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9264 offset
= (int)(point
- str
->stringval
);
9265 xmlBufAdd(target
, str
->stringval
, offset
);
9267 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9268 xmlBufContent(target
)));
9271 xmlXPathReleaseObject(ctxt
->context
, str
);
9272 xmlXPathReleaseObject(ctxt
->context
, find
);
9276 * xmlXPathSubstringAfterFunction:
9277 * @ctxt: the XPath Parser context
9278 * @nargs: the number of arguments
9280 * Implement the substring-after() XPath function
9281 * string substring-after(string, string)
9282 * The substring-after function returns the substring of the first
9283 * argument string that follows the first occurrence of the second
9284 * argument string in the first argument string, or the empty stringi
9285 * if the first argument string does not contain the second argument
9286 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9287 * and substring-after("1999/04/01","19") returns 99/04/01.
9290 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9291 xmlXPathObjectPtr str
;
9292 xmlXPathObjectPtr find
;
9294 const xmlChar
*point
;
9299 find
= valuePop(ctxt
);
9301 str
= valuePop(ctxt
);
9303 target
= xmlBufCreate();
9305 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9307 offset
= (int)(point
- str
->stringval
) + xmlStrlen(find
->stringval
);
9308 xmlBufAdd(target
, &str
->stringval
[offset
],
9309 xmlStrlen(str
->stringval
) - offset
);
9311 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9312 xmlBufContent(target
)));
9315 xmlXPathReleaseObject(ctxt
->context
, str
);
9316 xmlXPathReleaseObject(ctxt
->context
, find
);
9320 * xmlXPathNormalizeFunction:
9321 * @ctxt: the XPath Parser context
9322 * @nargs: the number of arguments
9324 * Implement the normalize-space() XPath function
9325 * string normalize-space(string?)
9326 * The normalize-space function returns the argument string with white
9327 * space normalized by stripping leading and trailing whitespace
9328 * and replacing sequences of whitespace characters by a single
9329 * space. Whitespace characters are the same allowed by the S production
9330 * in XML. If the argument is omitted, it defaults to the context
9331 * node converted to a string, in other words the value of the context node.
9334 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9335 xmlXPathObjectPtr obj
= NULL
;
9336 xmlChar
*source
= NULL
;
9340 if (ctxt
== NULL
) return;
9342 /* Use current context node */
9344 xmlXPathCacheWrapString(ctxt
->context
,
9345 xmlXPathCastNodeToString(ctxt
->context
->node
)));
9351 CHECK_TYPE(XPATH_STRING
);
9352 obj
= valuePop(ctxt
);
9353 source
= obj
->stringval
;
9355 target
= xmlBufCreate();
9356 if (target
&& source
) {
9358 /* Skip leading whitespaces */
9359 while (IS_BLANK_CH(*source
))
9362 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9365 if (IS_BLANK_CH(*source
)) {
9369 xmlBufAdd(target
, &blank
, 1);
9372 xmlBufAdd(target
, source
, 1);
9376 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9377 xmlBufContent(target
)));
9380 xmlXPathReleaseObject(ctxt
->context
, obj
);
9384 * xmlXPathTranslateFunction:
9385 * @ctxt: the XPath Parser context
9386 * @nargs: the number of arguments
9388 * Implement the translate() XPath function
9389 * string translate(string, string, string)
9390 * The translate function returns the first argument string with
9391 * occurrences of characters in the second argument string replaced
9392 * by the character at the corresponding position in the third argument
9393 * string. For example, translate("bar","abc","ABC") returns the string
9394 * BAr. If there is a character in the second argument string with no
9395 * character at a corresponding position in the third argument string
9396 * (because the second argument string is longer than the third argument
9397 * string), then occurrences of that character in the first argument
9398 * string are removed. For example, translate("--aaa--","abc-","ABC")
9399 * returns "AAA". If a character occurs more than once in second
9400 * argument string, then the first occurrence determines the replacement
9401 * character. If the third argument string is longer than the second
9402 * argument string, then excess characters are ignored.
9405 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9406 xmlXPathObjectPtr str
;
9407 xmlXPathObjectPtr from
;
9408 xmlXPathObjectPtr to
;
9412 const xmlChar
*point
;
9418 to
= valuePop(ctxt
);
9420 from
= valuePop(ctxt
);
9422 str
= valuePop(ctxt
);
9424 target
= xmlBufCreate();
9426 max
= xmlUTF8Strlen(to
->stringval
);
9427 for (cptr
= str
->stringval
; (ch
=*cptr
); ) {
9428 offset
= xmlUTF8Strloc(from
->stringval
, cptr
);
9431 point
= xmlUTF8Strpos(to
->stringval
, offset
);
9433 xmlBufAdd(target
, point
, xmlUTF8Strsize(point
, 1));
9436 xmlBufAdd(target
, cptr
, xmlUTF8Strsize(cptr
, 1));
9438 /* Step to next character in input */
9441 /* if not simple ascii, verify proper format */
9442 if ( (ch
& 0xc0) != 0xc0 ) {
9443 xmlGenericError(xmlGenericErrorContext
,
9444 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9445 /* not asserting an XPath error is probably better */
9448 /* then skip over remaining bytes for this char */
9449 while ( (ch
<<= 1) & 0x80 )
9450 if ( (*cptr
++ & 0xc0) != 0x80 ) {
9451 xmlGenericError(xmlGenericErrorContext
,
9452 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9453 /* not asserting an XPath error is probably better */
9456 if (ch
& 0x80) /* must have had error encountered */
9461 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9462 xmlBufContent(target
)));
9464 xmlXPathReleaseObject(ctxt
->context
, str
);
9465 xmlXPathReleaseObject(ctxt
->context
, from
);
9466 xmlXPathReleaseObject(ctxt
->context
, to
);
9470 * xmlXPathBooleanFunction:
9471 * @ctxt: the XPath Parser context
9472 * @nargs: the number of arguments
9474 * Implement the boolean() XPath function
9475 * boolean boolean(object)
9476 * The boolean function converts its argument to a boolean as follows:
9477 * - a number is true if and only if it is neither positive or
9478 * negative zero nor NaN
9479 * - a node-set is true if and only if it is non-empty
9480 * - a string is true if and only if its length is non-zero
9483 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9484 xmlXPathObjectPtr cur
;
9487 cur
= valuePop(ctxt
);
9488 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
9489 cur
= xmlXPathCacheConvertBoolean(ctxt
->context
, cur
);
9490 valuePush(ctxt
, cur
);
9494 * xmlXPathNotFunction:
9495 * @ctxt: the XPath Parser context
9496 * @nargs: the number of arguments
9498 * Implement the not() XPath function
9499 * boolean not(boolean)
9500 * The not function returns true if its argument is false,
9501 * and false otherwise.
9504 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9507 CHECK_TYPE(XPATH_BOOLEAN
);
9508 ctxt
->value
->boolval
= ! ctxt
->value
->boolval
;
9512 * xmlXPathTrueFunction:
9513 * @ctxt: the XPath Parser context
9514 * @nargs: the number of arguments
9516 * Implement the true() XPath function
9520 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9522 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9526 * xmlXPathFalseFunction:
9527 * @ctxt: the XPath Parser context
9528 * @nargs: the number of arguments
9530 * Implement the false() XPath function
9534 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9536 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9540 * xmlXPathLangFunction:
9541 * @ctxt: the XPath Parser context
9542 * @nargs: the number of arguments
9544 * Implement the lang() XPath function
9545 * boolean lang(string)
9546 * The lang function returns true or false depending on whether the
9547 * language of the context node as specified by xml:lang attributes
9548 * is the same as or is a sublanguage of the language specified by
9549 * the argument string. The language of the context node is determined
9550 * by the value of the xml:lang attribute on the context node, or, if
9551 * the context node has no xml:lang attribute, by the value of the
9552 * xml:lang attribute on the nearest ancestor of the context node that
9553 * has an xml:lang attribute. If there is no such attribute, then lang
9554 * returns false. If there is such an attribute, then lang returns
9555 * true if the attribute value is equal to the argument ignoring case,
9556 * or if there is some suffix starting with - such that the attribute
9557 * value is equal to the argument ignoring that suffix of the attribute
9558 * value and ignoring case.
9561 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9562 xmlXPathObjectPtr val
= NULL
;
9563 const xmlChar
*theLang
= NULL
;
9564 const xmlChar
*lang
;
9570 CHECK_TYPE(XPATH_STRING
);
9571 val
= valuePop(ctxt
);
9572 lang
= val
->stringval
;
9573 theLang
= xmlNodeGetLang(ctxt
->context
->node
);
9574 if ((theLang
!= NULL
) && (lang
!= NULL
)) {
9575 for (i
= 0;lang
[i
] != 0;i
++)
9576 if (toupper(lang
[i
]) != toupper(theLang
[i
]))
9578 if ((theLang
[i
] == 0) || (theLang
[i
] == '-'))
9582 if (theLang
!= NULL
)
9583 xmlFree((void *)theLang
);
9585 xmlXPathReleaseObject(ctxt
->context
, val
);
9586 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
9590 * xmlXPathNumberFunction:
9591 * @ctxt: the XPath Parser context
9592 * @nargs: the number of arguments
9594 * Implement the number() XPath function
9595 * number number(object?)
9598 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9599 xmlXPathObjectPtr cur
;
9602 if (ctxt
== NULL
) return;
9604 if (ctxt
->context
->node
== NULL
) {
9605 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0.0));
9607 xmlChar
* content
= xmlNodeGetContent(ctxt
->context
->node
);
9609 res
= xmlXPathStringEvalNumber(content
);
9610 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9617 cur
= valuePop(ctxt
);
9618 valuePush(ctxt
, xmlXPathCacheConvertNumber(ctxt
->context
, cur
));
9622 * xmlXPathSumFunction:
9623 * @ctxt: the XPath Parser context
9624 * @nargs: the number of arguments
9626 * Implement the sum() XPath function
9627 * number sum(node-set)
9628 * The sum function returns the sum of the values of the nodes in
9629 * the argument node-set.
9632 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9633 xmlXPathObjectPtr cur
;
9638 if ((ctxt
->value
== NULL
) ||
9639 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
9640 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
9641 XP_ERROR(XPATH_INVALID_TYPE
);
9642 cur
= valuePop(ctxt
);
9644 if ((cur
->nodesetval
!= NULL
) && (cur
->nodesetval
->nodeNr
!= 0)) {
9645 for (i
= 0; i
< cur
->nodesetval
->nodeNr
; i
++) {
9646 res
+= xmlXPathCastNodeToNumber(cur
->nodesetval
->nodeTab
[i
]);
9649 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9650 xmlXPathReleaseObject(ctxt
->context
, cur
);
9654 * xmlXPathFloorFunction:
9655 * @ctxt: the XPath Parser context
9656 * @nargs: the number of arguments
9658 * Implement the floor() XPath function
9659 * number floor(number)
9660 * The floor function returns the largest (closest to positive infinity)
9661 * number that is not greater than the argument and that is an integer.
9664 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9667 CHECK_TYPE(XPATH_NUMBER
);
9669 ctxt
->value
->floatval
= floor(ctxt
->value
->floatval
);
9673 * xmlXPathCeilingFunction:
9674 * @ctxt: the XPath Parser context
9675 * @nargs: the number of arguments
9677 * Implement the ceiling() XPath function
9678 * number ceiling(number)
9679 * The ceiling function returns the smallest (closest to negative infinity)
9680 * number that is not less than the argument and that is an integer.
9683 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9686 CHECK_TYPE(XPATH_NUMBER
);
9688 ctxt
->value
->floatval
= ceil(ctxt
->value
->floatval
);
9692 * xmlXPathRoundFunction:
9693 * @ctxt: the XPath Parser context
9694 * @nargs: the number of arguments
9696 * Implement the round() XPath function
9697 * number round(number)
9698 * The round function returns the number that is closest to the
9699 * argument and that is an integer. If there are two such numbers,
9700 * then the one that is closest to positive infinity is returned.
9703 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9708 CHECK_TYPE(XPATH_NUMBER
);
9710 f
= ctxt
->value
->floatval
;
9712 if ((f
>= -0.5) && (f
< 0.5)) {
9713 /* Handles negative zero. */
9714 ctxt
->value
->floatval
*= 0.0;
9717 double rounded
= floor(f
);
9718 if (f
- rounded
>= 0.5)
9720 ctxt
->value
->floatval
= rounded
;
9724 /************************************************************************
9728 ************************************************************************/
9731 * a few forward declarations since we use a recursive call based
9734 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
);
9735 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
);
9736 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
);
9737 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt
);
9738 static xmlChar
* xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
,
9742 * xmlXPathCurrentChar:
9743 * @ctxt: the XPath parser context
9744 * @cur: pointer to the beginning of the char
9745 * @len: pointer to the length of the char read
9747 * The current char value, if using UTF-8 this may actually span multiple
9748 * bytes in the input buffer.
9750 * Returns the current char value and its length
9754 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt
, int *len
) {
9764 * We are supposed to handle UTF8, check it's valid
9765 * From rfc2044: encoding of the Unicode values on UTF-8:
9767 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9768 * 0000 0000-0000 007F 0xxxxxxx
9769 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9770 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9772 * Check for the 0x110000 limit too
9776 if ((cur
[1] & 0xc0) != 0x80)
9777 goto encoding_error
;
9778 if ((c
& 0xe0) == 0xe0) {
9780 if ((cur
[2] & 0xc0) != 0x80)
9781 goto encoding_error
;
9782 if ((c
& 0xf0) == 0xf0) {
9783 if (((c
& 0xf8) != 0xf0) ||
9784 ((cur
[3] & 0xc0) != 0x80))
9785 goto encoding_error
;
9788 val
= (cur
[0] & 0x7) << 18;
9789 val
|= (cur
[1] & 0x3f) << 12;
9790 val
|= (cur
[2] & 0x3f) << 6;
9791 val
|= cur
[3] & 0x3f;
9795 val
= (cur
[0] & 0xf) << 12;
9796 val
|= (cur
[1] & 0x3f) << 6;
9797 val
|= cur
[2] & 0x3f;
9802 val
= (cur
[0] & 0x1f) << 6;
9803 val
|= cur
[1] & 0x3f;
9805 if (!IS_CHAR(val
)) {
9806 XP_ERROR0(XPATH_INVALID_CHAR_ERROR
);
9816 * If we detect an UTF8 error that probably means that the
9817 * input encoding didn't get properly advertised in the
9818 * declaration header. Report the error and switch the encoding
9819 * to ISO-Latin-1 (if you don't like this policy, just declare the
9823 XP_ERROR0(XPATH_ENCODING_ERROR
);
9827 * xmlXPathParseNCName:
9828 * @ctxt: the XPath Parser context
9830 * parse an XML namespace non qualified name.
9832 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9834 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9835 * CombiningChar | Extender
9837 * Returns the namespace name or NULL
9841 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt
) {
9846 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9848 * Accelerator for simple ASCII names
9851 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9852 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9855 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9856 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9857 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9858 (*in
== '_') || (*in
== '.') ||
9861 if ((*in
== ' ') || (*in
== '>') || (*in
== '/') ||
9862 (*in
== '[') || (*in
== ']') || (*in
== ':') ||
9863 (*in
== '@') || (*in
== '*')) {
9864 count
= in
- ctxt
->cur
;
9867 ret
= xmlStrndup(ctxt
->cur
, count
);
9872 return(xmlXPathParseNameComplex(ctxt
, 0));
9877 * xmlXPathParseQName:
9878 * @ctxt: the XPath Parser context
9879 * @prefix: a xmlChar **
9881 * parse an XML qualified name
9883 * [NS 5] QName ::= (Prefix ':')? LocalPart
9885 * [NS 6] Prefix ::= NCName
9887 * [NS 7] LocalPart ::= NCName
9889 * Returns the function returns the local part, and prefix is updated
9890 * to get the Prefix if any.
9894 xmlXPathParseQName(xmlXPathParserContextPtr ctxt
, xmlChar
**prefix
) {
9895 xmlChar
*ret
= NULL
;
9898 ret
= xmlXPathParseNCName(ctxt
);
9899 if (ret
&& CUR
== ':') {
9902 ret
= xmlXPathParseNCName(ctxt
);
9908 * xmlXPathParseName:
9909 * @ctxt: the XPath Parser context
9913 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9914 * CombiningChar | Extender
9916 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9918 * Returns the namespace name or NULL
9922 xmlXPathParseName(xmlXPathParserContextPtr ctxt
) {
9927 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9929 * Accelerator for simple ASCII names
9932 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9933 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9934 (*in
== '_') || (*in
== ':')) {
9936 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9937 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9938 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9939 (*in
== '_') || (*in
== '-') ||
9940 (*in
== ':') || (*in
== '.'))
9942 if ((*in
> 0) && (*in
< 0x80)) {
9943 count
= in
- ctxt
->cur
;
9944 if (count
> XML_MAX_NAME_LENGTH
) {
9946 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9948 ret
= xmlStrndup(ctxt
->cur
, count
);
9953 return(xmlXPathParseNameComplex(ctxt
, 1));
9957 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
, int qualified
) {
9958 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
9963 * Handler for more complex cases
9966 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
9967 (c
== '[') || (c
== ']') || (c
== '@') || /* accelerators */
9968 (c
== '*') || /* accelerators */
9969 (!IS_LETTER(c
) && (c
!= '_') &&
9970 ((!qualified
) || (c
!= ':')))) {
9974 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
9975 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
9976 (c
== '.') || (c
== '-') ||
9977 (c
== '_') || ((qualified
) && (c
== ':')) ||
9978 (IS_COMBINING(c
)) ||
9979 (IS_EXTENDER(c
)))) {
9980 COPY_BUF(l
,buf
,len
,c
);
9983 if (len
>= XML_MAX_NAMELEN
) {
9985 * Okay someone managed to make a huge name, so he's ready to pay
9986 * for the processing speed.
9991 if (len
> XML_MAX_NAME_LENGTH
) {
9992 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9994 buffer
= (xmlChar
*) xmlMallocAtomic(max
* sizeof(xmlChar
));
9995 if (buffer
== NULL
) {
9996 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
9998 memcpy(buffer
, buf
, len
);
9999 while ((IS_LETTER(c
)) || (IS_DIGIT(c
)) || /* test bigname.xml */
10000 (c
== '.') || (c
== '-') ||
10001 (c
== '_') || ((qualified
) && (c
== ':')) ||
10002 (IS_COMBINING(c
)) ||
10003 (IS_EXTENDER(c
))) {
10004 if (len
+ 10 > max
) {
10005 if (max
> XML_MAX_NAME_LENGTH
) {
10006 XP_ERRORNULL(XPATH_EXPR_ERROR
);
10009 buffer
= (xmlChar
*) xmlRealloc(buffer
,
10010 max
* sizeof(xmlChar
));
10011 if (buffer
== NULL
) {
10012 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
10015 COPY_BUF(l
,buffer
,len
,c
);
10025 return(xmlStrndup(buf
, len
));
10028 #define MAX_FRAC 20
10031 * xmlXPathStringEvalNumber:
10032 * @str: A string to scan
10034 * [30a] Float ::= Number ('e' Digits?)?
10036 * [30] Number ::= Digits ('.' Digits?)?
10038 * [31] Digits ::= [0-9]+
10040 * Compile a Number in the string
10041 * In complement of the Number expression, this function also handles
10042 * negative values : '-' Number.
10044 * Returns the double value.
10047 xmlXPathStringEvalNumber(const xmlChar
*str
) {
10048 const xmlChar
*cur
= str
;
10053 int is_exponent_negative
= 0;
10055 unsigned long tmp
= 0;
10058 if (cur
== NULL
) return(0);
10059 while (IS_BLANK_CH(*cur
)) cur
++;
10060 if ((*cur
!= '.') && ((*cur
< '0') || (*cur
> '9')) && (*cur
!= '-')) {
10070 * tmp/temp is a workaround against a gcc compiler bug
10071 * http://veillard.com/gcc.bug
10074 while ((*cur
>= '0') && (*cur
<= '9')) {
10076 tmp
= (*cur
- '0');
10079 temp
= (double) tmp
;
10084 while ((*cur
>= '0') && (*cur
<= '9')) {
10085 ret
= ret
* 10 + (*cur
- '0');
10092 int v
, frac
= 0, max
;
10093 double fraction
= 0;
10096 if (((*cur
< '0') || (*cur
> '9')) && (!ok
)) {
10099 while (*cur
== '0') {
10103 max
= frac
+ MAX_FRAC
;
10104 while (((*cur
>= '0') && (*cur
<= '9')) && (frac
< max
)) {
10106 fraction
= fraction
* 10 + v
;
10110 fraction
/= pow(10.0, frac
);
10111 ret
= ret
+ fraction
;
10112 while ((*cur
>= '0') && (*cur
<= '9'))
10115 if ((*cur
== 'e') || (*cur
== 'E')) {
10118 is_exponent_negative
= 1;
10120 } else if (*cur
== '+') {
10123 while ((*cur
>= '0') && (*cur
<= '9')) {
10124 if (exponent
< 1000000)
10125 exponent
= exponent
* 10 + (*cur
- '0');
10129 while (IS_BLANK_CH(*cur
)) cur
++;
10130 if (*cur
!= 0) return(NAN
);
10131 if (isneg
) ret
= -ret
;
10132 if (is_exponent_negative
) exponent
= -exponent
;
10133 ret
*= pow(10.0, (double)exponent
);
10138 * xmlXPathCompNumber:
10139 * @ctxt: the XPath Parser context
10141 * [30] Number ::= Digits ('.' Digits?)?
10143 * [31] Digits ::= [0-9]+
10145 * Compile a Number, then push it on the stack
10149 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt
)
10154 int is_exponent_negative
= 0;
10156 unsigned long tmp
= 0;
10161 if ((CUR
!= '.') && ((CUR
< '0') || (CUR
> '9'))) {
10162 XP_ERROR(XPATH_NUMBER_ERROR
);
10166 * tmp/temp is a workaround against a gcc compiler bug
10167 * http://veillard.com/gcc.bug
10170 while ((CUR
>= '0') && (CUR
<= '9')) {
10175 temp
= (double) tmp
;
10180 while ((CUR
>= '0') && (CUR
<= '9')) {
10181 ret
= ret
* 10 + (CUR
- '0');
10187 int v
, frac
= 0, max
;
10188 double fraction
= 0;
10191 if (((CUR
< '0') || (CUR
> '9')) && (!ok
)) {
10192 XP_ERROR(XPATH_NUMBER_ERROR
);
10194 while (CUR
== '0') {
10198 max
= frac
+ MAX_FRAC
;
10199 while ((CUR
>= '0') && (CUR
<= '9') && (frac
< max
)) {
10201 fraction
= fraction
* 10 + v
;
10205 fraction
/= pow(10.0, frac
);
10206 ret
= ret
+ fraction
;
10207 while ((CUR
>= '0') && (CUR
<= '9'))
10210 if ((CUR
== 'e') || (CUR
== 'E')) {
10213 is_exponent_negative
= 1;
10215 } else if (CUR
== '+') {
10218 while ((CUR
>= '0') && (CUR
<= '9')) {
10219 if (exponent
< 1000000)
10220 exponent
= exponent
* 10 + (CUR
- '0');
10223 if (is_exponent_negative
)
10224 exponent
= -exponent
;
10225 ret
*= pow(10.0, (double) exponent
);
10227 PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_NUMBER
, 0, 0,
10228 xmlXPathCacheNewFloat(ctxt
->context
, ret
), NULL
);
10232 * xmlXPathParseLiteral:
10233 * @ctxt: the XPath Parser context
10237 * [29] Literal ::= '"' [^"]* '"'
10240 * Returns the value found or NULL in case of error
10243 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt
) {
10245 xmlChar
*ret
= NULL
;
10250 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10252 if (!IS_CHAR_CH(CUR
)) {
10253 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10255 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10258 } else if (CUR
== '\'') {
10261 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10263 if (!IS_CHAR_CH(CUR
)) {
10264 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10266 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10270 XP_ERRORNULL(XPATH_START_LITERAL_ERROR
);
10276 * xmlXPathCompLiteral:
10277 * @ctxt: the XPath Parser context
10279 * Parse a Literal and push it on the stack.
10281 * [29] Literal ::= '"' [^"]* '"'
10284 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10287 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt
) {
10289 xmlChar
*ret
= NULL
;
10294 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10296 if (!IS_CHAR_CH(CUR
)) {
10297 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10299 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10302 } else if (CUR
== '\'') {
10305 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10307 if (!IS_CHAR_CH(CUR
)) {
10308 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10310 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10314 XP_ERROR(XPATH_START_LITERAL_ERROR
);
10316 if (ret
== NULL
) return;
10317 PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_STRING
, 0, 0,
10318 xmlXPathCacheNewString(ctxt
->context
, ret
), NULL
);
10323 * xmlXPathCompVariableReference:
10324 * @ctxt: the XPath Parser context
10326 * Parse a VariableReference, evaluate it and push it on the stack.
10328 * The variable bindings consist of a mapping from variable names
10329 * to variable values. The value of a variable is an object, which can be
10330 * of any of the types that are possible for the value of an expression,
10331 * and may also be of additional types not specified here.
10333 * Early evaluation is possible since:
10334 * The variable bindings [...] used to evaluate a subexpression are
10335 * always the same as those used to evaluate the containing expression.
10337 * [36] VariableReference ::= '$' QName
10340 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt
) {
10346 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10349 name
= xmlXPathParseQName(ctxt
, &prefix
);
10350 if (name
== NULL
) {
10352 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10354 ctxt
->comp
->last
= -1;
10355 PUSH_LONG_EXPR(XPATH_OP_VARIABLE
, 0, 0, 0,
10358 if ((ctxt
->context
!= NULL
) && (ctxt
->context
->flags
& XML_XPATH_NOVAR
)) {
10359 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR
);
10364 * xmlXPathIsNodeType:
10365 * @name: a name string
10367 * Is the name given a NodeType one.
10369 * [38] NodeType ::= 'comment'
10371 * | 'processing-instruction'
10374 * Returns 1 if true 0 otherwise
10377 xmlXPathIsNodeType(const xmlChar
*name
) {
10381 if (xmlStrEqual(name
, BAD_CAST
"node"))
10383 if (xmlStrEqual(name
, BAD_CAST
"text"))
10385 if (xmlStrEqual(name
, BAD_CAST
"comment"))
10387 if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
10393 * xmlXPathCompFunctionCall:
10394 * @ctxt: the XPath Parser context
10396 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10397 * [17] Argument ::= Expr
10399 * Compile a function call, the evaluation of all arguments are
10400 * pushed on the stack
10403 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt
) {
10409 name
= xmlXPathParseQName(ctxt
, &prefix
);
10410 if (name
== NULL
) {
10412 XP_ERROR(XPATH_EXPR_ERROR
);
10416 if (prefix
== NULL
)
10417 xmlGenericError(xmlGenericErrorContext
, "Calling function %s\n",
10420 xmlGenericError(xmlGenericErrorContext
, "Calling function %s:%s\n",
10427 XP_ERROR(XPATH_EXPR_ERROR
);
10433 * Optimization for count(): we don't need the node-set to be sorted.
10435 if ((prefix
== NULL
) && (name
[0] == 'c') &&
10436 xmlStrEqual(name
, BAD_CAST
"count"))
10440 ctxt
->comp
->last
= -1;
10443 int op1
= ctxt
->comp
->last
;
10444 ctxt
->comp
->last
= -1;
10445 xmlXPathCompileExpr(ctxt
, sort
);
10446 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
10451 PUSH_BINARY_EXPR(XPATH_OP_ARG
, op1
, ctxt
->comp
->last
, 0, 0);
10453 if (CUR
== ')') break;
10457 XP_ERROR(XPATH_EXPR_ERROR
);
10463 PUSH_LONG_EXPR(XPATH_OP_FUNCTION
, nbargs
, 0, 0,
10470 * xmlXPathCompPrimaryExpr:
10471 * @ctxt: the XPath Parser context
10473 * [15] PrimaryExpr ::= VariableReference
10479 * Compile a primary expression.
10482 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt
) {
10484 if (CUR
== '$') xmlXPathCompVariableReference(ctxt
);
10485 else if (CUR
== '(') {
10488 xmlXPathCompileExpr(ctxt
, 1);
10491 XP_ERROR(XPATH_EXPR_ERROR
);
10495 } else if (IS_ASCII_DIGIT(CUR
) || (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10496 xmlXPathCompNumber(ctxt
);
10497 } else if ((CUR
== '\'') || (CUR
== '"')) {
10498 xmlXPathCompLiteral(ctxt
);
10500 xmlXPathCompFunctionCall(ctxt
);
10506 * xmlXPathCompFilterExpr:
10507 * @ctxt: the XPath Parser context
10509 * [20] FilterExpr ::= PrimaryExpr
10510 * | FilterExpr Predicate
10512 * Compile a filter expression.
10513 * Square brackets are used to filter expressions in the same way that
10514 * they are used in location paths. It is an error if the expression to
10515 * be filtered does not evaluate to a node-set. The context node list
10516 * used for evaluating the expression in square brackets is the node-set
10517 * to be filtered listed in document order.
10521 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt
) {
10522 xmlXPathCompPrimaryExpr(ctxt
);
10526 while (CUR
== '[') {
10527 xmlXPathCompPredicate(ctxt
, 1);
10535 * xmlXPathScanName:
10536 * @ctxt: the XPath Parser context
10538 * Trickery: parse an XML name but without consuming the input flow
10539 * Needed to avoid insanity in the parser state.
10541 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10542 * CombiningChar | Extender
10544 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10546 * [6] Names ::= Name (S Name)*
10548 * Returns the Name parsed or NULL
10552 xmlXPathScanName(xmlXPathParserContextPtr ctxt
) {
10555 const xmlChar
*cur
;
10561 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
10562 (!IS_LETTER(c
) && (c
!= '_') &&
10567 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
10568 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
10569 (c
== '.') || (c
== '-') ||
10570 (c
== '_') || (c
== ':') ||
10571 (IS_COMBINING(c
)) ||
10572 (IS_EXTENDER(c
)))) {
10577 ret
= xmlStrndup(cur
, ctxt
->cur
- cur
);
10583 * xmlXPathCompPathExpr:
10584 * @ctxt: the XPath Parser context
10586 * [19] PathExpr ::= LocationPath
10588 * | FilterExpr '/' RelativeLocationPath
10589 * | FilterExpr '//' RelativeLocationPath
10591 * Compile a path expression.
10592 * The / operator and // operators combine an arbitrary expression
10593 * and a relative location path. It is an error if the expression
10594 * does not evaluate to a node-set.
10595 * The / operator does composition in the same way as when / is
10596 * used in a location path. As in location paths, // is short for
10597 * /descendant-or-self::node()/.
10601 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt
) {
10602 int lc
= 1; /* Should we branch to LocationPath ? */
10603 xmlChar
*name
= NULL
; /* we may have to preparse a name to find out */
10606 if ((CUR
== '$') || (CUR
== '(') ||
10607 (IS_ASCII_DIGIT(CUR
)) ||
10608 (CUR
== '\'') || (CUR
== '"') ||
10609 (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10611 } else if (CUR
== '*') {
10612 /* relative or absolute location path */
10614 } else if (CUR
== '/') {
10615 /* relative or absolute location path */
10617 } else if (CUR
== '@') {
10618 /* relative abbreviated attribute location path */
10620 } else if (CUR
== '.') {
10621 /* relative abbreviated attribute location path */
10625 * Problem is finding if we have a name here whether it's:
10627 * - a function call in which case it's followed by '('
10628 * - an axis in which case it's followed by ':'
10630 * We do an a priori analysis here rather than having to
10631 * maintain parsed token content through the recursive function
10632 * calls. This looks uglier but makes the code easier to
10633 * read/write/debug.
10636 name
= xmlXPathScanName(ctxt
);
10637 if ((name
!= NULL
) && (xmlStrstr(name
, (xmlChar
*) "::") != NULL
)) {
10639 xmlGenericError(xmlGenericErrorContext
,
10640 "PathExpr: Axis\n");
10644 } else if (name
!= NULL
) {
10645 int len
=xmlStrlen(name
);
10648 while (NXT(len
) != 0) {
10649 if (NXT(len
) == '/') {
10652 xmlGenericError(xmlGenericErrorContext
,
10653 "PathExpr: AbbrRelLocation\n");
10657 } else if (IS_BLANK_CH(NXT(len
))) {
10658 /* ignore blanks */
10660 } else if (NXT(len
) == ':') {
10662 xmlGenericError(xmlGenericErrorContext
,
10663 "PathExpr: AbbrRelLocation\n");
10667 } else if ((NXT(len
) == '(')) {
10668 /* Node Type or Function */
10669 if (xmlXPathIsNodeType(name
)) {
10671 xmlGenericError(xmlGenericErrorContext
,
10672 "PathExpr: Type search\n");
10675 #ifdef LIBXML_XPTR_ENABLED
10676 } else if (ctxt
->xptr
&&
10677 xmlStrEqual(name
, BAD_CAST
"range-to")) {
10682 xmlGenericError(xmlGenericErrorContext
,
10683 "PathExpr: function call\n");
10688 } else if ((NXT(len
) == '[')) {
10691 xmlGenericError(xmlGenericErrorContext
,
10692 "PathExpr: AbbrRelLocation\n");
10696 } else if ((NXT(len
) == '<') || (NXT(len
) == '>') ||
10697 (NXT(len
) == '=')) {
10706 if (NXT(len
) == 0) {
10708 xmlGenericError(xmlGenericErrorContext
,
10709 "PathExpr: AbbrRelLocation\n");
10716 /* make sure all cases are covered explicitly */
10717 XP_ERROR(XPATH_EXPR_ERROR
);
10723 PUSH_LEAVE_EXPR(XPATH_OP_ROOT
, 0, 0);
10725 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10727 xmlXPathCompLocationPath(ctxt
);
10729 xmlXPathCompFilterExpr(ctxt
);
10731 if ((CUR
== '/') && (NXT(1) == '/')) {
10735 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
10736 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
10737 PUSH_UNARY_EXPR(XPATH_OP_RESET
, ctxt
->comp
->last
, 1, 0);
10739 xmlXPathCompRelativeLocationPath(ctxt
);
10740 } else if (CUR
== '/') {
10741 xmlXPathCompRelativeLocationPath(ctxt
);
10748 * xmlXPathCompUnionExpr:
10749 * @ctxt: the XPath Parser context
10751 * [18] UnionExpr ::= PathExpr
10752 * | UnionExpr '|' PathExpr
10754 * Compile an union expression.
10758 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt
) {
10759 xmlXPathCompPathExpr(ctxt
);
10762 while (CUR
== '|') {
10763 int op1
= ctxt
->comp
->last
;
10764 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10768 xmlXPathCompPathExpr(ctxt
);
10770 PUSH_BINARY_EXPR(XPATH_OP_UNION
, op1
, ctxt
->comp
->last
, 0, 0);
10777 * xmlXPathCompUnaryExpr:
10778 * @ctxt: the XPath Parser context
10780 * [27] UnaryExpr ::= UnionExpr
10783 * Compile an unary expression.
10787 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt
) {
10792 while (CUR
== '-') {
10799 xmlXPathCompUnionExpr(ctxt
);
10803 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 2, 0);
10805 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 3, 0);
10810 * xmlXPathCompMultiplicativeExpr:
10811 * @ctxt: the XPath Parser context
10813 * [26] MultiplicativeExpr ::= UnaryExpr
10814 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10815 * | MultiplicativeExpr 'div' UnaryExpr
10816 * | MultiplicativeExpr 'mod' UnaryExpr
10817 * [34] MultiplyOperator ::= '*'
10819 * Compile an Additive expression.
10823 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt
) {
10824 xmlXPathCompUnaryExpr(ctxt
);
10827 while ((CUR
== '*') ||
10828 ((CUR
== 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10829 ((CUR
== 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10831 int op1
= ctxt
->comp
->last
;
10836 } else if (CUR
== 'd') {
10839 } else if (CUR
== 'm') {
10844 xmlXPathCompUnaryExpr(ctxt
);
10846 PUSH_BINARY_EXPR(XPATH_OP_MULT
, op1
, ctxt
->comp
->last
, op
, 0);
10852 * xmlXPathCompAdditiveExpr:
10853 * @ctxt: the XPath Parser context
10855 * [25] AdditiveExpr ::= MultiplicativeExpr
10856 * | AdditiveExpr '+' MultiplicativeExpr
10857 * | AdditiveExpr '-' MultiplicativeExpr
10859 * Compile an Additive expression.
10863 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt
) {
10865 xmlXPathCompMultiplicativeExpr(ctxt
);
10868 while ((CUR
== '+') || (CUR
== '-')) {
10870 int op1
= ctxt
->comp
->last
;
10872 if (CUR
== '+') plus
= 1;
10876 xmlXPathCompMultiplicativeExpr(ctxt
);
10878 PUSH_BINARY_EXPR(XPATH_OP_PLUS
, op1
, ctxt
->comp
->last
, plus
, 0);
10884 * xmlXPathCompRelationalExpr:
10885 * @ctxt: the XPath Parser context
10887 * [24] RelationalExpr ::= AdditiveExpr
10888 * | RelationalExpr '<' AdditiveExpr
10889 * | RelationalExpr '>' AdditiveExpr
10890 * | RelationalExpr '<=' AdditiveExpr
10891 * | RelationalExpr '>=' AdditiveExpr
10893 * A <= B > C is allowed ? Answer from James, yes with
10894 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10895 * which is basically what got implemented.
10897 * Compile a Relational expression, then push the result
10902 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt
) {
10903 xmlXPathCompAdditiveExpr(ctxt
);
10906 while ((CUR
== '<') ||
10908 ((CUR
== '<') && (NXT(1) == '=')) ||
10909 ((CUR
== '>') && (NXT(1) == '='))) {
10911 int op1
= ctxt
->comp
->last
;
10913 if (CUR
== '<') inf
= 1;
10915 if (NXT(1) == '=') strict
= 0;
10920 xmlXPathCompAdditiveExpr(ctxt
);
10922 PUSH_BINARY_EXPR(XPATH_OP_CMP
, op1
, ctxt
->comp
->last
, inf
, strict
);
10928 * xmlXPathCompEqualityExpr:
10929 * @ctxt: the XPath Parser context
10931 * [23] EqualityExpr ::= RelationalExpr
10932 * | EqualityExpr '=' RelationalExpr
10933 * | EqualityExpr '!=' RelationalExpr
10935 * A != B != C is allowed ? Answer from James, yes with
10936 * (RelationalExpr = RelationalExpr) = RelationalExpr
10937 * (RelationalExpr != RelationalExpr) != RelationalExpr
10938 * which is basically what got implemented.
10940 * Compile an Equality expression.
10944 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt
) {
10945 xmlXPathCompRelationalExpr(ctxt
);
10948 while ((CUR
== '=') || ((CUR
== '!') && (NXT(1) == '='))) {
10950 int op1
= ctxt
->comp
->last
;
10952 if (CUR
== '=') eq
= 1;
10957 xmlXPathCompRelationalExpr(ctxt
);
10959 PUSH_BINARY_EXPR(XPATH_OP_EQUAL
, op1
, ctxt
->comp
->last
, eq
, 0);
10965 * xmlXPathCompAndExpr:
10966 * @ctxt: the XPath Parser context
10968 * [22] AndExpr ::= EqualityExpr
10969 * | AndExpr 'and' EqualityExpr
10971 * Compile an AND expression.
10975 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt
) {
10976 xmlXPathCompEqualityExpr(ctxt
);
10979 while ((CUR
== 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10980 int op1
= ctxt
->comp
->last
;
10983 xmlXPathCompEqualityExpr(ctxt
);
10985 PUSH_BINARY_EXPR(XPATH_OP_AND
, op1
, ctxt
->comp
->last
, 0, 0);
10991 * xmlXPathCompileExpr:
10992 * @ctxt: the XPath Parser context
10994 * [14] Expr ::= OrExpr
10995 * [21] OrExpr ::= AndExpr
10996 * | OrExpr 'or' AndExpr
10998 * Parse and compile an expression
11001 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
) {
11002 xmlXPathCompAndExpr(ctxt
);
11005 while ((CUR
== 'o') && (NXT(1) == 'r')) {
11006 int op1
= ctxt
->comp
->last
;
11009 xmlXPathCompAndExpr(ctxt
);
11011 PUSH_BINARY_EXPR(XPATH_OP_OR
, op1
, ctxt
->comp
->last
, 0, 0);
11014 if ((sort
) && (ctxt
->comp
->steps
[ctxt
->comp
->last
].op
!= XPATH_OP_VALUE
)) {
11015 /* more ops could be optimized too */
11017 * This is the main place to eliminate sorting for
11018 * operations which don't require a sorted node-set.
11021 PUSH_UNARY_EXPR(XPATH_OP_SORT
, ctxt
->comp
->last
, 0, 0);
11026 * xmlXPathCompPredicate:
11027 * @ctxt: the XPath Parser context
11028 * @filter: act as a filter
11030 * [8] Predicate ::= '[' PredicateExpr ']'
11031 * [9] PredicateExpr ::= Expr
11033 * Compile a predicate expression
11036 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
) {
11037 int op1
= ctxt
->comp
->last
;
11041 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11046 ctxt
->comp
->last
= -1;
11048 * This call to xmlXPathCompileExpr() will deactivate sorting
11049 * of the predicate result.
11050 * TODO: Sorting is still activated for filters, since I'm not
11051 * sure if needed. Normally sorting should not be needed, since
11052 * a filter can only diminish the number of items in a sequence,
11053 * but won't change its order; so if the initial sequence is sorted,
11054 * subsequent sorting is not needed.
11057 xmlXPathCompileExpr(ctxt
, 0);
11059 xmlXPathCompileExpr(ctxt
, 1);
11063 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11067 PUSH_BINARY_EXPR(XPATH_OP_FILTER
, op1
, ctxt
->comp
->last
, 0, 0);
11069 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE
, op1
, ctxt
->comp
->last
, 0, 0);
11076 * xmlXPathCompNodeTest:
11077 * @ctxt: the XPath Parser context
11078 * @test: pointer to a xmlXPathTestVal
11079 * @type: pointer to a xmlXPathTypeVal
11080 * @prefix: placeholder for a possible name prefix
11082 * [7] NodeTest ::= NameTest
11083 * | NodeType '(' ')'
11084 * | 'processing-instruction' '(' Literal ')'
11086 * [37] NameTest ::= '*'
11089 * [38] NodeType ::= 'comment'
11091 * | 'processing-instruction'
11094 * Returns the name found and updates @test, @type and @prefix appropriately
11097 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt
, xmlXPathTestVal
*test
,
11098 xmlXPathTypeVal
*type
, const xmlChar
**prefix
,
11102 if ((test
== NULL
) || (type
== NULL
) || (prefix
== NULL
)) {
11106 *type
= (xmlXPathTypeVal
) 0;
11107 *test
= (xmlXPathTestVal
) 0;
11111 if ((name
== NULL
) && (CUR
== '*')) {
11116 *test
= NODE_TEST_ALL
;
11121 name
= xmlXPathParseNCName(ctxt
);
11122 if (name
== NULL
) {
11123 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11126 blanks
= IS_BLANK_CH(CUR
);
11131 * NodeType or PI search
11133 if (xmlStrEqual(name
, BAD_CAST
"comment"))
11134 *type
= NODE_TYPE_COMMENT
;
11135 else if (xmlStrEqual(name
, BAD_CAST
"node"))
11136 *type
= NODE_TYPE_NODE
;
11137 else if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
11138 *type
= NODE_TYPE_PI
;
11139 else if (xmlStrEqual(name
, BAD_CAST
"text"))
11140 *type
= NODE_TYPE_TEXT
;
11144 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11147 *test
= NODE_TEST_TYPE
;
11150 if (*type
== NODE_TYPE_PI
) {
11152 * Specific case: search a PI by name.
11158 name
= xmlXPathParseLiteral(ctxt
);
11160 *test
= NODE_TEST_PI
;
11167 XP_ERRORNULL(XPATH_UNCLOSED_ERROR
);
11172 *test
= NODE_TEST_NAME
;
11173 if ((!blanks
) && (CUR
== ':')) {
11177 * Since currently the parser context don't have a
11178 * namespace list associated:
11179 * The namespace name for this prefix can be computed
11180 * only at evaluation time. The compilation is done
11181 * outside of any context.
11184 *prefix
= xmlXPathNsLookup(ctxt
->context
, name
);
11187 if (*prefix
== NULL
) {
11188 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
11199 *test
= NODE_TEST_ALL
;
11203 name
= xmlXPathParseNCName(ctxt
);
11204 if (name
== NULL
) {
11205 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11212 * xmlXPathIsAxisName:
11213 * @name: a preparsed name token
11215 * [6] AxisName ::= 'ancestor'
11216 * | 'ancestor-or-self'
11220 * | 'descendant-or-self'
11222 * | 'following-sibling'
11226 * | 'preceding-sibling'
11229 * Returns the axis or 0
11231 static xmlXPathAxisVal
11232 xmlXPathIsAxisName(const xmlChar
*name
) {
11233 xmlXPathAxisVal ret
= (xmlXPathAxisVal
) 0;
11236 if (xmlStrEqual(name
, BAD_CAST
"ancestor"))
11237 ret
= AXIS_ANCESTOR
;
11238 if (xmlStrEqual(name
, BAD_CAST
"ancestor-or-self"))
11239 ret
= AXIS_ANCESTOR_OR_SELF
;
11240 if (xmlStrEqual(name
, BAD_CAST
"attribute"))
11241 ret
= AXIS_ATTRIBUTE
;
11244 if (xmlStrEqual(name
, BAD_CAST
"child"))
11248 if (xmlStrEqual(name
, BAD_CAST
"descendant"))
11249 ret
= AXIS_DESCENDANT
;
11250 if (xmlStrEqual(name
, BAD_CAST
"descendant-or-self"))
11251 ret
= AXIS_DESCENDANT_OR_SELF
;
11254 if (xmlStrEqual(name
, BAD_CAST
"following"))
11255 ret
= AXIS_FOLLOWING
;
11256 if (xmlStrEqual(name
, BAD_CAST
"following-sibling"))
11257 ret
= AXIS_FOLLOWING_SIBLING
;
11260 if (xmlStrEqual(name
, BAD_CAST
"namespace"))
11261 ret
= AXIS_NAMESPACE
;
11264 if (xmlStrEqual(name
, BAD_CAST
"parent"))
11266 if (xmlStrEqual(name
, BAD_CAST
"preceding"))
11267 ret
= AXIS_PRECEDING
;
11268 if (xmlStrEqual(name
, BAD_CAST
"preceding-sibling"))
11269 ret
= AXIS_PRECEDING_SIBLING
;
11272 if (xmlStrEqual(name
, BAD_CAST
"self"))
11280 * xmlXPathCompStep:
11281 * @ctxt: the XPath Parser context
11283 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11284 * | AbbreviatedStep
11286 * [12] AbbreviatedStep ::= '.' | '..'
11288 * [5] AxisSpecifier ::= AxisName '::'
11289 * | AbbreviatedAxisSpecifier
11291 * [13] AbbreviatedAxisSpecifier ::= '@'?
11293 * Modified for XPtr range support as:
11295 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11296 * | AbbreviatedStep
11297 * | 'range-to' '(' Expr ')' Predicate*
11299 * Compile one step in a Location Path
11300 * A location step of . is short for self::node(). This is
11301 * particularly useful in conjunction with //. For example, the
11302 * location path .//para is short for
11303 * self::node()/descendant-or-self::node()/child::para
11304 * and so will select all para descendant elements of the context
11306 * Similarly, a location step of .. is short for parent::node().
11307 * For example, ../title is short for parent::node()/child::title
11308 * and so will select the title children of the parent of the context
11312 xmlXPathCompStep(xmlXPathParserContextPtr ctxt
) {
11313 #ifdef LIBXML_XPTR_ENABLED
11319 if ((CUR
== '.') && (NXT(1) == '.')) {
11322 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_PARENT
,
11323 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11324 } else if (CUR
== '.') {
11328 xmlChar
*name
= NULL
;
11329 const xmlChar
*prefix
= NULL
;
11330 xmlXPathTestVal test
= (xmlXPathTestVal
) 0;
11331 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) 0;
11332 xmlXPathTypeVal type
= (xmlXPathTypeVal
) 0;
11336 * The modification needed for XPointer change to the production
11338 #ifdef LIBXML_XPTR_ENABLED
11340 name
= xmlXPathParseNCName(ctxt
);
11341 if ((name
!= NULL
) && (xmlStrEqual(name
, BAD_CAST
"range-to"))) {
11342 op2
= ctxt
->comp
->last
;
11346 XP_ERROR(XPATH_EXPR_ERROR
);
11351 xmlXPathCompileExpr(ctxt
, 1);
11352 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11357 XP_ERROR(XPATH_EXPR_ERROR
);
11361 goto eval_predicates
;
11369 name
= xmlXPathParseNCName(ctxt
);
11370 if (name
!= NULL
) {
11371 axis
= xmlXPathIsAxisName(name
);
11374 if ((CUR
== ':') && (NXT(1) == ':')) {
11379 /* an element name can conflict with an axis one :-\ */
11385 } else if (CUR
== '@') {
11387 axis
= AXIS_ATTRIBUTE
;
11393 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
11398 name
= xmlXPathCompNodeTest(ctxt
, &test
, &type
, &prefix
, name
);
11402 if ((prefix
!= NULL
) && (ctxt
->context
!= NULL
) &&
11403 (ctxt
->context
->flags
& XML_XPATH_CHECKNS
)) {
11404 if (xmlXPathNsLookup(ctxt
->context
, prefix
) == NULL
) {
11405 xmlXPathErr(ctxt
, XPATH_UNDEF_PREFIX_ERROR
);
11409 xmlGenericError(xmlGenericErrorContext
,
11410 "Basis : computing new set\n");
11414 xmlGenericError(xmlGenericErrorContext
, "Basis : ");
11415 if (ctxt
->value
== NULL
)
11416 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11417 else if (ctxt
->value
->nodesetval
== NULL
)
11418 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11420 xmlGenericErrorContextNodeSet(stdout
, ctxt
->value
->nodesetval
);
11423 #ifdef LIBXML_XPTR_ENABLED
11426 op1
= ctxt
->comp
->last
;
11427 ctxt
->comp
->last
= -1;
11430 while (CUR
== '[') {
11431 xmlXPathCompPredicate(ctxt
, 0);
11434 #ifdef LIBXML_XPTR_ENABLED
11436 PUSH_BINARY_EXPR(XPATH_OP_RANGETO
, op2
, op1
, 0, 0);
11439 PUSH_FULL_EXPR(XPATH_OP_COLLECT
, op1
, ctxt
->comp
->last
, axis
,
11440 test
, type
, (void *)prefix
, (void *)name
);
11444 xmlGenericError(xmlGenericErrorContext
, "Step : ");
11445 if (ctxt
->value
== NULL
)
11446 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11447 else if (ctxt
->value
->nodesetval
== NULL
)
11448 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11450 xmlGenericErrorContextNodeSet(xmlGenericErrorContext
,
11451 ctxt
->value
->nodesetval
);
11456 * xmlXPathCompRelativeLocationPath:
11457 * @ctxt: the XPath Parser context
11459 * [3] RelativeLocationPath ::= Step
11460 * | RelativeLocationPath '/' Step
11461 * | AbbreviatedRelativeLocationPath
11462 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11464 * Compile a relative location path.
11467 xmlXPathCompRelativeLocationPath
11468 (xmlXPathParserContextPtr ctxt
) {
11470 if ((CUR
== '/') && (NXT(1) == '/')) {
11473 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11474 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11475 } else if (CUR
== '/') {
11479 xmlXPathCompStep(ctxt
);
11482 while (CUR
== '/') {
11483 if ((CUR
== '/') && (NXT(1) == '/')) {
11486 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11487 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11488 xmlXPathCompStep(ctxt
);
11489 } else if (CUR
== '/') {
11492 xmlXPathCompStep(ctxt
);
11499 * xmlXPathCompLocationPath:
11500 * @ctxt: the XPath Parser context
11502 * [1] LocationPath ::= RelativeLocationPath
11503 * | AbsoluteLocationPath
11504 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11505 * | AbbreviatedAbsoluteLocationPath
11506 * [10] AbbreviatedAbsoluteLocationPath ::=
11507 * '//' RelativeLocationPath
11509 * Compile a location path
11511 * // is short for /descendant-or-self::node()/. For example,
11512 * //para is short for /descendant-or-self::node()/child::para and
11513 * so will select any para element in the document (even a para element
11514 * that is a document element will be selected by //para since the
11515 * document element node is a child of the root node); div//para is
11516 * short for div/descendant-or-self::node()/child::para and so will
11517 * select all para descendants of div children.
11520 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
) {
11523 xmlXPathCompRelativeLocationPath(ctxt
);
11525 while (CUR
== '/') {
11526 if ((CUR
== '/') && (NXT(1) == '/')) {
11529 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11530 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11531 xmlXPathCompRelativeLocationPath(ctxt
);
11532 } else if (CUR
== '/') {
11536 ((IS_ASCII_LETTER(CUR
)) || (CUR
== '_') || (CUR
== '.') ||
11537 (CUR
== '@') || (CUR
== '*')))
11538 xmlXPathCompRelativeLocationPath(ctxt
);
11545 /************************************************************************
11547 * XPath precompiled expression evaluation *
11549 ************************************************************************/
11552 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
);
11556 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op
,
11559 xmlGenericError(xmlGenericErrorContext
, "new step : ");
11560 switch (op
->value
) {
11561 case AXIS_ANCESTOR
:
11562 xmlGenericError(xmlGenericErrorContext
, "axis 'ancestors' ");
11564 case AXIS_ANCESTOR_OR_SELF
:
11565 xmlGenericError(xmlGenericErrorContext
,
11566 "axis 'ancestors-or-self' ");
11568 case AXIS_ATTRIBUTE
:
11569 xmlGenericError(xmlGenericErrorContext
, "axis 'attributes' ");
11572 xmlGenericError(xmlGenericErrorContext
, "axis 'child' ");
11574 case AXIS_DESCENDANT
:
11575 xmlGenericError(xmlGenericErrorContext
, "axis 'descendant' ");
11577 case AXIS_DESCENDANT_OR_SELF
:
11578 xmlGenericError(xmlGenericErrorContext
,
11579 "axis 'descendant-or-self' ");
11581 case AXIS_FOLLOWING
:
11582 xmlGenericError(xmlGenericErrorContext
, "axis 'following' ");
11584 case AXIS_FOLLOWING_SIBLING
:
11585 xmlGenericError(xmlGenericErrorContext
,
11586 "axis 'following-siblings' ");
11588 case AXIS_NAMESPACE
:
11589 xmlGenericError(xmlGenericErrorContext
, "axis 'namespace' ");
11592 xmlGenericError(xmlGenericErrorContext
, "axis 'parent' ");
11594 case AXIS_PRECEDING
:
11595 xmlGenericError(xmlGenericErrorContext
, "axis 'preceding' ");
11597 case AXIS_PRECEDING_SIBLING
:
11598 xmlGenericError(xmlGenericErrorContext
,
11599 "axis 'preceding-sibling' ");
11602 xmlGenericError(xmlGenericErrorContext
, "axis 'self' ");
11605 xmlGenericError(xmlGenericErrorContext
,
11606 " context contains %d nodes\n", nbNodes
);
11607 switch (op
->value2
) {
11608 case NODE_TEST_NONE
:
11609 xmlGenericError(xmlGenericErrorContext
,
11610 " searching for none !!!\n");
11612 case NODE_TEST_TYPE
:
11613 xmlGenericError(xmlGenericErrorContext
,
11614 " searching for type %d\n", op
->value3
);
11617 xmlGenericError(xmlGenericErrorContext
,
11618 " searching for PI !!!\n");
11620 case NODE_TEST_ALL
:
11621 xmlGenericError(xmlGenericErrorContext
,
11622 " searching for *\n");
11625 xmlGenericError(xmlGenericErrorContext
,
11626 " searching for namespace %s\n",
11629 case NODE_TEST_NAME
:
11630 xmlGenericError(xmlGenericErrorContext
,
11631 " searching for name %s\n", op
->value5
);
11633 xmlGenericError(xmlGenericErrorContext
,
11634 " with namespace %s\n", op
->value4
);
11637 xmlGenericError(xmlGenericErrorContext
, "Testing : ");
11639 #endif /* DEBUG_STEP */
11642 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt
,
11643 xmlXPathStepOpPtr op
,
11648 if (op
->ch1
!= -1) {
11649 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11651 * Process inner predicates first.
11653 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11655 * TODO: raise an internal error.
11658 contextSize
= xmlXPathCompOpEvalPredicate(ctxt
,
11659 &comp
->steps
[op
->ch1
], set
, contextSize
, hasNsNodes
);
11661 if (contextSize
<= 0)
11664 if (op
->ch2
!= -1) {
11665 xmlXPathContextPtr xpctxt
= ctxt
->context
;
11666 xmlNodePtr contextNode
, oldContextNode
;
11667 xmlDocPtr oldContextDoc
;
11668 int i
, res
, contextPos
= 0, newContextSize
;
11669 xmlXPathStepOpPtr exprOp
;
11670 xmlXPathObjectPtr contextObj
= NULL
, exprRes
= NULL
;
11672 #ifdef LIBXML_XPTR_ENABLED
11674 * URGENT TODO: Check the following:
11675 * We don't expect location sets if evaluating prediates, right?
11676 * Only filters should expect location sets, right?
11681 * "For each node in the node-set to be filtered, the
11682 * PredicateExpr is evaluated with that node as the
11683 * context node, with the number of nodes in the
11684 * node-set as the context size, and with the proximity
11685 * position of the node in the node-set with respect to
11686 * the axis as the context position;"
11687 * @oldset is the node-set" to be filtered.
11690 * "only predicates change the context position and
11691 * context size (see [2.4 Predicates])."
11693 * node-set context pos
11697 * After applying predicate [position() > 1] :
11698 * node-set context pos
11702 oldContextNode
= xpctxt
->node
;
11703 oldContextDoc
= xpctxt
->doc
;
11705 * Get the expression of this predicate.
11707 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11708 newContextSize
= 0;
11709 for (i
= 0; i
< set
->nodeNr
; i
++) {
11710 if (set
->nodeTab
[i
] == NULL
)
11713 contextNode
= set
->nodeTab
[i
];
11714 xpctxt
->node
= contextNode
;
11715 xpctxt
->contextSize
= contextSize
;
11716 xpctxt
->proximityPosition
= ++contextPos
;
11719 * Also set the xpath document in case things like
11720 * key() are evaluated in the predicate.
11722 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11723 (contextNode
->doc
!= NULL
))
11724 xpctxt
->doc
= contextNode
->doc
;
11726 * Evaluate the predicate expression with 1 context node
11727 * at a time; this node is packaged into a node set; this
11728 * node set is handed over to the evaluation mechanism.
11730 if (contextObj
== NULL
)
11731 contextObj
= xmlXPathCacheNewNodeSet(xpctxt
, contextNode
);
11733 if (xmlXPathNodeSetAddUnique(contextObj
->nodesetval
,
11734 contextNode
) < 0) {
11735 ctxt
->error
= XPATH_MEMORY_ERROR
;
11736 goto evaluation_exit
;
11740 valuePush(ctxt
, contextObj
);
11742 res
= xmlXPathCompOpEvalToBoolean(ctxt
, exprOp
, 1);
11744 if ((ctxt
->error
!= XPATH_EXPRESSION_OK
) || (res
== -1)) {
11745 xmlXPathNodeSetClear(set
, hasNsNodes
);
11746 newContextSize
= 0;
11747 goto evaluation_exit
;
11754 * Remove the entry from the initial node set.
11756 set
->nodeTab
[i
] = NULL
;
11757 if (contextNode
->type
== XML_NAMESPACE_DECL
)
11758 xmlXPathNodeSetFreeNs((xmlNsPtr
) contextNode
);
11760 if (ctxt
->value
== contextObj
) {
11762 * Don't free the temporary XPath object holding the
11763 * context node, in order to avoid massive recreation
11764 * inside this loop.
11767 xmlXPathNodeSetClear(contextObj
->nodesetval
, hasNsNodes
);
11770 * TODO: The object was lost in the evaluation machinery.
11771 * Can this happen? Maybe in internal-error cases.
11777 if (contextObj
!= NULL
) {
11778 if (ctxt
->value
== contextObj
)
11780 xmlXPathReleaseObject(xpctxt
, contextObj
);
11783 if (exprRes
!= NULL
)
11784 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11786 * Reset/invalidate the context.
11788 xpctxt
->node
= oldContextNode
;
11789 xpctxt
->doc
= oldContextDoc
;
11790 xpctxt
->contextSize
= -1;
11791 xpctxt
->proximityPosition
= -1;
11792 return(newContextSize
);
11794 return(contextSize
);
11798 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt
,
11799 xmlXPathStepOpPtr op
,
11806 if (op
->ch1
!= -1) {
11807 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11808 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11810 * TODO: raise an internal error.
11813 contextSize
= xmlXPathCompOpEvalPredicate(ctxt
,
11814 &comp
->steps
[op
->ch1
], set
, contextSize
, hasNsNodes
);
11816 if (contextSize
<= 0)
11820 * Check if the node set contains a sufficient number of nodes for
11821 * the requested range.
11823 if (contextSize
< minPos
) {
11824 xmlXPathNodeSetClear(set
, hasNsNodes
);
11827 if (op
->ch2
== -1) {
11829 * TODO: Can this ever happen?
11831 return (contextSize
);
11833 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
;
11855 * Get the expression of this predicate.
11857 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11858 for (i
= 0; i
< set
->nodeNr
; i
++) {
11859 xmlXPathObjectPtr tmp
;
11861 if (set
->nodeTab
[i
] == NULL
)
11864 contextNode
= set
->nodeTab
[i
];
11865 xpctxt
->node
= contextNode
;
11866 xpctxt
->contextSize
= contextSize
;
11867 xpctxt
->proximityPosition
= ++contextPos
;
11870 * Initialize the new set.
11871 * Also set the xpath document in case things like
11872 * key() evaluation are attempted on the predicate
11874 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11875 (contextNode
->doc
!= NULL
))
11876 xpctxt
->doc
= contextNode
->doc
;
11878 * Evaluate the predicate expression with 1 context node
11879 * at a time; this node is packaged into a node set; this
11880 * node set is handed over to the evaluation mechanism.
11882 if (contextObj
== NULL
)
11883 contextObj
= xmlXPathCacheNewNodeSet(xpctxt
, contextNode
);
11885 if (xmlXPathNodeSetAddUnique(contextObj
->nodesetval
,
11886 contextNode
) < 0) {
11887 ctxt
->error
= XPATH_MEMORY_ERROR
;
11888 goto evaluation_exit
;
11892 valuePush(ctxt
, contextObj
);
11893 frame
= xmlXPathSetFrame(ctxt
);
11894 res
= xmlXPathCompOpEvalToBoolean(ctxt
, exprOp
, 1);
11895 xmlXPathPopFrame(ctxt
, frame
);
11896 tmp
= valuePop(ctxt
);
11898 if ((ctxt
->error
!= XPATH_EXPRESSION_OK
) || (res
== -1)) {
11899 while (tmp
!= contextObj
) {
11901 * Free up the result
11902 * then pop off contextObj, which will be freed later
11904 xmlXPathReleaseObject(xpctxt
, tmp
);
11905 tmp
= valuePop(ctxt
);
11907 goto evaluation_error
;
11909 /* push the result back onto the stack */
11910 valuePush(ctxt
, tmp
);
11915 if (res
&& (pos
>= minPos
) && (pos
<= maxPos
)) {
11917 * Fits in the requested range.
11920 if (minPos
== maxPos
) {
11922 * Only 1 node was requested.
11924 if (contextNode
->type
== XML_NAMESPACE_DECL
) {
11926 * As always: take care of those nasty
11929 set
->nodeTab
[i
] = NULL
;
11931 xmlXPathNodeSetClear(set
, hasNsNodes
);
11933 set
->nodeTab
[0] = contextNode
;
11934 goto evaluation_exit
;
11936 if (pos
== maxPos
) {
11940 xmlXPathNodeSetClearFromPos(set
, i
+1, hasNsNodes
);
11941 goto evaluation_exit
;
11945 * Remove the entry from the initial node set.
11947 set
->nodeTab
[i
] = NULL
;
11948 if (contextNode
->type
== XML_NAMESPACE_DECL
)
11949 xmlXPathNodeSetFreeNs((xmlNsPtr
) contextNode
);
11951 if (exprRes
!= NULL
) {
11952 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11955 if (ctxt
->value
== contextObj
) {
11957 * Don't free the temporary XPath object holding the
11958 * context node, in order to avoid massive recreation
11959 * inside this loop.
11962 xmlXPathNodeSetClear(contextObj
->nodesetval
, hasNsNodes
);
11965 * The object was lost in the evaluation machinery.
11966 * Can this happen? Maybe in case of internal-errors.
11971 goto evaluation_exit
;
11974 xmlXPathNodeSetClear(set
, hasNsNodes
);
11975 newContextSize
= 0;
11978 if (contextObj
!= NULL
) {
11979 if (ctxt
->value
== contextObj
)
11981 xmlXPathReleaseObject(xpctxt
, contextObj
);
11983 if (exprRes
!= NULL
)
11984 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11986 * Reset/invalidate the context.
11988 xpctxt
->node
= oldContextNode
;
11989 xpctxt
->doc
= oldContextDoc
;
11990 xpctxt
->contextSize
= -1;
11991 xpctxt
->proximityPosition
= -1;
11992 return(newContextSize
);
11994 return(contextSize
);
11998 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt
,
11999 xmlXPathStepOpPtr op
,
12003 xmlXPathStepOpPtr exprOp
;
12006 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12010 * If not -1, then ch1 will point to:
12011 * 1) For predicates (XPATH_OP_PREDICATE):
12012 * - an inner predicate operator
12013 * 2) For filters (XPATH_OP_FILTER):
12014 * - an inner filter operater OR
12015 * - an expression selecting the node set.
12016 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12018 if ((op
->op
!= XPATH_OP_PREDICATE
) && (op
->op
!= XPATH_OP_FILTER
))
12021 if (op
->ch2
!= -1) {
12022 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
12026 if ((exprOp
!= NULL
) &&
12027 (exprOp
->op
== XPATH_OP_VALUE
) &&
12028 (exprOp
->value4
!= NULL
) &&
12029 (((xmlXPathObjectPtr
) exprOp
->value4
)->type
== XPATH_NUMBER
))
12031 double floatval
= ((xmlXPathObjectPtr
) exprOp
->value4
)->floatval
;
12034 * We have a "[n]" predicate here.
12035 * TODO: Unfortunately this simplistic test here is not
12036 * able to detect a position() predicate in compound
12037 * expressions like "[@attr = 'a" and position() = 1],
12038 * and even not the usage of position() in
12039 * "[position() = 1]"; thus - obviously - a position-range,
12040 * like it "[position() < 5]", is also not detected.
12041 * Maybe we could rewrite the AST to ease the optimization.
12044 if ((floatval
> INT_MIN
) && (floatval
< INT_MAX
)) {
12045 *maxPos
= (int) floatval
;
12046 if (floatval
== (double) *maxPos
)
12054 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt
,
12055 xmlXPathStepOpPtr op
,
12056 xmlNodePtr
* first
, xmlNodePtr
* last
,
12060 #define XP_TEST_HIT \
12061 if (hasAxisRange != 0) { \
12062 if (++pos == maxPos) { \
12063 if (addNode(seq, cur) < 0) \
12064 ctxt->error = XPATH_MEMORY_ERROR; \
12065 goto axis_range_end; } \
12067 if (addNode(seq, cur) < 0) \
12068 ctxt->error = XPATH_MEMORY_ERROR; \
12069 if (breakOnFirstHit) goto first_hit; }
12071 #define XP_TEST_HIT_NS \
12072 if (hasAxisRange != 0) { \
12073 if (++pos == maxPos) { \
12075 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12076 ctxt->error = XPATH_MEMORY_ERROR; \
12077 goto axis_range_end; } \
12080 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12081 ctxt->error = XPATH_MEMORY_ERROR; \
12082 if (breakOnFirstHit) goto first_hit; }
12084 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) op
->value
;
12085 xmlXPathTestVal test
= (xmlXPathTestVal
) op
->value2
;
12086 xmlXPathTypeVal type
= (xmlXPathTypeVal
) op
->value3
;
12087 const xmlChar
*prefix
= op
->value4
;
12088 const xmlChar
*name
= op
->value5
;
12089 const xmlChar
*URI
= NULL
;
12092 int nbMatches
= 0, prevMatches
= 0;
12094 int total
= 0, hasNsNodes
= 0;
12095 /* The popped object holding the context nodes */
12096 xmlXPathObjectPtr obj
;
12097 /* The set of context nodes for the node tests */
12098 xmlNodeSetPtr contextSeq
;
12100 xmlNodePtr contextNode
;
12101 /* The final resulting node set wrt to all context nodes */
12102 xmlNodeSetPtr outSeq
;
12104 * The temporary resulting node set wrt 1 context node.
12105 * Used to feed predicate evaluation.
12109 /* First predicate operator */
12110 xmlXPathStepOpPtr predOp
;
12111 int maxPos
; /* The requested position() (when a "[n]" predicate) */
12112 int hasPredicateRange
, hasAxisRange
, pos
, size
, newSize
;
12113 int breakOnFirstHit
;
12115 xmlXPathTraversalFunction next
= NULL
;
12116 int (*addNode
) (xmlNodeSetPtr
, xmlNodePtr
);
12117 xmlXPathNodeSetMergeFunction mergeAndClear
;
12118 xmlNodePtr oldContextNode
;
12119 xmlXPathContextPtr xpctxt
= ctxt
->context
;
12122 CHECK_TYPE0(XPATH_NODESET
);
12123 obj
= valuePop(ctxt
);
12125 * Setup namespaces.
12127 if (prefix
!= NULL
) {
12128 URI
= xmlXPathNsLookup(xpctxt
, prefix
);
12130 xmlXPathReleaseObject(xpctxt
, obj
);
12131 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
12137 * MAYBE FUTURE TODO: merging optimizations:
12138 * - If the nodes to be traversed wrt to the initial nodes and
12139 * the current axis cannot overlap, then we could avoid searching
12140 * for duplicates during the merge.
12141 * But the question is how/when to evaluate if they cannot overlap.
12142 * Example: if we know that for two initial nodes, the one is
12143 * not in the ancestor-or-self axis of the other, then we could safely
12144 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12145 * the descendant-or-self axis.
12147 mergeAndClear
= xmlXPathNodeSetMergeAndClear
;
12149 case AXIS_ANCESTOR
:
12151 next
= xmlXPathNextAncestor
;
12153 case AXIS_ANCESTOR_OR_SELF
:
12155 next
= xmlXPathNextAncestorOrSelf
;
12157 case AXIS_ATTRIBUTE
:
12160 next
= xmlXPathNextAttribute
;
12161 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12165 if (((test
== NODE_TEST_NAME
) || (test
== NODE_TEST_ALL
)) &&
12166 (type
== NODE_TYPE_NODE
))
12169 * Optimization if an element node type is 'element'.
12171 next
= xmlXPathNextChildElement
;
12173 next
= xmlXPathNextChild
;
12174 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12176 case AXIS_DESCENDANT
:
12178 next
= xmlXPathNextDescendant
;
12180 case AXIS_DESCENDANT_OR_SELF
:
12182 next
= xmlXPathNextDescendantOrSelf
;
12184 case AXIS_FOLLOWING
:
12186 next
= xmlXPathNextFollowing
;
12188 case AXIS_FOLLOWING_SIBLING
:
12190 next
= xmlXPathNextFollowingSibling
;
12192 case AXIS_NAMESPACE
:
12195 next
= (xmlXPathTraversalFunction
) xmlXPathNextNamespace
;
12196 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12200 next
= xmlXPathNextParent
;
12202 case AXIS_PRECEDING
:
12204 next
= xmlXPathNextPrecedingInternal
;
12206 case AXIS_PRECEDING_SIBLING
:
12208 next
= xmlXPathNextPrecedingSibling
;
12213 next
= xmlXPathNextSelf
;
12214 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12219 xmlXPathDebugDumpStepAxis(op
,
12220 (obj
->nodesetval
!= NULL
) ? obj
->nodesetval
->nodeNr
: 0);
12223 if (next
== NULL
) {
12224 xmlXPathReleaseObject(xpctxt
, obj
);
12227 contextSeq
= obj
->nodesetval
;
12228 if ((contextSeq
== NULL
) || (contextSeq
->nodeNr
<= 0)) {
12229 xmlXPathReleaseObject(xpctxt
, obj
);
12230 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, NULL
));
12234 * Predicate optimization ---------------------------------------------
12235 * If this step has a last predicate, which contains a position(),
12236 * then we'll optimize (although not exactly "position()", but only
12237 * the short-hand form, i.e., "[n]".
12239 * Example - expression "/foo[parent::bar][1]":
12241 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12243 * PREDICATE -- op->ch2 (predOp)
12244 * PREDICATE -- predOp->ch1 = [parent::bar]
12246 * COLLECT 'parent' 'name' 'node' bar
12248 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12253 hasPredicateRange
= 0;
12255 if (op
->ch2
!= -1) {
12257 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12259 predOp
= &ctxt
->comp
->steps
[op
->ch2
];
12260 if (xmlXPathIsPositionalPredicate(ctxt
, predOp
, &maxPos
)) {
12261 if (predOp
->ch1
!= -1) {
12263 * Use the next inner predicate operator.
12265 predOp
= &ctxt
->comp
->steps
[predOp
->ch1
];
12266 hasPredicateRange
= 1;
12269 * There's no other predicate than the [n] predicate.
12276 breakOnFirstHit
= ((toBool
) && (predOp
== NULL
)) ? 1 : 0;
12278 * Axis traversal -----------------------------------------------------
12282 * - For the attribute axis, the principal node type is attribute.
12283 * - For the namespace axis, the principal node type is namespace.
12284 * - For other axes, the principal node type is element.
12286 * A node test * is true for any node of the
12287 * principal node type. For example, child::* will
12288 * select all element children of the context node
12290 oldContextNode
= xpctxt
->node
;
12291 addNode
= xmlXPathNodeSetAddUnique
;
12294 contextNode
= NULL
;
12298 while (((contextIdx
< contextSeq
->nodeNr
) || (contextNode
!= NULL
)) &&
12299 (ctxt
->error
== XPATH_EXPRESSION_OK
)) {
12300 xpctxt
->node
= contextSeq
->nodeTab
[contextIdx
++];
12303 seq
= xmlXPathNodeSetCreate(NULL
);
12310 * Traverse the axis and test the nodes.
12316 cur
= next(ctxt
, cur
);
12321 * QUESTION TODO: What does the "first" and "last" stuff do?
12323 if ((first
!= NULL
) && (*first
!= NULL
)) {
12326 if (((total
% 256) == 0) &&
12327 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12328 (xmlXPathCmpNodesExt(*first
, cur
) >= 0))
12330 (xmlXPathCmpNodes(*first
, cur
) >= 0))
12336 if ((last
!= NULL
) && (*last
!= NULL
)) {
12339 if (((total
% 256) == 0) &&
12340 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12341 (xmlXPathCmpNodesExt(cur
, *last
) >= 0))
12343 (xmlXPathCmpNodes(cur
, *last
) >= 0))
12353 xmlGenericError(xmlGenericErrorContext
, " %s", cur
->name
);
12357 case NODE_TEST_NONE
:
12361 case NODE_TEST_TYPE
:
12362 if (type
== NODE_TYPE_NODE
) {
12363 switch (cur
->type
) {
12364 case XML_DOCUMENT_NODE
:
12365 case XML_HTML_DOCUMENT_NODE
:
12366 #ifdef LIBXML_DOCB_ENABLED
12367 case XML_DOCB_DOCUMENT_NODE
:
12369 case XML_ELEMENT_NODE
:
12370 case XML_ATTRIBUTE_NODE
:
12372 case XML_COMMENT_NODE
:
12373 case XML_CDATA_SECTION_NODE
:
12374 case XML_TEXT_NODE
:
12377 case XML_NAMESPACE_DECL
: {
12378 if (axis
== AXIS_NAMESPACE
) {
12389 } else if (cur
->type
== (xmlElementType
) type
) {
12390 if (cur
->type
== XML_NAMESPACE_DECL
)
12394 } else if ((type
== NODE_TYPE_TEXT
) &&
12395 (cur
->type
== XML_CDATA_SECTION_NODE
))
12401 if ((cur
->type
== XML_PI_NODE
) &&
12402 ((name
== NULL
) || xmlStrEqual(name
, cur
->name
)))
12407 case NODE_TEST_ALL
:
12408 if (axis
== AXIS_ATTRIBUTE
) {
12409 if (cur
->type
== XML_ATTRIBUTE_NODE
)
12411 if (prefix
== NULL
)
12414 } else if ((cur
->ns
!= NULL
) &&
12415 (xmlStrEqual(URI
, cur
->ns
->href
)))
12420 } else if (axis
== AXIS_NAMESPACE
) {
12421 if (cur
->type
== XML_NAMESPACE_DECL
)
12426 if (cur
->type
== XML_ELEMENT_NODE
) {
12427 if (prefix
== NULL
)
12431 } else if ((cur
->ns
!= NULL
) &&
12432 (xmlStrEqual(URI
, cur
->ns
->href
)))
12439 case NODE_TEST_NS
:{
12443 case NODE_TEST_NAME
:
12444 if (axis
== AXIS_ATTRIBUTE
) {
12445 if (cur
->type
!= XML_ATTRIBUTE_NODE
)
12447 } else if (axis
== AXIS_NAMESPACE
) {
12448 if (cur
->type
!= XML_NAMESPACE_DECL
)
12451 if (cur
->type
!= XML_ELEMENT_NODE
)
12454 switch (cur
->type
) {
12455 case XML_ELEMENT_NODE
:
12456 if (xmlStrEqual(name
, cur
->name
)) {
12457 if (prefix
== NULL
) {
12458 if (cur
->ns
== NULL
)
12463 if ((cur
->ns
!= NULL
) &&
12464 (xmlStrEqual(URI
, cur
->ns
->href
)))
12471 case XML_ATTRIBUTE_NODE
:{
12472 xmlAttrPtr attr
= (xmlAttrPtr
) cur
;
12474 if (xmlStrEqual(name
, attr
->name
)) {
12475 if (prefix
== NULL
) {
12476 if ((attr
->ns
== NULL
) ||
12477 (attr
->ns
->prefix
== NULL
))
12482 if ((attr
->ns
!= NULL
) &&
12492 case XML_NAMESPACE_DECL
:
12493 if (cur
->type
== XML_NAMESPACE_DECL
) {
12494 xmlNsPtr ns
= (xmlNsPtr
) cur
;
12496 if ((ns
->prefix
!= NULL
) && (name
!= NULL
)
12497 && (xmlStrEqual(ns
->prefix
, name
)))
12507 } /* switch(test) */
12508 } while ((cur
!= NULL
) && (ctxt
->error
== XPATH_EXPRESSION_OK
));
12510 goto apply_predicates
;
12512 axis_range_end
: /* ----------------------------------------------------- */
12514 * We have a "/foo[n]", and position() = n was reached.
12515 * Note that we can have as well "/foo/::parent::foo[1]", so
12516 * a duplicate-aware merge is still needed.
12517 * Merge with the result.
12519 if (outSeq
== NULL
) {
12523 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12525 * Break if only a true/false result was requested.
12531 first_hit
: /* ---------------------------------------------------------- */
12533 * Break if only a true/false result was requested and
12534 * no predicates existed and a node test succeeded.
12536 if (outSeq
== NULL
) {
12540 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12545 nbMatches
+= seq
->nodeNr
;
12548 apply_predicates
: /* --------------------------------------------------- */
12549 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
12553 * Apply predicates.
12555 if ((predOp
!= NULL
) && (seq
->nodeNr
> 0)) {
12557 * E.g. when we have a "/foo[some expression][n]".
12560 * QUESTION TODO: The old predicate evaluation took into
12561 * account location-sets.
12562 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12563 * Do we expect such a set here?
12564 * All what I learned now from the evaluation semantics
12565 * does not indicate that a location-set will be processed
12566 * here, so this looks OK.
12569 * Iterate over all predicates, starting with the outermost
12571 * TODO: Problem: we cannot execute the inner predicates first
12572 * since we cannot go back *up* the operator tree!
12574 * 1) Use of recursive functions (like is it currently done
12575 * via xmlXPathCompOpEval())
12576 * 2) Add a predicate evaluation information stack to the
12578 * 3) Change the way the operators are linked; we need a
12579 * "parent" field on xmlXPathStepOp
12581 * For the moment, I'll try to solve this with a recursive
12582 * function: xmlXPathCompOpEvalPredicate().
12584 size
= seq
->nodeNr
;
12585 if (hasPredicateRange
!= 0)
12586 newSize
= xmlXPathCompOpEvalPositionalPredicate(ctxt
,
12587 predOp
, seq
, size
, maxPos
, maxPos
, hasNsNodes
);
12589 newSize
= xmlXPathCompOpEvalPredicate(ctxt
,
12590 predOp
, seq
, size
, hasNsNodes
);
12592 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
12597 * Add the filtered set of nodes to the result node set.
12599 if (newSize
== 0) {
12601 * The predicates filtered all nodes out.
12603 xmlXPathNodeSetClear(seq
, hasNsNodes
);
12604 } else if (seq
->nodeNr
> 0) {
12606 * Add to result set.
12608 if (outSeq
== NULL
) {
12609 if (size
!= newSize
) {
12611 * We need to merge and clear here, since
12612 * the sequence will contained NULLed entries.
12614 outSeq
= mergeAndClear(NULL
, seq
, 1);
12620 outSeq
= mergeAndClear(outSeq
, seq
,
12621 (size
!= newSize
) ? 1: 0);
12623 * Break if only a true/false result was requested.
12628 } else if (seq
->nodeNr
> 0) {
12630 * Add to result set.
12632 if (outSeq
== NULL
) {
12636 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12642 if ((obj
->boolval
) && (obj
->user
!= NULL
)) {
12644 * QUESTION TODO: What does this do and why?
12645 * TODO: Do we have to do this also for the "error"
12646 * cleanup further down?
12648 ctxt
->value
->boolval
= 1;
12649 ctxt
->value
->user
= obj
->user
;
12653 xmlXPathReleaseObject(xpctxt
, obj
);
12656 * Ensure we return at least an emtpy set.
12658 if (outSeq
== NULL
) {
12659 if ((seq
!= NULL
) && (seq
->nodeNr
== 0))
12662 outSeq
= xmlXPathNodeSetCreate(NULL
);
12663 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12665 if ((seq
!= NULL
) && (seq
!= outSeq
)) {
12666 xmlXPathFreeNodeSet(seq
);
12669 * Hand over the result. Better to push the set also in
12672 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, outSeq
));
12674 * Reset the context node.
12676 xpctxt
->node
= oldContextNode
;
12678 * When traversing the namespace axis in "toBool" mode, it's
12679 * possible that tmpNsList wasn't freed.
12681 if (xpctxt
->tmpNsList
!= NULL
) {
12682 xmlFree(xpctxt
->tmpNsList
);
12683 xpctxt
->tmpNsList
= NULL
;
12687 xmlGenericError(xmlGenericErrorContext
,
12688 "\nExamined %d nodes, found %d nodes at that step\n",
12696 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12697 xmlXPathStepOpPtr op
, xmlNodePtr
* first
);
12700 * xmlXPathCompOpEvalFirst:
12701 * @ctxt: the XPath parser context with the compiled expression
12702 * @op: an XPath compiled operation
12703 * @first: the first elem found so far
12705 * Evaluate the Precompiled XPath operation searching only the first
12706 * element in document order
12708 * Returns the number of examined objects.
12711 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
12712 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12714 int total
= 0, cur
;
12715 xmlXPathCompExprPtr comp
;
12716 xmlXPathObjectPtr arg1
, arg2
;
12723 case XPATH_OP_UNION
:
12725 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12728 if ((ctxt
->value
!= NULL
)
12729 && (ctxt
->value
->type
== XPATH_NODESET
)
12730 && (ctxt
->value
->nodesetval
!= NULL
)
12731 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12733 * limit tree traversing to first node in the result
12736 * OPTIMIZE TODO: This implicitely sorts
12737 * the result, even if not needed. E.g. if the argument
12738 * of the count() function, no sorting is needed.
12739 * OPTIMIZE TODO: How do we know if the node-list wasn't
12742 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12743 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12744 *first
= ctxt
->value
->nodesetval
->nodeTab
[0];
12747 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch2
],
12751 arg2
= valuePop(ctxt
);
12752 arg1
= valuePop(ctxt
);
12753 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12754 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12755 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12756 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12757 XP_ERROR0(XPATH_INVALID_TYPE
);
12760 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12762 valuePush(ctxt
, arg1
);
12763 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12766 xmlXPathCompSwap(op
);
12767 return (total
+ cur
);
12768 case XPATH_OP_ROOT
:
12769 xmlXPathRoot(ctxt
);
12771 case XPATH_OP_NODE
:
12773 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12776 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12778 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12779 ctxt
->context
->node
));
12781 case XPATH_OP_RESET
:
12783 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12786 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12788 ctxt
->context
->node
= NULL
;
12790 case XPATH_OP_COLLECT
:{
12794 total
= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12797 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, first
, NULL
, 0);
12800 case XPATH_OP_VALUE
:
12802 xmlXPathCacheObjectCopy(ctxt
->context
,
12803 (xmlXPathObjectPtr
) op
->value4
));
12805 case XPATH_OP_SORT
:
12808 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12811 if ((ctxt
->value
!= NULL
)
12812 && (ctxt
->value
->type
== XPATH_NODESET
)
12813 && (ctxt
->value
->nodesetval
!= NULL
)
12814 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12815 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12817 #ifdef XP_OPTIMIZED_FILTER_FIRST
12818 case XPATH_OP_FILTER
:
12819 total
+= xmlXPathCompOpEvalFilterFirst(ctxt
, op
, first
);
12823 return (xmlXPathCompOpEval(ctxt
, op
));
12828 * xmlXPathCompOpEvalLast:
12829 * @ctxt: the XPath parser context with the compiled expression
12830 * @op: an XPath compiled operation
12831 * @last: the last elem found so far
12833 * Evaluate the Precompiled XPath operation searching only the last
12834 * element in document order
12836 * Returns the number of nodes traversed
12839 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
,
12842 int total
= 0, cur
;
12843 xmlXPathCompExprPtr comp
;
12844 xmlXPathObjectPtr arg1
, arg2
;
12855 case XPATH_OP_UNION
:
12856 bakd
= ctxt
->context
->doc
;
12857 bak
= ctxt
->context
->node
;
12858 pp
= ctxt
->context
->proximityPosition
;
12859 cs
= ctxt
->context
->contextSize
;
12861 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
], last
);
12863 if ((ctxt
->value
!= NULL
)
12864 && (ctxt
->value
->type
== XPATH_NODESET
)
12865 && (ctxt
->value
->nodesetval
!= NULL
)
12866 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12868 * limit tree traversing to first node in the result
12870 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12871 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12873 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->value
->
12874 nodesetval
->nodeNr
-
12877 ctxt
->context
->doc
= bakd
;
12878 ctxt
->context
->node
= bak
;
12879 ctxt
->context
->proximityPosition
= pp
;
12880 ctxt
->context
->contextSize
= cs
;
12882 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch2
], last
);
12884 if ((ctxt
->value
!= NULL
)
12885 && (ctxt
->value
->type
== XPATH_NODESET
)
12886 && (ctxt
->value
->nodesetval
!= NULL
)
12887 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) { /* TODO: NOP ? */
12890 arg2
= valuePop(ctxt
);
12891 arg1
= valuePop(ctxt
);
12892 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12893 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12894 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12895 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12896 XP_ERROR0(XPATH_INVALID_TYPE
);
12899 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12901 valuePush(ctxt
, arg1
);
12902 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12905 xmlXPathCompSwap(op
);
12906 return (total
+ cur
);
12907 case XPATH_OP_ROOT
:
12908 xmlXPathRoot(ctxt
);
12910 case XPATH_OP_NODE
:
12912 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12915 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12917 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12918 ctxt
->context
->node
));
12920 case XPATH_OP_RESET
:
12922 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12925 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12927 ctxt
->context
->node
= NULL
;
12929 case XPATH_OP_COLLECT
:{
12933 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12936 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, last
, 0);
12939 case XPATH_OP_VALUE
:
12941 xmlXPathCacheObjectCopy(ctxt
->context
,
12942 (xmlXPathObjectPtr
) op
->value4
));
12944 case XPATH_OP_SORT
:
12947 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
],
12950 if ((ctxt
->value
!= NULL
)
12951 && (ctxt
->value
->type
== XPATH_NODESET
)
12952 && (ctxt
->value
->nodesetval
!= NULL
)
12953 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12954 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12957 return (xmlXPathCompOpEval(ctxt
, op
));
12961 #ifdef XP_OPTIMIZED_FILTER_FIRST
12963 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12964 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12967 xmlXPathCompExprPtr comp
;
12968 xmlXPathObjectPtr res
;
12969 xmlXPathObjectPtr obj
;
12970 xmlNodeSetPtr oldset
;
12971 xmlNodePtr oldnode
;
12978 * Optimization for ()[last()] selection i.e. the last elem
12980 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
12981 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
12982 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
12983 int f
= comp
->steps
[op
->ch2
].ch1
;
12986 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
12987 (comp
->steps
[f
].value5
== NULL
) &&
12988 (comp
->steps
[f
].value
== 0) &&
12989 (comp
->steps
[f
].value4
!= NULL
) &&
12991 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
12992 xmlNodePtr last
= NULL
;
12995 xmlXPathCompOpEvalLast(ctxt
,
12996 &comp
->steps
[op
->ch1
],
13000 * The nodeset should be in document order,
13001 * Keep only the last value
13003 if ((ctxt
->value
!= NULL
) &&
13004 (ctxt
->value
->type
== XPATH_NODESET
) &&
13005 (ctxt
->value
->nodesetval
!= NULL
) &&
13006 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
13007 (ctxt
->value
->nodesetval
->nodeNr
> 1)) {
13008 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
13009 *first
= *(ctxt
->value
->nodesetval
->nodeTab
);
13016 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13020 if (ctxt
->value
== NULL
)
13023 #ifdef LIBXML_XPTR_ENABLED
13024 oldnode
= ctxt
->context
->node
;
13026 * Hum are we filtering the result of an XPointer expression
13028 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13029 xmlXPathObjectPtr tmp
= NULL
;
13030 xmlLocationSetPtr newlocset
= NULL
;
13031 xmlLocationSetPtr oldlocset
;
13034 * Extract the old locset, and then evaluate the result of the
13035 * expression for all the element in the locset. use it to grow
13038 CHECK_TYPE0(XPATH_LOCATIONSET
);
13039 obj
= valuePop(ctxt
);
13040 oldlocset
= obj
->user
;
13041 ctxt
->context
->node
= NULL
;
13043 if ((oldlocset
== NULL
) || (oldlocset
->locNr
== 0)) {
13044 ctxt
->context
->contextSize
= 0;
13045 ctxt
->context
->proximityPosition
= 0;
13047 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13048 res
= valuePop(ctxt
);
13050 xmlXPathReleaseObject(ctxt
->context
, res
);
13052 valuePush(ctxt
, obj
);
13056 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13058 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13060 * Run the evaluation with a node list made of a
13061 * single item in the nodelocset.
13063 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13064 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13065 ctxt
->context
->proximityPosition
= i
+ 1;
13067 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13068 ctxt
->context
->node
);
13070 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13071 ctxt
->context
->node
) < 0) {
13072 ctxt
->error
= XPATH_MEMORY_ERROR
;
13075 valuePush(ctxt
, tmp
);
13077 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13078 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13079 xmlXPathFreeObject(obj
);
13083 * The result of the evaluation need to be tested to
13084 * decided whether the filter succeeded or not
13086 res
= valuePop(ctxt
);
13087 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13088 xmlXPtrLocationSetAdd(newlocset
,
13089 xmlXPathCacheObjectCopy(ctxt
->context
,
13090 oldlocset
->locTab
[i
]));
13096 xmlXPathReleaseObject(ctxt
->context
, res
);
13098 if (ctxt
->value
== tmp
) {
13100 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13102 * REVISIT TODO: Don't create a temporary nodeset
13103 * for everly iteration.
13105 /* OLD: xmlXPathFreeObject(res); */
13108 ctxt
->context
->node
= NULL
;
13110 * Only put the first node in the result, then leave.
13112 if (newlocset
->locNr
> 0) {
13113 *first
= (xmlNodePtr
) oldlocset
->locTab
[i
]->user
;
13118 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13121 * The result is used as the new evaluation locset.
13123 xmlXPathReleaseObject(ctxt
->context
, obj
);
13124 ctxt
->context
->node
= NULL
;
13125 ctxt
->context
->contextSize
= -1;
13126 ctxt
->context
->proximityPosition
= -1;
13127 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13128 ctxt
->context
->node
= oldnode
;
13131 #endif /* LIBXML_XPTR_ENABLED */
13134 * Extract the old set, and then evaluate the result of the
13135 * expression for all the element in the set. use it to grow
13138 CHECK_TYPE0(XPATH_NODESET
);
13139 obj
= valuePop(ctxt
);
13140 oldset
= obj
->nodesetval
;
13142 oldnode
= ctxt
->context
->node
;
13143 oldDoc
= ctxt
->context
->doc
;
13144 ctxt
->context
->node
= NULL
;
13146 if ((oldset
== NULL
) || (oldset
->nodeNr
== 0)) {
13147 ctxt
->context
->contextSize
= 0;
13148 ctxt
->context
->proximityPosition
= 0;
13149 /* QUESTION TODO: Why was this code commented out?
13152 xmlXPathCompOpEval(ctxt,
13153 &comp->steps[op->ch2]);
13155 res = valuePop(ctxt);
13157 xmlXPathFreeObject(res);
13159 valuePush(ctxt
, obj
);
13160 ctxt
->context
->node
= oldnode
;
13163 xmlNodeSetPtr newset
;
13164 xmlXPathObjectPtr tmp
= NULL
;
13166 * Initialize the new set.
13167 * Also set the xpath document in case things like
13168 * key() evaluation are attempted on the predicate
13170 newset
= xmlXPathNodeSetCreate(NULL
);
13171 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13173 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13175 * Run the evaluation with a node list made of
13176 * a single item in the nodeset.
13178 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13179 if ((oldset
->nodeTab
[i
]->type
!= XML_NAMESPACE_DECL
) &&
13180 (oldset
->nodeTab
[i
]->doc
!= NULL
))
13181 ctxt
->context
->doc
= oldset
->nodeTab
[i
]->doc
;
13183 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13184 ctxt
->context
->node
);
13186 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13187 ctxt
->context
->node
) < 0) {
13188 ctxt
->error
= XPATH_MEMORY_ERROR
;
13191 valuePush(ctxt
, tmp
);
13192 ctxt
->context
->contextSize
= oldset
->nodeNr
;
13193 ctxt
->context
->proximityPosition
= i
+ 1;
13195 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13196 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13197 xmlXPathFreeNodeSet(newset
);
13198 xmlXPathFreeObject(obj
);
13202 * The result of the evaluation needs to be tested to
13203 * decide whether the filter succeeded or not
13205 res
= valuePop(ctxt
);
13206 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13207 if (xmlXPathNodeSetAdd(newset
, oldset
->nodeTab
[i
]) < 0)
13208 ctxt
->error
= XPATH_MEMORY_ERROR
;
13214 xmlXPathReleaseObject(ctxt
->context
, res
);
13216 if (ctxt
->value
== tmp
) {
13219 * Don't free the temporary nodeset
13220 * in order to avoid massive recreation inside this
13223 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13226 ctxt
->context
->node
= NULL
;
13228 * Only put the first node in the result, then leave.
13230 if (newset
->nodeNr
> 0) {
13231 *first
= *(newset
->nodeTab
);
13236 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13239 * The result is used as the new evaluation set.
13241 xmlXPathReleaseObject(ctxt
->context
, obj
);
13242 ctxt
->context
->node
= NULL
;
13243 ctxt
->context
->contextSize
= -1;
13244 ctxt
->context
->proximityPosition
= -1;
13245 /* may want to move this past the '}' later */
13246 ctxt
->context
->doc
= oldDoc
;
13247 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, newset
));
13249 ctxt
->context
->node
= oldnode
;
13252 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13255 * xmlXPathCompOpEval:
13256 * @ctxt: the XPath parser context with the compiled expression
13257 * @op: an XPath compiled operation
13259 * Evaluate the Precompiled XPath operation
13260 * Returns the number of nodes traversed
13263 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
)
13267 xmlXPathCompExprPtr comp
;
13268 xmlXPathObjectPtr arg1
, arg2
;
13280 bakd
= ctxt
->context
->doc
;
13281 bak
= ctxt
->context
->node
;
13282 pp
= ctxt
->context
->proximityPosition
;
13283 cs
= ctxt
->context
->contextSize
;
13284 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13286 xmlXPathBooleanFunction(ctxt
, 1);
13287 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 0))
13289 arg2
= valuePop(ctxt
);
13290 ctxt
->context
->doc
= bakd
;
13291 ctxt
->context
->node
= bak
;
13292 ctxt
->context
->proximityPosition
= pp
;
13293 ctxt
->context
->contextSize
= cs
;
13294 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13296 xmlXPathFreeObject(arg2
);
13299 xmlXPathBooleanFunction(ctxt
, 1);
13300 arg1
= valuePop(ctxt
);
13301 arg1
->boolval
&= arg2
->boolval
;
13302 valuePush(ctxt
, arg1
);
13303 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13306 bakd
= ctxt
->context
->doc
;
13307 bak
= ctxt
->context
->node
;
13308 pp
= ctxt
->context
->proximityPosition
;
13309 cs
= ctxt
->context
->contextSize
;
13310 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13312 xmlXPathBooleanFunction(ctxt
, 1);
13313 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 1))
13315 arg2
= valuePop(ctxt
);
13316 ctxt
->context
->doc
= bakd
;
13317 ctxt
->context
->node
= bak
;
13318 ctxt
->context
->proximityPosition
= pp
;
13319 ctxt
->context
->contextSize
= cs
;
13320 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13322 xmlXPathFreeObject(arg2
);
13325 xmlXPathBooleanFunction(ctxt
, 1);
13326 arg1
= valuePop(ctxt
);
13327 arg1
->boolval
|= arg2
->boolval
;
13328 valuePush(ctxt
, arg1
);
13329 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13331 case XPATH_OP_EQUAL
:
13332 bakd
= ctxt
->context
->doc
;
13333 bak
= ctxt
->context
->node
;
13334 pp
= ctxt
->context
->proximityPosition
;
13335 cs
= ctxt
->context
->contextSize
;
13336 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13338 ctxt
->context
->doc
= bakd
;
13339 ctxt
->context
->node
= bak
;
13340 ctxt
->context
->proximityPosition
= pp
;
13341 ctxt
->context
->contextSize
= cs
;
13342 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13345 equal
= xmlXPathEqualValues(ctxt
);
13347 equal
= xmlXPathNotEqualValues(ctxt
);
13348 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, equal
));
13351 bakd
= ctxt
->context
->doc
;
13352 bak
= ctxt
->context
->node
;
13353 pp
= ctxt
->context
->proximityPosition
;
13354 cs
= ctxt
->context
->contextSize
;
13355 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13357 ctxt
->context
->doc
= bakd
;
13358 ctxt
->context
->node
= bak
;
13359 ctxt
->context
->proximityPosition
= pp
;
13360 ctxt
->context
->contextSize
= cs
;
13361 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13363 ret
= xmlXPathCompareValues(ctxt
, op
->value
, op
->value2
);
13364 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
13366 case XPATH_OP_PLUS
:
13367 bakd
= ctxt
->context
->doc
;
13368 bak
= ctxt
->context
->node
;
13369 pp
= ctxt
->context
->proximityPosition
;
13370 cs
= ctxt
->context
->contextSize
;
13371 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13373 if (op
->ch2
!= -1) {
13374 ctxt
->context
->doc
= bakd
;
13375 ctxt
->context
->node
= bak
;
13376 ctxt
->context
->proximityPosition
= pp
;
13377 ctxt
->context
->contextSize
= cs
;
13378 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13381 if (op
->value
== 0)
13382 xmlXPathSubValues(ctxt
);
13383 else if (op
->value
== 1)
13384 xmlXPathAddValues(ctxt
);
13385 else if (op
->value
== 2)
13386 xmlXPathValueFlipSign(ctxt
);
13387 else if (op
->value
== 3) {
13389 CHECK_TYPE0(XPATH_NUMBER
);
13392 case XPATH_OP_MULT
:
13393 bakd
= ctxt
->context
->doc
;
13394 bak
= ctxt
->context
->node
;
13395 pp
= ctxt
->context
->proximityPosition
;
13396 cs
= ctxt
->context
->contextSize
;
13397 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13399 ctxt
->context
->doc
= bakd
;
13400 ctxt
->context
->node
= bak
;
13401 ctxt
->context
->proximityPosition
= pp
;
13402 ctxt
->context
->contextSize
= cs
;
13403 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13405 if (op
->value
== 0)
13406 xmlXPathMultValues(ctxt
);
13407 else if (op
->value
== 1)
13408 xmlXPathDivValues(ctxt
);
13409 else if (op
->value
== 2)
13410 xmlXPathModValues(ctxt
);
13412 case XPATH_OP_UNION
:
13413 bakd
= ctxt
->context
->doc
;
13414 bak
= ctxt
->context
->node
;
13415 pp
= ctxt
->context
->proximityPosition
;
13416 cs
= ctxt
->context
->contextSize
;
13417 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13419 ctxt
->context
->doc
= bakd
;
13420 ctxt
->context
->node
= bak
;
13421 ctxt
->context
->proximityPosition
= pp
;
13422 ctxt
->context
->contextSize
= cs
;
13423 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13426 arg2
= valuePop(ctxt
);
13427 arg1
= valuePop(ctxt
);
13428 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
13429 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
13430 xmlXPathReleaseObject(ctxt
->context
, arg1
);
13431 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13432 XP_ERROR0(XPATH_INVALID_TYPE
);
13435 if ((arg1
->nodesetval
== NULL
) ||
13436 ((arg2
->nodesetval
!= NULL
) &&
13437 (arg2
->nodesetval
->nodeNr
!= 0)))
13439 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
13443 valuePush(ctxt
, arg1
);
13444 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13446 case XPATH_OP_ROOT
:
13447 xmlXPathRoot(ctxt
);
13449 case XPATH_OP_NODE
:
13451 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13454 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13456 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
13457 ctxt
->context
->node
));
13459 case XPATH_OP_RESET
:
13461 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13464 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13466 ctxt
->context
->node
= NULL
;
13468 case XPATH_OP_COLLECT
:{
13472 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13475 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 0);
13478 case XPATH_OP_VALUE
:
13480 xmlXPathCacheObjectCopy(ctxt
->context
,
13481 (xmlXPathObjectPtr
) op
->value4
));
13483 case XPATH_OP_VARIABLE
:{
13484 xmlXPathObjectPtr val
;
13488 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13489 if (op
->value5
== NULL
) {
13490 val
= xmlXPathVariableLookup(ctxt
->context
, op
->value4
);
13492 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13493 valuePush(ctxt
, val
);
13495 const xmlChar
*URI
;
13497 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13499 xmlGenericError(xmlGenericErrorContext
,
13500 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13501 (char *) op
->value4
, (char *)op
->value5
);
13502 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13505 val
= xmlXPathVariableLookupNS(ctxt
->context
,
13508 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13509 valuePush(ctxt
, val
);
13513 case XPATH_OP_FUNCTION
:{
13514 xmlXPathFunction func
;
13515 const xmlChar
*oldFunc
, *oldFuncURI
;
13519 frame
= xmlXPathSetFrame(ctxt
);
13520 if (op
->ch1
!= -1) {
13522 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13523 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13524 xmlXPathPopFrame(ctxt
, frame
);
13528 if (ctxt
->valueNr
< ctxt
->valueFrame
+ op
->value
) {
13529 xmlGenericError(xmlGenericErrorContext
,
13530 "xmlXPathCompOpEval: parameter error\n");
13531 ctxt
->error
= XPATH_INVALID_OPERAND
;
13532 xmlXPathPopFrame(ctxt
, frame
);
13535 for (i
= 0; i
< op
->value
; i
++) {
13536 if (ctxt
->valueTab
[(ctxt
->valueNr
- 1) - i
] == NULL
) {
13537 xmlGenericError(xmlGenericErrorContext
,
13538 "xmlXPathCompOpEval: parameter error\n");
13539 ctxt
->error
= XPATH_INVALID_OPERAND
;
13540 xmlXPathPopFrame(ctxt
, frame
);
13544 if (op
->cache
!= NULL
)
13547 const xmlChar
*URI
= NULL
;
13549 if (op
->value5
== NULL
)
13551 xmlXPathFunctionLookup(ctxt
->context
,
13554 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13556 xmlGenericError(xmlGenericErrorContext
,
13557 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13558 (char *)op
->value4
, (char *)op
->value5
);
13559 xmlXPathPopFrame(ctxt
, frame
);
13560 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13563 func
= xmlXPathFunctionLookupNS(ctxt
->context
,
13566 if (func
== NULL
) {
13567 xmlGenericError(xmlGenericErrorContext
,
13568 "xmlXPathCompOpEval: function %s not found\n",
13569 (char *)op
->value4
);
13570 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR
);
13573 op
->cacheURI
= (void *) URI
;
13575 oldFunc
= ctxt
->context
->function
;
13576 oldFuncURI
= ctxt
->context
->functionURI
;
13577 ctxt
->context
->function
= op
->value4
;
13578 ctxt
->context
->functionURI
= op
->cacheURI
;
13579 func(ctxt
, op
->value
);
13580 ctxt
->context
->function
= oldFunc
;
13581 ctxt
->context
->functionURI
= oldFuncURI
;
13582 xmlXPathPopFrame(ctxt
, frame
);
13586 bakd
= ctxt
->context
->doc
;
13587 bak
= ctxt
->context
->node
;
13588 pp
= ctxt
->context
->proximityPosition
;
13589 cs
= ctxt
->context
->contextSize
;
13590 if (op
->ch1
!= -1) {
13591 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13592 ctxt
->context
->contextSize
= cs
;
13593 ctxt
->context
->proximityPosition
= pp
;
13594 ctxt
->context
->node
= bak
;
13595 ctxt
->context
->doc
= bakd
;
13598 if (op
->ch2
!= -1) {
13599 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13600 ctxt
->context
->contextSize
= cs
;
13601 ctxt
->context
->proximityPosition
= pp
;
13602 ctxt
->context
->node
= bak
;
13603 ctxt
->context
->doc
= bakd
;
13607 case XPATH_OP_PREDICATE
:
13608 case XPATH_OP_FILTER
:{
13609 xmlXPathObjectPtr res
;
13610 xmlXPathObjectPtr obj
, tmp
;
13611 xmlNodeSetPtr newset
= NULL
;
13612 xmlNodeSetPtr oldset
;
13613 xmlNodePtr oldnode
;
13618 * Optimization for ()[1] selection i.e. the first elem
13620 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13621 #ifdef XP_OPTIMIZED_FILTER_FIRST
13623 * FILTER TODO: Can we assume that the inner processing
13624 * will result in an ordered list if we have an
13626 * What about an additional field or flag on
13627 * xmlXPathObject like @sorted ? This way we wouln'd need
13628 * to assume anything, so it would be more robust and
13629 * easier to optimize.
13631 ((comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) || /* 18 */
13632 (comp
->steps
[op
->ch1
].op
== XPATH_OP_FILTER
)) && /* 17 */
13634 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13636 (comp
->steps
[op
->ch2
].op
== XPATH_OP_VALUE
)) { /* 12 */
13637 xmlXPathObjectPtr val
;
13639 val
= comp
->steps
[op
->ch2
].value4
;
13640 if ((val
!= NULL
) && (val
->type
== XPATH_NUMBER
) &&
13641 (val
->floatval
== 1.0)) {
13642 xmlNodePtr first
= NULL
;
13645 xmlXPathCompOpEvalFirst(ctxt
,
13646 &comp
->steps
[op
->ch1
],
13650 * The nodeset should be in document order,
13651 * Keep only the first value
13653 if ((ctxt
->value
!= NULL
) &&
13654 (ctxt
->value
->type
== XPATH_NODESET
) &&
13655 (ctxt
->value
->nodesetval
!= NULL
) &&
13656 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13657 xmlXPathNodeSetClearFromPos(ctxt
->value
->nodesetval
,
13663 * Optimization for ()[last()] selection i.e. the last elem
13665 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13666 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13667 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
13668 int f
= comp
->steps
[op
->ch2
].ch1
;
13671 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
13672 (comp
->steps
[f
].value5
== NULL
) &&
13673 (comp
->steps
[f
].value
== 0) &&
13674 (comp
->steps
[f
].value4
!= NULL
) &&
13676 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
13677 xmlNodePtr last
= NULL
;
13680 xmlXPathCompOpEvalLast(ctxt
,
13681 &comp
->steps
[op
->ch1
],
13685 * The nodeset should be in document order,
13686 * Keep only the last value
13688 if ((ctxt
->value
!= NULL
) &&
13689 (ctxt
->value
->type
== XPATH_NODESET
) &&
13690 (ctxt
->value
->nodesetval
!= NULL
) &&
13691 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
13692 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13693 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
13698 * Process inner predicates first.
13699 * Example "index[parent::book][1]":
13701 * PREDICATE <-- we are here "[1]"
13702 * PREDICATE <-- process "[parent::book]" first
13704 * COLLECT 'parent' 'name' 'node' book
13706 * ELEM Object is a number : 1
13710 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13714 if (ctxt
->value
== NULL
)
13717 oldnode
= ctxt
->context
->node
;
13719 #ifdef LIBXML_XPTR_ENABLED
13721 * Hum are we filtering the result of an XPointer expression
13723 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13724 xmlLocationSetPtr newlocset
= NULL
;
13725 xmlLocationSetPtr oldlocset
;
13728 * Extract the old locset, and then evaluate the result of the
13729 * expression for all the element in the locset. use it to grow
13732 CHECK_TYPE0(XPATH_LOCATIONSET
);
13733 obj
= valuePop(ctxt
);
13734 oldlocset
= obj
->user
;
13735 ctxt
->context
->node
= NULL
;
13737 if ((oldlocset
== NULL
) || (oldlocset
->locNr
== 0)) {
13738 ctxt
->context
->contextSize
= 0;
13739 ctxt
->context
->proximityPosition
= 0;
13742 xmlXPathCompOpEval(ctxt
,
13743 &comp
->steps
[op
->ch2
]);
13744 res
= valuePop(ctxt
);
13746 xmlXPathReleaseObject(ctxt
->context
, res
);
13748 valuePush(ctxt
, obj
);
13752 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13754 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13756 * Run the evaluation with a node list made of a
13757 * single item in the nodelocset.
13759 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13760 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13761 ctxt
->context
->proximityPosition
= i
+ 1;
13762 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13763 ctxt
->context
->node
);
13764 valuePush(ctxt
, tmp
);
13768 xmlXPathCompOpEval(ctxt
,
13769 &comp
->steps
[op
->ch2
]);
13770 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13771 xmlXPathFreeObject(obj
);
13776 * The result of the evaluation need to be tested to
13777 * decided whether the filter succeeded or not
13779 res
= valuePop(ctxt
);
13780 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13781 xmlXPtrLocationSetAdd(newlocset
,
13783 (oldlocset
->locTab
[i
]));
13790 xmlXPathReleaseObject(ctxt
->context
, res
);
13792 if (ctxt
->value
== tmp
) {
13793 res
= valuePop(ctxt
);
13794 xmlXPathReleaseObject(ctxt
->context
, res
);
13797 ctxt
->context
->node
= NULL
;
13801 * The result is used as the new evaluation locset.
13803 xmlXPathReleaseObject(ctxt
->context
, obj
);
13804 ctxt
->context
->node
= NULL
;
13805 ctxt
->context
->contextSize
= -1;
13806 ctxt
->context
->proximityPosition
= -1;
13807 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13808 ctxt
->context
->node
= oldnode
;
13811 #endif /* LIBXML_XPTR_ENABLED */
13814 * Extract the old set, and then evaluate the result of the
13815 * expression for all the element in the set. use it to grow
13818 CHECK_TYPE0(XPATH_NODESET
);
13819 obj
= valuePop(ctxt
);
13820 oldset
= obj
->nodesetval
;
13822 oldnode
= ctxt
->context
->node
;
13823 oldDoc
= ctxt
->context
->doc
;
13824 ctxt
->context
->node
= NULL
;
13826 if ((oldset
== NULL
) || (oldset
->nodeNr
== 0)) {
13827 ctxt
->context
->contextSize
= 0;
13828 ctxt
->context
->proximityPosition
= 0;
13832 xmlXPathCompOpEval(ctxt,
13833 &comp->steps[op->ch2]);
13835 res = valuePop(ctxt);
13837 xmlXPathFreeObject(res);
13839 valuePush(ctxt
, obj
);
13840 ctxt
->context
->node
= oldnode
;
13845 * Initialize the new set.
13846 * Also set the xpath document in case things like
13847 * key() evaluation are attempted on the predicate
13849 newset
= xmlXPathNodeSetCreate(NULL
);
13852 * "For each node in the node-set to be filtered, the
13853 * PredicateExpr is evaluated with that node as the
13854 * context node, with the number of nodes in the
13855 * node-set as the context size, and with the proximity
13856 * position of the node in the node-set with respect to
13857 * the axis as the context position;"
13858 * @oldset is the node-set" to be filtered.
13861 * "only predicates change the context position and
13862 * context size (see [2.4 Predicates])."
13864 * node-set context pos
13868 * After applying predicate [position() > 1] :
13869 * node-set context pos
13873 * removed the first node in the node-set, then
13874 * the context position of the
13876 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13878 * Run the evaluation with a node list made of
13879 * a single item in the nodeset.
13881 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13882 if ((oldset
->nodeTab
[i
]->type
!= XML_NAMESPACE_DECL
) &&
13883 (oldset
->nodeTab
[i
]->doc
!= NULL
))
13884 ctxt
->context
->doc
= oldset
->nodeTab
[i
]->doc
;
13886 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13887 ctxt
->context
->node
);
13889 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13890 ctxt
->context
->node
) < 0) {
13891 ctxt
->error
= XPATH_MEMORY_ERROR
;
13894 valuePush(ctxt
, tmp
);
13895 ctxt
->context
->contextSize
= oldset
->nodeNr
;
13896 ctxt
->context
->proximityPosition
= i
+ 1;
13898 * Evaluate the predicate against the context node.
13899 * Can/should we optimize position() predicates
13900 * here (e.g. "[1]")?
13904 xmlXPathCompOpEval(ctxt
,
13905 &comp
->steps
[op
->ch2
]);
13906 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13907 xmlXPathFreeNodeSet(newset
);
13908 xmlXPathFreeObject(obj
);
13913 * The result of the evaluation needs to be tested to
13914 * decide whether the filter succeeded or not
13917 * OPTIMIZE TODO: Can we use
13918 * xmlXPathNodeSetAdd*Unique()* instead?
13920 res
= valuePop(ctxt
);
13921 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13922 if (xmlXPathNodeSetAdd(newset
, oldset
->nodeTab
[i
])
13924 ctxt
->error
= XPATH_MEMORY_ERROR
;
13931 xmlXPathReleaseObject(ctxt
->context
, res
);
13933 if (ctxt
->value
== tmp
) {
13935 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13937 * Don't free the temporary nodeset
13938 * in order to avoid massive recreation inside this
13943 ctxt
->context
->node
= NULL
;
13946 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13948 * The result is used as the new evaluation set.
13950 xmlXPathReleaseObject(ctxt
->context
, obj
);
13951 ctxt
->context
->node
= NULL
;
13952 ctxt
->context
->contextSize
= -1;
13953 ctxt
->context
->proximityPosition
= -1;
13954 /* may want to move this past the '}' later */
13955 ctxt
->context
->doc
= oldDoc
;
13957 xmlXPathCacheWrapNodeSet(ctxt
->context
, newset
));
13959 ctxt
->context
->node
= oldnode
;
13962 case XPATH_OP_SORT
:
13964 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13966 if ((ctxt
->value
!= NULL
) &&
13967 (ctxt
->value
->type
== XPATH_NODESET
) &&
13968 (ctxt
->value
->nodesetval
!= NULL
) &&
13969 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13971 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
13974 #ifdef LIBXML_XPTR_ENABLED
13975 case XPATH_OP_RANGETO
:{
13976 xmlXPathObjectPtr range
;
13977 xmlXPathObjectPtr res
, obj
;
13978 xmlXPathObjectPtr tmp
;
13979 xmlLocationSetPtr newlocset
= NULL
;
13980 xmlLocationSetPtr oldlocset
;
13981 xmlNodeSetPtr oldset
;
13984 if (op
->ch1
!= -1) {
13986 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13989 if (ctxt
->value
== NULL
) {
13990 XP_ERROR0(XPATH_INVALID_OPERAND
);
13995 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13997 * Extract the old locset, and then evaluate the result of the
13998 * expression for all the element in the locset. use it to grow
14001 CHECK_TYPE0(XPATH_LOCATIONSET
);
14002 obj
= valuePop(ctxt
);
14003 oldlocset
= obj
->user
;
14005 if ((oldlocset
== NULL
) || (oldlocset
->locNr
== 0)) {
14006 ctxt
->context
->node
= NULL
;
14007 ctxt
->context
->contextSize
= 0;
14008 ctxt
->context
->proximityPosition
= 0;
14009 total
+= xmlXPathCompOpEval(ctxt
,&comp
->steps
[op
->ch2
]);
14010 res
= valuePop(ctxt
);
14012 xmlXPathReleaseObject(ctxt
->context
, res
);
14014 valuePush(ctxt
, obj
);
14018 newlocset
= xmlXPtrLocationSetCreate(NULL
);
14020 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
14022 * Run the evaluation with a node list made of a
14023 * single item in the nodelocset.
14025 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
14026 ctxt
->context
->contextSize
= oldlocset
->locNr
;
14027 ctxt
->context
->proximityPosition
= i
+ 1;
14028 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
14029 ctxt
->context
->node
);
14030 valuePush(ctxt
, tmp
);
14034 xmlXPathCompOpEval(ctxt
,
14035 &comp
->steps
[op
->ch2
]);
14036 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14037 xmlXPathFreeObject(obj
);
14041 res
= valuePop(ctxt
);
14042 if (res
->type
== XPATH_LOCATIONSET
) {
14043 xmlLocationSetPtr rloc
=
14044 (xmlLocationSetPtr
)res
->user
;
14045 for (j
=0; j
<rloc
->locNr
; j
++) {
14046 range
= xmlXPtrNewRange(
14047 oldlocset
->locTab
[i
]->user
,
14048 oldlocset
->locTab
[i
]->index
,
14049 rloc
->locTab
[j
]->user2
,
14050 rloc
->locTab
[j
]->index2
);
14051 if (range
!= NULL
) {
14052 xmlXPtrLocationSetAdd(newlocset
, range
);
14056 range
= xmlXPtrNewRangeNodeObject(
14057 (xmlNodePtr
)oldlocset
->locTab
[i
]->user
, res
);
14058 if (range
!= NULL
) {
14059 xmlXPtrLocationSetAdd(newlocset
,range
);
14067 xmlXPathReleaseObject(ctxt
->context
, res
);
14069 if (ctxt
->value
== tmp
) {
14070 res
= valuePop(ctxt
);
14071 xmlXPathReleaseObject(ctxt
->context
, res
);
14074 ctxt
->context
->node
= NULL
;
14076 } else { /* Not a location set */
14077 CHECK_TYPE0(XPATH_NODESET
);
14078 obj
= valuePop(ctxt
);
14079 oldset
= obj
->nodesetval
;
14080 ctxt
->context
->node
= NULL
;
14082 newlocset
= xmlXPtrLocationSetCreate(NULL
);
14084 if (oldset
!= NULL
) {
14085 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
14087 * Run the evaluation with a node list made of a single item
14090 ctxt
->context
->node
= oldset
->nodeTab
[i
];
14092 * OPTIMIZE TODO: Avoid recreation for every iteration.
14094 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
14095 ctxt
->context
->node
);
14096 valuePush(ctxt
, tmp
);
14100 xmlXPathCompOpEval(ctxt
,
14101 &comp
->steps
[op
->ch2
]);
14102 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14103 xmlXPathFreeObject(obj
);
14107 res
= valuePop(ctxt
);
14109 xmlXPtrNewRangeNodeObject(oldset
->nodeTab
[i
],
14111 if (range
!= NULL
) {
14112 xmlXPtrLocationSetAdd(newlocset
, range
);
14119 xmlXPathReleaseObject(ctxt
->context
, res
);
14121 if (ctxt
->value
== tmp
) {
14122 res
= valuePop(ctxt
);
14123 xmlXPathReleaseObject(ctxt
->context
, res
);
14126 ctxt
->context
->node
= NULL
;
14132 * The result is used as the new evaluation set.
14134 xmlXPathReleaseObject(ctxt
->context
, obj
);
14135 ctxt
->context
->node
= NULL
;
14136 ctxt
->context
->contextSize
= -1;
14137 ctxt
->context
->proximityPosition
= -1;
14138 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
14141 #endif /* LIBXML_XPTR_ENABLED */
14143 xmlGenericError(xmlGenericErrorContext
,
14144 "XPath: unknown precompiled operation %d\n", op
->op
);
14145 ctxt
->error
= XPATH_INVALID_OPERAND
;
14150 * xmlXPathCompOpEvalToBoolean:
14151 * @ctxt: the XPath parser context
14153 * Evaluates if the expression evaluates to true.
14155 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14158 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
14159 xmlXPathStepOpPtr op
,
14162 xmlXPathObjectPtr resObj
= NULL
;
14165 /* comp = ctxt->comp; */
14169 case XPATH_OP_VALUE
:
14170 resObj
= (xmlXPathObjectPtr
) op
->value4
;
14172 return(xmlXPathEvaluatePredicateResult(ctxt
, resObj
));
14173 return(xmlXPathCastToBoolean(resObj
));
14174 case XPATH_OP_SORT
:
14176 * We don't need sorting for boolean results. Skip this one.
14178 if (op
->ch1
!= -1) {
14179 op
= &ctxt
->comp
->steps
[op
->ch1
];
14183 case XPATH_OP_COLLECT
:
14187 xmlXPathCompOpEval(ctxt
, &ctxt
->comp
->steps
[op
->ch1
]);
14188 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14191 xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 1);
14192 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14195 resObj
= valuePop(ctxt
);
14196 if (resObj
== NULL
)
14201 * Fallback to call xmlXPathCompOpEval().
14203 xmlXPathCompOpEval(ctxt
, op
);
14204 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14207 resObj
= valuePop(ctxt
);
14208 if (resObj
== NULL
)
14216 if (resObj
->type
== XPATH_BOOLEAN
) {
14217 res
= resObj
->boolval
;
14218 } else if (isPredicate
) {
14220 * For predicates a result of type "number" is handled
14223 * "If the result is a number, the result will be converted
14224 * to true if the number is equal to the context position
14225 * and will be converted to false otherwise;"
14227 res
= xmlXPathEvaluatePredicateResult(ctxt
, resObj
);
14229 res
= xmlXPathCastToBoolean(resObj
);
14231 xmlXPathReleaseObject(ctxt
->context
, resObj
);
14238 #ifdef XPATH_STREAMING
14240 * xmlXPathRunStreamEval:
14241 * @ctxt: the XPath parser context with the compiled expression
14243 * Evaluate the Precompiled Streamable XPath expression in the given context.
14246 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt
, xmlPatternPtr comp
,
14247 xmlXPathObjectPtr
*resultSeq
, int toBool
)
14249 int max_depth
, min_depth
;
14252 int eval_all_nodes
;
14253 xmlNodePtr cur
= NULL
, limit
= NULL
;
14254 xmlStreamCtxtPtr patstream
= NULL
;
14258 if ((ctxt
== NULL
) || (comp
== NULL
))
14260 max_depth
= xmlPatternMaxDepth(comp
);
14261 if (max_depth
== -1)
14263 if (max_depth
== -2)
14265 min_depth
= xmlPatternMinDepth(comp
);
14266 if (min_depth
== -1)
14268 from_root
= xmlPatternFromRoot(comp
);
14272 printf("stream eval: depth %d from root %d\n", max_depth
, from_root
);
14276 if (resultSeq
== NULL
)
14278 *resultSeq
= xmlXPathCacheNewNodeSet(ctxt
, NULL
);
14279 if (*resultSeq
== NULL
)
14284 * handle the special cases of "/" amd "." being matched
14286 if (min_depth
== 0) {
14291 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
,
14292 (xmlNodePtr
) ctxt
->doc
);
14294 /* Select "self::node()" */
14297 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, ctxt
->node
);
14300 if (max_depth
== 0) {
14305 cur
= (xmlNodePtr
)ctxt
->doc
;
14306 } else if (ctxt
->node
!= NULL
) {
14307 switch (ctxt
->node
->type
) {
14308 case XML_ELEMENT_NODE
:
14309 case XML_DOCUMENT_NODE
:
14310 case XML_DOCUMENT_FRAG_NODE
:
14311 case XML_HTML_DOCUMENT_NODE
:
14312 #ifdef LIBXML_DOCB_ENABLED
14313 case XML_DOCB_DOCUMENT_NODE
:
14317 case XML_ATTRIBUTE_NODE
:
14318 case XML_TEXT_NODE
:
14319 case XML_CDATA_SECTION_NODE
:
14320 case XML_ENTITY_REF_NODE
:
14321 case XML_ENTITY_NODE
:
14323 case XML_COMMENT_NODE
:
14324 case XML_NOTATION_NODE
:
14326 case XML_DOCUMENT_TYPE_NODE
:
14327 case XML_ELEMENT_DECL
:
14328 case XML_ATTRIBUTE_DECL
:
14329 case XML_ENTITY_DECL
:
14330 case XML_NAMESPACE_DECL
:
14331 case XML_XINCLUDE_START
:
14332 case XML_XINCLUDE_END
:
14341 patstream
= xmlPatternGetStreamCtxt(comp
);
14342 if (patstream
== NULL
) {
14344 * QUESTION TODO: Is this an error?
14349 eval_all_nodes
= xmlStreamWantsAnyNode(patstream
);
14352 ret
= xmlStreamPush(patstream
, NULL
, NULL
);
14354 } else if (ret
== 1) {
14357 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
);
14361 goto scan_children
;
14366 switch (cur
->type
) {
14367 case XML_ELEMENT_NODE
:
14368 case XML_TEXT_NODE
:
14369 case XML_CDATA_SECTION_NODE
:
14370 case XML_COMMENT_NODE
:
14372 if (cur
->type
== XML_ELEMENT_NODE
) {
14373 ret
= xmlStreamPush(patstream
, cur
->name
,
14374 (cur
->ns
? cur
->ns
->href
: NULL
));
14375 } else if (eval_all_nodes
)
14376 ret
= xmlStreamPushNode(patstream
, NULL
, NULL
, cur
->type
);
14382 } else if (ret
== 1) {
14385 if (xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
)
14387 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
14388 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
14391 if ((cur
->children
== NULL
) || (depth
>= max_depth
)) {
14392 ret
= xmlStreamPop(patstream
);
14393 while (cur
->next
!= NULL
) {
14395 if ((cur
->type
!= XML_ENTITY_DECL
) &&
14396 (cur
->type
!= XML_DTD_NODE
))
14405 if (cur
->type
== XML_NAMESPACE_DECL
) break;
14406 if ((cur
->children
!= NULL
) && (depth
< max_depth
)) {
14408 * Do not descend on entities declarations
14410 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
14411 cur
= cur
->children
;
14416 if (cur
->type
!= XML_DTD_NODE
)
14424 while (cur
->next
!= NULL
) {
14426 if ((cur
->type
!= XML_ENTITY_DECL
) &&
14427 (cur
->type
!= XML_DTD_NODE
))
14434 if ((cur
== NULL
) || (cur
== limit
))
14436 if (cur
->type
== XML_ELEMENT_NODE
) {
14437 ret
= xmlStreamPop(patstream
);
14438 } else if ((eval_all_nodes
) &&
14439 ((cur
->type
== XML_TEXT_NODE
) ||
14440 (cur
->type
== XML_CDATA_SECTION_NODE
) ||
14441 (cur
->type
== XML_COMMENT_NODE
) ||
14442 (cur
->type
== XML_PI_NODE
)))
14444 ret
= xmlStreamPop(patstream
);
14446 if (cur
->next
!= NULL
) {
14450 } while (cur
!= NULL
);
14452 } while ((cur
!= NULL
) && (depth
>= 0));
14457 printf("stream eval: checked %d nodes selected %d\n",
14458 nb_nodes
, retObj
->nodesetval
->nodeNr
);
14462 xmlFreeStreamCtxt(patstream
);
14467 xmlFreeStreamCtxt(patstream
);
14470 #endif /* XPATH_STREAMING */
14474 * @ctxt: the XPath parser context with the compiled expression
14475 * @toBool: evaluate to a boolean result
14477 * Evaluate the Precompiled XPath expression in the given context.
14480 xmlXPathRunEval(xmlXPathParserContextPtr ctxt
, int toBool
)
14482 xmlXPathCompExprPtr comp
;
14484 if ((ctxt
== NULL
) || (ctxt
->comp
== NULL
))
14487 if (ctxt
->valueTab
== NULL
) {
14488 /* Allocate the value stack */
14489 ctxt
->valueTab
= (xmlXPathObjectPtr
*)
14490 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
14491 if (ctxt
->valueTab
== NULL
) {
14492 xmlXPathPErrMemory(ctxt
, "creating evaluation context\n");
14496 ctxt
->valueMax
= 10;
14497 ctxt
->value
= NULL
;
14498 ctxt
->valueFrame
= 0;
14500 #ifdef XPATH_STREAMING
14501 if (ctxt
->comp
->stream
) {
14506 * Evaluation to boolean result.
14508 res
= xmlXPathRunStreamEval(ctxt
->context
,
14509 ctxt
->comp
->stream
, NULL
, 1);
14513 xmlXPathObjectPtr resObj
= NULL
;
14516 * Evaluation to a sequence.
14518 res
= xmlXPathRunStreamEval(ctxt
->context
,
14519 ctxt
->comp
->stream
, &resObj
, 0);
14521 if ((res
!= -1) && (resObj
!= NULL
)) {
14522 valuePush(ctxt
, resObj
);
14525 if (resObj
!= NULL
)
14526 xmlXPathReleaseObject(ctxt
->context
, resObj
);
14529 * QUESTION TODO: This falls back to normal XPath evaluation
14530 * if res == -1. Is this intended?
14535 if (comp
->last
< 0) {
14536 xmlGenericError(xmlGenericErrorContext
,
14537 "xmlXPathRunEval: last is less than zero\n");
14541 return(xmlXPathCompOpEvalToBoolean(ctxt
,
14542 &comp
->steps
[comp
->last
], 0));
14544 xmlXPathCompOpEval(ctxt
, &comp
->steps
[comp
->last
]);
14549 /************************************************************************
14551 * Public interfaces *
14553 ************************************************************************/
14556 * xmlXPathEvalPredicate:
14557 * @ctxt: the XPath context
14558 * @res: the Predicate Expression evaluation result
14560 * Evaluate a predicate result for the current node.
14561 * A PredicateExpr is evaluated by evaluating the Expr and converting
14562 * the result to a boolean. If the result is a number, the result will
14563 * be converted to true if the number is equal to the position of the
14564 * context node in the context node list (as returned by the position
14565 * function) and will be converted to false otherwise; if the result
14566 * is not a number, then the result will be converted as if by a call
14567 * to the boolean function.
14569 * Returns 1 if predicate is true, 0 otherwise
14572 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr res
) {
14573 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14574 switch (res
->type
) {
14575 case XPATH_BOOLEAN
:
14576 return(res
->boolval
);
14578 return(res
->floatval
== ctxt
->proximityPosition
);
14579 case XPATH_NODESET
:
14580 case XPATH_XSLT_TREE
:
14581 if (res
->nodesetval
== NULL
)
14583 return(res
->nodesetval
->nodeNr
!= 0);
14585 return((res
->stringval
!= NULL
) &&
14586 (xmlStrlen(res
->stringval
) != 0));
14594 * xmlXPathEvaluatePredicateResult:
14595 * @ctxt: the XPath Parser context
14596 * @res: the Predicate Expression evaluation result
14598 * Evaluate a predicate result for the current node.
14599 * A PredicateExpr is evaluated by evaluating the Expr and converting
14600 * the result to a boolean. If the result is a number, the result will
14601 * be converted to true if the number is equal to the position of the
14602 * context node in the context node list (as returned by the position
14603 * function) and will be converted to false otherwise; if the result
14604 * is not a number, then the result will be converted as if by a call
14605 * to the boolean function.
14607 * Returns 1 if predicate is true, 0 otherwise
14610 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt
,
14611 xmlXPathObjectPtr res
) {
14612 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14613 switch (res
->type
) {
14614 case XPATH_BOOLEAN
:
14615 return(res
->boolval
);
14617 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14618 return((res
->floatval
== ctxt
->context
->proximityPosition
) &&
14619 (!xmlXPathIsNaN(res
->floatval
))); /* MSC pbm Mark Vakoc !*/
14621 return(res
->floatval
== ctxt
->context
->proximityPosition
);
14623 case XPATH_NODESET
:
14624 case XPATH_XSLT_TREE
:
14625 if (res
->nodesetval
== NULL
)
14627 return(res
->nodesetval
->nodeNr
!= 0);
14629 return((res
->stringval
!= NULL
) && (res
->stringval
[0] != 0));
14630 #ifdef LIBXML_XPTR_ENABLED
14631 case XPATH_LOCATIONSET
:{
14632 xmlLocationSetPtr ptr
= res
->user
;
14635 return (ptr
->locNr
!= 0);
14644 #ifdef XPATH_STREAMING
14646 * xmlXPathTryStreamCompile:
14647 * @ctxt: an XPath context
14648 * @str: the XPath expression
14650 * Try to compile the XPath expression as a streamable subset.
14652 * Returns the compiled expression or NULL if failed to compile.
14654 static xmlXPathCompExprPtr
14655 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14657 * Optimization: use streaming patterns when the XPath expression can
14658 * be compiled to a stream lookup
14660 xmlPatternPtr stream
;
14661 xmlXPathCompExprPtr comp
;
14662 xmlDictPtr dict
= NULL
;
14663 const xmlChar
**namespaces
= NULL
;
14667 if ((!xmlStrchr(str
, '[')) && (!xmlStrchr(str
, '(')) &&
14668 (!xmlStrchr(str
, '@'))) {
14669 const xmlChar
*tmp
;
14672 * We don't try to handle expressions using the verbose axis
14673 * specifiers ("::"), just the simplied form at this point.
14674 * Additionally, if there is no list of namespaces available and
14675 * there's a ":" in the expression, indicating a prefixed QName,
14676 * then we won't try to compile either. xmlPatterncompile() needs
14677 * to have a list of namespaces at compilation time in order to
14678 * compile prefixed name tests.
14680 tmp
= xmlStrchr(str
, ':');
14681 if ((tmp
!= NULL
) &&
14682 ((ctxt
== NULL
) || (ctxt
->nsNr
== 0) || (tmp
[1] == ':')))
14685 if (ctxt
!= NULL
) {
14687 if (ctxt
->nsNr
> 0) {
14688 namespaces
= xmlMalloc(2 * (ctxt
->nsNr
+ 1) * sizeof(xmlChar
*));
14689 if (namespaces
== NULL
) {
14690 xmlXPathErrMemory(ctxt
, "allocating namespaces array\n");
14693 for (i
= 0, j
= 0; (j
< ctxt
->nsNr
); j
++) {
14694 ns
= ctxt
->namespaces
[j
];
14695 namespaces
[i
++] = ns
->href
;
14696 namespaces
[i
++] = ns
->prefix
;
14698 namespaces
[i
++] = NULL
;
14699 namespaces
[i
] = NULL
;
14703 stream
= xmlPatterncompile(str
, dict
, XML_PATTERN_XPATH
,
14705 if (namespaces
!= NULL
) {
14706 xmlFree((xmlChar
**)namespaces
);
14708 if ((stream
!= NULL
) && (xmlPatternStreamable(stream
) == 1)) {
14709 comp
= xmlXPathNewCompExpr();
14710 if (comp
== NULL
) {
14711 xmlXPathErrMemory(ctxt
, "allocating streamable expression\n");
14714 comp
->stream
= stream
;
14717 xmlDictReference(comp
->dict
);
14720 xmlFreePattern(stream
);
14724 #endif /* XPATH_STREAMING */
14727 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp
, xmlXPathStepOpPtr op
)
14730 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14731 * internal representation.
14734 if ((op
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14736 (op
->ch2
== -1 /* no predicate */))
14738 xmlXPathStepOpPtr prevop
= &comp
->steps
[op
->ch1
];
14740 if ((prevop
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14741 ((xmlXPathAxisVal
) prevop
->value
==
14742 AXIS_DESCENDANT_OR_SELF
) &&
14743 (prevop
->ch2
== -1) &&
14744 ((xmlXPathTestVal
) prevop
->value2
== NODE_TEST_TYPE
) &&
14745 ((xmlXPathTypeVal
) prevop
->value3
== NODE_TYPE_NODE
))
14748 * This is a "descendant-or-self::node()" without predicates.
14749 * Try to eliminate it.
14752 switch ((xmlXPathAxisVal
) op
->value
) {
14754 case AXIS_DESCENDANT
:
14756 * Convert "descendant-or-self::node()/child::" or
14757 * "descendant-or-self::node()/descendant::" to
14760 op
->ch1
= prevop
->ch1
;
14761 op
->value
= AXIS_DESCENDANT
;
14764 case AXIS_DESCENDANT_OR_SELF
:
14766 * Convert "descendant-or-self::node()/self::" or
14767 * "descendant-or-self::node()/descendant-or-self::" to
14768 * to "descendant-or-self::"
14770 op
->ch1
= prevop
->ch1
;
14771 op
->value
= AXIS_DESCENDANT_OR_SELF
;
14779 /* OP_VALUE has invalid ch1. */
14780 if (op
->op
== XPATH_OP_VALUE
)
14785 xmlXPathOptimizeExpression(comp
, &comp
->steps
[op
->ch1
]);
14787 xmlXPathOptimizeExpression(comp
, &comp
->steps
[op
->ch2
]);
14791 * xmlXPathCtxtCompile:
14792 * @ctxt: an XPath context
14793 * @str: the XPath expression
14795 * Compile an XPath expression
14797 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14798 * the caller has to free the object.
14800 xmlXPathCompExprPtr
14801 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14802 xmlXPathParserContextPtr pctxt
;
14803 xmlXPathCompExprPtr comp
;
14805 #ifdef XPATH_STREAMING
14806 comp
= xmlXPathTryStreamCompile(ctxt
, str
);
14813 pctxt
= xmlXPathNewParserContext(str
, ctxt
);
14816 xmlXPathCompileExpr(pctxt
, 1);
14818 if( pctxt
->error
!= XPATH_EXPRESSION_OK
)
14820 xmlXPathFreeParserContext(pctxt
);
14824 if (*pctxt
->cur
!= 0) {
14826 * aleksey: in some cases this line prints *second* error message
14827 * (see bug #78858) and probably this should be fixed.
14828 * However, we are not sure that all error messages are printed
14829 * out in other places. It's not critical so we leave it as-is for now
14831 xmlXPatherror(pctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
14834 comp
= pctxt
->comp
;
14835 pctxt
->comp
= NULL
;
14837 xmlXPathFreeParserContext(pctxt
);
14839 if (comp
!= NULL
) {
14840 comp
->expr
= xmlStrdup(str
);
14841 #ifdef DEBUG_EVAL_COUNTS
14842 comp
->string
= xmlStrdup(str
);
14845 if ((comp
->nbStep
> 1) && (comp
->last
>= 0)) {
14846 xmlXPathOptimizeExpression(comp
, &comp
->steps
[comp
->last
]);
14854 * @str: the XPath expression
14856 * Compile an XPath expression
14858 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14859 * the caller has to free the object.
14861 xmlXPathCompExprPtr
14862 xmlXPathCompile(const xmlChar
*str
) {
14863 return(xmlXPathCtxtCompile(NULL
, str
));
14867 * xmlXPathCompiledEvalInternal:
14868 * @comp: the compiled XPath expression
14869 * @ctxt: the XPath context
14870 * @resObj: the resulting XPath object or NULL
14871 * @toBool: 1 if only a boolean result is requested
14873 * Evaluate the Precompiled XPath expression in the given context.
14874 * The caller has to free @resObj.
14876 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14877 * the caller has to free the object.
14880 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp
,
14881 xmlXPathContextPtr ctxt
,
14882 xmlXPathObjectPtr
*resObjPtr
,
14885 xmlXPathParserContextPtr pctxt
;
14886 xmlXPathObjectPtr resObj
;
14887 #ifndef LIBXML_THREAD_ENABLED
14888 static int reentance
= 0;
14892 CHECK_CTXT_NEG(ctxt
)
14898 #ifndef LIBXML_THREAD_ENABLED
14901 xmlXPathDisableOptimizer
= 1;
14904 #ifdef DEBUG_EVAL_COUNTS
14906 if ((comp
->string
!= NULL
) && (comp
->nb
> 100)) {
14907 fprintf(stderr
, "100 x %s\n", comp
->string
);
14911 pctxt
= xmlXPathCompParserContext(comp
, ctxt
);
14912 res
= xmlXPathRunEval(pctxt
, toBool
);
14914 if (pctxt
->error
!= XPATH_EXPRESSION_OK
) {
14917 resObj
= valuePop(pctxt
);
14918 if (resObj
== NULL
) {
14920 xmlGenericError(xmlGenericErrorContext
,
14921 "xmlXPathCompiledEval: No result on the stack.\n");
14922 } else if (pctxt
->valueNr
> 0) {
14923 xmlGenericError(xmlGenericErrorContext
,
14924 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14930 *resObjPtr
= resObj
;
14932 xmlXPathReleaseObject(ctxt
, resObj
);
14934 pctxt
->comp
= NULL
;
14935 xmlXPathFreeParserContext(pctxt
);
14936 #ifndef LIBXML_THREAD_ENABLED
14944 * xmlXPathCompiledEval:
14945 * @comp: the compiled XPath expression
14946 * @ctx: the XPath context
14948 * Evaluate the Precompiled XPath expression in the given context.
14950 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14951 * the caller has to free the object.
14954 xmlXPathCompiledEval(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctx
)
14956 xmlXPathObjectPtr res
= NULL
;
14958 xmlXPathCompiledEvalInternal(comp
, ctx
, &res
, 0);
14963 * xmlXPathCompiledEvalToBoolean:
14964 * @comp: the compiled XPath expression
14965 * @ctxt: the XPath context
14967 * Applies the XPath boolean() function on the result of the given
14968 * compiled expression.
14970 * Returns 1 if the expression evaluated to true, 0 if to false and
14971 * -1 in API and internal errors.
14974 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp
,
14975 xmlXPathContextPtr ctxt
)
14977 return(xmlXPathCompiledEvalInternal(comp
, ctxt
, NULL
, 1));
14981 * xmlXPathEvalExpr:
14982 * @ctxt: the XPath Parser context
14984 * Parse and evaluate an XPath expression in the given context,
14985 * then push the result on the context stack
14988 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt
) {
14989 #ifdef XPATH_STREAMING
14990 xmlXPathCompExprPtr comp
;
14993 if (ctxt
== NULL
) return;
14995 #ifdef XPATH_STREAMING
14996 comp
= xmlXPathTryStreamCompile(ctxt
->context
, ctxt
->base
);
14997 if (comp
!= NULL
) {
14998 if (ctxt
->comp
!= NULL
)
14999 xmlXPathFreeCompExpr(ctxt
->comp
);
15004 xmlXPathCompileExpr(ctxt
, 1);
15007 /* Check for trailing characters. */
15008 if (*ctxt
->cur
!= 0)
15009 XP_ERROR(XPATH_EXPR_ERROR
);
15011 if ((ctxt
->comp
->nbStep
> 1) && (ctxt
->comp
->last
>= 0))
15012 xmlXPathOptimizeExpression(ctxt
->comp
,
15013 &ctxt
->comp
->steps
[ctxt
->comp
->last
]);
15016 xmlXPathRunEval(ctxt
, 0);
15021 * @str: the XPath expression
15022 * @ctx: the XPath context
15024 * Evaluate the XPath Location Path in the given context.
15026 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15027 * the caller has to free the object.
15030 xmlXPathEval(const xmlChar
*str
, xmlXPathContextPtr ctx
) {
15031 xmlXPathParserContextPtr ctxt
;
15032 xmlXPathObjectPtr res
;
15038 ctxt
= xmlXPathNewParserContext(str
, ctx
);
15041 xmlXPathEvalExpr(ctxt
);
15043 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
15046 res
= valuePop(ctxt
);
15048 xmlGenericError(xmlGenericErrorContext
,
15049 "xmlXPathCompiledEval: No result on the stack.\n");
15050 } else if (ctxt
->valueNr
> 0) {
15051 xmlGenericError(xmlGenericErrorContext
,
15052 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15057 xmlXPathFreeParserContext(ctxt
);
15062 * xmlXPathSetContextNode:
15063 * @node: the node to to use as the context node
15064 * @ctx: the XPath context
15066 * Sets 'node' as the context node. The node must be in the same
15067 * document as that associated with the context.
15069 * Returns -1 in case of error or 0 if successful
15072 xmlXPathSetContextNode(xmlNodePtr node
, xmlXPathContextPtr ctx
) {
15073 if ((node
== NULL
) || (ctx
== NULL
))
15076 if (node
->doc
== ctx
->doc
) {
15084 * xmlXPathNodeEval:
15085 * @node: the node to to use as the context node
15086 * @str: the XPath expression
15087 * @ctx: the XPath context
15089 * Evaluate the XPath Location Path in the given context. The node 'node'
15090 * is set as the context node. The context node is not restored.
15092 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15093 * the caller has to free the object.
15096 xmlXPathNodeEval(xmlNodePtr node
, const xmlChar
*str
, xmlXPathContextPtr ctx
) {
15099 if (xmlXPathSetContextNode(node
, ctx
) < 0)
15101 return(xmlXPathEval(str
, ctx
));
15105 * xmlXPathEvalExpression:
15106 * @str: the XPath expression
15107 * @ctxt: the XPath context
15109 * Alias for xmlXPathEval().
15111 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15112 * the caller has to free the object.
15115 xmlXPathEvalExpression(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
15116 return(xmlXPathEval(str
, ctxt
));
15119 /************************************************************************
15121 * Extra functions not pertaining to the XPath spec *
15123 ************************************************************************/
15125 * xmlXPathEscapeUriFunction:
15126 * @ctxt: the XPath Parser context
15127 * @nargs: the number of arguments
15129 * Implement the escape-uri() XPath function
15130 * string escape-uri(string $str, bool $escape-reserved)
15132 * This function applies the URI escaping rules defined in section 2 of [RFC
15133 * 2396] to the string supplied as $uri-part, which typically represents all
15134 * or part of a URI. The effect of the function is to replace any special
15135 * character in the string by an escape sequence of the form %xx%yy...,
15136 * where xxyy... is the hexadecimal representation of the octets used to
15137 * represent the character in UTF-8.
15139 * The set of characters that are escaped depends on the setting of the
15140 * boolean argument $escape-reserved.
15142 * If $escape-reserved is true, all characters are escaped other than lower
15143 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15144 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15145 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15146 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15149 * If $escape-reserved is false, the behavior differs in that characters
15150 * referred to in [RFC 2396] as reserved characters are not escaped. These
15151 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15153 * [RFC 2396] does not define whether escaped URIs should use lower case or
15154 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15155 * compared using string comparison functions, this function must always use
15156 * the upper-case letters A-F.
15158 * Generally, $escape-reserved should be set to true when escaping a string
15159 * that is to form a single part of a URI, and to false when escaping an
15160 * entire URI or URI reference.
15162 * In the case of non-ascii characters, the string is encoded according to
15163 * utf-8 and then converted according to RFC 2396.
15166 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15167 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15168 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15169 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15173 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
15174 xmlXPathObjectPtr str
;
15175 int escape_reserved
;
15182 escape_reserved
= xmlXPathPopBoolean(ctxt
);
15185 str
= valuePop(ctxt
);
15187 target
= xmlBufCreate();
15193 for (cptr
= str
->stringval
; *cptr
; cptr
++) {
15194 if ((*cptr
>= 'A' && *cptr
<= 'Z') ||
15195 (*cptr
>= 'a' && *cptr
<= 'z') ||
15196 (*cptr
>= '0' && *cptr
<= '9') ||
15197 *cptr
== '-' || *cptr
== '_' || *cptr
== '.' ||
15198 *cptr
== '!' || *cptr
== '~' || *cptr
== '*' ||
15199 *cptr
== '\''|| *cptr
== '(' || *cptr
== ')' ||
15201 ((cptr
[1] >= 'A' && cptr
[1] <= 'F') ||
15202 (cptr
[1] >= 'a' && cptr
[1] <= 'f') ||
15203 (cptr
[1] >= '0' && cptr
[1] <= '9')) &&
15204 ((cptr
[2] >= 'A' && cptr
[2] <= 'F') ||
15205 (cptr
[2] >= 'a' && cptr
[2] <= 'f') ||
15206 (cptr
[2] >= '0' && cptr
[2] <= '9'))) ||
15207 (!escape_reserved
&&
15208 (*cptr
== ';' || *cptr
== '/' || *cptr
== '?' ||
15209 *cptr
== ':' || *cptr
== '@' || *cptr
== '&' ||
15210 *cptr
== '=' || *cptr
== '+' || *cptr
== '$' ||
15212 xmlBufAdd(target
, cptr
, 1);
15214 if ((*cptr
>> 4) < 10)
15215 escape
[1] = '0' + (*cptr
>> 4);
15217 escape
[1] = 'A' - 10 + (*cptr
>> 4);
15218 if ((*cptr
& 0xF) < 10)
15219 escape
[2] = '0' + (*cptr
& 0xF);
15221 escape
[2] = 'A' - 10 + (*cptr
& 0xF);
15223 xmlBufAdd(target
, &escape
[0], 3);
15227 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
15228 xmlBufContent(target
)));
15229 xmlBufFree(target
);
15230 xmlXPathReleaseObject(ctxt
->context
, str
);
15234 * xmlXPathRegisterAllFunctions:
15235 * @ctxt: the XPath context
15237 * Registers all default XPath functions in this context
15240 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt
)
15242 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"boolean",
15243 xmlXPathBooleanFunction
);
15244 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"ceiling",
15245 xmlXPathCeilingFunction
);
15246 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"count",
15247 xmlXPathCountFunction
);
15248 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"concat",
15249 xmlXPathConcatFunction
);
15250 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"contains",
15251 xmlXPathContainsFunction
);
15252 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"id",
15253 xmlXPathIdFunction
);
15254 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"false",
15255 xmlXPathFalseFunction
);
15256 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"floor",
15257 xmlXPathFloorFunction
);
15258 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"last",
15259 xmlXPathLastFunction
);
15260 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"lang",
15261 xmlXPathLangFunction
);
15262 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"local-name",
15263 xmlXPathLocalNameFunction
);
15264 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"not",
15265 xmlXPathNotFunction
);
15266 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"name",
15267 xmlXPathNameFunction
);
15268 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"namespace-uri",
15269 xmlXPathNamespaceURIFunction
);
15270 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"normalize-space",
15271 xmlXPathNormalizeFunction
);
15272 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"number",
15273 xmlXPathNumberFunction
);
15274 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"position",
15275 xmlXPathPositionFunction
);
15276 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"round",
15277 xmlXPathRoundFunction
);
15278 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string",
15279 xmlXPathStringFunction
);
15280 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string-length",
15281 xmlXPathStringLengthFunction
);
15282 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"starts-with",
15283 xmlXPathStartsWithFunction
);
15284 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring",
15285 xmlXPathSubstringFunction
);
15286 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-before",
15287 xmlXPathSubstringBeforeFunction
);
15288 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-after",
15289 xmlXPathSubstringAfterFunction
);
15290 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"sum",
15291 xmlXPathSumFunction
);
15292 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"true",
15293 xmlXPathTrueFunction
);
15294 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"translate",
15295 xmlXPathTranslateFunction
);
15297 xmlXPathRegisterFuncNS(ctxt
, (const xmlChar
*)"escape-uri",
15298 (const xmlChar
*)"http://www.w3.org/2002/08/xquery-functions",
15299 xmlXPathEscapeUriFunction
);
15302 #endif /* LIBXML_XPATH_ENABLED */
15303 #define bottom_xpath
15304 #include "elfgcchack.h"