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")
32 #include <libxml/xmlmemory.h>
33 #include <libxml/tree.h>
34 #include <libxml/valid.h>
35 #include <libxml/xpath.h>
36 #include <libxml/xpathInternals.h>
37 #include <libxml/parserInternals.h>
38 #include <libxml/hash.h>
39 #ifdef LIBXML_XPTR_LOCS_ENABLED
40 #include <libxml/xpointer.h>
42 #ifdef LIBXML_DEBUG_ENABLED
43 #include <libxml/debugXML.h>
45 #include <libxml/xmlerror.h>
46 #include <libxml/threads.h>
47 #include <libxml/globals.h>
48 #ifdef LIBXML_PATTERN_ENABLED
49 #include <libxml/pattern.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #define XPATH_STREAMING
59 xmlGenericError(xmlGenericErrorContext, \
60 "Unimplemented block at %s:%d\n", \
66 * Use the Timsort algorithm provided in timsort.h to sort
67 * nodeset as this is a great improvement over the old Shell sort
68 * used in xmlXPathNodeSetSort()
73 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
74 * If defined, this will use xmlXPathCmpNodesExt() instead of
75 * xmlXPathCmpNodes(). The new function is optimized comparison of
76 * non-element nodes; actually it will speed up comparison only if
77 * xmlXPathOrderDocElems() was called in order to index the elements of
78 * a tree in document order; Libxslt does such an indexing, thus it will
79 * benefit from this optimization.
81 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
84 * XP_OPTIMIZED_FILTER_FIRST:
85 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
86 * in a way, that it stop evaluation at the first node.
88 #define XP_OPTIMIZED_FILTER_FIRST
92 * Internal flag to enable tracking of how much XPath objects have been
95 /* #define XP_DEBUG_OBJ_USAGE */
99 * when compiling an XPath expression we arbitrary limit the maximum
100 * number of step operation in the compiled expression. 1000000 is
101 * an insanely large value which should never be reached under normal
104 #define XPATH_MAX_STEPS 1000000
107 * XPATH_MAX_STACK_DEPTH:
108 * when evaluating an XPath expression we arbitrary limit the maximum
109 * number of object allowed to be pushed on the stack. 1000000 is
110 * an insanely large value which should never be reached under normal
113 #define XPATH_MAX_STACK_DEPTH 1000000
116 * XPATH_MAX_NODESET_LENGTH:
117 * when evaluating an XPath expression nodesets are created and we
118 * arbitrary limit the maximum length of those node set. 10000000 is
119 * an insanely large value which should never be reached under normal
120 * circumstances, one would first need to construct an in memory tree
121 * with more than 10 millions nodes.
123 #define XPATH_MAX_NODESET_LENGTH 10000000
126 * XPATH_MAX_RECRUSION_DEPTH:
127 * Maximum amount of nested functions calls when parsing or evaluating
130 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
131 #define XPATH_MAX_RECURSION_DEPTH 500
133 #define XPATH_MAX_RECURSION_DEPTH 5000
138 * There are a few spots where some tests are done which depend upon ascii
139 * data. These should be enhanced for full UTF8 support (see particularly
140 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
143 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
145 * xmlXPathCmpNodesExt:
146 * @node1: the first node
147 * @node2: the second node
149 * Compare two nodes w.r.t document order.
150 * This one is optimized for handling of non-element nodes.
152 * Returns -2 in case of error 1 if first point < second point, 0 if
153 * it's the same node, -1 otherwise
156 xmlXPathCmpNodesExt(xmlNodePtr node1
, xmlNodePtr node2
) {
158 int misc
= 0, precedence1
= 0, precedence2
= 0;
159 xmlNodePtr miscNode1
= NULL
, miscNode2
= NULL
;
160 xmlNodePtr cur
, root
;
163 if ((node1
== NULL
) || (node2
== NULL
))
170 * a couple of optimizations which will avoid computations in most cases
172 switch (node1
->type
) {
173 case XML_ELEMENT_NODE
:
174 if (node2
->type
== XML_ELEMENT_NODE
) {
175 if ((0 > (ptrdiff_t) node1
->content
) &&
176 (0 > (ptrdiff_t) node2
->content
) &&
177 (node1
->doc
== node2
->doc
))
179 l1
= -((ptrdiff_t) node1
->content
);
180 l2
= -((ptrdiff_t) node2
->content
);
186 goto turtle_comparison
;
189 case XML_ATTRIBUTE_NODE
:
190 precedence1
= 1; /* element is owner */
192 node1
= node1
->parent
;
196 case XML_CDATA_SECTION_NODE
:
197 case XML_COMMENT_NODE
:
201 * Find nearest element node.
203 if (node1
->prev
!= NULL
) {
206 if (node1
->type
== XML_ELEMENT_NODE
) {
207 precedence1
= 3; /* element in prev-sibl axis */
210 if (node1
->prev
== NULL
) {
211 precedence1
= 2; /* element is parent */
213 * URGENT TODO: Are there any cases, where the
214 * parent of such a node is not an element node?
216 node1
= node1
->parent
;
221 precedence1
= 2; /* element is parent */
222 node1
= node1
->parent
;
224 if ((node1
== NULL
) || (node1
->type
!= XML_ELEMENT_NODE
) ||
225 (0 <= (ptrdiff_t) node1
->content
)) {
227 * Fallback for whatever case.
235 case XML_NAMESPACE_DECL
:
237 * TODO: why do we return 1 for namespace nodes?
243 switch (node2
->type
) {
244 case XML_ELEMENT_NODE
:
246 case XML_ATTRIBUTE_NODE
:
247 precedence2
= 1; /* element is owner */
249 node2
= node2
->parent
;
253 case XML_CDATA_SECTION_NODE
:
254 case XML_COMMENT_NODE
:
257 if (node2
->prev
!= NULL
) {
260 if (node2
->type
== XML_ELEMENT_NODE
) {
261 precedence2
= 3; /* element in prev-sibl axis */
264 if (node2
->prev
== NULL
) {
265 precedence2
= 2; /* element is parent */
266 node2
= node2
->parent
;
271 precedence2
= 2; /* element is parent */
272 node2
= node2
->parent
;
274 if ((node2
== NULL
) || (node2
->type
!= XML_ELEMENT_NODE
) ||
275 (0 <= (ptrdiff_t) node2
->content
))
283 case XML_NAMESPACE_DECL
:
289 if (node1
== node2
) {
290 if (precedence1
== precedence2
) {
292 * The ugly case; but normally there aren't many
293 * adjacent non-element nodes around.
295 cur
= miscNode2
->prev
;
296 while (cur
!= NULL
) {
297 if (cur
== miscNode1
)
299 if (cur
->type
== XML_ELEMENT_NODE
)
306 * Evaluate based on higher precedence wrt to the element.
307 * TODO: This assumes attributes are sorted before content.
308 * Is this 100% correct?
310 if (precedence1
< precedence2
)
317 * Special case: One of the helper-elements is contained by the other.
320 * <node1>Text-1(precedence1 == 2)</node1>
322 * Text-6(precedence2 == 3)
325 if ((precedence2
== 3) && (precedence1
> 1)) {
333 if ((precedence1
== 3) && (precedence2
> 1)) {
344 * Speedup using document order if available.
346 if ((node1
->type
== XML_ELEMENT_NODE
) &&
347 (node2
->type
== XML_ELEMENT_NODE
) &&
348 (0 > (ptrdiff_t) node1
->content
) &&
349 (0 > (ptrdiff_t) node2
->content
) &&
350 (node1
->doc
== node2
->doc
)) {
352 l1
= -((ptrdiff_t) node1
->content
);
353 l2
= -((ptrdiff_t) node2
->content
);
362 if (node1
== node2
->prev
)
364 if (node1
== node2
->next
)
367 * compute depth to root
369 for (depth2
= 0, cur
= node2
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
370 if (cur
->parent
== node1
)
375 for (depth1
= 0, cur
= node1
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
376 if (cur
->parent
== node2
)
381 * Distinct document (or distinct entities :-( ) case.
387 * get the nearest common ancestor.
389 while (depth1
> depth2
) {
391 node1
= node1
->parent
;
393 while (depth2
> depth1
) {
395 node2
= node2
->parent
;
397 while (node1
->parent
!= node2
->parent
) {
398 node1
= node1
->parent
;
399 node2
= node2
->parent
;
400 /* should not happen but just in case ... */
401 if ((node1
== NULL
) || (node2
== NULL
))
407 if (node1
== node2
->prev
)
409 if (node1
== node2
->next
)
412 * Speedup using document order if available.
414 if ((node1
->type
== XML_ELEMENT_NODE
) &&
415 (node2
->type
== XML_ELEMENT_NODE
) &&
416 (0 > (ptrdiff_t) node1
->content
) &&
417 (0 > (ptrdiff_t) node2
->content
) &&
418 (node1
->doc
== node2
->doc
)) {
420 l1
= -((ptrdiff_t) node1
->content
);
421 l2
= -((ptrdiff_t) node2
->content
);
428 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
431 return(-1); /* assume there is no sibling list corruption */
433 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
436 * Wrapper for the Timsort algorithm from timsort.h
439 #define SORT_NAME libxml_domnode
440 #define SORT_TYPE xmlNodePtr
446 * Comparison function for the Timsort implementation
448 * Returns -2 in case of error -1 if first point < second point, 0 if
449 * it's the same node, +1 otherwise
452 int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
);
453 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
454 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
456 int res
= xmlXPathCmpNodesExt(x
, y
);
457 return res
== -2 ? res
: -res
;
460 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
462 int res
= xmlXPathCmpNodes(x
, y
);
463 return res
== -2 ? res
: -res
;
466 #define SORT_CMP(x, y) (wrap_cmp(x, y))
468 #endif /* WITH_TIM_SORT */
470 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
472 /************************************************************************
474 * Floating point stuff *
476 ************************************************************************/
478 double xmlXPathNAN
= 0.0;
479 double xmlXPathPINF
= 0.0;
480 double xmlXPathNINF
= 0.0;
485 * DEPRECATED: This function will be made private. Call xmlInitParser to
486 * initialize the library.
488 * Initialize the XPath environment
490 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
493 #if defined(NAN) && defined(INFINITY)
495 xmlXPathPINF
= INFINITY
;
496 xmlXPathNINF
= -INFINITY
;
498 /* MSVC doesn't allow division by zero in constant expressions. */
500 xmlXPathNAN
= 0.0 / zero
;
501 xmlXPathPINF
= 1.0 / zero
;
502 xmlXPathNINF
= -xmlXPathPINF
;
508 * @val: a double value
510 * Returns 1 if the value is a NaN, 0 otherwise
513 xmlXPathIsNaN(double val
) {
517 return !(val
== val
);
523 * @val: a double value
525 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
528 xmlXPathIsInf(double val
) {
530 return isinf(val
) ? (val
> 0 ? 1 : -1) : 0;
532 if (val
>= xmlXPathPINF
)
534 if (val
<= -xmlXPathPINF
)
540 #endif /* SCHEMAS or XPATH */
542 #ifdef LIBXML_XPATH_ENABLED
545 * TODO: when compatibility allows remove all "fake node libxslt" strings
546 * the test should just be name[0] = ' '
548 #ifdef DEBUG_XPATH_EXPRESSION
551 #define DEBUG_EVAL_COUNTS
554 static xmlNs xmlXPathXMLNamespaceStruct
= {
562 static xmlNsPtr xmlXPathXMLNamespace
= &xmlXPathXMLNamespaceStruct
;
563 #ifndef LIBXML_THREAD_ENABLED
565 * Optimizer is disabled only when threaded apps are detected while
566 * the library ain't compiled for thread safety.
568 static int xmlXPathDisableOptimizer
= 0;
571 /************************************************************************
573 * Error handling routines *
575 ************************************************************************/
581 * Macro to raise an XPath error and return NULL.
583 #define XP_ERRORNULL(X) \
584 { xmlXPathErr(ctxt, X); return(NULL); }
587 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
589 static const char* const xmlXPathErrorMessages
[] = {
592 "Unfinished literal\n",
593 "Start of literal\n",
594 "Expected $ for variable reference\n",
595 "Undefined variable\n",
596 "Invalid predicate\n",
597 "Invalid expression\n",
598 "Missing closing curly brace\n",
599 "Unregistered function\n",
602 "Invalid number of arguments\n",
603 "Invalid context size\n",
604 "Invalid context position\n",
605 "Memory allocation error\n",
608 "Sub resource error\n",
609 "Undefined namespace prefix\n",
611 "Char out of XML range\n",
612 "Invalid or incomplete context\n",
613 "Stack usage error\n",
614 "Forbidden variable\n",
615 "Operation limit exceeded\n",
616 "Recursion limit exceeded\n",
617 "?? Unknown error ??\n" /* Must be last in the list! */
619 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
620 sizeof(xmlXPathErrorMessages[0])) - 1)
623 * @ctxt: an XPath context
624 * @extra: extra information
626 * Handle a redefinition of attribute error
629 xmlXPathErrMemory(xmlXPathContextPtr ctxt
, const char *extra
)
632 xmlResetError(&ctxt
->lastError
);
636 xmlStrPrintf(buf
, 200,
637 "Memory allocation failed : %s\n",
639 ctxt
->lastError
.message
= (char *) xmlStrdup(buf
);
641 ctxt
->lastError
.message
= (char *)
642 xmlStrdup(BAD_CAST
"Memory allocation failed\n");
644 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
645 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
646 if (ctxt
->error
!= NULL
)
647 ctxt
->error(ctxt
->userData
, &ctxt
->lastError
);
650 __xmlRaiseError(NULL
, NULL
, NULL
,
651 NULL
, NULL
, XML_FROM_XPATH
,
652 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
653 extra
, NULL
, NULL
, 0, 0,
654 "Memory allocation failed : %s\n", extra
);
656 __xmlRaiseError(NULL
, NULL
, NULL
,
657 NULL
, NULL
, XML_FROM_XPATH
,
658 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
659 NULL
, NULL
, NULL
, 0, 0,
660 "Memory allocation failed\n");
665 * xmlXPathPErrMemory:
666 * @ctxt: an XPath parser context
667 * @extra: extra information
669 * Handle a redefinition of attribute error
672 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt
, const char *extra
)
675 xmlXPathErrMemory(NULL
, extra
);
677 ctxt
->error
= XPATH_MEMORY_ERROR
;
678 xmlXPathErrMemory(ctxt
->context
, extra
);
684 * @ctxt: a XPath parser context
685 * @error: the error code
687 * Handle an XPath error
690 xmlXPathErr(xmlXPathParserContextPtr ctxt
, int error
)
692 if ((error
< 0) || (error
> MAXERRNO
))
695 __xmlRaiseError(NULL
, NULL
, NULL
,
696 NULL
, NULL
, XML_FROM_XPATH
,
697 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
698 XML_ERR_ERROR
, NULL
, 0,
699 NULL
, NULL
, NULL
, 0, 0,
700 "%s", xmlXPathErrorMessages
[error
]);
704 if (ctxt
->context
== NULL
) {
705 __xmlRaiseError(NULL
, NULL
, NULL
,
706 NULL
, NULL
, XML_FROM_XPATH
,
707 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
708 XML_ERR_ERROR
, NULL
, 0,
709 (const char *) ctxt
->base
, NULL
, NULL
,
710 ctxt
->cur
- ctxt
->base
, 0,
711 "%s", xmlXPathErrorMessages
[error
]);
715 /* cleanup current last error */
716 xmlResetError(&ctxt
->context
->lastError
);
718 ctxt
->context
->lastError
.domain
= XML_FROM_XPATH
;
719 ctxt
->context
->lastError
.code
= error
+ XML_XPATH_EXPRESSION_OK
-
721 ctxt
->context
->lastError
.level
= XML_ERR_ERROR
;
722 ctxt
->context
->lastError
.str1
= (char *) xmlStrdup(ctxt
->base
);
723 ctxt
->context
->lastError
.int1
= ctxt
->cur
- ctxt
->base
;
724 ctxt
->context
->lastError
.node
= ctxt
->context
->debugNode
;
725 if (ctxt
->context
->error
!= NULL
) {
726 ctxt
->context
->error(ctxt
->context
->userData
,
727 &ctxt
->context
->lastError
);
729 __xmlRaiseError(NULL
, NULL
, NULL
,
730 NULL
, ctxt
->context
->debugNode
, XML_FROM_XPATH
,
731 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
732 XML_ERR_ERROR
, NULL
, 0,
733 (const char *) ctxt
->base
, NULL
, NULL
,
734 ctxt
->cur
- ctxt
->base
, 0,
735 "%s", xmlXPathErrorMessages
[error
]);
742 * @ctxt: the XPath Parser context
743 * @file: the file name
744 * @line: the line number
745 * @no: the error number
747 * Formats an error message.
750 xmlXPatherror(xmlXPathParserContextPtr ctxt
, const char *file ATTRIBUTE_UNUSED
,
751 int line ATTRIBUTE_UNUSED
, int no
) {
752 xmlXPathErr(ctxt
, no
);
756 * xmlXPathCheckOpLimit:
757 * @ctxt: the XPath Parser context
758 * @opCount: the number of operations to be added
760 * Adds opCount to the running total of operations and returns -1 if the
761 * operation limit is exceeded. Returns 0 otherwise.
764 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt
, unsigned long opCount
) {
765 xmlXPathContextPtr xpctxt
= ctxt
->context
;
767 if ((opCount
> xpctxt
->opLimit
) ||
768 (xpctxt
->opCount
> xpctxt
->opLimit
- opCount
)) {
769 xpctxt
->opCount
= xpctxt
->opLimit
;
770 xmlXPathErr(ctxt
, XPATH_OP_LIMIT_EXCEEDED
);
774 xpctxt
->opCount
+= opCount
;
778 #define OP_LIMIT_EXCEEDED(ctxt, n) \
779 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
781 /************************************************************************
785 ************************************************************************/
790 * Pointer-list for various purposes.
792 typedef struct _xmlPointerList xmlPointerList
;
793 typedef xmlPointerList
*xmlPointerListPtr
;
794 struct _xmlPointerList
{
800 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
801 * and here, we should make the functions public.
804 xmlPointerListAddSize(xmlPointerListPtr list
,
808 if (list
->items
== NULL
) {
809 if (initialSize
<= 0)
811 list
->items
= (void **) xmlMalloc(initialSize
* sizeof(void *));
812 if (list
->items
== NULL
) {
813 xmlXPathErrMemory(NULL
,
814 "xmlPointerListCreate: allocating item\n");
818 list
->size
= initialSize
;
819 } else if (list
->size
<= list
->number
) {
820 if (list
->size
> 50000000) {
821 xmlXPathErrMemory(NULL
,
822 "xmlPointerListAddSize: re-allocating item\n");
826 list
->items
= (void **) xmlRealloc(list
->items
,
827 list
->size
* sizeof(void *));
828 if (list
->items
== NULL
) {
829 xmlXPathErrMemory(NULL
,
830 "xmlPointerListAddSize: re-allocating item\n");
835 list
->items
[list
->number
++] = item
;
840 * xsltPointerListCreate:
842 * Creates an xsltPointerList structure.
844 * Returns a xsltPointerList structure or NULL in case of an error.
846 static xmlPointerListPtr
847 xmlPointerListCreate(int initialSize
)
849 xmlPointerListPtr ret
;
851 ret
= xmlMalloc(sizeof(xmlPointerList
));
853 xmlXPathErrMemory(NULL
,
854 "xmlPointerListCreate: allocating item\n");
857 memset(ret
, 0, sizeof(xmlPointerList
));
858 if (initialSize
> 0) {
859 xmlPointerListAddSize(ret
, NULL
, initialSize
);
866 * xsltPointerListFree:
868 * Frees the xsltPointerList structure. This does not free
869 * the content of the list.
872 xmlPointerListFree(xmlPointerListPtr list
)
876 if (list
->items
!= NULL
)
877 xmlFree(list
->items
);
881 /************************************************************************
885 ************************************************************************/
903 XPATH_OP_VALUE
, /* 11 */
908 XPATH_OP_FILTER
, /* 16 */
909 XPATH_OP_SORT
/* 17 */
910 #ifdef LIBXML_XPTR_LOCS_ENABLED
917 AXIS_ANCESTOR_OR_SELF
,
921 AXIS_DESCENDANT_OR_SELF
,
923 AXIS_FOLLOWING_SIBLING
,
927 AXIS_PRECEDING_SIBLING
,
942 NODE_TYPE_COMMENT
= XML_COMMENT_NODE
,
943 NODE_TYPE_TEXT
= XML_TEXT_NODE
,
944 NODE_TYPE_PI
= XML_PI_NODE
947 typedef struct _xmlXPathStepOp xmlXPathStepOp
;
948 typedef xmlXPathStepOp
*xmlXPathStepOpPtr
;
949 struct _xmlXPathStepOp
{
950 xmlXPathOp op
; /* The identifier of the operation */
951 int ch1
; /* First child */
952 int ch2
; /* Second child */
958 xmlXPathFunction cache
;
962 struct _xmlXPathCompExpr
{
963 int nbStep
; /* Number of steps in this expression */
964 int maxStep
; /* Maximum number of steps allocated */
965 xmlXPathStepOp
*steps
; /* ops for computation of this expression */
966 int last
; /* index of last step in expression */
967 xmlChar
*expr
; /* the expression being computed */
968 xmlDictPtr dict
; /* the dictionary to use if any */
969 #ifdef DEBUG_EVAL_COUNTS
973 #ifdef XPATH_STREAMING
974 xmlPatternPtr stream
;
978 /************************************************************************
980 * Forward declarations *
982 ************************************************************************/
984 xmlXPathFreeValueTree(xmlNodeSetPtr obj
);
986 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
);
988 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
989 xmlXPathStepOpPtr op
, xmlNodePtr
*first
);
991 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
992 xmlXPathStepOpPtr op
,
995 xmlXPathFreeObjectEntry(void *obj
, const xmlChar
*name
);
997 /************************************************************************
999 * Parser Type functions *
1001 ************************************************************************/
1004 * xmlXPathNewCompExpr:
1006 * Create a new Xpath component
1008 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1010 static xmlXPathCompExprPtr
1011 xmlXPathNewCompExpr(void) {
1012 xmlXPathCompExprPtr cur
;
1014 cur
= (xmlXPathCompExprPtr
) xmlMalloc(sizeof(xmlXPathCompExpr
));
1016 xmlXPathErrMemory(NULL
, "allocating component\n");
1019 memset(cur
, 0, sizeof(xmlXPathCompExpr
));
1022 cur
->steps
= (xmlXPathStepOp
*) xmlMalloc(cur
->maxStep
*
1023 sizeof(xmlXPathStepOp
));
1024 if (cur
->steps
== NULL
) {
1025 xmlXPathErrMemory(NULL
, "allocating steps\n");
1029 memset(cur
->steps
, 0, cur
->maxStep
* sizeof(xmlXPathStepOp
));
1031 #ifdef DEBUG_EVAL_COUNTS
1038 * xmlXPathFreeCompExpr:
1039 * @comp: an XPATH comp
1041 * Free up the memory allocated by @comp
1044 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp
)
1046 xmlXPathStepOpPtr op
;
1051 if (comp
->dict
== NULL
) {
1052 for (i
= 0; i
< comp
->nbStep
; i
++) {
1053 op
= &comp
->steps
[i
];
1054 if (op
->value4
!= NULL
) {
1055 if (op
->op
== XPATH_OP_VALUE
)
1056 xmlXPathFreeObject(op
->value4
);
1058 xmlFree(op
->value4
);
1060 if (op
->value5
!= NULL
)
1061 xmlFree(op
->value5
);
1064 for (i
= 0; i
< comp
->nbStep
; i
++) {
1065 op
= &comp
->steps
[i
];
1066 if (op
->value4
!= NULL
) {
1067 if (op
->op
== XPATH_OP_VALUE
)
1068 xmlXPathFreeObject(op
->value4
);
1071 xmlDictFree(comp
->dict
);
1073 if (comp
->steps
!= NULL
) {
1074 xmlFree(comp
->steps
);
1076 #ifdef DEBUG_EVAL_COUNTS
1077 if (comp
->string
!= NULL
) {
1078 xmlFree(comp
->string
);
1081 #ifdef XPATH_STREAMING
1082 if (comp
->stream
!= NULL
) {
1083 xmlFreePatternList(comp
->stream
);
1086 if (comp
->expr
!= NULL
) {
1087 xmlFree(comp
->expr
);
1094 * xmlXPathCompExprAdd:
1095 * @comp: the compiled expression
1096 * @ch1: first child index
1097 * @ch2: second child index
1099 * @value: the first int value
1100 * @value2: the second int value
1101 * @value3: the third int value
1102 * @value4: the first string value
1103 * @value5: the second string value
1105 * Add a step to an XPath Compiled Expression
1107 * Returns -1 in case of failure, the index otherwise
1110 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt
, int ch1
, int ch2
,
1111 xmlXPathOp op
, int value
,
1112 int value2
, int value3
, void *value4
, void *value5
) {
1113 xmlXPathCompExprPtr comp
= ctxt
->comp
;
1114 if (comp
->nbStep
>= comp
->maxStep
) {
1115 xmlXPathStepOp
*real
;
1117 if (comp
->maxStep
>= XPATH_MAX_STEPS
) {
1118 xmlXPathPErrMemory(ctxt
, "adding step\n");
1122 real
= (xmlXPathStepOp
*) xmlRealloc(comp
->steps
,
1123 comp
->maxStep
* sizeof(xmlXPathStepOp
));
1126 xmlXPathPErrMemory(ctxt
, "adding step\n");
1131 comp
->last
= comp
->nbStep
;
1132 comp
->steps
[comp
->nbStep
].ch1
= ch1
;
1133 comp
->steps
[comp
->nbStep
].ch2
= ch2
;
1134 comp
->steps
[comp
->nbStep
].op
= op
;
1135 comp
->steps
[comp
->nbStep
].value
= value
;
1136 comp
->steps
[comp
->nbStep
].value2
= value2
;
1137 comp
->steps
[comp
->nbStep
].value3
= value3
;
1138 if ((comp
->dict
!= NULL
) &&
1139 ((op
== XPATH_OP_FUNCTION
) || (op
== XPATH_OP_VARIABLE
) ||
1140 (op
== XPATH_OP_COLLECT
))) {
1141 if (value4
!= NULL
) {
1142 comp
->steps
[comp
->nbStep
].value4
= (xmlChar
*)
1143 (void *)xmlDictLookup(comp
->dict
, value4
, -1);
1146 comp
->steps
[comp
->nbStep
].value4
= NULL
;
1147 if (value5
!= NULL
) {
1148 comp
->steps
[comp
->nbStep
].value5
= (xmlChar
*)
1149 (void *)xmlDictLookup(comp
->dict
, value5
, -1);
1152 comp
->steps
[comp
->nbStep
].value5
= NULL
;
1154 comp
->steps
[comp
->nbStep
].value4
= value4
;
1155 comp
->steps
[comp
->nbStep
].value5
= value5
;
1157 comp
->steps
[comp
->nbStep
].cache
= NULL
;
1158 return(comp
->nbStep
++);
1163 * @comp: the compiled expression
1164 * @op: operation index
1166 * Swaps 2 operations in the compiled expression
1169 xmlXPathCompSwap(xmlXPathStepOpPtr op
) {
1172 #ifndef LIBXML_THREAD_ENABLED
1174 * Since this manipulates possibly shared variables, this is
1175 * disabled if one detects that the library is used in a multithreaded
1178 if (xmlXPathDisableOptimizer
)
1187 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1188 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1189 (op), (val), (val2), (val3), (val4), (val5))
1190 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1191 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1192 (op), (val), (val2), (val3), (val4), (val5))
1194 #define PUSH_LEAVE_EXPR(op, val, val2) \
1195 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1197 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1198 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1200 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1201 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1202 (val), (val2), 0 ,NULL ,NULL)
1204 /************************************************************************
1206 * XPath object cache structures *
1208 ************************************************************************/
1210 /* #define XP_DEFAULT_CACHE_ON */
1212 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1214 typedef struct _xmlXPathContextCache xmlXPathContextCache
;
1215 typedef xmlXPathContextCache
*xmlXPathContextCachePtr
;
1216 struct _xmlXPathContextCache
{
1217 xmlPointerListPtr nodesetObjs
; /* contains xmlXPathObjectPtr */
1218 xmlPointerListPtr stringObjs
; /* contains xmlXPathObjectPtr */
1219 xmlPointerListPtr booleanObjs
; /* contains xmlXPathObjectPtr */
1220 xmlPointerListPtr numberObjs
; /* contains xmlXPathObjectPtr */
1221 xmlPointerListPtr miscObjs
; /* contains xmlXPathObjectPtr */
1227 #ifdef XP_DEBUG_OBJ_USAGE
1229 int dbgCachedNodeset
;
1230 int dbgCachedString
;
1232 int dbgCachedNumber
;
1235 int dbgCachedLocset
;
1237 int dbgCachedXSLTTree
;
1238 int dbgCachedUndefined
;
1242 int dbgReusedNodeset
;
1243 int dbgReusedString
;
1245 int dbgReusedNumber
;
1248 int dbgReusedLocset
;
1250 int dbgReusedXSLTTree
;
1251 int dbgReusedUndefined
;
1256 /************************************************************************
1258 * Debugging related functions *
1260 ************************************************************************/
1263 xmlGenericError(xmlGenericErrorContext, \
1264 "Internal error at %s:%d\n", \
1265 __FILE__, __LINE__);
1267 #ifdef LIBXML_DEBUG_ENABLED
1269 xmlXPathDebugDumpNode(FILE *output
, xmlNodePtr cur
, int depth
) {
1273 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1274 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1275 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1277 fprintf(output
, "%s", shift
);
1278 fprintf(output
, "Node is NULL !\n");
1283 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
1284 (cur
->type
== XML_HTML_DOCUMENT_NODE
)) {
1285 fprintf(output
, "%s", shift
);
1286 fprintf(output
, " /\n");
1287 } else if (cur
->type
== XML_ATTRIBUTE_NODE
)
1288 xmlDebugDumpAttr(output
, (xmlAttrPtr
)cur
, depth
);
1290 xmlDebugDumpOneNode(output
, cur
, depth
);
1293 xmlXPathDebugDumpNodeList(FILE *output
, xmlNodePtr cur
, int depth
) {
1298 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1299 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1300 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1302 fprintf(output
, "%s", shift
);
1303 fprintf(output
, "Node is NULL !\n");
1308 while (cur
!= NULL
) {
1311 xmlDebugDumpOneNode(output
, tmp
, depth
);
1316 xmlXPathDebugDumpNodeSet(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1320 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1321 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1322 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1325 fprintf(output
, "%s", shift
);
1326 fprintf(output
, "NodeSet is NULL !\n");
1332 fprintf(output
, "Set contains %d nodes:\n", cur
->nodeNr
);
1333 for (i
= 0;i
< cur
->nodeNr
;i
++) {
1334 fprintf(output
, "%s", shift
);
1335 fprintf(output
, "%d", i
+ 1);
1336 xmlXPathDebugDumpNode(output
, cur
->nodeTab
[i
], depth
+ 1);
1342 xmlXPathDebugDumpValueTree(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1346 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1347 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1348 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1350 if ((cur
== NULL
) || (cur
->nodeNr
== 0) || (cur
->nodeTab
[0] == NULL
)) {
1351 fprintf(output
, "%s", shift
);
1352 fprintf(output
, "Value Tree is NULL !\n");
1357 fprintf(output
, "%s", shift
);
1358 fprintf(output
, "%d", i
+ 1);
1359 xmlXPathDebugDumpNodeList(output
, cur
->nodeTab
[0]->children
, depth
+ 1);
1361 #if defined(LIBXML_XPTR_LOCS_ENABLED)
1363 xmlXPathDebugDumpLocationSet(FILE *output
, xmlLocationSetPtr cur
, int depth
) {
1367 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1368 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1369 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1372 fprintf(output
, "%s", shift
);
1373 fprintf(output
, "LocationSet is NULL !\n");
1378 for (i
= 0;i
< cur
->locNr
;i
++) {
1379 fprintf(output
, "%s", shift
);
1380 fprintf(output
, "%d : ", i
+ 1);
1381 xmlXPathDebugDumpObject(output
, cur
->locTab
[i
], depth
+ 1);
1384 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1387 * xmlXPathDebugDumpObject:
1388 * @output: the FILE * to dump the output
1389 * @cur: the object to inspect
1390 * @depth: indentation level
1392 * Dump the content of the object for debugging purposes
1395 xmlXPathDebugDumpObject(FILE *output
, xmlXPathObjectPtr cur
, int depth
) {
1399 if (output
== NULL
) return;
1401 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1402 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1403 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1406 fprintf(output
, "%s", shift
);
1409 fprintf(output
, "Object is empty (NULL)\n");
1413 case XPATH_UNDEFINED
:
1414 fprintf(output
, "Object is uninitialized\n");
1417 fprintf(output
, "Object is a Node Set :\n");
1418 xmlXPathDebugDumpNodeSet(output
, cur
->nodesetval
, depth
);
1420 case XPATH_XSLT_TREE
:
1421 fprintf(output
, "Object is an XSLT value tree :\n");
1422 xmlXPathDebugDumpValueTree(output
, cur
->nodesetval
, depth
);
1425 fprintf(output
, "Object is a Boolean : ");
1426 if (cur
->boolval
) fprintf(output
, "true\n");
1427 else fprintf(output
, "false\n");
1430 switch (xmlXPathIsInf(cur
->floatval
)) {
1432 fprintf(output
, "Object is a number : Infinity\n");
1435 fprintf(output
, "Object is a number : -Infinity\n");
1438 if (xmlXPathIsNaN(cur
->floatval
)) {
1439 fprintf(output
, "Object is a number : NaN\n");
1440 } else if (cur
->floatval
== 0) {
1441 /* Omit sign for negative zero. */
1442 fprintf(output
, "Object is a number : 0\n");
1444 fprintf(output
, "Object is a number : %0g\n", cur
->floatval
);
1449 fprintf(output
, "Object is a string : ");
1450 xmlDebugDumpString(output
, cur
->stringval
);
1451 fprintf(output
, "\n");
1453 #ifdef LIBXML_XPTR_LOCS_ENABLED
1455 fprintf(output
, "Object is a point : index %d in node", cur
->index
);
1456 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
, depth
+ 1);
1457 fprintf(output
, "\n");
1460 if ((cur
->user2
== NULL
) ||
1461 ((cur
->user2
== cur
->user
) && (cur
->index
== cur
->index2
))) {
1462 fprintf(output
, "Object is a collapsed range :\n");
1463 fprintf(output
, "%s", shift
);
1464 if (cur
->index
>= 0)
1465 fprintf(output
, "index %d in ", cur
->index
);
1466 fprintf(output
, "node\n");
1467 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1470 fprintf(output
, "Object is a range :\n");
1471 fprintf(output
, "%s", shift
);
1472 fprintf(output
, "From ");
1473 if (cur
->index
>= 0)
1474 fprintf(output
, "index %d in ", cur
->index
);
1475 fprintf(output
, "node\n");
1476 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1478 fprintf(output
, "%s", shift
);
1479 fprintf(output
, "To ");
1480 if (cur
->index2
>= 0)
1481 fprintf(output
, "index %d in ", cur
->index2
);
1482 fprintf(output
, "node\n");
1483 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user2
,
1485 fprintf(output
, "\n");
1488 case XPATH_LOCATIONSET
:
1489 fprintf(output
, "Object is a Location Set:\n");
1490 xmlXPathDebugDumpLocationSet(output
,
1491 (xmlLocationSetPtr
) cur
->user
, depth
);
1493 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1495 fprintf(output
, "Object is user defined\n");
1501 xmlXPathDebugDumpStepOp(FILE *output
, xmlXPathCompExprPtr comp
,
1502 xmlXPathStepOpPtr op
, int depth
) {
1506 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1507 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1508 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1510 fprintf(output
, "%s", shift
);
1512 fprintf(output
, "Step is NULL\n");
1517 fprintf(output
, "END"); break;
1519 fprintf(output
, "AND"); break;
1521 fprintf(output
, "OR"); break;
1522 case XPATH_OP_EQUAL
:
1524 fprintf(output
, "EQUAL =");
1526 fprintf(output
, "EQUAL !=");
1530 fprintf(output
, "CMP <");
1532 fprintf(output
, "CMP >");
1534 fprintf(output
, "=");
1538 fprintf(output
, "PLUS -");
1539 else if (op
->value
== 1)
1540 fprintf(output
, "PLUS +");
1541 else if (op
->value
== 2)
1542 fprintf(output
, "PLUS unary -");
1543 else if (op
->value
== 3)
1544 fprintf(output
, "PLUS unary - -");
1548 fprintf(output
, "MULT *");
1549 else if (op
->value
== 1)
1550 fprintf(output
, "MULT div");
1552 fprintf(output
, "MULT mod");
1554 case XPATH_OP_UNION
:
1555 fprintf(output
, "UNION"); break;
1557 fprintf(output
, "ROOT"); break;
1559 fprintf(output
, "NODE"); break;
1561 fprintf(output
, "SORT"); break;
1562 case XPATH_OP_COLLECT
: {
1563 xmlXPathAxisVal axis
= (xmlXPathAxisVal
)op
->value
;
1564 xmlXPathTestVal test
= (xmlXPathTestVal
)op
->value2
;
1565 xmlXPathTypeVal type
= (xmlXPathTypeVal
)op
->value3
;
1566 const xmlChar
*prefix
= op
->value4
;
1567 const xmlChar
*name
= op
->value5
;
1569 fprintf(output
, "COLLECT ");
1572 fprintf(output
, " 'ancestors' "); break;
1573 case AXIS_ANCESTOR_OR_SELF
:
1574 fprintf(output
, " 'ancestors-or-self' "); break;
1575 case AXIS_ATTRIBUTE
:
1576 fprintf(output
, " 'attributes' "); break;
1578 fprintf(output
, " 'child' "); break;
1579 case AXIS_DESCENDANT
:
1580 fprintf(output
, " 'descendant' "); break;
1581 case AXIS_DESCENDANT_OR_SELF
:
1582 fprintf(output
, " 'descendant-or-self' "); break;
1583 case AXIS_FOLLOWING
:
1584 fprintf(output
, " 'following' "); break;
1585 case AXIS_FOLLOWING_SIBLING
:
1586 fprintf(output
, " 'following-siblings' "); break;
1587 case AXIS_NAMESPACE
:
1588 fprintf(output
, " 'namespace' "); break;
1590 fprintf(output
, " 'parent' "); break;
1591 case AXIS_PRECEDING
:
1592 fprintf(output
, " 'preceding' "); break;
1593 case AXIS_PRECEDING_SIBLING
:
1594 fprintf(output
, " 'preceding-sibling' "); break;
1596 fprintf(output
, " 'self' "); break;
1599 case NODE_TEST_NONE
:
1600 fprintf(output
, "'none' "); break;
1601 case NODE_TEST_TYPE
:
1602 fprintf(output
, "'type' "); break;
1604 fprintf(output
, "'PI' "); break;
1606 fprintf(output
, "'all' "); break;
1608 fprintf(output
, "'namespace' "); break;
1609 case NODE_TEST_NAME
:
1610 fprintf(output
, "'name' "); break;
1613 case NODE_TYPE_NODE
:
1614 fprintf(output
, "'node' "); break;
1615 case NODE_TYPE_COMMENT
:
1616 fprintf(output
, "'comment' "); break;
1617 case NODE_TYPE_TEXT
:
1618 fprintf(output
, "'text' "); break;
1620 fprintf(output
, "'PI' "); break;
1623 fprintf(output
, "%s:", prefix
);
1625 fprintf(output
, "%s", (const char *) name
);
1629 case XPATH_OP_VALUE
: {
1630 xmlXPathObjectPtr object
= (xmlXPathObjectPtr
) op
->value4
;
1632 fprintf(output
, "ELEM ");
1633 xmlXPathDebugDumpObject(output
, object
, 0);
1636 case XPATH_OP_VARIABLE
: {
1637 const xmlChar
*prefix
= op
->value5
;
1638 const xmlChar
*name
= op
->value4
;
1641 fprintf(output
, "VARIABLE %s:%s", prefix
, name
);
1643 fprintf(output
, "VARIABLE %s", name
);
1646 case XPATH_OP_FUNCTION
: {
1647 int nbargs
= op
->value
;
1648 const xmlChar
*prefix
= op
->value5
;
1649 const xmlChar
*name
= op
->value4
;
1652 fprintf(output
, "FUNCTION %s:%s(%d args)",
1653 prefix
, name
, nbargs
);
1655 fprintf(output
, "FUNCTION %s(%d args)", name
, nbargs
);
1658 case XPATH_OP_ARG
: fprintf(output
, "ARG"); break;
1659 case XPATH_OP_PREDICATE
: fprintf(output
, "PREDICATE"); break;
1660 case XPATH_OP_FILTER
: fprintf(output
, "FILTER"); break;
1661 #ifdef LIBXML_XPTR_LOCS_ENABLED
1662 case XPATH_OP_RANGETO
: fprintf(output
, "RANGETO"); break;
1665 fprintf(output
, "UNKNOWN %d\n", op
->op
); return;
1667 fprintf(output
, "\n");
1670 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch1
], depth
+ 1);
1672 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch2
], depth
+ 1);
1676 * xmlXPathDebugDumpCompExpr:
1677 * @output: the FILE * for the output
1678 * @comp: the precompiled XPath expression
1679 * @depth: the indentation level.
1681 * Dumps the tree of the compiled XPath expression.
1684 xmlXPathDebugDumpCompExpr(FILE *output
, xmlXPathCompExprPtr comp
,
1689 if ((output
== NULL
) || (comp
== NULL
)) return;
1691 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1692 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1693 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1695 fprintf(output
, "%s", shift
);
1697 #ifdef XPATH_STREAMING
1699 fprintf(output
, "Streaming Expression\n");
1703 fprintf(output
, "Compiled Expression : %d elements\n",
1706 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[i
], depth
+ 1);
1710 #ifdef XP_DEBUG_OBJ_USAGE
1713 * XPath object usage related debugging variables.
1715 static int xmlXPathDebugObjCounterUndefined
= 0;
1716 static int xmlXPathDebugObjCounterNodeset
= 0;
1717 static int xmlXPathDebugObjCounterBool
= 0;
1718 static int xmlXPathDebugObjCounterNumber
= 0;
1719 static int xmlXPathDebugObjCounterString
= 0;
1720 static int xmlXPathDebugObjCounterPoint
= 0;
1721 static int xmlXPathDebugObjCounterRange
= 0;
1722 static int xmlXPathDebugObjCounterLocset
= 0;
1723 static int xmlXPathDebugObjCounterUsers
= 0;
1724 static int xmlXPathDebugObjCounterXSLTTree
= 0;
1725 static int xmlXPathDebugObjCounterAll
= 0;
1727 static int xmlXPathDebugObjTotalUndefined
= 0;
1728 static int xmlXPathDebugObjTotalNodeset
= 0;
1729 static int xmlXPathDebugObjTotalBool
= 0;
1730 static int xmlXPathDebugObjTotalNumber
= 0;
1731 static int xmlXPathDebugObjTotalString
= 0;
1732 static int xmlXPathDebugObjTotalPoint
= 0;
1733 static int xmlXPathDebugObjTotalRange
= 0;
1734 static int xmlXPathDebugObjTotalLocset
= 0;
1735 static int xmlXPathDebugObjTotalUsers
= 0;
1736 static int xmlXPathDebugObjTotalXSLTTree
= 0;
1737 static int xmlXPathDebugObjTotalAll
= 0;
1739 static int xmlXPathDebugObjMaxUndefined
= 0;
1740 static int xmlXPathDebugObjMaxNodeset
= 0;
1741 static int xmlXPathDebugObjMaxBool
= 0;
1742 static int xmlXPathDebugObjMaxNumber
= 0;
1743 static int xmlXPathDebugObjMaxString
= 0;
1744 static int xmlXPathDebugObjMaxPoint
= 0;
1745 static int xmlXPathDebugObjMaxRange
= 0;
1746 static int xmlXPathDebugObjMaxLocset
= 0;
1747 static int xmlXPathDebugObjMaxUsers
= 0;
1748 static int xmlXPathDebugObjMaxXSLTTree
= 0;
1749 static int xmlXPathDebugObjMaxAll
= 0;
1752 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt
)
1755 if (ctxt
->cache
!= NULL
) {
1756 xmlXPathContextCachePtr cache
=
1757 (xmlXPathContextCachePtr
) ctxt
->cache
;
1759 cache
->dbgCachedAll
= 0;
1760 cache
->dbgCachedNodeset
= 0;
1761 cache
->dbgCachedString
= 0;
1762 cache
->dbgCachedBool
= 0;
1763 cache
->dbgCachedNumber
= 0;
1764 cache
->dbgCachedPoint
= 0;
1765 cache
->dbgCachedRange
= 0;
1766 cache
->dbgCachedLocset
= 0;
1767 cache
->dbgCachedUsers
= 0;
1768 cache
->dbgCachedXSLTTree
= 0;
1769 cache
->dbgCachedUndefined
= 0;
1771 cache
->dbgReusedAll
= 0;
1772 cache
->dbgReusedNodeset
= 0;
1773 cache
->dbgReusedString
= 0;
1774 cache
->dbgReusedBool
= 0;
1775 cache
->dbgReusedNumber
= 0;
1776 cache
->dbgReusedPoint
= 0;
1777 cache
->dbgReusedRange
= 0;
1778 cache
->dbgReusedLocset
= 0;
1779 cache
->dbgReusedUsers
= 0;
1780 cache
->dbgReusedXSLTTree
= 0;
1781 cache
->dbgReusedUndefined
= 0;
1785 xmlXPathDebugObjCounterUndefined
= 0;
1786 xmlXPathDebugObjCounterNodeset
= 0;
1787 xmlXPathDebugObjCounterBool
= 0;
1788 xmlXPathDebugObjCounterNumber
= 0;
1789 xmlXPathDebugObjCounterString
= 0;
1790 xmlXPathDebugObjCounterPoint
= 0;
1791 xmlXPathDebugObjCounterRange
= 0;
1792 xmlXPathDebugObjCounterLocset
= 0;
1793 xmlXPathDebugObjCounterUsers
= 0;
1794 xmlXPathDebugObjCounterXSLTTree
= 0;
1795 xmlXPathDebugObjCounterAll
= 0;
1797 xmlXPathDebugObjTotalUndefined
= 0;
1798 xmlXPathDebugObjTotalNodeset
= 0;
1799 xmlXPathDebugObjTotalBool
= 0;
1800 xmlXPathDebugObjTotalNumber
= 0;
1801 xmlXPathDebugObjTotalString
= 0;
1802 xmlXPathDebugObjTotalPoint
= 0;
1803 xmlXPathDebugObjTotalRange
= 0;
1804 xmlXPathDebugObjTotalLocset
= 0;
1805 xmlXPathDebugObjTotalUsers
= 0;
1806 xmlXPathDebugObjTotalXSLTTree
= 0;
1807 xmlXPathDebugObjTotalAll
= 0;
1809 xmlXPathDebugObjMaxUndefined
= 0;
1810 xmlXPathDebugObjMaxNodeset
= 0;
1811 xmlXPathDebugObjMaxBool
= 0;
1812 xmlXPathDebugObjMaxNumber
= 0;
1813 xmlXPathDebugObjMaxString
= 0;
1814 xmlXPathDebugObjMaxPoint
= 0;
1815 xmlXPathDebugObjMaxRange
= 0;
1816 xmlXPathDebugObjMaxLocset
= 0;
1817 xmlXPathDebugObjMaxUsers
= 0;
1818 xmlXPathDebugObjMaxXSLTTree
= 0;
1819 xmlXPathDebugObjMaxAll
= 0;
1824 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt
,
1825 xmlXPathObjectType objType
)
1830 if (ctxt
->cache
!= NULL
) {
1831 xmlXPathContextCachePtr cache
=
1832 (xmlXPathContextCachePtr
) ctxt
->cache
;
1836 cache
->dbgReusedAll
++;
1838 case XPATH_UNDEFINED
:
1839 cache
->dbgReusedUndefined
++;
1842 cache
->dbgReusedNodeset
++;
1845 cache
->dbgReusedBool
++;
1848 cache
->dbgReusedNumber
++;
1851 cache
->dbgReusedString
++;
1853 #ifdef LIBXML_XPTR_LOCS_ENABLED
1855 cache
->dbgReusedPoint
++;
1858 cache
->dbgReusedRange
++;
1860 case XPATH_LOCATIONSET
:
1861 cache
->dbgReusedLocset
++;
1863 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1865 cache
->dbgReusedUsers
++;
1867 case XPATH_XSLT_TREE
:
1868 cache
->dbgReusedXSLTTree
++;
1877 case XPATH_UNDEFINED
:
1879 xmlXPathDebugObjTotalUndefined
++;
1880 xmlXPathDebugObjCounterUndefined
++;
1881 if (xmlXPathDebugObjCounterUndefined
>
1882 xmlXPathDebugObjMaxUndefined
)
1883 xmlXPathDebugObjMaxUndefined
=
1884 xmlXPathDebugObjCounterUndefined
;
1888 xmlXPathDebugObjTotalNodeset
++;
1889 xmlXPathDebugObjCounterNodeset
++;
1890 if (xmlXPathDebugObjCounterNodeset
>
1891 xmlXPathDebugObjMaxNodeset
)
1892 xmlXPathDebugObjMaxNodeset
=
1893 xmlXPathDebugObjCounterNodeset
;
1897 xmlXPathDebugObjTotalBool
++;
1898 xmlXPathDebugObjCounterBool
++;
1899 if (xmlXPathDebugObjCounterBool
>
1900 xmlXPathDebugObjMaxBool
)
1901 xmlXPathDebugObjMaxBool
=
1902 xmlXPathDebugObjCounterBool
;
1906 xmlXPathDebugObjTotalNumber
++;
1907 xmlXPathDebugObjCounterNumber
++;
1908 if (xmlXPathDebugObjCounterNumber
>
1909 xmlXPathDebugObjMaxNumber
)
1910 xmlXPathDebugObjMaxNumber
=
1911 xmlXPathDebugObjCounterNumber
;
1915 xmlXPathDebugObjTotalString
++;
1916 xmlXPathDebugObjCounterString
++;
1917 if (xmlXPathDebugObjCounterString
>
1918 xmlXPathDebugObjMaxString
)
1919 xmlXPathDebugObjMaxString
=
1920 xmlXPathDebugObjCounterString
;
1922 #ifdef LIBXML_XPTR_LOCS_ENABLED
1925 xmlXPathDebugObjTotalPoint
++;
1926 xmlXPathDebugObjCounterPoint
++;
1927 if (xmlXPathDebugObjCounterPoint
>
1928 xmlXPathDebugObjMaxPoint
)
1929 xmlXPathDebugObjMaxPoint
=
1930 xmlXPathDebugObjCounterPoint
;
1934 xmlXPathDebugObjTotalRange
++;
1935 xmlXPathDebugObjCounterRange
++;
1936 if (xmlXPathDebugObjCounterRange
>
1937 xmlXPathDebugObjMaxRange
)
1938 xmlXPathDebugObjMaxRange
=
1939 xmlXPathDebugObjCounterRange
;
1941 case XPATH_LOCATIONSET
:
1943 xmlXPathDebugObjTotalLocset
++;
1944 xmlXPathDebugObjCounterLocset
++;
1945 if (xmlXPathDebugObjCounterLocset
>
1946 xmlXPathDebugObjMaxLocset
)
1947 xmlXPathDebugObjMaxLocset
=
1948 xmlXPathDebugObjCounterLocset
;
1950 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1953 xmlXPathDebugObjTotalUsers
++;
1954 xmlXPathDebugObjCounterUsers
++;
1955 if (xmlXPathDebugObjCounterUsers
>
1956 xmlXPathDebugObjMaxUsers
)
1957 xmlXPathDebugObjMaxUsers
=
1958 xmlXPathDebugObjCounterUsers
;
1960 case XPATH_XSLT_TREE
:
1962 xmlXPathDebugObjTotalXSLTTree
++;
1963 xmlXPathDebugObjCounterXSLTTree
++;
1964 if (xmlXPathDebugObjCounterXSLTTree
>
1965 xmlXPathDebugObjMaxXSLTTree
)
1966 xmlXPathDebugObjMaxXSLTTree
=
1967 xmlXPathDebugObjCounterXSLTTree
;
1973 xmlXPathDebugObjTotalAll
++;
1974 xmlXPathDebugObjCounterAll
++;
1975 if (xmlXPathDebugObjCounterAll
>
1976 xmlXPathDebugObjMaxAll
)
1977 xmlXPathDebugObjMaxAll
=
1978 xmlXPathDebugObjCounterAll
;
1982 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt
,
1983 xmlXPathObjectType objType
)
1988 if (ctxt
->cache
!= NULL
) {
1989 xmlXPathContextCachePtr cache
=
1990 (xmlXPathContextCachePtr
) ctxt
->cache
;
1994 cache
->dbgCachedAll
++;
1996 case XPATH_UNDEFINED
:
1997 cache
->dbgCachedUndefined
++;
2000 cache
->dbgCachedNodeset
++;
2003 cache
->dbgCachedBool
++;
2006 cache
->dbgCachedNumber
++;
2009 cache
->dbgCachedString
++;
2011 #ifdef LIBXML_XPTR_LOCS_ENABLED
2013 cache
->dbgCachedPoint
++;
2016 cache
->dbgCachedRange
++;
2018 case XPATH_LOCATIONSET
:
2019 cache
->dbgCachedLocset
++;
2021 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2023 cache
->dbgCachedUsers
++;
2025 case XPATH_XSLT_TREE
:
2026 cache
->dbgCachedXSLTTree
++;
2035 case XPATH_UNDEFINED
:
2036 xmlXPathDebugObjCounterUndefined
--;
2039 xmlXPathDebugObjCounterNodeset
--;
2042 xmlXPathDebugObjCounterBool
--;
2045 xmlXPathDebugObjCounterNumber
--;
2048 xmlXPathDebugObjCounterString
--;
2050 #ifdef LIBXML_XPTR_LOCS_ENABLED
2052 xmlXPathDebugObjCounterPoint
--;
2055 xmlXPathDebugObjCounterRange
--;
2057 case XPATH_LOCATIONSET
:
2058 xmlXPathDebugObjCounterLocset
--;
2060 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2062 xmlXPathDebugObjCounterUsers
--;
2064 case XPATH_XSLT_TREE
:
2065 xmlXPathDebugObjCounterXSLTTree
--;
2070 xmlXPathDebugObjCounterAll
--;
2074 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt
)
2076 int reqAll
, reqNodeset
, reqString
, reqBool
, reqNumber
,
2077 reqXSLTTree
, reqUndefined
;
2078 int caAll
= 0, caNodeset
= 0, caString
= 0, caBool
= 0,
2079 caNumber
= 0, caXSLTTree
= 0, caUndefined
= 0;
2080 int reAll
= 0, reNodeset
= 0, reString
= 0, reBool
= 0,
2081 reNumber
= 0, reXSLTTree
= 0, reUndefined
= 0;
2082 int leftObjs
= xmlXPathDebugObjCounterAll
;
2084 reqAll
= xmlXPathDebugObjTotalAll
;
2085 reqNodeset
= xmlXPathDebugObjTotalNodeset
;
2086 reqString
= xmlXPathDebugObjTotalString
;
2087 reqBool
= xmlXPathDebugObjTotalBool
;
2088 reqNumber
= xmlXPathDebugObjTotalNumber
;
2089 reqXSLTTree
= xmlXPathDebugObjTotalXSLTTree
;
2090 reqUndefined
= xmlXPathDebugObjTotalUndefined
;
2092 printf("# XPath object usage:\n");
2095 if (ctxt
->cache
!= NULL
) {
2096 xmlXPathContextCachePtr cache
=
2097 (xmlXPathContextCachePtr
) ctxt
->cache
;
2099 reAll
= cache
->dbgReusedAll
;
2101 reNodeset
= cache
->dbgReusedNodeset
;
2102 reqNodeset
+= reNodeset
;
2103 reString
= cache
->dbgReusedString
;
2104 reqString
+= reString
;
2105 reBool
= cache
->dbgReusedBool
;
2107 reNumber
= cache
->dbgReusedNumber
;
2108 reqNumber
+= reNumber
;
2109 reXSLTTree
= cache
->dbgReusedXSLTTree
;
2110 reqXSLTTree
+= reXSLTTree
;
2111 reUndefined
= cache
->dbgReusedUndefined
;
2112 reqUndefined
+= reUndefined
;
2114 caAll
= cache
->dbgCachedAll
;
2115 caBool
= cache
->dbgCachedBool
;
2116 caNodeset
= cache
->dbgCachedNodeset
;
2117 caString
= cache
->dbgCachedString
;
2118 caNumber
= cache
->dbgCachedNumber
;
2119 caXSLTTree
= cache
->dbgCachedXSLTTree
;
2120 caUndefined
= cache
->dbgCachedUndefined
;
2122 if (cache
->nodesetObjs
)
2123 leftObjs
-= cache
->nodesetObjs
->number
;
2124 if (cache
->stringObjs
)
2125 leftObjs
-= cache
->stringObjs
->number
;
2126 if (cache
->booleanObjs
)
2127 leftObjs
-= cache
->booleanObjs
->number
;
2128 if (cache
->numberObjs
)
2129 leftObjs
-= cache
->numberObjs
->number
;
2130 if (cache
->miscObjs
)
2131 leftObjs
-= cache
->miscObjs
->number
;
2136 printf("# total : %d\n", reqAll
);
2137 printf("# left : %d\n", leftObjs
);
2138 printf("# created: %d\n", xmlXPathDebugObjTotalAll
);
2139 printf("# reused : %d\n", reAll
);
2140 printf("# max : %d\n", xmlXPathDebugObjMaxAll
);
2142 printf("# node-sets\n");
2143 printf("# total : %d\n", reqNodeset
);
2144 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset
);
2145 printf("# reused : %d\n", reNodeset
);
2146 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset
);
2148 printf("# strings\n");
2149 printf("# total : %d\n", reqString
);
2150 printf("# created: %d\n", xmlXPathDebugObjTotalString
);
2151 printf("# reused : %d\n", reString
);
2152 printf("# max : %d\n", xmlXPathDebugObjMaxString
);
2154 printf("# booleans\n");
2155 printf("# total : %d\n", reqBool
);
2156 printf("# created: %d\n", xmlXPathDebugObjTotalBool
);
2157 printf("# reused : %d\n", reBool
);
2158 printf("# max : %d\n", xmlXPathDebugObjMaxBool
);
2160 printf("# numbers\n");
2161 printf("# total : %d\n", reqNumber
);
2162 printf("# created: %d\n", xmlXPathDebugObjTotalNumber
);
2163 printf("# reused : %d\n", reNumber
);
2164 printf("# max : %d\n", xmlXPathDebugObjMaxNumber
);
2166 printf("# XSLT result tree fragments\n");
2167 printf("# total : %d\n", reqXSLTTree
);
2168 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree
);
2169 printf("# reused : %d\n", reXSLTTree
);
2170 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree
);
2172 printf("# undefined\n");
2173 printf("# total : %d\n", reqUndefined
);
2174 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined
);
2175 printf("# reused : %d\n", reUndefined
);
2176 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined
);
2180 #endif /* XP_DEBUG_OBJ_USAGE */
2182 #endif /* LIBXML_DEBUG_ENABLED */
2184 /************************************************************************
2186 * XPath object caching *
2188 ************************************************************************/
2193 * Create a new object cache
2195 * Returns the xmlXPathCache just allocated.
2197 static xmlXPathContextCachePtr
2198 xmlXPathNewCache(void)
2200 xmlXPathContextCachePtr ret
;
2202 ret
= (xmlXPathContextCachePtr
) xmlMalloc(sizeof(xmlXPathContextCache
));
2204 xmlXPathErrMemory(NULL
, "creating object cache\n");
2207 memset(ret
, 0 , (size_t) sizeof(xmlXPathContextCache
));
2208 ret
->maxNodeset
= 100;
2209 ret
->maxString
= 100;
2210 ret
->maxBoolean
= 100;
2211 ret
->maxNumber
= 100;
2217 xmlXPathCacheFreeObjectList(xmlPointerListPtr list
)
2220 xmlXPathObjectPtr obj
;
2225 for (i
= 0; i
< list
->number
; i
++) {
2226 obj
= list
->items
[i
];
2228 * Note that it is already assured that we don't need to
2229 * look out for namespace nodes in the node-set.
2231 if (obj
->nodesetval
!= NULL
) {
2232 if (obj
->nodesetval
->nodeTab
!= NULL
)
2233 xmlFree(obj
->nodesetval
->nodeTab
);
2234 xmlFree(obj
->nodesetval
);
2237 #ifdef XP_DEBUG_OBJ_USAGE
2238 xmlXPathDebugObjCounterAll
--;
2241 xmlPointerListFree(list
);
2245 xmlXPathFreeCache(xmlXPathContextCachePtr cache
)
2249 if (cache
->nodesetObjs
)
2250 xmlXPathCacheFreeObjectList(cache
->nodesetObjs
);
2251 if (cache
->stringObjs
)
2252 xmlXPathCacheFreeObjectList(cache
->stringObjs
);
2253 if (cache
->booleanObjs
)
2254 xmlXPathCacheFreeObjectList(cache
->booleanObjs
);
2255 if (cache
->numberObjs
)
2256 xmlXPathCacheFreeObjectList(cache
->numberObjs
);
2257 if (cache
->miscObjs
)
2258 xmlXPathCacheFreeObjectList(cache
->miscObjs
);
2263 * xmlXPathContextSetCache:
2265 * @ctxt: the XPath context
2266 * @active: enables/disables (creates/frees) the cache
2267 * @value: a value with semantics dependent on @options
2268 * @options: options (currently only the value 0 is used)
2270 * Creates/frees an object cache on the XPath context.
2271 * If activates XPath objects (xmlXPathObject) will be cached internally
2274 * 0: This will set the XPath object caching:
2276 * This will set the maximum number of XPath objects
2277 * to be cached per slot
2278 * There are 5 slots for: node-set, string, number, boolean, and
2279 * misc objects. Use <0 for the default number (100).
2280 * Other values for @options have currently no effect.
2282 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2285 xmlXPathContextSetCache(xmlXPathContextPtr ctxt
,
2293 xmlXPathContextCachePtr cache
;
2295 if (ctxt
->cache
== NULL
) {
2296 ctxt
->cache
= xmlXPathNewCache();
2297 if (ctxt
->cache
== NULL
)
2300 cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2304 cache
->maxNodeset
= value
;
2305 cache
->maxString
= value
;
2306 cache
->maxNumber
= value
;
2307 cache
->maxBoolean
= value
;
2308 cache
->maxMisc
= value
;
2310 } else if (ctxt
->cache
!= NULL
) {
2311 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
2318 * xmlXPathCacheWrapNodeSet:
2319 * @ctxt: the XPath context
2320 * @val: the NodePtr value
2322 * This is the cached version of xmlXPathWrapNodeSet().
2323 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2325 * Returns the created or reused object.
2327 static xmlXPathObjectPtr
2328 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt
, xmlNodeSetPtr val
)
2330 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2331 xmlXPathContextCachePtr cache
=
2332 (xmlXPathContextCachePtr
) ctxt
->cache
;
2334 if ((cache
->miscObjs
!= NULL
) &&
2335 (cache
->miscObjs
->number
!= 0))
2337 xmlXPathObjectPtr ret
;
2339 ret
= (xmlXPathObjectPtr
)
2340 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2341 ret
->type
= XPATH_NODESET
;
2342 ret
->nodesetval
= val
;
2343 #ifdef XP_DEBUG_OBJ_USAGE
2344 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2350 return(xmlXPathWrapNodeSet(val
));
2355 * xmlXPathCacheWrapString:
2356 * @ctxt: the XPath context
2357 * @val: the xmlChar * value
2359 * This is the cached version of xmlXPathWrapString().
2360 * Wraps the @val string into an XPath object.
2362 * Returns the created or reused object.
2364 static xmlXPathObjectPtr
2365 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt
, xmlChar
*val
)
2367 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2368 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2370 if ((cache
->stringObjs
!= NULL
) &&
2371 (cache
->stringObjs
->number
!= 0))
2374 xmlXPathObjectPtr ret
;
2376 ret
= (xmlXPathObjectPtr
)
2377 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2378 ret
->type
= XPATH_STRING
;
2379 ret
->stringval
= val
;
2380 #ifdef XP_DEBUG_OBJ_USAGE
2381 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2384 } else if ((cache
->miscObjs
!= NULL
) &&
2385 (cache
->miscObjs
->number
!= 0))
2387 xmlXPathObjectPtr ret
;
2389 * Fallback to misc-cache.
2391 ret
= (xmlXPathObjectPtr
)
2392 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2394 ret
->type
= XPATH_STRING
;
2395 ret
->stringval
= val
;
2396 #ifdef XP_DEBUG_OBJ_USAGE
2397 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2402 return(xmlXPathWrapString(val
));
2406 * xmlXPathCacheNewNodeSet:
2407 * @ctxt: the XPath context
2408 * @val: the NodePtr value
2410 * This is the cached version of xmlXPathNewNodeSet().
2411 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2412 * it with the single Node @val
2414 * Returns the created or reused object.
2416 static xmlXPathObjectPtr
2417 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt
, xmlNodePtr val
)
2419 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2420 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2422 if ((cache
->nodesetObjs
!= NULL
) &&
2423 (cache
->nodesetObjs
->number
!= 0))
2425 xmlXPathObjectPtr ret
;
2427 * Use the nodeset-cache.
2429 ret
= (xmlXPathObjectPtr
)
2430 cache
->nodesetObjs
->items
[--cache
->nodesetObjs
->number
];
2431 ret
->type
= XPATH_NODESET
;
2434 if ((ret
->nodesetval
->nodeMax
== 0) ||
2435 (val
->type
== XML_NAMESPACE_DECL
))
2437 /* TODO: Check memory error. */
2438 xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
);
2440 ret
->nodesetval
->nodeTab
[0] = val
;
2441 ret
->nodesetval
->nodeNr
= 1;
2444 #ifdef XP_DEBUG_OBJ_USAGE
2445 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2448 } else if ((cache
->miscObjs
!= NULL
) &&
2449 (cache
->miscObjs
->number
!= 0))
2451 xmlXPathObjectPtr ret
;
2453 * Fallback to misc-cache.
2456 ret
= (xmlXPathObjectPtr
)
2457 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2459 ret
->type
= XPATH_NODESET
;
2461 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
2462 if (ret
->nodesetval
== NULL
) {
2463 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
2464 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
2467 #ifdef XP_DEBUG_OBJ_USAGE
2468 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2473 return(xmlXPathNewNodeSet(val
));
2477 * xmlXPathCacheNewCString:
2478 * @ctxt: the XPath context
2479 * @val: the char * value
2481 * This is the cached version of xmlXPathNewCString().
2482 * Acquire an xmlXPathObjectPtr of type string and of value @val
2484 * Returns the created or reused object.
2486 static xmlXPathObjectPtr
2487 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt
, const char *val
)
2489 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2490 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2492 if ((cache
->stringObjs
!= NULL
) &&
2493 (cache
->stringObjs
->number
!= 0))
2495 xmlXPathObjectPtr ret
;
2497 ret
= (xmlXPathObjectPtr
)
2498 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2500 ret
->type
= XPATH_STRING
;
2501 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2502 #ifdef XP_DEBUG_OBJ_USAGE
2503 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2506 } else if ((cache
->miscObjs
!= NULL
) &&
2507 (cache
->miscObjs
->number
!= 0))
2509 xmlXPathObjectPtr ret
;
2511 ret
= (xmlXPathObjectPtr
)
2512 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2514 ret
->type
= XPATH_STRING
;
2515 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2516 #ifdef XP_DEBUG_OBJ_USAGE
2517 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2522 return(xmlXPathNewCString(val
));
2526 * xmlXPathCacheNewString:
2527 * @ctxt: the XPath context
2528 * @val: the xmlChar * value
2530 * This is the cached version of xmlXPathNewString().
2531 * Acquire an xmlXPathObjectPtr of type string and of value @val
2533 * Returns the created or reused object.
2535 static xmlXPathObjectPtr
2536 xmlXPathCacheNewString(xmlXPathContextPtr ctxt
, const xmlChar
*val
)
2538 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2539 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2541 if ((cache
->stringObjs
!= NULL
) &&
2542 (cache
->stringObjs
->number
!= 0))
2544 xmlXPathObjectPtr ret
;
2546 ret
= (xmlXPathObjectPtr
)
2547 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2548 ret
->type
= XPATH_STRING
;
2550 ret
->stringval
= xmlStrdup(val
);
2552 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2553 #ifdef XP_DEBUG_OBJ_USAGE
2554 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2557 } else if ((cache
->miscObjs
!= NULL
) &&
2558 (cache
->miscObjs
->number
!= 0))
2560 xmlXPathObjectPtr ret
;
2562 ret
= (xmlXPathObjectPtr
)
2563 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2565 ret
->type
= XPATH_STRING
;
2567 ret
->stringval
= xmlStrdup(val
);
2569 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2570 #ifdef XP_DEBUG_OBJ_USAGE
2571 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2576 return(xmlXPathNewString(val
));
2580 * xmlXPathCacheNewBoolean:
2581 * @ctxt: the XPath context
2582 * @val: the boolean value
2584 * This is the cached version of xmlXPathNewBoolean().
2585 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2587 * Returns the created or reused object.
2589 static xmlXPathObjectPtr
2590 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt
, int val
)
2592 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2593 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2595 if ((cache
->booleanObjs
!= NULL
) &&
2596 (cache
->booleanObjs
->number
!= 0))
2598 xmlXPathObjectPtr ret
;
2600 ret
= (xmlXPathObjectPtr
)
2601 cache
->booleanObjs
->items
[--cache
->booleanObjs
->number
];
2602 ret
->type
= XPATH_BOOLEAN
;
2603 ret
->boolval
= (val
!= 0);
2604 #ifdef XP_DEBUG_OBJ_USAGE
2605 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2608 } else if ((cache
->miscObjs
!= NULL
) &&
2609 (cache
->miscObjs
->number
!= 0))
2611 xmlXPathObjectPtr ret
;
2613 ret
= (xmlXPathObjectPtr
)
2614 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2616 ret
->type
= XPATH_BOOLEAN
;
2617 ret
->boolval
= (val
!= 0);
2618 #ifdef XP_DEBUG_OBJ_USAGE
2619 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2624 return(xmlXPathNewBoolean(val
));
2628 * xmlXPathCacheNewFloat:
2629 * @ctxt: the XPath context
2630 * @val: the double value
2632 * This is the cached version of xmlXPathNewFloat().
2633 * Acquires an xmlXPathObjectPtr of type double and of value @val
2635 * Returns the created or reused object.
2637 static xmlXPathObjectPtr
2638 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt
, double val
)
2640 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2641 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2643 if ((cache
->numberObjs
!= NULL
) &&
2644 (cache
->numberObjs
->number
!= 0))
2646 xmlXPathObjectPtr ret
;
2648 ret
= (xmlXPathObjectPtr
)
2649 cache
->numberObjs
->items
[--cache
->numberObjs
->number
];
2650 ret
->type
= XPATH_NUMBER
;
2651 ret
->floatval
= val
;
2652 #ifdef XP_DEBUG_OBJ_USAGE
2653 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2656 } else if ((cache
->miscObjs
!= NULL
) &&
2657 (cache
->miscObjs
->number
!= 0))
2659 xmlXPathObjectPtr ret
;
2661 ret
= (xmlXPathObjectPtr
)
2662 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2664 ret
->type
= XPATH_NUMBER
;
2665 ret
->floatval
= val
;
2666 #ifdef XP_DEBUG_OBJ_USAGE
2667 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2672 return(xmlXPathNewFloat(val
));
2676 * xmlXPathCacheConvertString:
2677 * @ctxt: the XPath context
2678 * @val: an XPath object
2680 * This is the cached version of xmlXPathConvertString().
2681 * Converts an existing object to its string() equivalent
2683 * Returns a created or reused object, the old one is freed (cached)
2684 * (or the operation is done directly on @val)
2687 static xmlXPathObjectPtr
2688 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2689 xmlChar
*res
= NULL
;
2692 return(xmlXPathCacheNewCString(ctxt
, ""));
2694 switch (val
->type
) {
2695 case XPATH_UNDEFINED
:
2697 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
2701 case XPATH_XSLT_TREE
:
2702 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
2707 res
= xmlXPathCastBooleanToString(val
->boolval
);
2710 res
= xmlXPathCastNumberToString(val
->floatval
);
2713 #ifdef LIBXML_XPTR_LOCS_ENABLED
2716 case XPATH_LOCATIONSET
:
2717 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2721 xmlXPathReleaseObject(ctxt
, val
);
2723 return(xmlXPathCacheNewCString(ctxt
, ""));
2724 return(xmlXPathCacheWrapString(ctxt
, res
));
2728 * xmlXPathCacheObjectCopy:
2729 * @ctxt: the XPath context
2730 * @val: the original object
2732 * This is the cached version of xmlXPathObjectCopy().
2733 * Acquire a copy of a given object
2735 * Returns a created or reused created object.
2737 static xmlXPathObjectPtr
2738 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
)
2743 if (XP_HAS_CACHE(ctxt
)) {
2744 switch (val
->type
) {
2746 return(xmlXPathCacheWrapNodeSet(ctxt
,
2747 xmlXPathNodeSetMerge(NULL
, val
->nodesetval
)));
2749 return(xmlXPathCacheNewString(ctxt
, val
->stringval
));
2751 return(xmlXPathCacheNewBoolean(ctxt
, val
->boolval
));
2753 return(xmlXPathCacheNewFloat(ctxt
, val
->floatval
));
2758 return(xmlXPathObjectCopy(val
));
2762 * xmlXPathCacheConvertBoolean:
2763 * @ctxt: the XPath context
2764 * @val: an XPath object
2766 * This is the cached version of xmlXPathConvertBoolean().
2767 * Converts an existing object to its boolean() equivalent
2769 * Returns a created or reused object, the old one is freed (or the operation
2770 * is done directly on @val)
2772 static xmlXPathObjectPtr
2773 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2774 xmlXPathObjectPtr ret
;
2777 return(xmlXPathCacheNewBoolean(ctxt
, 0));
2778 if (val
->type
== XPATH_BOOLEAN
)
2780 ret
= xmlXPathCacheNewBoolean(ctxt
, xmlXPathCastToBoolean(val
));
2781 xmlXPathReleaseObject(ctxt
, val
);
2786 * xmlXPathCacheConvertNumber:
2787 * @ctxt: the XPath context
2788 * @val: an XPath object
2790 * This is the cached version of xmlXPathConvertNumber().
2791 * Converts an existing object to its number() equivalent
2793 * Returns a created or reused object, the old one is freed (or the operation
2794 * is done directly on @val)
2796 static xmlXPathObjectPtr
2797 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2798 xmlXPathObjectPtr ret
;
2801 return(xmlXPathCacheNewFloat(ctxt
, 0.0));
2802 if (val
->type
== XPATH_NUMBER
)
2804 ret
= xmlXPathCacheNewFloat(ctxt
, xmlXPathCastToNumber(val
));
2805 xmlXPathReleaseObject(ctxt
, val
);
2809 /************************************************************************
2811 * Parser stacks related functions and macros *
2813 ************************************************************************/
2817 * @ctxt: an XPath parser context
2819 * Set the callee evaluation frame
2821 * Returns the previous frame value to be restored once done
2824 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt
) {
2829 ret
= ctxt
->valueFrame
;
2830 ctxt
->valueFrame
= ctxt
->valueNr
;
2836 * @ctxt: an XPath parser context
2837 * @frame: the previous frame value
2839 * Remove the callee evaluation frame
2842 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt
, int frame
) {
2845 if (ctxt
->valueNr
< ctxt
->valueFrame
) {
2846 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2848 ctxt
->valueFrame
= frame
;
2853 * @ctxt: an XPath evaluation context
2855 * Pops the top XPath object from the value stack
2857 * Returns the XPath object just removed
2860 valuePop(xmlXPathParserContextPtr ctxt
)
2862 xmlXPathObjectPtr ret
;
2864 if ((ctxt
== NULL
) || (ctxt
->valueNr
<= 0))
2867 if (ctxt
->valueNr
<= ctxt
->valueFrame
) {
2868 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2873 if (ctxt
->valueNr
> 0)
2874 ctxt
->value
= ctxt
->valueTab
[ctxt
->valueNr
- 1];
2877 ret
= ctxt
->valueTab
[ctxt
->valueNr
];
2878 ctxt
->valueTab
[ctxt
->valueNr
] = NULL
;
2883 * @ctxt: an XPath evaluation context
2884 * @value: the XPath object
2886 * Pushes a new XPath object on top of the value stack. If value is NULL,
2887 * a memory error is recorded in the parser context.
2889 * Returns the number of items on the value stack, or -1 in case of error.
2892 valuePush(xmlXPathParserContextPtr ctxt
, xmlXPathObjectPtr value
)
2894 if (ctxt
== NULL
) return(-1);
2895 if (value
== NULL
) {
2897 * A NULL value typically indicates that a memory allocation failed,
2898 * so we set ctxt->error here to propagate the error.
2900 ctxt
->error
= XPATH_MEMORY_ERROR
;
2903 if (ctxt
->valueNr
>= ctxt
->valueMax
) {
2904 xmlXPathObjectPtr
*tmp
;
2906 if (ctxt
->valueMax
>= XPATH_MAX_STACK_DEPTH
) {
2907 xmlXPathPErrMemory(ctxt
, "XPath stack depth limit reached\n");
2910 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(ctxt
->valueTab
,
2911 2 * ctxt
->valueMax
*
2912 sizeof(ctxt
->valueTab
[0]));
2914 xmlXPathPErrMemory(ctxt
, "pushing value\n");
2917 ctxt
->valueMax
*= 2;
2918 ctxt
->valueTab
= tmp
;
2920 ctxt
->valueTab
[ctxt
->valueNr
] = value
;
2921 ctxt
->value
= value
;
2922 return (ctxt
->valueNr
++);
2926 * xmlXPathPopBoolean:
2927 * @ctxt: an XPath parser context
2929 * Pops a boolean from the stack, handling conversion if needed.
2930 * Check error with #xmlXPathCheckError.
2932 * Returns the boolean
2935 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt
) {
2936 xmlXPathObjectPtr obj
;
2939 obj
= valuePop(ctxt
);
2941 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2944 if (obj
->type
!= XPATH_BOOLEAN
)
2945 ret
= xmlXPathCastToBoolean(obj
);
2948 xmlXPathReleaseObject(ctxt
->context
, obj
);
2953 * xmlXPathPopNumber:
2954 * @ctxt: an XPath parser context
2956 * Pops a number from the stack, handling conversion if needed.
2957 * Check error with #xmlXPathCheckError.
2959 * Returns the number
2962 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt
) {
2963 xmlXPathObjectPtr obj
;
2966 obj
= valuePop(ctxt
);
2968 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2971 if (obj
->type
!= XPATH_NUMBER
)
2972 ret
= xmlXPathCastToNumber(obj
);
2974 ret
= obj
->floatval
;
2975 xmlXPathReleaseObject(ctxt
->context
, obj
);
2980 * xmlXPathPopString:
2981 * @ctxt: an XPath parser context
2983 * Pops a string from the stack, handling conversion if needed.
2984 * Check error with #xmlXPathCheckError.
2986 * Returns the string
2989 xmlXPathPopString (xmlXPathParserContextPtr ctxt
) {
2990 xmlXPathObjectPtr obj
;
2993 obj
= valuePop(ctxt
);
2995 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2998 ret
= xmlXPathCastToString(obj
); /* this does required strdup */
2999 /* TODO: needs refactoring somewhere else */
3000 if (obj
->stringval
== ret
)
3001 obj
->stringval
= NULL
;
3002 xmlXPathReleaseObject(ctxt
->context
, obj
);
3007 * xmlXPathPopNodeSet:
3008 * @ctxt: an XPath parser context
3010 * Pops a node-set from the stack, handling conversion if needed.
3011 * Check error with #xmlXPathCheckError.
3013 * Returns the node-set
3016 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt
) {
3017 xmlXPathObjectPtr obj
;
3020 if (ctxt
== NULL
) return(NULL
);
3021 if (ctxt
->value
== NULL
) {
3022 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
3025 if (!xmlXPathStackIsNodeSet(ctxt
)) {
3026 xmlXPathSetTypeError(ctxt
);
3029 obj
= valuePop(ctxt
);
3030 ret
= obj
->nodesetval
;
3032 /* to fix memory leak of not clearing obj->user */
3033 if (obj
->boolval
&& obj
->user
!= NULL
)
3034 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
3036 obj
->nodesetval
= NULL
;
3037 xmlXPathReleaseObject(ctxt
->context
, obj
);
3042 * xmlXPathPopExternal:
3043 * @ctxt: an XPath parser context
3045 * Pops an external object from the stack, handling conversion if needed.
3046 * Check error with #xmlXPathCheckError.
3048 * Returns the object
3051 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt
) {
3052 xmlXPathObjectPtr obj
;
3055 if ((ctxt
== NULL
) || (ctxt
->value
== NULL
)) {
3056 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
3059 if (ctxt
->value
->type
!= XPATH_USERS
) {
3060 xmlXPathSetTypeError(ctxt
);
3063 obj
= valuePop(ctxt
);
3066 xmlXPathReleaseObject(ctxt
->context
, obj
);
3071 * Macros for accessing the content. Those should be used only by the parser,
3074 * Dirty macros, i.e. one need to make assumption on the context to use them
3076 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3077 * CUR returns the current xmlChar value, i.e. a 8 bit value
3078 * in ISO-Latin or UTF-8.
3079 * This should be used internally by the parser
3080 * only to compare to ASCII values otherwise it would break when
3081 * running with UTF-8 encoding.
3082 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3083 * to compare on ASCII based substring.
3084 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3085 * strings within the parser.
3086 * CURRENT Returns the current char value, with the full decoding of
3087 * UTF-8 if we are using this mode. It returns an int.
3088 * NEXT Skip to the next character, this does the proper decoding
3089 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3090 * It returns the pointer to the current xmlChar.
3093 #define CUR (*ctxt->cur)
3094 #define SKIP(val) ctxt->cur += (val)
3095 #define NXT(val) ctxt->cur[(val)]
3096 #define CUR_PTR ctxt->cur
3097 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3099 #define COPY_BUF(l,b,i,v) \
3100 if (l == 1) b[i++] = (xmlChar) v; \
3101 else i += xmlCopyChar(l,&b[i],v)
3103 #define NEXTL(l) ctxt->cur += l
3105 #define SKIP_BLANKS \
3106 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3108 #define CURRENT (*ctxt->cur)
3109 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3116 #define DBL_EPSILON 1E-9
3119 #define UPPER_DOUBLE 1E9
3120 #define LOWER_DOUBLE 1E-5
3121 #define LOWER_DOUBLE_EXP 5
3123 #define INTEGER_DIGITS DBL_DIG
3124 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3125 #define EXPONENT_DIGITS (3 + 2)
3128 * xmlXPathFormatNumber:
3129 * @number: number to format
3130 * @buffer: output buffer
3131 * @buffersize: size of output buffer
3133 * Convert the number into a string representation.
3136 xmlXPathFormatNumber(double number
, char buffer
[], int buffersize
)
3138 switch (xmlXPathIsInf(number
)) {
3140 if (buffersize
> (int)sizeof("Infinity"))
3141 snprintf(buffer
, buffersize
, "Infinity");
3144 if (buffersize
> (int)sizeof("-Infinity"))
3145 snprintf(buffer
, buffersize
, "-Infinity");
3148 if (xmlXPathIsNaN(number
)) {
3149 if (buffersize
> (int)sizeof("NaN"))
3150 snprintf(buffer
, buffersize
, "NaN");
3151 } else if (number
== 0) {
3152 /* Omit sign for negative zero. */
3153 snprintf(buffer
, buffersize
, "0");
3154 } else if ((number
> INT_MIN
) && (number
< INT_MAX
) &&
3155 (number
== (int) number
)) {
3158 int value
= (int) number
;
3164 snprintf(work
, 29, "%d", value
);
3166 while ((*cur
) && (ptr
- buffer
< buffersize
)) {
3170 if (ptr
- buffer
< buffersize
) {
3172 } else if (buffersize
> 0) {
3178 For the dimension of work,
3179 DBL_DIG is number of significant digits
3180 EXPONENT is only needed for "scientific notation"
3181 3 is sign, decimal point, and terminating zero
3182 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3183 Note that this dimension is slightly (a few characters)
3184 larger than actually necessary.
3186 char work
[DBL_DIG
+ EXPONENT_DIGITS
+ 3 + LOWER_DOUBLE_EXP
];
3187 int integer_place
, fraction_place
;
3189 char *after_fraction
;
3190 double absolute_value
;
3193 absolute_value
= fabs(number
);
3196 * First choose format - scientific or regular floating point.
3197 * In either case, result is in work, and after_fraction points
3198 * just past the fractional part.
3200 if ( ((absolute_value
> UPPER_DOUBLE
) ||
3201 (absolute_value
< LOWER_DOUBLE
)) &&
3202 (absolute_value
!= 0.0) ) {
3203 /* Use scientific notation */
3204 integer_place
= DBL_DIG
+ EXPONENT_DIGITS
+ 1;
3205 fraction_place
= DBL_DIG
- 1;
3206 size
= snprintf(work
, sizeof(work
),"%*.*e",
3207 integer_place
, fraction_place
, number
);
3208 while ((size
> 0) && (work
[size
] != 'e')) size
--;
3212 /* Use regular notation */
3213 if (absolute_value
> 0.0) {
3214 integer_place
= (int)log10(absolute_value
);
3215 if (integer_place
> 0)
3216 fraction_place
= DBL_DIG
- integer_place
- 1;
3218 fraction_place
= DBL_DIG
- integer_place
;
3222 size
= snprintf(work
, sizeof(work
), "%0.*f",
3223 fraction_place
, number
);
3226 /* Remove leading spaces sometimes inserted by snprintf */
3227 while (work
[0] == ' ') {
3228 for (ptr
= &work
[0];(ptr
[0] = ptr
[1]);ptr
++);
3232 /* Remove fractional trailing zeroes */
3233 after_fraction
= work
+ size
;
3234 ptr
= after_fraction
;
3235 while (*(--ptr
) == '0')
3239 while ((*ptr
++ = *after_fraction
++) != 0);
3241 /* Finally copy result back to caller */
3242 size
= strlen(work
) + 1;
3243 if (size
> buffersize
) {
3244 work
[buffersize
- 1] = 0;
3247 memmove(buffer
, work
, size
);
3254 /************************************************************************
3256 * Routines to handle NodeSets *
3258 ************************************************************************/
3261 * xmlXPathOrderDocElems:
3262 * @doc: an input document
3264 * Call this routine to speed up XPath computation on static documents.
3265 * This stamps all the element nodes with the document order
3266 * Like for line information, the order is kept in the element->content
3267 * field, the value stored is actually - the node number (starting at -1)
3268 * to be able to differentiate from line numbers.
3270 * Returns the number of elements found in the document or -1 in case
3274 xmlXPathOrderDocElems(xmlDocPtr doc
) {
3275 ptrdiff_t count
= 0;
3280 cur
= doc
->children
;
3281 while (cur
!= NULL
) {
3282 if (cur
->type
== XML_ELEMENT_NODE
) {
3283 cur
->content
= (void *) (-(++count
));
3284 if (cur
->children
!= NULL
) {
3285 cur
= cur
->children
;
3289 if (cur
->next
!= NULL
) {
3297 if (cur
== (xmlNodePtr
) doc
) {
3301 if (cur
->next
!= NULL
) {
3305 } while (cur
!= NULL
);
3307 return((long) count
);
3312 * @node1: the first node
3313 * @node2: the second node
3315 * Compare two nodes w.r.t document order
3317 * Returns -2 in case of error 1 if first point < second point, 0 if
3318 * it's the same node, -1 otherwise
3321 xmlXPathCmpNodes(xmlNodePtr node1
, xmlNodePtr node2
) {
3323 int attr1
= 0, attr2
= 0;
3324 xmlNodePtr attrNode1
= NULL
, attrNode2
= NULL
;
3325 xmlNodePtr cur
, root
;
3327 if ((node1
== NULL
) || (node2
== NULL
))
3330 * a couple of optimizations which will avoid computations in most cases
3332 if (node1
== node2
) /* trivial case */
3334 if (node1
->type
== XML_ATTRIBUTE_NODE
) {
3337 node1
= node1
->parent
;
3339 if (node2
->type
== XML_ATTRIBUTE_NODE
) {
3342 node2
= node2
->parent
;
3344 if (node1
== node2
) {
3345 if (attr1
== attr2
) {
3346 /* not required, but we keep attributes in order */
3348 cur
= attrNode2
->prev
;
3349 while (cur
!= NULL
) {
3350 if (cur
== attrNode1
)
3362 if ((node1
->type
== XML_NAMESPACE_DECL
) ||
3363 (node2
->type
== XML_NAMESPACE_DECL
))
3365 if (node1
== node2
->prev
)
3367 if (node1
== node2
->next
)
3371 * Speedup using document order if available.
3373 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3374 (node2
->type
== XML_ELEMENT_NODE
) &&
3375 (0 > (ptrdiff_t) node1
->content
) &&
3376 (0 > (ptrdiff_t) node2
->content
) &&
3377 (node1
->doc
== node2
->doc
)) {
3380 l1
= -((ptrdiff_t) node1
->content
);
3381 l2
= -((ptrdiff_t) node2
->content
);
3389 * compute depth to root
3391 for (depth2
= 0, cur
= node2
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3392 if (cur
->parent
== node1
)
3397 for (depth1
= 0, cur
= node1
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3398 if (cur
->parent
== node2
)
3403 * Distinct document (or distinct entities :-( ) case.
3409 * get the nearest common ancestor.
3411 while (depth1
> depth2
) {
3413 node1
= node1
->parent
;
3415 while (depth2
> depth1
) {
3417 node2
= node2
->parent
;
3419 while (node1
->parent
!= node2
->parent
) {
3420 node1
= node1
->parent
;
3421 node2
= node2
->parent
;
3422 /* should not happen but just in case ... */
3423 if ((node1
== NULL
) || (node2
== NULL
))
3429 if (node1
== node2
->prev
)
3431 if (node1
== node2
->next
)
3434 * Speedup using document order if available.
3436 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3437 (node2
->type
== XML_ELEMENT_NODE
) &&
3438 (0 > (ptrdiff_t) node1
->content
) &&
3439 (0 > (ptrdiff_t) node2
->content
) &&
3440 (node1
->doc
== node2
->doc
)) {
3443 l1
= -((ptrdiff_t) node1
->content
);
3444 l2
= -((ptrdiff_t) node2
->content
);
3451 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
3454 return(-1); /* assume there is no sibling list corruption */
3458 * xmlXPathNodeSetSort:
3459 * @set: the node set
3461 * Sort the node set in document order
3464 xmlXPathNodeSetSort(xmlNodeSetPtr set
) {
3465 #ifndef WITH_TIM_SORT
3466 int i
, j
, incr
, len
;
3473 #ifndef WITH_TIM_SORT
3475 * Use the old Shell's sort implementation to sort the node-set
3476 * Timsort ought to be quite faster
3479 for (incr
= len
/ 2; incr
> 0; incr
/= 2) {
3480 for (i
= incr
; i
< len
; i
++) {
3483 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3484 if (xmlXPathCmpNodesExt(set
->nodeTab
[j
],
3485 set
->nodeTab
[j
+ incr
]) == -1)
3487 if (xmlXPathCmpNodes(set
->nodeTab
[j
],
3488 set
->nodeTab
[j
+ incr
]) == -1)
3491 tmp
= set
->nodeTab
[j
];
3492 set
->nodeTab
[j
] = set
->nodeTab
[j
+ incr
];
3493 set
->nodeTab
[j
+ incr
] = tmp
;
3500 #else /* WITH_TIM_SORT */
3501 libxml_domnode_tim_sort(set
->nodeTab
, set
->nodeNr
);
3502 #endif /* WITH_TIM_SORT */
3505 #define XML_NODESET_DEFAULT 10
3507 * xmlXPathNodeSetDupNs:
3508 * @node: the parent node of the namespace XPath node
3509 * @ns: the libxml namespace declaration node.
3511 * Namespace node in libxml don't match the XPath semantic. In a node set
3512 * the namespace nodes are duplicated and the next pointer is set to the
3513 * parent node in the XPath semantic.
3515 * Returns the newly created object.
3518 xmlXPathNodeSetDupNs(xmlNodePtr node
, xmlNsPtr ns
) {
3521 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3523 if ((node
== NULL
) || (node
->type
== XML_NAMESPACE_DECL
))
3524 return((xmlNodePtr
) ns
);
3527 * Allocate a new Namespace and fill the fields.
3529 cur
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
3531 xmlXPathErrMemory(NULL
, "duplicating namespace\n");
3534 memset(cur
, 0, sizeof(xmlNs
));
3535 cur
->type
= XML_NAMESPACE_DECL
;
3536 if (ns
->href
!= NULL
)
3537 cur
->href
= xmlStrdup(ns
->href
);
3538 if (ns
->prefix
!= NULL
)
3539 cur
->prefix
= xmlStrdup(ns
->prefix
);
3540 cur
->next
= (xmlNsPtr
) node
;
3541 return((xmlNodePtr
) cur
);
3545 * xmlXPathNodeSetFreeNs:
3546 * @ns: the XPath namespace node found in a nodeset.
3548 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3549 * the namespace nodes are duplicated and the next pointer is set to the
3550 * parent node in the XPath semantic. Check if such a node needs to be freed
3553 xmlXPathNodeSetFreeNs(xmlNsPtr ns
) {
3554 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3557 if ((ns
->next
!= NULL
) && (ns
->next
->type
!= XML_NAMESPACE_DECL
)) {
3558 if (ns
->href
!= NULL
)
3559 xmlFree((xmlChar
*)ns
->href
);
3560 if (ns
->prefix
!= NULL
)
3561 xmlFree((xmlChar
*)ns
->prefix
);
3567 * xmlXPathNodeSetCreate:
3568 * @val: an initial xmlNodePtr, or NULL
3570 * Create a new xmlNodeSetPtr of type double and of value @val
3572 * Returns the newly created object.
3575 xmlXPathNodeSetCreate(xmlNodePtr val
) {
3578 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3580 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3583 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3585 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3586 sizeof(xmlNodePtr
));
3587 if (ret
->nodeTab
== NULL
) {
3588 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3592 memset(ret
->nodeTab
, 0 ,
3593 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3594 ret
->nodeMax
= XML_NODESET_DEFAULT
;
3595 if (val
->type
== XML_NAMESPACE_DECL
) {
3596 xmlNsPtr ns
= (xmlNsPtr
) val
;
3598 /* TODO: Check memory error. */
3599 ret
->nodeTab
[ret
->nodeNr
++] =
3600 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3602 ret
->nodeTab
[ret
->nodeNr
++] = val
;
3608 * xmlXPathNodeSetContains:
3609 * @cur: the node-set
3612 * checks whether @cur contains @val
3614 * Returns true (1) if @cur contains @val, false (0) otherwise
3617 xmlXPathNodeSetContains (xmlNodeSetPtr cur
, xmlNodePtr val
) {
3620 if ((cur
== NULL
) || (val
== NULL
)) return(0);
3621 if (val
->type
== XML_NAMESPACE_DECL
) {
3622 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3623 if (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
3626 ns1
= (xmlNsPtr
) val
;
3627 ns2
= (xmlNsPtr
) cur
->nodeTab
[i
];
3630 if ((ns1
->next
!= NULL
) && (ns2
->next
== ns1
->next
) &&
3631 (xmlStrEqual(ns1
->prefix
, ns2
->prefix
)))
3636 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3637 if (cur
->nodeTab
[i
] == val
)
3645 * xmlXPathNodeSetAddNs:
3646 * @cur: the initial node set
3647 * @node: the hosting node
3648 * @ns: a the namespace node
3650 * add a new namespace node to an existing NodeSet
3652 * Returns 0 in case of success and -1 in case of error
3655 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur
, xmlNodePtr node
, xmlNsPtr ns
) {
3659 if ((cur
== NULL
) || (ns
== NULL
) || (node
== NULL
) ||
3660 (ns
->type
!= XML_NAMESPACE_DECL
) ||
3661 (node
->type
!= XML_ELEMENT_NODE
))
3664 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3666 * prevent duplicates
3668 for (i
= 0;i
< cur
->nodeNr
;i
++) {
3669 if ((cur
->nodeTab
[i
] != NULL
) &&
3670 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) &&
3671 (((xmlNsPtr
)cur
->nodeTab
[i
])->next
== (xmlNsPtr
) node
) &&
3672 (xmlStrEqual(ns
->prefix
, ((xmlNsPtr
)cur
->nodeTab
[i
])->prefix
)))
3677 * grow the nodeTab if needed
3679 if (cur
->nodeMax
== 0) {
3680 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3681 sizeof(xmlNodePtr
));
3682 if (cur
->nodeTab
== NULL
) {
3683 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3686 memset(cur
->nodeTab
, 0 ,
3687 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3688 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3689 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3692 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3693 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3696 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3697 sizeof(xmlNodePtr
));
3699 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3703 cur
->nodeTab
= temp
;
3705 /* TODO: Check memory error. */
3706 cur
->nodeTab
[cur
->nodeNr
++] = xmlXPathNodeSetDupNs(node
, ns
);
3711 * xmlXPathNodeSetAdd:
3712 * @cur: the initial node set
3713 * @val: a new xmlNodePtr
3715 * add a new xmlNodePtr to an existing NodeSet
3717 * Returns 0 in case of success, and -1 in case of error
3720 xmlXPathNodeSetAdd(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3723 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3725 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3727 * prevent duplicates
3729 for (i
= 0;i
< cur
->nodeNr
;i
++)
3730 if (cur
->nodeTab
[i
] == val
) return(0);
3733 * grow the nodeTab if needed
3735 if (cur
->nodeMax
== 0) {
3736 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3737 sizeof(xmlNodePtr
));
3738 if (cur
->nodeTab
== NULL
) {
3739 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3742 memset(cur
->nodeTab
, 0 ,
3743 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3744 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3745 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3748 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3749 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3752 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3753 sizeof(xmlNodePtr
));
3755 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3759 cur
->nodeTab
= temp
;
3761 if (val
->type
== XML_NAMESPACE_DECL
) {
3762 xmlNsPtr ns
= (xmlNsPtr
) val
;
3764 /* TODO: Check memory error. */
3765 cur
->nodeTab
[cur
->nodeNr
++] =
3766 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3768 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3773 * xmlXPathNodeSetAddUnique:
3774 * @cur: the initial node set
3775 * @val: a new xmlNodePtr
3777 * add a new xmlNodePtr to an existing NodeSet, optimized version
3778 * when we are sure the node is not already in the set.
3780 * Returns 0 in case of success and -1 in case of failure
3783 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3784 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3786 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3788 * grow the nodeTab if needed
3790 if (cur
->nodeMax
== 0) {
3791 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3792 sizeof(xmlNodePtr
));
3793 if (cur
->nodeTab
== NULL
) {
3794 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3797 memset(cur
->nodeTab
, 0 ,
3798 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3799 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3800 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3803 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3804 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3807 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3808 sizeof(xmlNodePtr
));
3810 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3813 cur
->nodeTab
= temp
;
3816 if (val
->type
== XML_NAMESPACE_DECL
) {
3817 xmlNsPtr ns
= (xmlNsPtr
) val
;
3819 /* TODO: Check memory error. */
3820 cur
->nodeTab
[cur
->nodeNr
++] =
3821 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3823 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3828 * xmlXPathNodeSetMerge:
3829 * @val1: the first NodeSet or NULL
3830 * @val2: the second NodeSet
3832 * Merges two nodesets, all nodes from @val2 are added to @val1
3833 * if @val1 is NULL, a new set is created and copied from @val2
3835 * Returns @val1 once extended or NULL in case of error.
3838 xmlXPathNodeSetMerge(xmlNodeSetPtr val1
, xmlNodeSetPtr val2
) {
3839 int i
, j
, initNr
, skip
;
3842 if (val2
== NULL
) return(val1
);
3844 val1
= xmlXPathNodeSetCreate(NULL
);
3849 * TODO: The optimization won't work in every case, since
3850 * those nasty namespace nodes need to be added with
3851 * xmlXPathNodeSetDupNs() to the set; thus a pure
3852 * memcpy is not possible.
3853 * If there was a flag on the nodesetval, indicating that
3854 * some temporary nodes are in, that would be helpful.
3857 * Optimization: Create an equally sized node-set
3858 * and memcpy the content.
3860 val1
= xmlXPathNodeSetCreateSize(val2
->nodeNr
);
3863 if (val2
->nodeNr
!= 0) {
3864 if (val2
->nodeNr
== 1)
3865 *(val1
->nodeTab
) = *(val2
->nodeTab
);
3867 memcpy(val1
->nodeTab
, val2
->nodeTab
,
3868 val2
->nodeNr
* sizeof(xmlNodePtr
));
3870 val1
->nodeNr
= val2
->nodeNr
;
3876 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3877 initNr
= val1
->nodeNr
;
3879 for (i
= 0;i
< val2
->nodeNr
;i
++) {
3880 n2
= val2
->nodeTab
[i
];
3882 * check against duplicates
3885 for (j
= 0; j
< initNr
; j
++) {
3886 n1
= val1
->nodeTab
[j
];
3890 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3891 (n2
->type
== XML_NAMESPACE_DECL
)) {
3892 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3893 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3894 ((xmlNsPtr
) n2
)->prefix
)))
3905 * grow the nodeTab if needed
3907 if (val1
->nodeMax
== 0) {
3908 val1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3909 sizeof(xmlNodePtr
));
3910 if (val1
->nodeTab
== NULL
) {
3911 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3914 memset(val1
->nodeTab
, 0 ,
3915 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3916 val1
->nodeMax
= XML_NODESET_DEFAULT
;
3917 } else if (val1
->nodeNr
== val1
->nodeMax
) {
3920 if (val1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3921 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
3924 temp
= (xmlNodePtr
*) xmlRealloc(val1
->nodeTab
, val1
->nodeMax
* 2 *
3925 sizeof(xmlNodePtr
));
3927 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3930 val1
->nodeTab
= temp
;
3933 if (n2
->type
== XML_NAMESPACE_DECL
) {
3934 xmlNsPtr ns
= (xmlNsPtr
) n2
;
3936 /* TODO: Check memory error. */
3937 val1
->nodeTab
[val1
->nodeNr
++] =
3938 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3940 val1
->nodeTab
[val1
->nodeNr
++] = n2
;
3948 * xmlXPathNodeSetMergeAndClear:
3949 * @set1: the first NodeSet or NULL
3950 * @set2: the second NodeSet
3952 * Merges two nodesets, all nodes from @set2 are added to @set1.
3953 * Checks for duplicate nodes. Clears set2.
3955 * Returns @set1 once extended or NULL in case of error.
3957 static xmlNodeSetPtr
3958 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
)
3961 int i
, j
, initNbSet1
;
3964 initNbSet1
= set1
->nodeNr
;
3965 for (i
= 0;i
< set2
->nodeNr
;i
++) {
3966 n2
= set2
->nodeTab
[i
];
3970 for (j
= 0; j
< initNbSet1
; j
++) {
3971 n1
= set1
->nodeTab
[j
];
3974 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3975 (n2
->type
== XML_NAMESPACE_DECL
))
3977 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3978 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3979 ((xmlNsPtr
) n2
)->prefix
)))
3982 * Free the namespace node.
3984 set2
->nodeTab
[i
] = NULL
;
3985 xmlXPathNodeSetFreeNs((xmlNsPtr
) n2
);
3991 * grow the nodeTab if needed
3993 if (set1
->nodeMax
== 0) {
3994 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
3995 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3996 if (set1
->nodeTab
== NULL
) {
3997 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4000 memset(set1
->nodeTab
, 0,
4001 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4002 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4003 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4006 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4007 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4010 temp
= (xmlNodePtr
*) xmlRealloc(
4011 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4013 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4016 set1
->nodeTab
= temp
;
4019 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4029 * xmlXPathNodeSetMergeAndClearNoDupls:
4030 * @set1: the first NodeSet or NULL
4031 * @set2: the second NodeSet
4033 * Merges two nodesets, all nodes from @set2 are added to @set1.
4034 * Doesn't check for duplicate nodes. Clears set2.
4036 * Returns @set1 once extended or NULL in case of error.
4038 static xmlNodeSetPtr
4039 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
)
4045 for (i
= 0;i
< set2
->nodeNr
;i
++) {
4046 n2
= set2
->nodeTab
[i
];
4047 if (set1
->nodeMax
== 0) {
4048 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
4049 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4050 if (set1
->nodeTab
== NULL
) {
4051 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4054 memset(set1
->nodeTab
, 0,
4055 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4056 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4057 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4060 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4061 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4064 temp
= (xmlNodePtr
*) xmlRealloc(
4065 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4067 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4070 set1
->nodeTab
= temp
;
4073 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4081 * xmlXPathNodeSetDel:
4082 * @cur: the initial node set
4083 * @val: an xmlNodePtr
4085 * Removes an xmlNodePtr from an existing NodeSet
4088 xmlXPathNodeSetDel(xmlNodeSetPtr cur
, xmlNodePtr val
) {
4091 if (cur
== NULL
) return;
4092 if (val
== NULL
) return;
4095 * find node in nodeTab
4097 for (i
= 0;i
< cur
->nodeNr
;i
++)
4098 if (cur
->nodeTab
[i
] == val
) break;
4100 if (i
>= cur
->nodeNr
) { /* not found */
4102 xmlGenericError(xmlGenericErrorContext
,
4103 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4108 if ((cur
->nodeTab
[i
] != NULL
) &&
4109 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4110 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[i
]);
4112 for (;i
< cur
->nodeNr
;i
++)
4113 cur
->nodeTab
[i
] = cur
->nodeTab
[i
+ 1];
4114 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4118 * xmlXPathNodeSetRemove:
4119 * @cur: the initial node set
4120 * @val: the index to remove
4122 * Removes an entry from an existing NodeSet list.
4125 xmlXPathNodeSetRemove(xmlNodeSetPtr cur
, int val
) {
4126 if (cur
== NULL
) return;
4127 if (val
>= cur
->nodeNr
) return;
4128 if ((cur
->nodeTab
[val
] != NULL
) &&
4129 (cur
->nodeTab
[val
]->type
== XML_NAMESPACE_DECL
))
4130 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[val
]);
4132 for (;val
< cur
->nodeNr
;val
++)
4133 cur
->nodeTab
[val
] = cur
->nodeTab
[val
+ 1];
4134 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4138 * xmlXPathFreeNodeSet:
4139 * @obj: the xmlNodeSetPtr to free
4141 * Free the NodeSet compound (not the actual nodes !).
4144 xmlXPathFreeNodeSet(xmlNodeSetPtr obj
) {
4145 if (obj
== NULL
) return;
4146 if (obj
->nodeTab
!= NULL
) {
4149 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4150 for (i
= 0;i
< obj
->nodeNr
;i
++)
4151 if ((obj
->nodeTab
[i
] != NULL
) &&
4152 (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4153 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4154 xmlFree(obj
->nodeTab
);
4160 * xmlXPathNodeSetClearFromPos:
4161 * @set: the node set to be cleared
4162 * @pos: the start position to clear from
4164 * Clears the list from temporary XPath objects (e.g. namespace nodes
4165 * are feed) starting with the entry at @pos, but does *not* free the list
4166 * itself. Sets the length of the list to @pos.
4169 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set
, int pos
, int hasNsNodes
)
4171 if ((set
== NULL
) || (pos
>= set
->nodeNr
))
4173 else if ((hasNsNodes
)) {
4177 for (i
= pos
; i
< set
->nodeNr
; i
++) {
4178 node
= set
->nodeTab
[i
];
4179 if ((node
!= NULL
) &&
4180 (node
->type
== XML_NAMESPACE_DECL
))
4181 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4188 * xmlXPathNodeSetClear:
4189 * @set: the node set to clear
4191 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4192 * are feed), but does *not* free the list itself. Sets the length of the
4196 xmlXPathNodeSetClear(xmlNodeSetPtr set
, int hasNsNodes
)
4198 xmlXPathNodeSetClearFromPos(set
, 0, hasNsNodes
);
4202 * xmlXPathNodeSetKeepLast:
4203 * @set: the node set to be cleared
4205 * Move the last node to the first position and clear temporary XPath objects
4206 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4210 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set
)
4215 if ((set
== NULL
) || (set
->nodeNr
<= 1))
4217 for (i
= 0; i
< set
->nodeNr
- 1; i
++) {
4218 node
= set
->nodeTab
[i
];
4219 if ((node
!= NULL
) &&
4220 (node
->type
== XML_NAMESPACE_DECL
))
4221 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4223 set
->nodeTab
[0] = set
->nodeTab
[set
->nodeNr
-1];
4228 * xmlXPathFreeValueTree:
4229 * @obj: the xmlNodeSetPtr to free
4231 * Free the NodeSet compound and the actual tree, this is different
4232 * from xmlXPathFreeNodeSet()
4235 xmlXPathFreeValueTree(xmlNodeSetPtr obj
) {
4238 if (obj
== NULL
) return;
4240 if (obj
->nodeTab
!= NULL
) {
4241 for (i
= 0;i
< obj
->nodeNr
;i
++) {
4242 if (obj
->nodeTab
[i
] != NULL
) {
4243 if (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
4244 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4246 xmlFreeNodeList(obj
->nodeTab
[i
]);
4250 xmlFree(obj
->nodeTab
);
4255 #if defined(DEBUG) || defined(DEBUG_STEP)
4257 * xmlGenericErrorContextNodeSet:
4258 * @output: a FILE * for the output
4259 * @obj: the xmlNodeSetPtr to display
4261 * Quick display of a NodeSet
4264 xmlGenericErrorContextNodeSet(FILE *output
, xmlNodeSetPtr obj
) {
4267 if (output
== NULL
) output
= xmlGenericErrorContext
;
4269 fprintf(output
, "NodeSet == NULL !\n");
4272 if (obj
->nodeNr
== 0) {
4273 fprintf(output
, "NodeSet is empty\n");
4276 if (obj
->nodeTab
== NULL
) {
4277 fprintf(output
, " nodeTab == NULL !\n");
4280 for (i
= 0; i
< obj
->nodeNr
; i
++) {
4281 if (obj
->nodeTab
[i
] == NULL
) {
4282 fprintf(output
, " NULL !\n");
4285 if ((obj
->nodeTab
[i
]->type
== XML_DOCUMENT_NODE
) ||
4286 (obj
->nodeTab
[i
]->type
== XML_HTML_DOCUMENT_NODE
))
4287 fprintf(output
, " /");
4288 else if (obj
->nodeTab
[i
]->name
== NULL
)
4289 fprintf(output
, " noname!");
4290 else fprintf(output
, " %s", obj
->nodeTab
[i
]->name
);
4292 fprintf(output
, "\n");
4297 * xmlXPathNewNodeSet:
4298 * @val: the NodePtr value
4300 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4301 * it with the single Node @val
4303 * Returns the newly created object.
4306 xmlXPathNewNodeSet(xmlNodePtr val
) {
4307 xmlXPathObjectPtr ret
;
4309 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4311 xmlXPathErrMemory(NULL
, "creating nodeset\n");
4314 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4315 ret
->type
= XPATH_NODESET
;
4317 /* TODO: Check memory error. */
4318 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4319 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4320 #ifdef XP_DEBUG_OBJ_USAGE
4321 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4327 * xmlXPathNewValueTree:
4328 * @val: the NodePtr value
4330 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4331 * it with the tree root @val
4333 * Returns the newly created object.
4336 xmlXPathNewValueTree(xmlNodePtr val
) {
4337 xmlXPathObjectPtr ret
;
4339 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4341 xmlXPathErrMemory(NULL
, "creating result value tree\n");
4344 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4345 ret
->type
= XPATH_XSLT_TREE
;
4347 ret
->user
= (void *) val
;
4348 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4349 #ifdef XP_DEBUG_OBJ_USAGE
4350 xmlXPathDebugObjUsageRequested(NULL
, XPATH_XSLT_TREE
);
4356 * xmlXPathNewNodeSetList:
4357 * @val: an existing NodeSet
4359 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4360 * it with the Nodeset @val
4362 * Returns the newly created object.
4365 xmlXPathNewNodeSetList(xmlNodeSetPtr val
)
4367 xmlXPathObjectPtr ret
;
4372 else if (val
->nodeTab
== NULL
)
4373 ret
= xmlXPathNewNodeSet(NULL
);
4375 ret
= xmlXPathNewNodeSet(val
->nodeTab
[0]);
4377 for (i
= 1; i
< val
->nodeNr
; ++i
) {
4378 /* TODO: Propagate memory error. */
4379 if (xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
->nodeTab
[i
])
4389 * xmlXPathWrapNodeSet:
4390 * @val: the NodePtr value
4392 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4394 * Returns the newly created object.
4397 xmlXPathWrapNodeSet(xmlNodeSetPtr val
) {
4398 xmlXPathObjectPtr ret
;
4400 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4402 xmlXPathErrMemory(NULL
, "creating node set object\n");
4405 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4406 ret
->type
= XPATH_NODESET
;
4407 ret
->nodesetval
= val
;
4408 #ifdef XP_DEBUG_OBJ_USAGE
4409 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4415 * xmlXPathFreeNodeSetList:
4416 * @obj: an existing NodeSetList object
4418 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4419 * the list contrary to xmlXPathFreeObject().
4422 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj
) {
4423 if (obj
== NULL
) return;
4424 #ifdef XP_DEBUG_OBJ_USAGE
4425 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
4431 * xmlXPathDifference:
4432 * @nodes1: a node-set
4433 * @nodes2: a node-set
4435 * Implements the EXSLT - Sets difference() function:
4436 * node-set set:difference (node-set, node-set)
4438 * Returns the difference between the two node sets, or nodes1 if
4442 xmlXPathDifference (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4447 if (xmlXPathNodeSetIsEmpty(nodes2
))
4450 /* TODO: Check memory error. */
4451 ret
= xmlXPathNodeSetCreate(NULL
);
4452 if (xmlXPathNodeSetIsEmpty(nodes1
))
4455 l1
= xmlXPathNodeSetGetLength(nodes1
);
4457 for (i
= 0; i
< l1
; i
++) {
4458 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4459 if (!xmlXPathNodeSetContains(nodes2
, cur
)) {
4460 /* TODO: Propagate memory error. */
4461 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4469 * xmlXPathIntersection:
4470 * @nodes1: a node-set
4471 * @nodes2: a node-set
4473 * Implements the EXSLT - Sets intersection() function:
4474 * node-set set:intersection (node-set, node-set)
4476 * Returns a node set comprising the nodes that are within both the
4477 * node sets passed as arguments
4480 xmlXPathIntersection (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4481 xmlNodeSetPtr ret
= xmlXPathNodeSetCreate(NULL
);
4487 if (xmlXPathNodeSetIsEmpty(nodes1
))
4489 if (xmlXPathNodeSetIsEmpty(nodes2
))
4492 l1
= xmlXPathNodeSetGetLength(nodes1
);
4494 for (i
= 0; i
< l1
; i
++) {
4495 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4496 if (xmlXPathNodeSetContains(nodes2
, cur
)) {
4497 /* TODO: Propagate memory error. */
4498 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4506 * xmlXPathDistinctSorted:
4507 * @nodes: a node-set, sorted by document order
4509 * Implements the EXSLT - Sets distinct() function:
4510 * node-set set:distinct (node-set)
4512 * Returns a subset of the nodes contained in @nodes, or @nodes if
4516 xmlXPathDistinctSorted (xmlNodeSetPtr nodes
) {
4518 xmlHashTablePtr hash
;
4523 if (xmlXPathNodeSetIsEmpty(nodes
))
4526 ret
= xmlXPathNodeSetCreate(NULL
);
4529 l
= xmlXPathNodeSetGetLength(nodes
);
4530 hash
= xmlHashCreate (l
);
4531 for (i
= 0; i
< l
; i
++) {
4532 cur
= xmlXPathNodeSetItem(nodes
, i
);
4533 strval
= xmlXPathCastNodeToString(cur
);
4534 if (xmlHashLookup(hash
, strval
) == NULL
) {
4535 xmlHashAddEntry(hash
, strval
, strval
);
4536 /* TODO: Propagate memory error. */
4537 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4543 xmlHashFree(hash
, xmlHashDefaultDeallocator
);
4549 * @nodes: a node-set
4551 * Implements the EXSLT - Sets distinct() function:
4552 * node-set set:distinct (node-set)
4553 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4554 * is called with the sorted node-set
4556 * Returns a subset of the nodes contained in @nodes, or @nodes if
4560 xmlXPathDistinct (xmlNodeSetPtr nodes
) {
4561 if (xmlXPathNodeSetIsEmpty(nodes
))
4564 xmlXPathNodeSetSort(nodes
);
4565 return(xmlXPathDistinctSorted(nodes
));
4569 * xmlXPathHasSameNodes:
4570 * @nodes1: a node-set
4571 * @nodes2: a node-set
4573 * Implements the EXSLT - Sets has-same-nodes function:
4574 * boolean set:has-same-node(node-set, node-set)
4576 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4580 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4584 if (xmlXPathNodeSetIsEmpty(nodes1
) ||
4585 xmlXPathNodeSetIsEmpty(nodes2
))
4588 l
= xmlXPathNodeSetGetLength(nodes1
);
4589 for (i
= 0; i
< l
; i
++) {
4590 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4591 if (xmlXPathNodeSetContains(nodes2
, cur
))
4598 * xmlXPathNodeLeadingSorted:
4599 * @nodes: a node-set, sorted by document order
4602 * Implements the EXSLT - Sets leading() function:
4603 * node-set set:leading (node-set, node-set)
4605 * Returns the nodes in @nodes that precede @node in document order,
4606 * @nodes if @node is NULL or an empty node-set if @nodes
4607 * doesn't contain @node
4610 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4618 ret
= xmlXPathNodeSetCreate(NULL
);
4621 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4622 (!xmlXPathNodeSetContains(nodes
, node
)))
4625 l
= xmlXPathNodeSetGetLength(nodes
);
4626 for (i
= 0; i
< l
; i
++) {
4627 cur
= xmlXPathNodeSetItem(nodes
, i
);
4630 /* TODO: Propagate memory error. */
4631 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4638 * xmlXPathNodeLeading:
4639 * @nodes: a node-set
4642 * Implements the EXSLT - Sets leading() function:
4643 * node-set set:leading (node-set, node-set)
4644 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4647 * Returns the nodes in @nodes that precede @node in document order,
4648 * @nodes if @node is NULL or an empty node-set if @nodes
4649 * doesn't contain @node
4652 xmlXPathNodeLeading (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4653 xmlXPathNodeSetSort(nodes
);
4654 return(xmlXPathNodeLeadingSorted(nodes
, node
));
4658 * xmlXPathLeadingSorted:
4659 * @nodes1: a node-set, sorted by document order
4660 * @nodes2: a node-set, sorted by document order
4662 * Implements the EXSLT - Sets leading() function:
4663 * node-set set:leading (node-set, node-set)
4665 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4666 * in document order, @nodes1 if @nodes2 is NULL or empty or
4667 * an empty node-set if @nodes1 doesn't contain @nodes2
4670 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4671 if (xmlXPathNodeSetIsEmpty(nodes2
))
4673 return(xmlXPathNodeLeadingSorted(nodes1
,
4674 xmlXPathNodeSetItem(nodes2
, 1)));
4679 * @nodes1: a node-set
4680 * @nodes2: a node-set
4682 * Implements the EXSLT - Sets leading() function:
4683 * node-set set:leading (node-set, node-set)
4684 * @nodes1 and @nodes2 are sorted by document order, then
4685 * #exslSetsLeadingSorted is called.
4687 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4688 * in document order, @nodes1 if @nodes2 is NULL or empty or
4689 * an empty node-set if @nodes1 doesn't contain @nodes2
4692 xmlXPathLeading (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4693 if (xmlXPathNodeSetIsEmpty(nodes2
))
4695 if (xmlXPathNodeSetIsEmpty(nodes1
))
4696 return(xmlXPathNodeSetCreate(NULL
));
4697 xmlXPathNodeSetSort(nodes1
);
4698 xmlXPathNodeSetSort(nodes2
);
4699 return(xmlXPathNodeLeadingSorted(nodes1
,
4700 xmlXPathNodeSetItem(nodes2
, 1)));
4704 * xmlXPathNodeTrailingSorted:
4705 * @nodes: a node-set, sorted by document order
4708 * Implements the EXSLT - Sets trailing() function:
4709 * node-set set:trailing (node-set, node-set)
4711 * Returns the nodes in @nodes that follow @node in document order,
4712 * @nodes if @node is NULL or an empty node-set if @nodes
4713 * doesn't contain @node
4716 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4724 ret
= xmlXPathNodeSetCreate(NULL
);
4727 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4728 (!xmlXPathNodeSetContains(nodes
, node
)))
4731 l
= xmlXPathNodeSetGetLength(nodes
);
4732 for (i
= l
- 1; i
>= 0; i
--) {
4733 cur
= xmlXPathNodeSetItem(nodes
, i
);
4736 /* TODO: Propagate memory error. */
4737 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4740 xmlXPathNodeSetSort(ret
); /* bug 413451 */
4745 * xmlXPathNodeTrailing:
4746 * @nodes: a node-set
4749 * Implements the EXSLT - Sets trailing() function:
4750 * node-set set:trailing (node-set, node-set)
4751 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4754 * Returns the nodes in @nodes that follow @node in document order,
4755 * @nodes if @node is NULL or an empty node-set if @nodes
4756 * doesn't contain @node
4759 xmlXPathNodeTrailing (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4760 xmlXPathNodeSetSort(nodes
);
4761 return(xmlXPathNodeTrailingSorted(nodes
, node
));
4765 * xmlXPathTrailingSorted:
4766 * @nodes1: a node-set, sorted by document order
4767 * @nodes2: a node-set, sorted by document order
4769 * Implements the EXSLT - Sets trailing() function:
4770 * node-set set:trailing (node-set, node-set)
4772 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4773 * in document order, @nodes1 if @nodes2 is NULL or empty or
4774 * an empty node-set if @nodes1 doesn't contain @nodes2
4777 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4778 if (xmlXPathNodeSetIsEmpty(nodes2
))
4780 return(xmlXPathNodeTrailingSorted(nodes1
,
4781 xmlXPathNodeSetItem(nodes2
, 0)));
4786 * @nodes1: a node-set
4787 * @nodes2: a node-set
4789 * Implements the EXSLT - Sets trailing() function:
4790 * node-set set:trailing (node-set, node-set)
4791 * @nodes1 and @nodes2 are sorted by document order, then
4792 * #xmlXPathTrailingSorted is called.
4794 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4795 * in document order, @nodes1 if @nodes2 is NULL or empty or
4796 * an empty node-set if @nodes1 doesn't contain @nodes2
4799 xmlXPathTrailing (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4800 if (xmlXPathNodeSetIsEmpty(nodes2
))
4802 if (xmlXPathNodeSetIsEmpty(nodes1
))
4803 return(xmlXPathNodeSetCreate(NULL
));
4804 xmlXPathNodeSetSort(nodes1
);
4805 xmlXPathNodeSetSort(nodes2
);
4806 return(xmlXPathNodeTrailingSorted(nodes1
,
4807 xmlXPathNodeSetItem(nodes2
, 0)));
4810 /************************************************************************
4812 * Routines to handle extra functions *
4814 ************************************************************************/
4817 * xmlXPathRegisterFunc:
4818 * @ctxt: the XPath context
4819 * @name: the function name
4820 * @f: the function implementation or NULL
4822 * Register a new function. If @f is NULL it unregisters the function
4824 * Returns 0 in case of success, -1 in case of error
4827 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4828 xmlXPathFunction f
) {
4829 return(xmlXPathRegisterFuncNS(ctxt
, name
, NULL
, f
));
4833 * xmlXPathRegisterFuncNS:
4834 * @ctxt: the XPath context
4835 * @name: the function name
4836 * @ns_uri: the function namespace URI
4837 * @f: the function implementation or NULL
4839 * Register a new function. If @f is NULL it unregisters the function
4841 * Returns 0 in case of success, -1 in case of error
4844 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4845 const xmlChar
*ns_uri
, xmlXPathFunction f
) {
4851 if (ctxt
->funcHash
== NULL
)
4852 ctxt
->funcHash
= xmlHashCreate(0);
4853 if (ctxt
->funcHash
== NULL
)
4856 return(xmlHashRemoveEntry2(ctxt
->funcHash
, name
, ns_uri
, NULL
));
4857 XML_IGNORE_PEDANTIC_WARNINGS
4858 return(xmlHashAddEntry2(ctxt
->funcHash
, name
, ns_uri
, (void *) f
));
4863 * xmlXPathRegisterFuncLookup:
4864 * @ctxt: the XPath context
4865 * @f: the lookup function
4866 * @funcCtxt: the lookup data
4868 * Registers an external mechanism to do function lookup.
4871 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt
,
4872 xmlXPathFuncLookupFunc f
,
4876 ctxt
->funcLookupFunc
= f
;
4877 ctxt
->funcLookupData
= funcCtxt
;
4881 * xmlXPathFunctionLookup:
4882 * @ctxt: the XPath context
4883 * @name: the function name
4885 * Search in the Function array of the context for the given
4888 * Returns the xmlXPathFunction or NULL if not found
4891 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
4895 if (ctxt
->funcLookupFunc
!= NULL
) {
4896 xmlXPathFunction ret
;
4897 xmlXPathFuncLookupFunc f
;
4899 f
= ctxt
->funcLookupFunc
;
4900 ret
= f(ctxt
->funcLookupData
, name
, NULL
);
4904 return(xmlXPathFunctionLookupNS(ctxt
, name
, NULL
));
4908 * xmlXPathFunctionLookupNS:
4909 * @ctxt: the XPath context
4910 * @name: the function name
4911 * @ns_uri: the function namespace URI
4913 * Search in the Function array of the context for the given
4916 * Returns the xmlXPathFunction or NULL if not found
4919 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4920 const xmlChar
*ns_uri
) {
4921 xmlXPathFunction ret
;
4928 if (ctxt
->funcLookupFunc
!= NULL
) {
4929 xmlXPathFuncLookupFunc f
;
4931 f
= ctxt
->funcLookupFunc
;
4932 ret
= f(ctxt
->funcLookupData
, name
, ns_uri
);
4937 if (ctxt
->funcHash
== NULL
)
4940 XML_IGNORE_PEDANTIC_WARNINGS
4941 ret
= (xmlXPathFunction
) xmlHashLookup2(ctxt
->funcHash
, name
, ns_uri
);
4947 * xmlXPathRegisteredFuncsCleanup:
4948 * @ctxt: the XPath context
4950 * Cleanup the XPath context data associated to registered functions
4953 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt
) {
4957 xmlHashFree(ctxt
->funcHash
, NULL
);
4958 ctxt
->funcHash
= NULL
;
4961 /************************************************************************
4963 * Routines to handle Variables *
4965 ************************************************************************/
4968 * xmlXPathRegisterVariable:
4969 * @ctxt: the XPath context
4970 * @name: the variable name
4971 * @value: the variable value or NULL
4973 * Register a new variable value. If @value is NULL it unregisters
4976 * Returns 0 in case of success, -1 in case of error
4979 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4980 xmlXPathObjectPtr value
) {
4981 return(xmlXPathRegisterVariableNS(ctxt
, name
, NULL
, value
));
4985 * xmlXPathRegisterVariableNS:
4986 * @ctxt: the XPath context
4987 * @name: the variable name
4988 * @ns_uri: the variable namespace URI
4989 * @value: the variable value or NULL
4991 * Register a new variable value. If @value is NULL it unregisters
4994 * Returns 0 in case of success, -1 in case of error
4997 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4998 const xmlChar
*ns_uri
,
4999 xmlXPathObjectPtr value
) {
5005 if (ctxt
->varHash
== NULL
)
5006 ctxt
->varHash
= xmlHashCreate(0);
5007 if (ctxt
->varHash
== NULL
)
5010 return(xmlHashRemoveEntry2(ctxt
->varHash
, name
, ns_uri
,
5011 xmlXPathFreeObjectEntry
));
5012 return(xmlHashUpdateEntry2(ctxt
->varHash
, name
, ns_uri
,
5013 (void *) value
, xmlXPathFreeObjectEntry
));
5017 * xmlXPathRegisterVariableLookup:
5018 * @ctxt: the XPath context
5019 * @f: the lookup function
5020 * @data: the lookup data
5022 * register an external mechanism to do variable lookup
5025 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt
,
5026 xmlXPathVariableLookupFunc f
, void *data
) {
5029 ctxt
->varLookupFunc
= f
;
5030 ctxt
->varLookupData
= data
;
5034 * xmlXPathVariableLookup:
5035 * @ctxt: the XPath context
5036 * @name: the variable name
5038 * Search in the Variable array of the context for the given
5041 * Returns a copy of the value or NULL if not found
5044 xmlXPathVariableLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
5048 if (ctxt
->varLookupFunc
!= NULL
) {
5049 xmlXPathObjectPtr ret
;
5051 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5052 (ctxt
->varLookupData
, name
, NULL
);
5055 return(xmlXPathVariableLookupNS(ctxt
, name
, NULL
));
5059 * xmlXPathVariableLookupNS:
5060 * @ctxt: the XPath context
5061 * @name: the variable name
5062 * @ns_uri: the variable namespace URI
5064 * Search in the Variable array of the context for the given
5067 * Returns the a copy of the value or NULL if not found
5070 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5071 const xmlChar
*ns_uri
) {
5075 if (ctxt
->varLookupFunc
!= NULL
) {
5076 xmlXPathObjectPtr ret
;
5078 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5079 (ctxt
->varLookupData
, name
, ns_uri
);
5080 if (ret
!= NULL
) return(ret
);
5083 if (ctxt
->varHash
== NULL
)
5088 return(xmlXPathCacheObjectCopy(ctxt
, (xmlXPathObjectPtr
)
5089 xmlHashLookup2(ctxt
->varHash
, name
, ns_uri
)));
5093 * xmlXPathRegisteredVariablesCleanup:
5094 * @ctxt: the XPath context
5096 * Cleanup the XPath context data associated to registered variables
5099 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt
) {
5103 xmlHashFree(ctxt
->varHash
, xmlXPathFreeObjectEntry
);
5104 ctxt
->varHash
= NULL
;
5108 * xmlXPathRegisterNs:
5109 * @ctxt: the XPath context
5110 * @prefix: the namespace prefix cannot be NULL or empty string
5111 * @ns_uri: the namespace name
5113 * Register a new namespace. If @ns_uri is NULL it unregisters
5116 * Returns 0 in case of success, -1 in case of error
5119 xmlXPathRegisterNs(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
,
5120 const xmlChar
*ns_uri
) {
5128 if (ctxt
->nsHash
== NULL
)
5129 ctxt
->nsHash
= xmlHashCreate(10);
5130 if (ctxt
->nsHash
== NULL
)
5133 return(xmlHashRemoveEntry(ctxt
->nsHash
, prefix
,
5134 xmlHashDefaultDeallocator
));
5135 return(xmlHashUpdateEntry(ctxt
->nsHash
, prefix
, (void *) xmlStrdup(ns_uri
),
5136 xmlHashDefaultDeallocator
));
5141 * @ctxt: the XPath context
5142 * @prefix: the namespace prefix value
5144 * Search in the namespace declaration array of the context for the given
5145 * namespace name associated to the given prefix
5147 * Returns the value or NULL if not found
5150 xmlXPathNsLookup(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
) {
5156 #ifdef XML_XML_NAMESPACE
5157 if (xmlStrEqual(prefix
, (const xmlChar
*) "xml"))
5158 return(XML_XML_NAMESPACE
);
5161 if (ctxt
->namespaces
!= NULL
) {
5164 for (i
= 0;i
< ctxt
->nsNr
;i
++) {
5165 if ((ctxt
->namespaces
[i
] != NULL
) &&
5166 (xmlStrEqual(ctxt
->namespaces
[i
]->prefix
, prefix
)))
5167 return(ctxt
->namespaces
[i
]->href
);
5171 return((const xmlChar
*) xmlHashLookup(ctxt
->nsHash
, prefix
));
5175 * xmlXPathRegisteredNsCleanup:
5176 * @ctxt: the XPath context
5178 * Cleanup the XPath context data associated to registered variables
5181 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt
) {
5185 xmlHashFree(ctxt
->nsHash
, xmlHashDefaultDeallocator
);
5186 ctxt
->nsHash
= NULL
;
5189 /************************************************************************
5191 * Routines to handle Values *
5193 ************************************************************************/
5195 /* Allocations are terrible, one needs to optimize all this !!! */
5199 * @val: the double value
5201 * Create a new xmlXPathObjectPtr of type double and of value @val
5203 * Returns the newly created object.
5206 xmlXPathNewFloat(double val
) {
5207 xmlXPathObjectPtr ret
;
5209 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5211 xmlXPathErrMemory(NULL
, "creating float object\n");
5214 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5215 ret
->type
= XPATH_NUMBER
;
5216 ret
->floatval
= val
;
5217 #ifdef XP_DEBUG_OBJ_USAGE
5218 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NUMBER
);
5224 * xmlXPathNewBoolean:
5225 * @val: the boolean value
5227 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5229 * Returns the newly created object.
5232 xmlXPathNewBoolean(int val
) {
5233 xmlXPathObjectPtr ret
;
5235 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5237 xmlXPathErrMemory(NULL
, "creating boolean object\n");
5240 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5241 ret
->type
= XPATH_BOOLEAN
;
5242 ret
->boolval
= (val
!= 0);
5243 #ifdef XP_DEBUG_OBJ_USAGE
5244 xmlXPathDebugObjUsageRequested(NULL
, XPATH_BOOLEAN
);
5250 * xmlXPathNewString:
5251 * @val: the xmlChar * value
5253 * Create a new xmlXPathObjectPtr of type string and of value @val
5255 * Returns the newly created object.
5258 xmlXPathNewString(const xmlChar
*val
) {
5259 xmlXPathObjectPtr ret
;
5261 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5263 xmlXPathErrMemory(NULL
, "creating string object\n");
5266 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5267 ret
->type
= XPATH_STRING
;
5269 ret
->stringval
= xmlStrdup(val
);
5271 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
5272 #ifdef XP_DEBUG_OBJ_USAGE
5273 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5279 * xmlXPathWrapString:
5280 * @val: the xmlChar * value
5282 * Wraps the @val string into an XPath object.
5284 * Returns the newly created object.
5287 xmlXPathWrapString (xmlChar
*val
) {
5288 xmlXPathObjectPtr ret
;
5290 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5292 xmlXPathErrMemory(NULL
, "creating string object\n");
5295 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5296 ret
->type
= XPATH_STRING
;
5297 ret
->stringval
= val
;
5298 #ifdef XP_DEBUG_OBJ_USAGE
5299 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5305 * xmlXPathNewCString:
5306 * @val: the char * value
5308 * Create a new xmlXPathObjectPtr of type string and of value @val
5310 * Returns the newly created object.
5313 xmlXPathNewCString(const char *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
= xmlStrdup(BAD_CAST val
);
5324 #ifdef XP_DEBUG_OBJ_USAGE
5325 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5331 * xmlXPathWrapCString:
5332 * @val: the char * value
5334 * Wraps a string into an XPath object.
5336 * Returns the newly created object.
5339 xmlXPathWrapCString (char * val
) {
5340 return(xmlXPathWrapString((xmlChar
*)(val
)));
5344 * xmlXPathWrapExternal:
5345 * @val: the user data
5347 * Wraps the @val data into an XPath object.
5349 * Returns the newly created object.
5352 xmlXPathWrapExternal (void *val
) {
5353 xmlXPathObjectPtr ret
;
5355 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5357 xmlXPathErrMemory(NULL
, "creating user object\n");
5360 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5361 ret
->type
= XPATH_USERS
;
5363 #ifdef XP_DEBUG_OBJ_USAGE
5364 xmlXPathDebugObjUsageRequested(NULL
, XPATH_USERS
);
5370 * xmlXPathObjectCopy:
5371 * @val: the original object
5373 * allocate a new copy of a given object
5375 * Returns the newly created object.
5378 xmlXPathObjectCopy(xmlXPathObjectPtr val
) {
5379 xmlXPathObjectPtr ret
;
5384 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5386 xmlXPathErrMemory(NULL
, "copying object\n");
5389 memcpy(ret
, val
, (size_t) sizeof(xmlXPathObject
));
5390 #ifdef XP_DEBUG_OBJ_USAGE
5391 xmlXPathDebugObjUsageRequested(NULL
, val
->type
);
5393 switch (val
->type
) {
5396 #ifdef LIBXML_XPTR_LOCS_ENABLED
5399 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5402 ret
->stringval
= xmlStrdup(val
->stringval
);
5404 case XPATH_XSLT_TREE
:
5407 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5408 this previous handling is no longer correct, and can cause some serious
5409 problems (ref. bug 145547)
5411 if ((val
->nodesetval
!= NULL
) &&
5412 (val
->nodesetval
->nodeTab
!= NULL
)) {
5413 xmlNodePtr cur
, tmp
;
5417 top
= xmlNewDoc(NULL
);
5418 top
->name
= (char *)
5419 xmlStrdup(val
->nodesetval
->nodeTab
[0]->name
);
5423 cur
= val
->nodesetval
->nodeTab
[0]->children
;
5424 while (cur
!= NULL
) {
5425 tmp
= xmlDocCopyNode(cur
, top
, 1);
5426 xmlAddChild((xmlNodePtr
) top
, tmp
);
5431 ret
->nodesetval
= xmlXPathNodeSetCreate((xmlNodePtr
) top
);
5433 ret
->nodesetval
= xmlXPathNodeSetCreate(NULL
);
5434 /* Deallocate the copied tree value */
5438 /* TODO: Check memory error. */
5439 ret
->nodesetval
= xmlXPathNodeSetMerge(NULL
, val
->nodesetval
);
5440 /* Do not deallocate the copied tree value */
5443 #ifdef LIBXML_XPTR_LOCS_ENABLED
5444 case XPATH_LOCATIONSET
:
5446 xmlLocationSetPtr loc
= val
->user
;
5447 ret
->user
= (void *) xmlXPtrLocationSetMerge(NULL
, loc
);
5452 ret
->user
= val
->user
;
5454 case XPATH_UNDEFINED
:
5455 xmlGenericError(xmlGenericErrorContext
,
5456 "xmlXPathObjectCopy: unsupported type %d\n",
5464 * xmlXPathFreeObject:
5465 * @obj: the object to free
5467 * Free up an xmlXPathObjectPtr object.
5470 xmlXPathFreeObject(xmlXPathObjectPtr obj
) {
5471 if (obj
== NULL
) return;
5472 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
5475 if (obj
->user
!= NULL
) {
5476 xmlXPathFreeNodeSet(obj
->nodesetval
);
5477 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
5480 obj
->type
= XPATH_XSLT_TREE
; /* TODO: Just for debugging. */
5481 if (obj
->nodesetval
!= NULL
)
5482 xmlXPathFreeValueTree(obj
->nodesetval
);
5484 if (obj
->nodesetval
!= NULL
)
5485 xmlXPathFreeNodeSet(obj
->nodesetval
);
5487 #ifdef LIBXML_XPTR_LOCS_ENABLED
5488 } else if (obj
->type
== XPATH_LOCATIONSET
) {
5489 if (obj
->user
!= NULL
)
5490 xmlXPtrFreeLocationSet(obj
->user
);
5492 } else if (obj
->type
== XPATH_STRING
) {
5493 if (obj
->stringval
!= NULL
)
5494 xmlFree(obj
->stringval
);
5496 #ifdef XP_DEBUG_OBJ_USAGE
5497 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5503 xmlXPathFreeObjectEntry(void *obj
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
5504 xmlXPathFreeObject((xmlXPathObjectPtr
) obj
);
5508 * xmlXPathReleaseObject:
5509 * @obj: the xmlXPathObjectPtr to free or to cache
5511 * Depending on the state of the cache this frees the given
5512 * XPath object or stores it in the cache.
5515 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
)
5517 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5518 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5519 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5521 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5525 if ((ctxt
== NULL
) || (ctxt
->cache
== NULL
)) {
5526 xmlXPathFreeObject(obj
);
5528 xmlXPathContextCachePtr cache
=
5529 (xmlXPathContextCachePtr
) ctxt
->cache
;
5531 switch (obj
->type
) {
5533 case XPATH_XSLT_TREE
:
5534 if (obj
->nodesetval
!= NULL
) {
5537 * It looks like the @boolval is used for
5538 * evaluation if this an XSLT Result Tree Fragment.
5539 * TODO: Check if this assumption is correct.
5541 obj
->type
= XPATH_XSLT_TREE
; /* just for debugging */
5542 xmlXPathFreeValueTree(obj
->nodesetval
);
5543 obj
->nodesetval
= NULL
;
5544 } else if ((obj
->nodesetval
->nodeMax
<= 40) &&
5545 (XP_CACHE_WANTS(cache
->nodesetObjs
,
5546 cache
->maxNodeset
)))
5548 XP_CACHE_ADD(cache
->nodesetObjs
, obj
);
5551 xmlXPathFreeNodeSet(obj
->nodesetval
);
5552 obj
->nodesetval
= NULL
;
5557 if (obj
->stringval
!= NULL
)
5558 xmlFree(obj
->stringval
);
5560 if (XP_CACHE_WANTS(cache
->stringObjs
, cache
->maxString
)) {
5561 XP_CACHE_ADD(cache
->stringObjs
, obj
);
5566 if (XP_CACHE_WANTS(cache
->booleanObjs
, cache
->maxBoolean
)) {
5567 XP_CACHE_ADD(cache
->booleanObjs
, obj
);
5572 if (XP_CACHE_WANTS(cache
->numberObjs
, cache
->maxNumber
)) {
5573 XP_CACHE_ADD(cache
->numberObjs
, obj
);
5577 #ifdef LIBXML_XPTR_LOCS_ENABLED
5578 case XPATH_LOCATIONSET
:
5579 if (obj
->user
!= NULL
) {
5580 xmlXPtrFreeLocationSet(obj
->user
);
5589 * Fallback to adding to the misc-objects slot.
5591 if (XP_CACHE_WANTS(cache
->miscObjs
, cache
->maxMisc
)) {
5592 XP_CACHE_ADD(cache
->miscObjs
, obj
);
5598 #ifdef XP_DEBUG_OBJ_USAGE
5599 xmlXPathDebugObjUsageReleased(ctxt
, obj
->type
);
5602 if (obj
->nodesetval
!= NULL
) {
5603 xmlNodeSetPtr tmpset
= obj
->nodesetval
;
5606 * TODO: Due to those nasty ns-nodes, we need to traverse
5607 * the list and free the ns-nodes.
5608 * URGENT TODO: Check if it's actually slowing things down.
5609 * Maybe we shouldn't try to preserve the list.
5611 if (tmpset
->nodeNr
> 1) {
5615 for (i
= 0; i
< tmpset
->nodeNr
; i
++) {
5616 node
= tmpset
->nodeTab
[i
];
5617 if ((node
!= NULL
) &&
5618 (node
->type
== XML_NAMESPACE_DECL
))
5620 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
5623 } else if (tmpset
->nodeNr
== 1) {
5624 if ((tmpset
->nodeTab
[0] != NULL
) &&
5625 (tmpset
->nodeTab
[0]->type
== XML_NAMESPACE_DECL
))
5626 xmlXPathNodeSetFreeNs((xmlNsPtr
) tmpset
->nodeTab
[0]);
5629 memset(obj
, 0, sizeof(xmlXPathObject
));
5630 obj
->nodesetval
= tmpset
;
5632 memset(obj
, 0, sizeof(xmlXPathObject
));
5638 * Cache is full; free the object.
5640 if (obj
->nodesetval
!= NULL
)
5641 xmlXPathFreeNodeSet(obj
->nodesetval
);
5642 #ifdef XP_DEBUG_OBJ_USAGE
5643 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5651 /************************************************************************
5653 * Type Casting Routines *
5655 ************************************************************************/
5658 * xmlXPathCastBooleanToString:
5661 * Converts a boolean to its string value.
5663 * Returns a newly allocated string.
5666 xmlXPathCastBooleanToString (int val
) {
5669 ret
= xmlStrdup((const xmlChar
*) "true");
5671 ret
= xmlStrdup((const xmlChar
*) "false");
5676 * xmlXPathCastNumberToString:
5679 * Converts a number to its string value.
5681 * Returns a newly allocated string.
5684 xmlXPathCastNumberToString (double val
) {
5686 switch (xmlXPathIsInf(val
)) {
5688 ret
= xmlStrdup((const xmlChar
*) "Infinity");
5691 ret
= xmlStrdup((const xmlChar
*) "-Infinity");
5694 if (xmlXPathIsNaN(val
)) {
5695 ret
= xmlStrdup((const xmlChar
*) "NaN");
5696 } else if (val
== 0) {
5697 /* Omit sign for negative zero. */
5698 ret
= xmlStrdup((const xmlChar
*) "0");
5700 /* could be improved */
5702 xmlXPathFormatNumber(val
, buf
, 99);
5704 ret
= xmlStrdup((const xmlChar
*) buf
);
5711 * xmlXPathCastNodeToString:
5714 * Converts a node to its string value.
5716 * Returns a newly allocated string.
5719 xmlXPathCastNodeToString (xmlNodePtr node
) {
5721 if ((ret
= xmlNodeGetContent(node
)) == NULL
)
5722 ret
= xmlStrdup((const xmlChar
*) "");
5727 * xmlXPathCastNodeSetToString:
5730 * Converts a node-set to its string value.
5732 * Returns a newly allocated string.
5735 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns
) {
5736 if ((ns
== NULL
) || (ns
->nodeNr
== 0) || (ns
->nodeTab
== NULL
))
5737 return(xmlStrdup((const xmlChar
*) ""));
5740 xmlXPathNodeSetSort(ns
);
5741 return(xmlXPathCastNodeToString(ns
->nodeTab
[0]));
5745 * xmlXPathCastToString:
5746 * @val: an XPath object
5748 * Converts an existing object to its string() equivalent
5750 * Returns the allocated string value of the object, NULL in case of error.
5751 * It's up to the caller to free the string memory with xmlFree().
5754 xmlXPathCastToString(xmlXPathObjectPtr val
) {
5755 xmlChar
*ret
= NULL
;
5758 return(xmlStrdup((const xmlChar
*) ""));
5759 switch (val
->type
) {
5760 case XPATH_UNDEFINED
:
5762 xmlGenericError(xmlGenericErrorContext
, "String: undefined\n");
5764 ret
= xmlStrdup((const xmlChar
*) "");
5767 case XPATH_XSLT_TREE
:
5768 ret
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5771 return(xmlStrdup(val
->stringval
));
5773 ret
= xmlXPathCastBooleanToString(val
->boolval
);
5775 case XPATH_NUMBER
: {
5776 ret
= xmlXPathCastNumberToString(val
->floatval
);
5780 #ifdef LIBXML_XPTR_LOCS_ENABLED
5783 case XPATH_LOCATIONSET
:
5784 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5786 ret
= xmlStrdup((const xmlChar
*) "");
5793 * xmlXPathConvertString:
5794 * @val: an XPath object
5796 * Converts an existing object to its string() equivalent
5798 * Returns the new object, the old one is freed (or the operation
5799 * is done directly on @val)
5802 xmlXPathConvertString(xmlXPathObjectPtr val
) {
5803 xmlChar
*res
= NULL
;
5806 return(xmlXPathNewCString(""));
5808 switch (val
->type
) {
5809 case XPATH_UNDEFINED
:
5811 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
5815 case XPATH_XSLT_TREE
:
5816 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5821 res
= xmlXPathCastBooleanToString(val
->boolval
);
5824 res
= xmlXPathCastNumberToString(val
->floatval
);
5827 #ifdef LIBXML_XPTR_LOCS_ENABLED
5830 case XPATH_LOCATIONSET
:
5831 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5835 xmlXPathFreeObject(val
);
5837 return(xmlXPathNewCString(""));
5838 return(xmlXPathWrapString(res
));
5842 * xmlXPathCastBooleanToNumber:
5845 * Converts a boolean to its number value
5847 * Returns the number value
5850 xmlXPathCastBooleanToNumber(int val
) {
5857 * xmlXPathCastStringToNumber:
5860 * Converts a string to its number value
5862 * Returns the number value
5865 xmlXPathCastStringToNumber(const xmlChar
* val
) {
5866 return(xmlXPathStringEvalNumber(val
));
5870 * xmlXPathCastNodeToNumber:
5873 * Converts a node to its number value
5875 * Returns the number value
5878 xmlXPathCastNodeToNumber (xmlNodePtr node
) {
5883 return(xmlXPathNAN
);
5884 strval
= xmlXPathCastNodeToString(node
);
5886 return(xmlXPathNAN
);
5887 ret
= xmlXPathCastStringToNumber(strval
);
5894 * xmlXPathCastNodeSetToNumber:
5897 * Converts a node-set to its number value
5899 * Returns the number value
5902 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns
) {
5907 return(xmlXPathNAN
);
5908 str
= xmlXPathCastNodeSetToString(ns
);
5909 ret
= xmlXPathCastStringToNumber(str
);
5915 * xmlXPathCastToNumber:
5916 * @val: an XPath object
5918 * Converts an XPath object to its number value
5920 * Returns the number value
5923 xmlXPathCastToNumber(xmlXPathObjectPtr val
) {
5927 return(xmlXPathNAN
);
5928 switch (val
->type
) {
5929 case XPATH_UNDEFINED
:
5931 xmlGenericError(xmlGenericErrorContext
, "NUMBER: undefined\n");
5936 case XPATH_XSLT_TREE
:
5937 ret
= xmlXPathCastNodeSetToNumber(val
->nodesetval
);
5940 ret
= xmlXPathCastStringToNumber(val
->stringval
);
5943 ret
= val
->floatval
;
5946 ret
= xmlXPathCastBooleanToNumber(val
->boolval
);
5949 #ifdef LIBXML_XPTR_LOCS_ENABLED
5952 case XPATH_LOCATIONSET
:
5953 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5962 * xmlXPathConvertNumber:
5963 * @val: an XPath object
5965 * Converts an existing object to its number() equivalent
5967 * Returns the new object, the old one is freed (or the operation
5968 * is done directly on @val)
5971 xmlXPathConvertNumber(xmlXPathObjectPtr val
) {
5972 xmlXPathObjectPtr ret
;
5975 return(xmlXPathNewFloat(0.0));
5976 if (val
->type
== XPATH_NUMBER
)
5978 ret
= xmlXPathNewFloat(xmlXPathCastToNumber(val
));
5979 xmlXPathFreeObject(val
);
5984 * xmlXPathCastNumberToBoolean:
5987 * Converts a number to its boolean value
5989 * Returns the boolean value
5992 xmlXPathCastNumberToBoolean (double val
) {
5993 if (xmlXPathIsNaN(val
) || (val
== 0.0))
5999 * xmlXPathCastStringToBoolean:
6002 * Converts a string to its boolean value
6004 * Returns the boolean value
6007 xmlXPathCastStringToBoolean (const xmlChar
*val
) {
6008 if ((val
== NULL
) || (xmlStrlen(val
) == 0))
6014 * xmlXPathCastNodeSetToBoolean:
6017 * Converts a node-set to its boolean value
6019 * Returns the boolean value
6022 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns
) {
6023 if ((ns
== NULL
) || (ns
->nodeNr
== 0))
6029 * xmlXPathCastToBoolean:
6030 * @val: an XPath object
6032 * Converts an XPath object to its boolean value
6034 * Returns the boolean value
6037 xmlXPathCastToBoolean (xmlXPathObjectPtr val
) {
6042 switch (val
->type
) {
6043 case XPATH_UNDEFINED
:
6045 xmlGenericError(xmlGenericErrorContext
, "BOOLEAN: undefined\n");
6050 case XPATH_XSLT_TREE
:
6051 ret
= xmlXPathCastNodeSetToBoolean(val
->nodesetval
);
6054 ret
= xmlXPathCastStringToBoolean(val
->stringval
);
6057 ret
= xmlXPathCastNumberToBoolean(val
->floatval
);
6063 #ifdef LIBXML_XPTR_LOCS_ENABLED
6066 case XPATH_LOCATIONSET
:
6067 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6077 * xmlXPathConvertBoolean:
6078 * @val: an XPath object
6080 * Converts an existing object to its boolean() equivalent
6082 * Returns the new object, the old one is freed (or the operation
6083 * is done directly on @val)
6086 xmlXPathConvertBoolean(xmlXPathObjectPtr val
) {
6087 xmlXPathObjectPtr ret
;
6090 return(xmlXPathNewBoolean(0));
6091 if (val
->type
== XPATH_BOOLEAN
)
6093 ret
= xmlXPathNewBoolean(xmlXPathCastToBoolean(val
));
6094 xmlXPathFreeObject(val
);
6098 /************************************************************************
6100 * Routines to handle XPath contexts *
6102 ************************************************************************/
6105 * xmlXPathNewContext:
6106 * @doc: the XML document
6108 * Create a new xmlXPathContext
6110 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6113 xmlXPathNewContext(xmlDocPtr doc
) {
6114 xmlXPathContextPtr ret
;
6116 ret
= (xmlXPathContextPtr
) xmlMalloc(sizeof(xmlXPathContext
));
6118 xmlXPathErrMemory(NULL
, "creating context\n");
6121 memset(ret
, 0 , (size_t) sizeof(xmlXPathContext
));
6125 ret
->varHash
= NULL
;
6131 ret
->funcHash
= xmlHashCreate(0);
6140 ret
->contextSize
= -1;
6141 ret
->proximityPosition
= -1;
6143 #ifdef XP_DEFAULT_CACHE_ON
6144 if (xmlXPathContextSetCache(ret
, 1, -1, 0) == -1) {
6145 xmlXPathFreeContext(ret
);
6150 xmlXPathRegisterAllFunctions(ret
);
6156 * xmlXPathFreeContext:
6157 * @ctxt: the context to free
6159 * Free up an xmlXPathContext
6162 xmlXPathFreeContext(xmlXPathContextPtr ctxt
) {
6163 if (ctxt
== NULL
) return;
6165 if (ctxt
->cache
!= NULL
)
6166 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
6167 xmlXPathRegisteredNsCleanup(ctxt
);
6168 xmlXPathRegisteredFuncsCleanup(ctxt
);
6169 xmlXPathRegisteredVariablesCleanup(ctxt
);
6170 xmlResetError(&ctxt
->lastError
);
6174 /************************************************************************
6176 * Routines to handle XPath parser contexts *
6178 ************************************************************************/
6180 #define CHECK_CTXT(ctxt) \
6181 if (ctxt == NULL) { \
6182 __xmlRaiseError(NULL, NULL, NULL, \
6183 NULL, NULL, XML_FROM_XPATH, \
6184 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6185 __FILE__, __LINE__, \
6186 NULL, NULL, NULL, 0, 0, \
6187 "NULL context pointer\n"); \
6191 #define CHECK_CTXT_NEG(ctxt) \
6192 if (ctxt == NULL) { \
6193 __xmlRaiseError(NULL, NULL, NULL, \
6194 NULL, NULL, XML_FROM_XPATH, \
6195 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6196 __FILE__, __LINE__, \
6197 NULL, NULL, NULL, 0, 0, \
6198 "NULL context pointer\n"); \
6203 #define CHECK_CONTEXT(ctxt) \
6204 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6205 (ctxt->doc->children == NULL)) { \
6206 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6212 * xmlXPathNewParserContext:
6213 * @str: the XPath expression
6214 * @ctxt: the XPath context
6216 * Create a new xmlXPathParserContext
6218 * Returns the xmlXPathParserContext just allocated.
6220 xmlXPathParserContextPtr
6221 xmlXPathNewParserContext(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
6222 xmlXPathParserContextPtr ret
;
6224 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6226 xmlXPathErrMemory(ctxt
, "creating parser context\n");
6229 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6230 ret
->cur
= ret
->base
= str
;
6231 ret
->context
= ctxt
;
6233 ret
->comp
= xmlXPathNewCompExpr();
6234 if (ret
->comp
== NULL
) {
6235 xmlFree(ret
->valueTab
);
6239 if ((ctxt
!= NULL
) && (ctxt
->dict
!= NULL
)) {
6240 ret
->comp
->dict
= ctxt
->dict
;
6241 xmlDictReference(ret
->comp
->dict
);
6248 * xmlXPathCompParserContext:
6249 * @comp: the XPath compiled expression
6250 * @ctxt: the XPath context
6252 * Create a new xmlXPathParserContext when processing a compiled expression
6254 * Returns the xmlXPathParserContext just allocated.
6256 static xmlXPathParserContextPtr
6257 xmlXPathCompParserContext(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctxt
) {
6258 xmlXPathParserContextPtr ret
;
6260 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6262 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6265 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6267 /* Allocate the value stack */
6268 ret
->valueTab
= (xmlXPathObjectPtr
*)
6269 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
6270 if (ret
->valueTab
== NULL
) {
6272 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6278 ret
->valueFrame
= 0;
6280 ret
->context
= ctxt
;
6287 * xmlXPathFreeParserContext:
6288 * @ctxt: the context to free
6290 * Free up an xmlXPathParserContext
6293 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt
) {
6296 if (ctxt
->valueTab
!= NULL
) {
6297 for (i
= 0; i
< ctxt
->valueNr
; i
++) {
6299 xmlXPathReleaseObject(ctxt
->context
, ctxt
->valueTab
[i
]);
6301 xmlXPathFreeObject(ctxt
->valueTab
[i
]);
6303 xmlFree(ctxt
->valueTab
);
6305 if (ctxt
->comp
!= NULL
) {
6306 #ifdef XPATH_STREAMING
6307 if (ctxt
->comp
->stream
!= NULL
) {
6308 xmlFreePatternList(ctxt
->comp
->stream
);
6309 ctxt
->comp
->stream
= NULL
;
6312 xmlXPathFreeCompExpr(ctxt
->comp
);
6317 /************************************************************************
6319 * The implicit core function library *
6321 ************************************************************************/
6324 * xmlXPathNodeValHash:
6325 * @node: a node pointer
6327 * Function computing the beginning of the string value of the node,
6328 * used to speed up comparisons
6330 * Returns an int usable as a hash
6333 xmlXPathNodeValHash(xmlNodePtr node
) {
6335 const xmlChar
* string
= NULL
;
6336 xmlNodePtr tmp
= NULL
;
6337 unsigned int ret
= 0;
6342 if (node
->type
== XML_DOCUMENT_NODE
) {
6343 tmp
= xmlDocGetRootElement((xmlDocPtr
) node
);
6345 node
= node
->children
;
6353 switch (node
->type
) {
6354 case XML_COMMENT_NODE
:
6356 case XML_CDATA_SECTION_NODE
:
6358 string
= node
->content
;
6363 return(((unsigned int) string
[0]) +
6364 (((unsigned int) string
[1]) << 8));
6365 case XML_NAMESPACE_DECL
:
6366 string
= ((xmlNsPtr
)node
)->href
;
6371 return(((unsigned int) string
[0]) +
6372 (((unsigned int) string
[1]) << 8));
6373 case XML_ATTRIBUTE_NODE
:
6374 tmp
= ((xmlAttrPtr
) node
)->children
;
6376 case XML_ELEMENT_NODE
:
6377 tmp
= node
->children
;
6382 while (tmp
!= NULL
) {
6383 switch (tmp
->type
) {
6384 case XML_CDATA_SECTION_NODE
:
6386 string
= tmp
->content
;
6392 if ((string
!= NULL
) && (string
[0] != 0)) {
6394 return(ret
+ (((unsigned int) string
[0]) << 8));
6396 if (string
[1] == 0) {
6398 ret
= (unsigned int) string
[0];
6400 return(((unsigned int) string
[0]) +
6401 (((unsigned int) string
[1]) << 8));
6407 if ((tmp
->children
!= NULL
) && (tmp
->type
!= XML_DTD_NODE
)) {
6408 if (tmp
->children
->type
!= XML_ENTITY_DECL
) {
6409 tmp
= tmp
->children
;
6416 if (tmp
->next
!= NULL
) {
6429 if (tmp
->next
!= NULL
) {
6433 } while (tmp
!= NULL
);
6439 * xmlXPathStringHash:
6442 * Function computing the beginning of the string value of the node,
6443 * used to speed up comparisons
6445 * Returns an int usable as a hash
6448 xmlXPathStringHash(const xmlChar
* string
) {
6450 return((unsigned int) 0);
6453 return(((unsigned int) string
[0]) +
6454 (((unsigned int) string
[1]) << 8));
6458 * xmlXPathCompareNodeSetFloat:
6459 * @ctxt: the XPath Parser context
6460 * @inf: less than (1) or greater than (0)
6461 * @strict: is the comparison strict
6462 * @arg: the node set
6465 * Implement the compare operation between a nodeset and a number
6466 * @ns < @val (1, 1, ...
6467 * @ns <= @val (1, 0, ...
6468 * @ns > @val (0, 1, ...
6469 * @ns >= @val (0, 0, ...
6471 * If one object to be compared is a node-set and the other is a number,
6472 * then the comparison will be true if and only if there is a node in the
6473 * node-set such that the result of performing the comparison on the number
6474 * to be compared and on the result of converting the string-value of that
6475 * node to a number using the number function is true.
6477 * Returns 0 or 1 depending on the results of the test.
6480 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6481 xmlXPathObjectPtr arg
, xmlXPathObjectPtr f
) {
6486 if ((f
== NULL
) || (arg
== NULL
) ||
6487 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6488 xmlXPathReleaseObject(ctxt
->context
, arg
);
6489 xmlXPathReleaseObject(ctxt
->context
, f
);
6492 ns
= arg
->nodesetval
;
6494 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6495 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6498 xmlXPathCacheNewString(ctxt
->context
, str2
));
6500 xmlXPathNumberFunction(ctxt
, 1);
6501 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, f
));
6502 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6508 xmlXPathReleaseObject(ctxt
->context
, arg
);
6509 xmlXPathReleaseObject(ctxt
->context
, f
);
6514 * xmlXPathCompareNodeSetString:
6515 * @ctxt: the XPath Parser context
6516 * @inf: less than (1) or greater than (0)
6517 * @strict: is the comparison strict
6518 * @arg: the node set
6521 * Implement the compare operation between a nodeset and a string
6522 * @ns < @val (1, 1, ...
6523 * @ns <= @val (1, 0, ...
6524 * @ns > @val (0, 1, ...
6525 * @ns >= @val (0, 0, ...
6527 * If one object to be compared is a node-set and the other is a string,
6528 * then the comparison will be true if and only if there is a node in
6529 * the node-set such that the result of performing the comparison on the
6530 * string-value of the node and the other string is true.
6532 * Returns 0 or 1 depending on the results of the test.
6535 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6536 xmlXPathObjectPtr arg
, xmlXPathObjectPtr s
) {
6541 if ((s
== NULL
) || (arg
== NULL
) ||
6542 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6543 xmlXPathReleaseObject(ctxt
->context
, arg
);
6544 xmlXPathReleaseObject(ctxt
->context
, s
);
6547 ns
= arg
->nodesetval
;
6549 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6550 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6553 xmlXPathCacheNewString(ctxt
->context
, str2
));
6555 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, s
));
6556 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6562 xmlXPathReleaseObject(ctxt
->context
, arg
);
6563 xmlXPathReleaseObject(ctxt
->context
, s
);
6568 * xmlXPathCompareNodeSets:
6569 * @inf: less than (1) or greater than (0)
6570 * @strict: is the comparison strict
6571 * @arg1: the first node set object
6572 * @arg2: the second node set object
6574 * Implement the compare operation on nodesets:
6576 * If both objects to be compared are node-sets, then the comparison
6577 * will be true if and only if there is a node in the first node-set
6578 * and a node in the second node-set such that the result of performing
6579 * the comparison on the string-values of the two nodes is true.
6581 * When neither object to be compared is a node-set and the operator
6582 * is <=, <, >= or >, then the objects are compared by converting both
6583 * objects to numbers and comparing the numbers according to IEEE 754.
6585 * The number function converts its argument to a number as follows:
6586 * - a string that consists of optional whitespace followed by an
6587 * optional minus sign followed by a Number followed by whitespace
6588 * is converted to the IEEE 754 number that is nearest (according
6589 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6590 * represented by the string; any other string is converted to NaN
6592 * Conclusion all nodes need to be converted first to their string value
6593 * and then the comparison must be done when possible
6596 xmlXPathCompareNodeSets(int inf
, int strict
,
6597 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6605 if ((arg1
== NULL
) ||
6606 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
))) {
6607 xmlXPathFreeObject(arg2
);
6610 if ((arg2
== NULL
) ||
6611 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
))) {
6612 xmlXPathFreeObject(arg1
);
6613 xmlXPathFreeObject(arg2
);
6617 ns1
= arg1
->nodesetval
;
6618 ns2
= arg2
->nodesetval
;
6620 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0)) {
6621 xmlXPathFreeObject(arg1
);
6622 xmlXPathFreeObject(arg2
);
6625 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0)) {
6626 xmlXPathFreeObject(arg1
);
6627 xmlXPathFreeObject(arg2
);
6631 values2
= (double *) xmlMalloc(ns2
->nodeNr
* sizeof(double));
6632 if (values2
== NULL
) {
6633 /* TODO: Propagate memory error. */
6634 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6635 xmlXPathFreeObject(arg1
);
6636 xmlXPathFreeObject(arg2
);
6639 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6640 val1
= xmlXPathCastNodeToNumber(ns1
->nodeTab
[i
]);
6641 if (xmlXPathIsNaN(val1
))
6643 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6645 values2
[j
] = xmlXPathCastNodeToNumber(ns2
->nodeTab
[j
]);
6647 if (xmlXPathIsNaN(values2
[j
]))
6650 ret
= (val1
< values2
[j
]);
6651 else if (inf
&& !strict
)
6652 ret
= (val1
<= values2
[j
]);
6653 else if (!inf
&& strict
)
6654 ret
= (val1
> values2
[j
]);
6655 else if (!inf
&& !strict
)
6656 ret
= (val1
>= values2
[j
]);
6665 xmlXPathFreeObject(arg1
);
6666 xmlXPathFreeObject(arg2
);
6671 * xmlXPathCompareNodeSetValue:
6672 * @ctxt: the XPath Parser context
6673 * @inf: less than (1) or greater than (0)
6674 * @strict: is the comparison strict
6675 * @arg: the node set
6678 * Implement the compare operation between a nodeset and a value
6679 * @ns < @val (1, 1, ...
6680 * @ns <= @val (1, 0, ...
6681 * @ns > @val (0, 1, ...
6682 * @ns >= @val (0, 0, ...
6684 * If one object to be compared is a node-set and the other is a boolean,
6685 * then the comparison will be true if and only if the result of performing
6686 * the comparison on the boolean and on the result of converting
6687 * the node-set to a boolean using the boolean function is true.
6689 * Returns 0 or 1 depending on the results of the test.
6692 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6693 xmlXPathObjectPtr arg
, xmlXPathObjectPtr val
) {
6694 if ((val
== NULL
) || (arg
== NULL
) ||
6695 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6700 return(xmlXPathCompareNodeSetFloat(ctxt
, inf
, strict
, arg
, val
));
6702 case XPATH_XSLT_TREE
:
6703 return(xmlXPathCompareNodeSets(inf
, strict
, arg
, val
));
6705 return(xmlXPathCompareNodeSetString(ctxt
, inf
, strict
, arg
, val
));
6707 valuePush(ctxt
, arg
);
6708 xmlXPathBooleanFunction(ctxt
, 1);
6709 valuePush(ctxt
, val
);
6710 return(xmlXPathCompareValues(ctxt
, inf
, strict
));
6712 xmlGenericError(xmlGenericErrorContext
,
6713 "xmlXPathCompareNodeSetValue: Can't compare node set "
6714 "and object of type %d\n",
6716 xmlXPathReleaseObject(ctxt
->context
, arg
);
6717 xmlXPathReleaseObject(ctxt
->context
, val
);
6718 XP_ERROR0(XPATH_INVALID_TYPE
);
6724 * xmlXPathEqualNodeSetString:
6725 * @arg: the nodeset object argument
6726 * @str: the string to compare to.
6727 * @neq: flag to show whether for '=' (0) or '!=' (1)
6729 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6730 * If one object to be compared is a node-set and the other is a string,
6731 * then the comparison will be true if and only if there is a node in
6732 * the node-set such that the result of performing the comparison on the
6733 * string-value of the node and the other string is true.
6735 * Returns 0 or 1 depending on the results of the test.
6738 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg
, const xmlChar
* str
, int neq
)
6745 if ((str
== NULL
) || (arg
== NULL
) ||
6746 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6748 ns
= arg
->nodesetval
;
6750 * A NULL nodeset compared with a string is always false
6751 * (since there is no node equal, and no node not equal)
6753 if ((ns
== NULL
) || (ns
->nodeNr
<= 0) )
6755 hash
= xmlXPathStringHash(str
);
6756 for (i
= 0; i
< ns
->nodeNr
; i
++) {
6757 if (xmlXPathNodeValHash(ns
->nodeTab
[i
]) == hash
) {
6758 str2
= xmlNodeGetContent(ns
->nodeTab
[i
]);
6759 if ((str2
!= NULL
) && (xmlStrEqual(str
, str2
))) {
6764 } else if ((str2
== NULL
) && (xmlStrEqual(str
, BAD_CAST
""))) {
6782 * xmlXPathEqualNodeSetFloat:
6783 * @arg: the nodeset object argument
6784 * @f: the float to compare to
6785 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6787 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6788 * If one object to be compared is a node-set and the other is a number,
6789 * then the comparison will be true if and only if there is a node in
6790 * the node-set such that the result of performing the comparison on the
6791 * number to be compared and on the result of converting the string-value
6792 * of that node to a number using the number function is true.
6794 * Returns 0 or 1 depending on the results of the test.
6797 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt
,
6798 xmlXPathObjectPtr arg
, double f
, int neq
) {
6802 xmlXPathObjectPtr val
;
6805 if ((arg
== NULL
) ||
6806 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6809 ns
= arg
->nodesetval
;
6811 for (i
=0;i
<ns
->nodeNr
;i
++) {
6812 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6814 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, str2
));
6816 xmlXPathNumberFunction(ctxt
, 1);
6817 val
= valuePop(ctxt
);
6819 xmlXPathReleaseObject(ctxt
->context
, val
);
6820 if (!xmlXPathIsNaN(v
)) {
6821 if ((!neq
) && (v
==f
)) {
6824 } else if ((neq
) && (v
!=f
)) {
6828 } else { /* NaN is unequal to any value */
6841 * xmlXPathEqualNodeSets:
6842 * @arg1: first nodeset object argument
6843 * @arg2: second nodeset object argument
6844 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6846 * Implement the equal / not equal operation on XPath nodesets:
6847 * @arg1 == @arg2 or @arg1 != @arg2
6848 * If both objects to be compared are node-sets, then the comparison
6849 * will be true if and only if there is a node in the first node-set and
6850 * a node in the second node-set such that the result of performing the
6851 * comparison on the string-values of the two nodes is true.
6853 * (needless to say, this is a costly operation)
6855 * Returns 0 or 1 depending on the results of the test.
6858 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
, int neq
) {
6860 unsigned int *hashs1
;
6861 unsigned int *hashs2
;
6868 if ((arg1
== NULL
) ||
6869 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)))
6871 if ((arg2
== NULL
) ||
6872 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
)))
6875 ns1
= arg1
->nodesetval
;
6876 ns2
= arg2
->nodesetval
;
6878 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0))
6880 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0))
6884 * for equal, check if there is a node pertaining to both sets
6887 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6888 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6889 if (ns1
->nodeTab
[i
] == ns2
->nodeTab
[j
])
6892 values1
= (xmlChar
**) xmlMalloc(ns1
->nodeNr
* sizeof(xmlChar
*));
6893 if (values1
== NULL
) {
6894 /* TODO: Propagate memory error. */
6895 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6898 hashs1
= (unsigned int *) xmlMalloc(ns1
->nodeNr
* sizeof(unsigned int));
6899 if (hashs1
== NULL
) {
6900 /* TODO: Propagate memory error. */
6901 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6905 memset(values1
, 0, ns1
->nodeNr
* sizeof(xmlChar
*));
6906 values2
= (xmlChar
**) xmlMalloc(ns2
->nodeNr
* sizeof(xmlChar
*));
6907 if (values2
== NULL
) {
6908 /* TODO: Propagate memory error. */
6909 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6914 hashs2
= (unsigned int *) xmlMalloc(ns2
->nodeNr
* sizeof(unsigned int));
6915 if (hashs2
== NULL
) {
6916 /* TODO: Propagate memory error. */
6917 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6923 memset(values2
, 0, ns2
->nodeNr
* sizeof(xmlChar
*));
6924 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6925 hashs1
[i
] = xmlXPathNodeValHash(ns1
->nodeTab
[i
]);
6926 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6928 hashs2
[j
] = xmlXPathNodeValHash(ns2
->nodeTab
[j
]);
6929 if (hashs1
[i
] != hashs2
[j
]) {
6936 if (values1
[i
] == NULL
)
6937 values1
[i
] = xmlNodeGetContent(ns1
->nodeTab
[i
]);
6938 if (values2
[j
] == NULL
)
6939 values2
[j
] = xmlNodeGetContent(ns2
->nodeTab
[j
]);
6940 ret
= xmlStrEqual(values1
[i
], values2
[j
]) ^ neq
;
6948 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6949 if (values1
[i
] != NULL
)
6950 xmlFree(values1
[i
]);
6951 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6952 if (values2
[j
] != NULL
)
6953 xmlFree(values2
[j
]);
6962 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt
,
6963 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6966 *At this point we are assured neither arg1 nor arg2
6967 *is a nodeset, so we can just pick the appropriate routine.
6969 switch (arg1
->type
) {
6970 case XPATH_UNDEFINED
:
6972 xmlGenericError(xmlGenericErrorContext
,
6973 "Equal: undefined\n");
6977 switch (arg2
->type
) {
6978 case XPATH_UNDEFINED
:
6980 xmlGenericError(xmlGenericErrorContext
,
6981 "Equal: undefined\n");
6986 xmlGenericError(xmlGenericErrorContext
,
6987 "Equal: %d boolean %d \n",
6988 arg1
->boolval
, arg2
->boolval
);
6990 ret
= (arg1
->boolval
== arg2
->boolval
);
6993 ret
= (arg1
->boolval
==
6994 xmlXPathCastNumberToBoolean(arg2
->floatval
));
6997 if ((arg2
->stringval
== NULL
) ||
6998 (arg2
->stringval
[0] == 0)) ret
= 0;
7001 ret
= (arg1
->boolval
== ret
);
7004 #ifdef LIBXML_XPTR_LOCS_ENABLED
7007 case XPATH_LOCATIONSET
:
7008 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7012 case XPATH_XSLT_TREE
:
7017 switch (arg2
->type
) {
7018 case XPATH_UNDEFINED
:
7020 xmlGenericError(xmlGenericErrorContext
,
7021 "Equal: undefined\n");
7025 ret
= (arg2
->boolval
==
7026 xmlXPathCastNumberToBoolean(arg1
->floatval
));
7029 valuePush(ctxt
, arg2
);
7030 xmlXPathNumberFunction(ctxt
, 1);
7031 arg2
= valuePop(ctxt
);
7032 /* Falls through. */
7034 /* Hand check NaN and Infinity equalities */
7035 if (xmlXPathIsNaN(arg1
->floatval
) ||
7036 xmlXPathIsNaN(arg2
->floatval
)) {
7038 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7039 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7043 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7044 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7048 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7049 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7053 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7054 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7059 ret
= (arg1
->floatval
== arg2
->floatval
);
7063 #ifdef LIBXML_XPTR_LOCS_ENABLED
7066 case XPATH_LOCATIONSET
:
7067 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7071 case XPATH_XSLT_TREE
:
7076 switch (arg2
->type
) {
7077 case XPATH_UNDEFINED
:
7079 xmlGenericError(xmlGenericErrorContext
,
7080 "Equal: undefined\n");
7084 if ((arg1
->stringval
== NULL
) ||
7085 (arg1
->stringval
[0] == 0)) ret
= 0;
7088 ret
= (arg2
->boolval
== ret
);
7091 ret
= xmlStrEqual(arg1
->stringval
, arg2
->stringval
);
7094 valuePush(ctxt
, arg1
);
7095 xmlXPathNumberFunction(ctxt
, 1);
7096 arg1
= valuePop(ctxt
);
7097 /* Hand check NaN and Infinity equalities */
7098 if (xmlXPathIsNaN(arg1
->floatval
) ||
7099 xmlXPathIsNaN(arg2
->floatval
)) {
7101 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7102 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7106 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7107 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7111 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7112 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7116 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7117 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7122 ret
= (arg1
->floatval
== arg2
->floatval
);
7126 #ifdef LIBXML_XPTR_LOCS_ENABLED
7129 case XPATH_LOCATIONSET
:
7130 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7134 case XPATH_XSLT_TREE
:
7139 #ifdef LIBXML_XPTR_LOCS_ENABLED
7142 case XPATH_LOCATIONSET
:
7143 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7147 case XPATH_XSLT_TREE
:
7150 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7151 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7156 * xmlXPathEqualValues:
7157 * @ctxt: the XPath Parser context
7159 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7161 * Returns 0 or 1 depending on the results of the test.
7164 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt
) {
7165 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7168 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7169 arg2
= valuePop(ctxt
);
7170 arg1
= valuePop(ctxt
);
7171 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7173 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7175 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7176 XP_ERROR0(XPATH_INVALID_OPERAND
);
7181 xmlGenericError(xmlGenericErrorContext
,
7182 "Equal: by pointer\n");
7184 xmlXPathFreeObject(arg1
);
7189 *If either argument is a nodeset, it's a 'special case'
7191 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7192 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7194 *Hack it to assure arg1 is the nodeset
7196 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7201 switch (arg2
->type
) {
7202 case XPATH_UNDEFINED
:
7204 xmlGenericError(xmlGenericErrorContext
,
7205 "Equal: undefined\n");
7209 case XPATH_XSLT_TREE
:
7210 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 0);
7213 if ((arg1
->nodesetval
== NULL
) ||
7214 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7217 ret
= (ret
== arg2
->boolval
);
7220 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 0);
7223 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
, 0);
7226 #ifdef LIBXML_XPTR_LOCS_ENABLED
7229 case XPATH_LOCATIONSET
:
7230 #endif /* LIBXML_XPTR_LOCS_ENABLED */
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);
7313 #ifdef LIBXML_XPTR_LOCS_ENABLED
7316 case XPATH_LOCATIONSET
:
7317 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7321 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7322 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7326 return (!xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7330 * xmlXPathCompareValues:
7331 * @ctxt: the XPath Parser context
7332 * @inf: less than (1) or greater than (0)
7333 * @strict: is the comparison strict
7335 * Implement the compare operation on XPath objects:
7336 * @arg1 < @arg2 (1, 1, ...
7337 * @arg1 <= @arg2 (1, 0, ...
7338 * @arg1 > @arg2 (0, 1, ...
7339 * @arg1 >= @arg2 (0, 0, ...
7341 * When neither object to be compared is a node-set and the operator is
7342 * <=, <, >=, >, then the objects are compared by converted both objects
7343 * to numbers and comparing the numbers according to IEEE 754. The <
7344 * comparison will be true if and only if the first number is less than the
7345 * second number. The <= comparison will be true if and only if the first
7346 * number is less than or equal to the second number. The > comparison
7347 * will be true if and only if the first number is greater than the second
7348 * number. The >= comparison will be true if and only if the first number
7349 * is greater than or equal to the second number.
7351 * Returns 1 if the comparison succeeded, 0 if it failed
7354 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt
, int inf
, int strict
) {
7355 int ret
= 0, arg1i
= 0, arg2i
= 0;
7356 xmlXPathObjectPtr arg1
, arg2
;
7358 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7359 arg2
= valuePop(ctxt
);
7360 arg1
= valuePop(ctxt
);
7361 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7363 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7365 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7366 XP_ERROR0(XPATH_INVALID_OPERAND
);
7369 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7370 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7372 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7373 * are not freed from within this routine; they will be freed from the
7374 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7376 if (((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
)) &&
7377 ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
))){
7378 ret
= xmlXPathCompareNodeSets(inf
, strict
, arg1
, arg2
);
7380 if ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7381 ret
= xmlXPathCompareNodeSetValue(ctxt
, inf
, strict
,
7384 ret
= xmlXPathCompareNodeSetValue(ctxt
, !inf
, strict
,
7391 if (arg1
->type
!= XPATH_NUMBER
) {
7392 valuePush(ctxt
, arg1
);
7393 xmlXPathNumberFunction(ctxt
, 1);
7394 arg1
= valuePop(ctxt
);
7396 if (arg1
->type
!= XPATH_NUMBER
) {
7397 xmlXPathFreeObject(arg1
);
7398 xmlXPathFreeObject(arg2
);
7399 XP_ERROR0(XPATH_INVALID_OPERAND
);
7401 if (arg2
->type
!= XPATH_NUMBER
) {
7402 valuePush(ctxt
, arg2
);
7403 xmlXPathNumberFunction(ctxt
, 1);
7404 arg2
= valuePop(ctxt
);
7406 if (arg2
->type
!= XPATH_NUMBER
) {
7407 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7408 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7409 XP_ERROR0(XPATH_INVALID_OPERAND
);
7412 * Add tests for infinity and nan
7413 * => feedback on 3.4 for Inf and NaN
7415 /* Hand check NaN and Infinity comparisons */
7416 if (xmlXPathIsNaN(arg1
->floatval
) || xmlXPathIsNaN(arg2
->floatval
)) {
7419 arg1i
=xmlXPathIsInf(arg1
->floatval
);
7420 arg2i
=xmlXPathIsInf(arg2
->floatval
);
7421 if (inf
&& strict
) {
7422 if ((arg1i
== -1 && arg2i
!= -1) ||
7423 (arg2i
== 1 && arg1i
!= 1)) {
7425 } else if (arg1i
== 0 && arg2i
== 0) {
7426 ret
= (arg1
->floatval
< arg2
->floatval
);
7431 else if (inf
&& !strict
) {
7432 if (arg1i
== -1 || arg2i
== 1) {
7434 } else if (arg1i
== 0 && arg2i
== 0) {
7435 ret
= (arg1
->floatval
<= arg2
->floatval
);
7440 else if (!inf
&& strict
) {
7441 if ((arg1i
== 1 && arg2i
!= 1) ||
7442 (arg2i
== -1 && arg1i
!= -1)) {
7444 } else if (arg1i
== 0 && arg2i
== 0) {
7445 ret
= (arg1
->floatval
> arg2
->floatval
);
7450 else if (!inf
&& !strict
) {
7451 if (arg1i
== 1 || arg2i
== -1) {
7453 } else if (arg1i
== 0 && arg2i
== 0) {
7454 ret
= (arg1
->floatval
>= arg2
->floatval
);
7460 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7461 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7466 * xmlXPathValueFlipSign:
7467 * @ctxt: the XPath Parser context
7469 * Implement the unary - operation on an XPath object
7470 * The numeric operators convert their operands to numbers as if
7471 * by calling the number function.
7474 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt
) {
7475 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return;
7477 CHECK_TYPE(XPATH_NUMBER
);
7478 ctxt
->value
->floatval
= -ctxt
->value
->floatval
;
7482 * xmlXPathAddValues:
7483 * @ctxt: the XPath Parser context
7485 * Implement the add operation on XPath objects:
7486 * The numeric operators convert their operands to numbers as if
7487 * by calling the number function.
7490 xmlXPathAddValues(xmlXPathParserContextPtr ctxt
) {
7491 xmlXPathObjectPtr arg
;
7494 arg
= valuePop(ctxt
);
7496 XP_ERROR(XPATH_INVALID_OPERAND
);
7497 val
= xmlXPathCastToNumber(arg
);
7498 xmlXPathReleaseObject(ctxt
->context
, arg
);
7500 CHECK_TYPE(XPATH_NUMBER
);
7501 ctxt
->value
->floatval
+= val
;
7505 * xmlXPathSubValues:
7506 * @ctxt: the XPath Parser context
7508 * Implement the subtraction operation on XPath objects:
7509 * The numeric operators convert their operands to numbers as if
7510 * by calling the number function.
7513 xmlXPathSubValues(xmlXPathParserContextPtr ctxt
) {
7514 xmlXPathObjectPtr arg
;
7517 arg
= valuePop(ctxt
);
7519 XP_ERROR(XPATH_INVALID_OPERAND
);
7520 val
= xmlXPathCastToNumber(arg
);
7521 xmlXPathReleaseObject(ctxt
->context
, arg
);
7523 CHECK_TYPE(XPATH_NUMBER
);
7524 ctxt
->value
->floatval
-= val
;
7528 * xmlXPathMultValues:
7529 * @ctxt: the XPath Parser context
7531 * Implement the multiply operation on XPath objects:
7532 * The numeric operators convert their operands to numbers as if
7533 * by calling the number function.
7536 xmlXPathMultValues(xmlXPathParserContextPtr ctxt
) {
7537 xmlXPathObjectPtr arg
;
7540 arg
= valuePop(ctxt
);
7542 XP_ERROR(XPATH_INVALID_OPERAND
);
7543 val
= xmlXPathCastToNumber(arg
);
7544 xmlXPathReleaseObject(ctxt
->context
, arg
);
7546 CHECK_TYPE(XPATH_NUMBER
);
7547 ctxt
->value
->floatval
*= val
;
7551 * xmlXPathDivValues:
7552 * @ctxt: the XPath Parser context
7554 * Implement the div operation on XPath objects @arg1 / @arg2:
7555 * The numeric operators convert their operands to numbers as if
7556 * by calling the number function.
7558 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7560 xmlXPathDivValues(xmlXPathParserContextPtr ctxt
) {
7561 xmlXPathObjectPtr arg
;
7564 arg
= valuePop(ctxt
);
7566 XP_ERROR(XPATH_INVALID_OPERAND
);
7567 val
= xmlXPathCastToNumber(arg
);
7568 xmlXPathReleaseObject(ctxt
->context
, arg
);
7570 CHECK_TYPE(XPATH_NUMBER
);
7571 ctxt
->value
->floatval
/= val
;
7575 * xmlXPathModValues:
7576 * @ctxt: the XPath Parser context
7578 * Implement the mod operation on XPath objects: @arg1 / @arg2
7579 * The numeric operators convert their operands to numbers as if
7580 * by calling the number function.
7583 xmlXPathModValues(xmlXPathParserContextPtr ctxt
) {
7584 xmlXPathObjectPtr arg
;
7587 arg
= valuePop(ctxt
);
7589 XP_ERROR(XPATH_INVALID_OPERAND
);
7590 arg2
= xmlXPathCastToNumber(arg
);
7591 xmlXPathReleaseObject(ctxt
->context
, arg
);
7593 CHECK_TYPE(XPATH_NUMBER
);
7594 arg1
= ctxt
->value
->floatval
;
7596 ctxt
->value
->floatval
= xmlXPathNAN
;
7598 ctxt
->value
->floatval
= fmod(arg1
, arg2
);
7602 /************************************************************************
7604 * The traversal functions *
7606 ************************************************************************/
7609 * A traversal function enumerates nodes along an axis.
7610 * Initially it must be called with NULL, and it indicates
7611 * termination on the axis by returning NULL.
7613 typedef xmlNodePtr (*xmlXPathTraversalFunction
)
7614 (xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
);
7617 * xmlXPathTraversalFunctionExt:
7618 * A traversal function enumerates nodes along an axis.
7619 * Initially it must be called with NULL, and it indicates
7620 * termination on the axis by returning NULL.
7621 * The context node of the traversal is specified via @contextNode.
7623 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt
)
7624 (xmlNodePtr cur
, xmlNodePtr contextNode
);
7627 * xmlXPathNodeSetMergeFunction:
7628 * Used for merging node sets in xmlXPathCollectAndTest().
7630 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction
)
7631 (xmlNodeSetPtr
, xmlNodeSetPtr
);
7636 * @ctxt: the XPath Parser context
7637 * @cur: the current node in the traversal
7639 * Traversal function for the "self" direction
7640 * The self axis contains just the context node itself
7642 * Returns the next element following that axis
7645 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7646 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7648 return(ctxt
->context
->node
);
7653 * xmlXPathNextChild:
7654 * @ctxt: the XPath Parser context
7655 * @cur: the current node in the traversal
7657 * Traversal function for the "child" direction
7658 * The child axis contains the children of the context node in document order.
7660 * Returns the next element following that axis
7663 xmlXPathNextChild(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7664 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7666 if (ctxt
->context
->node
== NULL
) return(NULL
);
7667 switch (ctxt
->context
->node
->type
) {
7668 case XML_ELEMENT_NODE
:
7670 case XML_CDATA_SECTION_NODE
:
7671 case XML_ENTITY_REF_NODE
:
7672 case XML_ENTITY_NODE
:
7674 case XML_COMMENT_NODE
:
7675 case XML_NOTATION_NODE
:
7677 return(ctxt
->context
->node
->children
);
7678 case XML_DOCUMENT_NODE
:
7679 case XML_DOCUMENT_TYPE_NODE
:
7680 case XML_DOCUMENT_FRAG_NODE
:
7681 case XML_HTML_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 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7744 * Get the next sibling element node.
7746 switch (cur
->type
) {
7747 case XML_ELEMENT_NODE
:
7749 case XML_ENTITY_REF_NODE
:
7750 case XML_ENTITY_NODE
:
7751 case XML_CDATA_SECTION_NODE
:
7753 case XML_COMMENT_NODE
:
7754 case XML_XINCLUDE_END
:
7756 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7760 if (cur
->next
!= NULL
) {
7761 if (cur
->next
->type
== XML_ELEMENT_NODE
)
7766 } while ((cur
!= NULL
) && (cur
->type
!= XML_ELEMENT_NODE
));
7774 * xmlXPathNextDescendantOrSelfElemParent:
7775 * @ctxt: the XPath Parser context
7776 * @cur: the current node in the traversal
7778 * Traversal function for the "descendant-or-self" axis.
7779 * Additionally it returns only nodes which can be parents of
7783 * Returns the next element following that axis
7786 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur
,
7787 xmlNodePtr contextNode
)
7790 if (contextNode
== NULL
)
7792 switch (contextNode
->type
) {
7793 case XML_ELEMENT_NODE
:
7794 case XML_XINCLUDE_START
:
7795 case XML_DOCUMENT_FRAG_NODE
:
7796 case XML_DOCUMENT_NODE
:
7797 case XML_HTML_DOCUMENT_NODE
:
7798 return(contextNode
);
7804 xmlNodePtr start
= cur
;
7806 while (cur
!= NULL
) {
7807 switch (cur
->type
) {
7808 case XML_ELEMENT_NODE
:
7809 /* TODO: OK to have XInclude here? */
7810 case XML_XINCLUDE_START
:
7811 case XML_DOCUMENT_FRAG_NODE
:
7814 if (cur
->children
!= NULL
) {
7815 cur
= cur
->children
;
7819 /* Not sure if we need those here. */
7820 case XML_DOCUMENT_NODE
:
7821 case XML_HTML_DOCUMENT_NODE
:
7824 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7830 if ((cur
== NULL
) || (cur
== contextNode
))
7832 if (cur
->next
!= NULL
) {
7845 * xmlXPathNextDescendant:
7846 * @ctxt: the XPath Parser context
7847 * @cur: the current node in the traversal
7849 * Traversal function for the "descendant" direction
7850 * the descendant axis contains the descendants of the context node in document
7851 * order; a descendant is a child or a child of a child and so on.
7853 * Returns the next element following that axis
7856 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7857 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7859 if (ctxt
->context
->node
== NULL
)
7861 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7862 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7865 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
7866 return(ctxt
->context
->doc
->children
);
7867 return(ctxt
->context
->node
->children
);
7870 if (cur
->type
== XML_NAMESPACE_DECL
)
7872 if (cur
->children
!= NULL
) {
7874 * Do not descend on entities declarations
7876 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
7877 cur
= cur
->children
;
7881 if (cur
->type
!= XML_DTD_NODE
)
7886 if (cur
== ctxt
->context
->node
) return(NULL
);
7888 while (cur
->next
!= NULL
) {
7890 if ((cur
->type
!= XML_ENTITY_DECL
) &&
7891 (cur
->type
!= XML_DTD_NODE
))
7897 if (cur
== NULL
) break;
7898 if (cur
== ctxt
->context
->node
) return(NULL
);
7899 if (cur
->next
!= NULL
) {
7903 } while (cur
!= NULL
);
7908 * xmlXPathNextDescendantOrSelf:
7909 * @ctxt: the XPath Parser context
7910 * @cur: the current node in the traversal
7912 * Traversal function for the "descendant-or-self" direction
7913 * the descendant-or-self axis contains the context node and the descendants
7914 * of the context node in document order; thus the context node is the first
7915 * node on the axis, and the first child of the context node is the second node
7918 * Returns the next element following that axis
7921 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7922 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7924 return(ctxt
->context
->node
);
7926 if (ctxt
->context
->node
== NULL
)
7928 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7929 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7932 return(xmlXPathNextDescendant(ctxt
, cur
));
7936 * xmlXPathNextParent:
7937 * @ctxt: the XPath Parser context
7938 * @cur: the current node in the traversal
7940 * Traversal function for the "parent" direction
7941 * The parent axis contains the parent of the context node, if there is one.
7943 * Returns the next element following that axis
7946 xmlXPathNextParent(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7947 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7949 * the parent of an attribute or namespace node is the element
7950 * to which the attribute or namespace node is attached
7951 * Namespace handling !!!
7954 if (ctxt
->context
->node
== NULL
) return(NULL
);
7955 switch (ctxt
->context
->node
->type
) {
7956 case XML_ELEMENT_NODE
:
7958 case XML_CDATA_SECTION_NODE
:
7959 case XML_ENTITY_REF_NODE
:
7960 case XML_ENTITY_NODE
:
7962 case XML_COMMENT_NODE
:
7963 case XML_NOTATION_NODE
:
7965 case XML_ELEMENT_DECL
:
7966 case XML_ATTRIBUTE_DECL
:
7967 case XML_XINCLUDE_START
:
7968 case XML_XINCLUDE_END
:
7969 case XML_ENTITY_DECL
:
7970 if (ctxt
->context
->node
->parent
== NULL
)
7971 return((xmlNodePtr
) ctxt
->context
->doc
);
7972 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
7973 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
7974 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
7975 BAD_CAST
"fake node libxslt"))))
7977 return(ctxt
->context
->node
->parent
);
7978 case XML_ATTRIBUTE_NODE
: {
7979 xmlAttrPtr att
= (xmlAttrPtr
) ctxt
->context
->node
;
7981 return(att
->parent
);
7983 case XML_DOCUMENT_NODE
:
7984 case XML_DOCUMENT_TYPE_NODE
:
7985 case XML_DOCUMENT_FRAG_NODE
:
7986 case XML_HTML_DOCUMENT_NODE
:
7988 case XML_NAMESPACE_DECL
: {
7989 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
7991 if ((ns
->next
!= NULL
) &&
7992 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
7993 return((xmlNodePtr
) ns
->next
);
8002 * xmlXPathNextAncestor:
8003 * @ctxt: the XPath Parser context
8004 * @cur: the current node in the traversal
8006 * Traversal function for the "ancestor" direction
8007 * the ancestor axis contains the ancestors of the context node; the ancestors
8008 * of the context node consist of the parent of context node and the parent's
8009 * parent and so on; the nodes are ordered in reverse document order; thus the
8010 * parent is the first node on the axis, and the parent's parent is the second
8013 * Returns the next element following that axis
8016 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8017 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8019 * the parent of an attribute or namespace node is the element
8020 * to which the attribute or namespace node is attached
8024 if (ctxt
->context
->node
== NULL
) return(NULL
);
8025 switch (ctxt
->context
->node
->type
) {
8026 case XML_ELEMENT_NODE
:
8028 case XML_CDATA_SECTION_NODE
:
8029 case XML_ENTITY_REF_NODE
:
8030 case XML_ENTITY_NODE
:
8032 case XML_COMMENT_NODE
:
8034 case XML_ELEMENT_DECL
:
8035 case XML_ATTRIBUTE_DECL
:
8036 case XML_ENTITY_DECL
:
8037 case XML_NOTATION_NODE
:
8038 case XML_XINCLUDE_START
:
8039 case XML_XINCLUDE_END
:
8040 if (ctxt
->context
->node
->parent
== NULL
)
8041 return((xmlNodePtr
) ctxt
->context
->doc
);
8042 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
8043 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
8044 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
8045 BAD_CAST
"fake node libxslt"))))
8047 return(ctxt
->context
->node
->parent
);
8048 case XML_ATTRIBUTE_NODE
: {
8049 xmlAttrPtr tmp
= (xmlAttrPtr
) ctxt
->context
->node
;
8051 return(tmp
->parent
);
8053 case XML_DOCUMENT_NODE
:
8054 case XML_DOCUMENT_TYPE_NODE
:
8055 case XML_DOCUMENT_FRAG_NODE
:
8056 case XML_HTML_DOCUMENT_NODE
:
8058 case XML_NAMESPACE_DECL
: {
8059 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8061 if ((ns
->next
!= NULL
) &&
8062 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8063 return((xmlNodePtr
) ns
->next
);
8064 /* Bad, how did that namespace end up here ? */
8070 if (cur
== ctxt
->context
->doc
->children
)
8071 return((xmlNodePtr
) ctxt
->context
->doc
);
8072 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8074 switch (cur
->type
) {
8075 case XML_ELEMENT_NODE
:
8077 case XML_CDATA_SECTION_NODE
:
8078 case XML_ENTITY_REF_NODE
:
8079 case XML_ENTITY_NODE
:
8081 case XML_COMMENT_NODE
:
8082 case XML_NOTATION_NODE
:
8084 case XML_ELEMENT_DECL
:
8085 case XML_ATTRIBUTE_DECL
:
8086 case XML_ENTITY_DECL
:
8087 case XML_XINCLUDE_START
:
8088 case XML_XINCLUDE_END
:
8089 if (cur
->parent
== NULL
)
8091 if ((cur
->parent
->type
== XML_ELEMENT_NODE
) &&
8092 ((cur
->parent
->name
[0] == ' ') ||
8093 (xmlStrEqual(cur
->parent
->name
,
8094 BAD_CAST
"fake node libxslt"))))
8096 return(cur
->parent
);
8097 case XML_ATTRIBUTE_NODE
: {
8098 xmlAttrPtr att
= (xmlAttrPtr
) cur
;
8100 return(att
->parent
);
8102 case XML_NAMESPACE_DECL
: {
8103 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8105 if ((ns
->next
!= NULL
) &&
8106 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8107 return((xmlNodePtr
) ns
->next
);
8108 /* Bad, how did that namespace end up here ? */
8111 case XML_DOCUMENT_NODE
:
8112 case XML_DOCUMENT_TYPE_NODE
:
8113 case XML_DOCUMENT_FRAG_NODE
:
8114 case XML_HTML_DOCUMENT_NODE
:
8121 * xmlXPathNextAncestorOrSelf:
8122 * @ctxt: the XPath Parser context
8123 * @cur: the current node in the traversal
8125 * Traversal function for the "ancestor-or-self" direction
8126 * he ancestor-or-self axis contains the context node and ancestors of
8127 * the context node in reverse document order; thus the context node is
8128 * the first node on the axis, and the context node's parent the second;
8129 * parent here is defined the same as with the parent axis.
8131 * Returns the next element following that axis
8134 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8135 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8137 return(ctxt
->context
->node
);
8138 return(xmlXPathNextAncestor(ctxt
, cur
));
8142 * xmlXPathNextFollowingSibling:
8143 * @ctxt: the XPath Parser context
8144 * @cur: the current node in the traversal
8146 * Traversal function for the "following-sibling" direction
8147 * The following-sibling axis contains the following siblings of the context
8148 * node in document order.
8150 * Returns the next element following that axis
8153 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8154 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8155 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8156 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8158 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8161 return(ctxt
->context
->node
->next
);
8166 * xmlXPathNextPrecedingSibling:
8167 * @ctxt: the XPath Parser context
8168 * @cur: the current node in the traversal
8170 * Traversal function for the "preceding-sibling" direction
8171 * The preceding-sibling axis contains the preceding siblings of the context
8172 * node in reverse document order; the first preceding sibling is first on the
8173 * axis; the sibling preceding that node is the second on the axis and so on.
8175 * Returns the next element following that axis
8178 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8179 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8180 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8181 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8183 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8186 return(ctxt
->context
->node
->prev
);
8187 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
)) {
8190 return(ctxt
->context
->node
->prev
);
8196 * xmlXPathNextFollowing:
8197 * @ctxt: the XPath Parser context
8198 * @cur: the current node in the traversal
8200 * Traversal function for the "following" direction
8201 * The following axis contains all nodes in the same document as the context
8202 * node that are after the context node in document order, excluding any
8203 * descendants and excluding attribute nodes and namespace nodes; the nodes
8204 * are ordered in document order
8206 * Returns the next element following that axis
8209 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8210 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8211 if ((cur
!= NULL
) && (cur
->type
!= XML_ATTRIBUTE_NODE
) &&
8212 (cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->children
!= NULL
))
8213 return(cur
->children
);
8216 cur
= ctxt
->context
->node
;
8217 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8219 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8220 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8222 if ((ns
->next
== NULL
) ||
8223 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8225 cur
= (xmlNodePtr
) ns
->next
;
8228 if (cur
== NULL
) return(NULL
) ; /* ERROR */
8229 if (cur
->next
!= NULL
) return(cur
->next
) ;
8232 if (cur
== NULL
) break;
8233 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
) return(NULL
);
8234 if (cur
->next
!= NULL
) return(cur
->next
);
8235 } while (cur
!= NULL
);
8240 * xmlXPathIsAncestor:
8241 * @ancestor: the ancestor node
8242 * @node: the current node
8244 * Check that @ancestor is a @node's ancestor
8246 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8249 xmlXPathIsAncestor(xmlNodePtr ancestor
, xmlNodePtr node
) {
8250 if ((ancestor
== NULL
) || (node
== NULL
)) return(0);
8251 if (node
->type
== XML_NAMESPACE_DECL
)
8253 if (ancestor
->type
== XML_NAMESPACE_DECL
)
8255 /* nodes need to be in the same document */
8256 if (ancestor
->doc
!= node
->doc
) return(0);
8257 /* avoid searching if ancestor or node is the root node */
8258 if (ancestor
== (xmlNodePtr
) node
->doc
) return(1);
8259 if (node
== (xmlNodePtr
) ancestor
->doc
) return(0);
8260 while (node
->parent
!= NULL
) {
8261 if (node
->parent
== ancestor
)
8263 node
= node
->parent
;
8269 * xmlXPathNextPreceding:
8270 * @ctxt: the XPath Parser context
8271 * @cur: the current node in the traversal
8273 * Traversal function for the "preceding" direction
8274 * the preceding axis contains all nodes in the same document as the context
8275 * node that are before the context node in document order, excluding any
8276 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8277 * ordered in reverse document order
8279 * Returns the next element following that axis
8282 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
)
8284 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8286 cur
= ctxt
->context
->node
;
8287 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8289 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8290 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8292 if ((ns
->next
== NULL
) ||
8293 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8295 cur
= (xmlNodePtr
) ns
->next
;
8298 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
8300 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8303 if (cur
->prev
!= NULL
) {
8304 for (cur
= cur
->prev
; cur
->last
!= NULL
; cur
= cur
->last
) ;
8311 if (cur
== ctxt
->context
->doc
->children
)
8313 } while (xmlXPathIsAncestor(cur
, ctxt
->context
->node
));
8318 * xmlXPathNextPrecedingInternal:
8319 * @ctxt: the XPath Parser context
8320 * @cur: the current node in the traversal
8322 * Traversal function for the "preceding" direction
8323 * the preceding axis contains all nodes in the same document as the context
8324 * node that are before the context node in document order, excluding any
8325 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8326 * ordered in reverse document order
8327 * This is a faster implementation but internal only since it requires a
8328 * state kept in the parser context: ctxt->ancestor.
8330 * Returns the next element following that axis
8333 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt
,
8336 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8338 cur
= ctxt
->context
->node
;
8341 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8343 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8344 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8346 if ((ns
->next
== NULL
) ||
8347 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8349 cur
= (xmlNodePtr
) ns
->next
;
8351 ctxt
->ancestor
= cur
->parent
;
8353 if (cur
->type
== XML_NAMESPACE_DECL
)
8355 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8357 while (cur
->prev
== NULL
) {
8361 if (cur
== ctxt
->context
->doc
->children
)
8363 if (cur
!= ctxt
->ancestor
)
8365 ctxt
->ancestor
= cur
->parent
;
8368 while (cur
->last
!= NULL
)
8374 * xmlXPathNextNamespace:
8375 * @ctxt: the XPath Parser context
8376 * @cur: the current attribute in the traversal
8378 * Traversal function for the "namespace" direction
8379 * the namespace axis contains the namespace nodes of the context node;
8380 * the order of nodes on this axis is implementation-defined; the axis will
8381 * be empty unless the context node is an element
8383 * We keep the XML namespace node at the end of the list.
8385 * Returns the next element following that axis
8388 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8389 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8390 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
) return(NULL
);
8392 if (ctxt
->context
->tmpNsList
!= NULL
)
8393 xmlFree(ctxt
->context
->tmpNsList
);
8394 ctxt
->context
->tmpNsList
=
8395 xmlGetNsList(ctxt
->context
->doc
, ctxt
->context
->node
);
8396 ctxt
->context
->tmpNsNr
= 0;
8397 if (ctxt
->context
->tmpNsList
!= NULL
) {
8398 while (ctxt
->context
->tmpNsList
[ctxt
->context
->tmpNsNr
] != NULL
) {
8399 ctxt
->context
->tmpNsNr
++;
8402 return((xmlNodePtr
) xmlXPathXMLNamespace
);
8404 if (ctxt
->context
->tmpNsNr
> 0) {
8405 return (xmlNodePtr
)ctxt
->context
->tmpNsList
[--ctxt
->context
->tmpNsNr
];
8407 if (ctxt
->context
->tmpNsList
!= NULL
)
8408 xmlFree(ctxt
->context
->tmpNsList
);
8409 ctxt
->context
->tmpNsList
= NULL
;
8415 * xmlXPathNextAttribute:
8416 * @ctxt: the XPath Parser context
8417 * @cur: the current attribute in the traversal
8419 * Traversal function for the "attribute" direction
8420 * TODO: support DTD inherited default attributes
8422 * Returns the next element following that axis
8425 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8426 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8427 if (ctxt
->context
->node
== NULL
)
8429 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
)
8432 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
8434 return((xmlNodePtr
)ctxt
->context
->node
->properties
);
8436 return((xmlNodePtr
)cur
->next
);
8439 /************************************************************************
8441 * NodeTest Functions *
8443 ************************************************************************/
8445 #define IS_FUNCTION 200
8448 /************************************************************************
8450 * Implicit tree core function library *
8452 ************************************************************************/
8456 * @ctxt: the XPath Parser context
8458 * Initialize the context to the root of the document
8461 xmlXPathRoot(xmlXPathParserContextPtr ctxt
) {
8462 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8464 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8465 (xmlNodePtr
) ctxt
->context
->doc
));
8468 /************************************************************************
8470 * The explicit core function library *
8471 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8473 ************************************************************************/
8477 * xmlXPathLastFunction:
8478 * @ctxt: the XPath Parser context
8479 * @nargs: the number of arguments
8481 * Implement the last() XPath function
8483 * The last function returns the number of nodes in the context node list.
8486 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8488 if (ctxt
->context
->contextSize
>= 0) {
8490 xmlXPathCacheNewFloat(ctxt
->context
,
8491 (double) ctxt
->context
->contextSize
));
8493 xmlGenericError(xmlGenericErrorContext
,
8494 "last() : %d\n", ctxt
->context
->contextSize
);
8497 XP_ERROR(XPATH_INVALID_CTXT_SIZE
);
8502 * xmlXPathPositionFunction:
8503 * @ctxt: the XPath Parser context
8504 * @nargs: the number of arguments
8506 * Implement the position() XPath function
8508 * The position function returns the position of the context node in the
8509 * context node list. The first position is 1, and so the last position
8510 * will be equal to last().
8513 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8515 if (ctxt
->context
->proximityPosition
>= 0) {
8517 xmlXPathCacheNewFloat(ctxt
->context
,
8518 (double) ctxt
->context
->proximityPosition
));
8520 xmlGenericError(xmlGenericErrorContext
, "position() : %d\n",
8521 ctxt
->context
->proximityPosition
);
8524 XP_ERROR(XPATH_INVALID_CTXT_POSITION
);
8529 * xmlXPathCountFunction:
8530 * @ctxt: the XPath Parser context
8531 * @nargs: the number of arguments
8533 * Implement the count() XPath function
8534 * number count(node-set)
8537 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8538 xmlXPathObjectPtr cur
;
8541 if ((ctxt
->value
== NULL
) ||
8542 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8543 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8544 XP_ERROR(XPATH_INVALID_TYPE
);
8545 cur
= valuePop(ctxt
);
8547 if ((cur
== NULL
) || (cur
->nodesetval
== NULL
))
8548 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8550 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8551 (double) cur
->nodesetval
->nodeNr
));
8552 xmlXPathReleaseObject(ctxt
->context
, cur
);
8556 * xmlXPathGetElementsByIds:
8557 * @doc: the document
8558 * @ids: a whitespace separated list of IDs
8560 * Selects elements by their unique ID.
8562 * Returns a node-set of selected elements.
8564 static xmlNodeSetPtr
8565 xmlXPathGetElementsByIds (xmlDocPtr doc
, const xmlChar
*ids
) {
8567 const xmlChar
*cur
= ids
;
8570 xmlNodePtr elem
= NULL
;
8572 if (ids
== NULL
) return(NULL
);
8574 ret
= xmlXPathNodeSetCreate(NULL
);
8578 while (IS_BLANK_CH(*cur
)) cur
++;
8580 while ((!IS_BLANK_CH(*cur
)) && (*cur
!= 0))
8583 ID
= xmlStrndup(ids
, cur
- ids
);
8586 * We used to check the fact that the value passed
8587 * was an NCName, but this generated much troubles for
8588 * me and Aleksey Sanin, people blatantly violated that
8589 * constraint, like Visa3D spec.
8590 * if (xmlValidateNCName(ID, 1) == 0)
8592 attr
= xmlGetID(doc
, ID
);
8594 if (attr
->type
== XML_ATTRIBUTE_NODE
)
8595 elem
= attr
->parent
;
8596 else if (attr
->type
== XML_ELEMENT_NODE
)
8597 elem
= (xmlNodePtr
) attr
;
8600 /* TODO: Check memory error. */
8602 xmlXPathNodeSetAdd(ret
, elem
);
8607 while (IS_BLANK_CH(*cur
)) cur
++;
8614 * xmlXPathIdFunction:
8615 * @ctxt: the XPath Parser context
8616 * @nargs: the number of arguments
8618 * Implement the id() XPath function
8619 * node-set id(object)
8620 * The id function selects elements by their unique ID
8621 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8622 * then the result is the union of the result of applying id to the
8623 * string value of each of the nodes in the argument node-set. When the
8624 * argument to id is of any other type, the argument is converted to a
8625 * string as if by a call to the string function; the string is split
8626 * into a whitespace-separated list of tokens (whitespace is any sequence
8627 * of characters matching the production S); the result is a node-set
8628 * containing the elements in the same document as the context node that
8629 * have a unique ID equal to any of the tokens in the list.
8632 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8635 xmlXPathObjectPtr obj
;
8638 obj
= valuePop(ctxt
);
8639 if (obj
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8640 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
8644 /* TODO: Check memory error. */
8645 ret
= xmlXPathNodeSetCreate(NULL
);
8647 if (obj
->nodesetval
!= NULL
) {
8648 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
8650 xmlXPathCastNodeToString(obj
->nodesetval
->nodeTab
[i
]);
8651 ns
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, tokens
);
8652 /* TODO: Check memory error. */
8653 ret
= xmlXPathNodeSetMerge(ret
, ns
);
8654 xmlXPathFreeNodeSet(ns
);
8659 xmlXPathReleaseObject(ctxt
->context
, obj
);
8660 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8663 obj
= xmlXPathCacheConvertString(ctxt
->context
, obj
);
8664 if (obj
== NULL
) return;
8665 ret
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, obj
->stringval
);
8666 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8667 xmlXPathReleaseObject(ctxt
->context
, obj
);
8672 * xmlXPathLocalNameFunction:
8673 * @ctxt: the XPath Parser context
8674 * @nargs: the number of arguments
8676 * Implement the local-name() XPath function
8677 * string local-name(node-set?)
8678 * The local-name function returns a string containing the local part
8679 * of the name of the node in the argument node-set that is first in
8680 * document order. If the node-set is empty or the first node has no
8681 * name, an empty string is returned. If the argument is omitted it
8682 * defaults to the context node.
8685 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8686 xmlXPathObjectPtr cur
;
8688 if (ctxt
== NULL
) return;
8691 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8692 ctxt
->context
->node
));
8697 if ((ctxt
->value
== NULL
) ||
8698 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8699 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8700 XP_ERROR(XPATH_INVALID_TYPE
);
8701 cur
= valuePop(ctxt
);
8703 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8704 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8706 int i
= 0; /* Should be first in document order !!!!! */
8707 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8708 case XML_ELEMENT_NODE
:
8709 case XML_ATTRIBUTE_NODE
:
8711 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8712 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8715 xmlXPathCacheNewString(ctxt
->context
,
8716 cur
->nodesetval
->nodeTab
[i
]->name
));
8718 case XML_NAMESPACE_DECL
:
8719 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8720 ((xmlNsPtr
)cur
->nodesetval
->nodeTab
[i
])->prefix
));
8723 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8726 xmlXPathReleaseObject(ctxt
->context
, cur
);
8730 * xmlXPathNamespaceURIFunction:
8731 * @ctxt: the XPath Parser context
8732 * @nargs: the number of arguments
8734 * Implement the namespace-uri() XPath function
8735 * string namespace-uri(node-set?)
8736 * The namespace-uri function returns a string containing the
8737 * namespace URI of the expanded name of the node in the argument
8738 * node-set that is first in document order. If the node-set is empty,
8739 * the first node has no name, or the expanded name has no namespace
8740 * URI, an empty string is returned. If the argument is omitted it
8741 * defaults to the context node.
8744 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8745 xmlXPathObjectPtr cur
;
8747 if (ctxt
== NULL
) return;
8750 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8751 ctxt
->context
->node
));
8755 if ((ctxt
->value
== NULL
) ||
8756 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8757 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8758 XP_ERROR(XPATH_INVALID_TYPE
);
8759 cur
= valuePop(ctxt
);
8761 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8762 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8764 int i
= 0; /* Should be first in document order !!!!! */
8765 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8766 case XML_ELEMENT_NODE
:
8767 case XML_ATTRIBUTE_NODE
:
8768 if (cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
)
8769 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8771 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8772 cur
->nodesetval
->nodeTab
[i
]->ns
->href
));
8775 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8778 xmlXPathReleaseObject(ctxt
->context
, cur
);
8782 * xmlXPathNameFunction:
8783 * @ctxt: the XPath Parser context
8784 * @nargs: the number of arguments
8786 * Implement the name() XPath function
8787 * string name(node-set?)
8788 * The name function returns a string containing a QName representing
8789 * the name of the node in the argument node-set that is first in document
8790 * order. The QName must represent the name with respect to the namespace
8791 * declarations in effect on the node whose name is being represented.
8792 * Typically, this will be the form in which the name occurred in the XML
8793 * source. This need not be the case if there are namespace declarations
8794 * in effect on the node that associate multiple prefixes with the same
8795 * namespace. However, an implementation may include information about
8796 * the original prefix in its representation of nodes; in this case, an
8797 * implementation can ensure that the returned string is always the same
8798 * as the QName used in the XML source. If the argument it omitted it
8799 * defaults to the context node.
8800 * Libxml keep the original prefix so the "real qualified name" used is
8804 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
8806 xmlXPathObjectPtr cur
;
8809 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8810 ctxt
->context
->node
));
8815 if ((ctxt
->value
== NULL
) ||
8816 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8817 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8818 XP_ERROR(XPATH_INVALID_TYPE
);
8819 cur
= valuePop(ctxt
);
8821 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8822 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8824 int i
= 0; /* Should be first in document order !!!!! */
8826 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8827 case XML_ELEMENT_NODE
:
8828 case XML_ATTRIBUTE_NODE
:
8829 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8831 xmlXPathCacheNewCString(ctxt
->context
, ""));
8832 else if ((cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
) ||
8833 (cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
== NULL
)) {
8835 xmlXPathCacheNewString(ctxt
->context
,
8836 cur
->nodesetval
->nodeTab
[i
]->name
));
8840 fullname
= xmlBuildQName(cur
->nodesetval
->nodeTab
[i
]->name
,
8841 cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
,
8843 if (fullname
== cur
->nodesetval
->nodeTab
[i
]->name
)
8844 fullname
= xmlStrdup(cur
->nodesetval
->nodeTab
[i
]->name
);
8845 if (fullname
== NULL
) {
8846 XP_ERROR(XPATH_MEMORY_ERROR
);
8848 valuePush(ctxt
, xmlXPathCacheWrapString(
8849 ctxt
->context
, fullname
));
8853 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8854 cur
->nodesetval
->nodeTab
[i
]));
8855 xmlXPathLocalNameFunction(ctxt
, 1);
8858 xmlXPathReleaseObject(ctxt
->context
, cur
);
8863 * xmlXPathStringFunction:
8864 * @ctxt: the XPath Parser context
8865 * @nargs: the number of arguments
8867 * Implement the string() XPath function
8868 * string string(object?)
8869 * The string function converts an object to a string as follows:
8870 * - A node-set is converted to a string by returning the value of
8871 * the node in the node-set that is first in document order.
8872 * If the node-set is empty, an empty string is returned.
8873 * - A number is converted to a string as follows
8874 * + NaN is converted to the string NaN
8875 * + positive zero is converted to the string 0
8876 * + negative zero is converted to the string 0
8877 * + positive infinity is converted to the string Infinity
8878 * + negative infinity is converted to the string -Infinity
8879 * + if the number is an integer, the number is represented in
8880 * decimal form as a Number with no decimal point and no leading
8881 * zeros, preceded by a minus sign (-) if the number is negative
8882 * + otherwise, the number is represented in decimal form as a
8883 * Number including a decimal point with at least one digit
8884 * before the decimal point and at least one digit after the
8885 * decimal point, preceded by a minus sign (-) if the number
8886 * is negative; there must be no leading zeros before the decimal
8887 * point apart possibly from the one required digit immediately
8888 * before the decimal point; beyond the one required digit
8889 * after the decimal point there must be as many, but only as
8890 * many, more digits as are needed to uniquely distinguish the
8891 * number from all other IEEE 754 numeric values.
8892 * - The boolean false value is converted to the string false.
8893 * The boolean true value is converted to the string true.
8895 * If the argument is omitted, it defaults to a node-set with the
8896 * context node as its only member.
8899 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8900 xmlXPathObjectPtr cur
;
8902 if (ctxt
== NULL
) return;
8905 xmlXPathCacheWrapString(ctxt
->context
,
8906 xmlXPathCastNodeToString(ctxt
->context
->node
)));
8911 cur
= valuePop(ctxt
);
8912 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8913 valuePush(ctxt
, xmlXPathCacheConvertString(ctxt
->context
, cur
));
8917 * xmlXPathStringLengthFunction:
8918 * @ctxt: the XPath Parser context
8919 * @nargs: the number of arguments
8921 * Implement the string-length() XPath function
8922 * number string-length(string?)
8923 * The string-length returns the number of characters in the string
8924 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8925 * the context node converted to a string, in other words the value
8926 * of the context node.
8929 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8930 xmlXPathObjectPtr cur
;
8933 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8935 if (ctxt
->context
->node
== NULL
) {
8936 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0));
8940 content
= xmlXPathCastNodeToString(ctxt
->context
->node
);
8941 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8942 xmlUTF8Strlen(content
)));
8949 CHECK_TYPE(XPATH_STRING
);
8950 cur
= valuePop(ctxt
);
8951 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8952 xmlUTF8Strlen(cur
->stringval
)));
8953 xmlXPathReleaseObject(ctxt
->context
, cur
);
8957 * xmlXPathConcatFunction:
8958 * @ctxt: the XPath Parser context
8959 * @nargs: the number of arguments
8961 * Implement the concat() XPath function
8962 * string concat(string, string, string*)
8963 * The concat function returns the concatenation of its arguments.
8966 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8967 xmlXPathObjectPtr cur
, newobj
;
8970 if (ctxt
== NULL
) return;
8976 cur
= valuePop(ctxt
);
8977 if ((cur
== NULL
) || (cur
->type
!= XPATH_STRING
)) {
8978 xmlXPathReleaseObject(ctxt
->context
, cur
);
8985 newobj
= valuePop(ctxt
);
8986 if ((newobj
== NULL
) || (newobj
->type
!= XPATH_STRING
)) {
8987 xmlXPathReleaseObject(ctxt
->context
, newobj
);
8988 xmlXPathReleaseObject(ctxt
->context
, cur
);
8989 XP_ERROR(XPATH_INVALID_TYPE
);
8991 tmp
= xmlStrcat(newobj
->stringval
, cur
->stringval
);
8992 newobj
->stringval
= cur
->stringval
;
8993 cur
->stringval
= tmp
;
8994 xmlXPathReleaseObject(ctxt
->context
, newobj
);
8997 valuePush(ctxt
, cur
);
9001 * xmlXPathContainsFunction:
9002 * @ctxt: the XPath Parser context
9003 * @nargs: the number of arguments
9005 * Implement the contains() XPath function
9006 * boolean contains(string, string)
9007 * The contains function returns true if the first argument string
9008 * contains the second argument string, and otherwise returns false.
9011 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9012 xmlXPathObjectPtr hay
, needle
;
9016 CHECK_TYPE(XPATH_STRING
);
9017 needle
= valuePop(ctxt
);
9019 hay
= valuePop(ctxt
);
9021 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9022 xmlXPathReleaseObject(ctxt
->context
, hay
);
9023 xmlXPathReleaseObject(ctxt
->context
, needle
);
9024 XP_ERROR(XPATH_INVALID_TYPE
);
9026 if (xmlStrstr(hay
->stringval
, needle
->stringval
))
9027 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9029 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9030 xmlXPathReleaseObject(ctxt
->context
, hay
);
9031 xmlXPathReleaseObject(ctxt
->context
, needle
);
9035 * xmlXPathStartsWithFunction:
9036 * @ctxt: the XPath Parser context
9037 * @nargs: the number of arguments
9039 * Implement the starts-with() XPath function
9040 * boolean starts-with(string, string)
9041 * The starts-with function returns true if the first argument string
9042 * starts with the second argument string, and otherwise returns false.
9045 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9046 xmlXPathObjectPtr hay
, needle
;
9051 CHECK_TYPE(XPATH_STRING
);
9052 needle
= valuePop(ctxt
);
9054 hay
= valuePop(ctxt
);
9056 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9057 xmlXPathReleaseObject(ctxt
->context
, hay
);
9058 xmlXPathReleaseObject(ctxt
->context
, needle
);
9059 XP_ERROR(XPATH_INVALID_TYPE
);
9061 n
= xmlStrlen(needle
->stringval
);
9062 if (xmlStrncmp(hay
->stringval
, needle
->stringval
, n
))
9063 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9065 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9066 xmlXPathReleaseObject(ctxt
->context
, hay
);
9067 xmlXPathReleaseObject(ctxt
->context
, needle
);
9071 * xmlXPathSubstringFunction:
9072 * @ctxt: the XPath Parser context
9073 * @nargs: the number of arguments
9075 * Implement the substring() XPath function
9076 * string substring(string, number, number?)
9077 * The substring function returns the substring of the first argument
9078 * starting at the position specified in the second argument with
9079 * length specified in the third argument. For example,
9080 * substring("12345",2,3) returns "234". If the third argument is not
9081 * specified, it returns the substring starting at the position specified
9082 * in the second argument and continuing to the end of the string. For
9083 * example, substring("12345",2) returns "2345". More precisely, each
9084 * character in the string (see [3.6 Strings]) is considered to have a
9085 * numeric position: the position of the first character is 1, the position
9086 * of the second character is 2 and so on. The returned substring contains
9087 * those characters for which the position of the character is greater than
9088 * or equal to the second argument and, if the third argument is specified,
9089 * less than the sum of the second and third arguments; the comparisons
9090 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9091 * - substring("12345", 1.5, 2.6) returns "234"
9092 * - substring("12345", 0, 3) returns "12"
9093 * - substring("12345", 0 div 0, 3) returns ""
9094 * - substring("12345", 1, 0 div 0) returns ""
9095 * - substring("12345", -42, 1 div 0) returns "12345"
9096 * - substring("12345", -1 div 0, 1 div 0) returns ""
9099 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9100 xmlXPathObjectPtr str
, start
, len
;
9102 int i
= 1, j
= INT_MAX
;
9111 * take care of possible last (position) argument
9115 CHECK_TYPE(XPATH_NUMBER
);
9116 len
= valuePop(ctxt
);
9118 xmlXPathReleaseObject(ctxt
->context
, len
);
9122 CHECK_TYPE(XPATH_NUMBER
);
9123 start
= valuePop(ctxt
);
9124 in
= start
->floatval
;
9125 xmlXPathReleaseObject(ctxt
->context
, start
);
9127 CHECK_TYPE(XPATH_STRING
);
9128 str
= valuePop(ctxt
);
9130 if (!(in
< INT_MAX
)) { /* Logical NOT to handle NaNs */
9132 } else if (in
>= 1.0) {
9134 if (in
- floor(in
) >= 0.5)
9139 double rin
, rle
, end
;
9142 if (in
- rin
>= 0.5)
9146 if (le
- rle
>= 0.5)
9150 if (!(end
>= 1.0)) { /* Logical NOT to handle NaNs */
9152 } else if (end
< INT_MAX
) {
9158 xmlChar
*ret
= xmlUTF8Strsub(str
->stringval
, i
- 1, j
- i
);
9159 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, ret
));
9162 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
9165 xmlXPathReleaseObject(ctxt
->context
, str
);
9169 * xmlXPathSubstringBeforeFunction:
9170 * @ctxt: the XPath Parser context
9171 * @nargs: the number of arguments
9173 * Implement the substring-before() XPath function
9174 * string substring-before(string, string)
9175 * The substring-before function returns the substring of the first
9176 * argument string that precedes the first occurrence of the second
9177 * argument string in the first argument string, or the empty string
9178 * if the first argument string does not contain the second argument
9179 * string. For example, substring-before("1999/04/01","/") returns 1999.
9182 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9183 xmlXPathObjectPtr str
;
9184 xmlXPathObjectPtr find
;
9186 const xmlChar
*point
;
9191 find
= valuePop(ctxt
);
9193 str
= valuePop(ctxt
);
9195 target
= xmlBufCreate();
9197 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9199 offset
= (int)(point
- str
->stringval
);
9200 xmlBufAdd(target
, str
->stringval
, offset
);
9202 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9203 xmlBufContent(target
)));
9206 xmlXPathReleaseObject(ctxt
->context
, str
);
9207 xmlXPathReleaseObject(ctxt
->context
, find
);
9211 * xmlXPathSubstringAfterFunction:
9212 * @ctxt: the XPath Parser context
9213 * @nargs: the number of arguments
9215 * Implement the substring-after() XPath function
9216 * string substring-after(string, string)
9217 * The substring-after function returns the substring of the first
9218 * argument string that follows the first occurrence of the second
9219 * argument string in the first argument string, or the empty stringi
9220 * if the first argument string does not contain the second argument
9221 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9222 * and substring-after("1999/04/01","19") returns 99/04/01.
9225 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9226 xmlXPathObjectPtr str
;
9227 xmlXPathObjectPtr find
;
9229 const xmlChar
*point
;
9234 find
= valuePop(ctxt
);
9236 str
= valuePop(ctxt
);
9238 target
= xmlBufCreate();
9240 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9242 offset
= (int)(point
- str
->stringval
) + xmlStrlen(find
->stringval
);
9243 xmlBufAdd(target
, &str
->stringval
[offset
],
9244 xmlStrlen(str
->stringval
) - offset
);
9246 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9247 xmlBufContent(target
)));
9250 xmlXPathReleaseObject(ctxt
->context
, str
);
9251 xmlXPathReleaseObject(ctxt
->context
, find
);
9255 * xmlXPathNormalizeFunction:
9256 * @ctxt: the XPath Parser context
9257 * @nargs: the number of arguments
9259 * Implement the normalize-space() XPath function
9260 * string normalize-space(string?)
9261 * The normalize-space function returns the argument string with white
9262 * space normalized by stripping leading and trailing whitespace
9263 * and replacing sequences of whitespace characters by a single
9264 * space. Whitespace characters are the same allowed by the S production
9265 * in XML. If the argument is omitted, it defaults to the context
9266 * node converted to a string, in other words the value of the context node.
9269 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9270 xmlChar
*source
, *target
;
9273 if (ctxt
== NULL
) return;
9275 /* Use current context node */
9277 xmlXPathCacheWrapString(ctxt
->context
,
9278 xmlXPathCastNodeToString(ctxt
->context
->node
)));
9284 CHECK_TYPE(XPATH_STRING
);
9285 source
= ctxt
->value
->stringval
;
9290 /* Skip leading whitespaces */
9291 while (IS_BLANK_CH(*source
))
9294 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9297 if (IS_BLANK_CH(*source
)) {
9304 *target
++ = *source
;
9312 * xmlXPathTranslateFunction:
9313 * @ctxt: the XPath Parser context
9314 * @nargs: the number of arguments
9316 * Implement the translate() XPath function
9317 * string translate(string, string, string)
9318 * The translate function returns the first argument string with
9319 * occurrences of characters in the second argument string replaced
9320 * by the character at the corresponding position in the third argument
9321 * string. For example, translate("bar","abc","ABC") returns the string
9322 * BAr. If there is a character in the second argument string with no
9323 * character at a corresponding position in the third argument string
9324 * (because the second argument string is longer than the third argument
9325 * string), then occurrences of that character in the first argument
9326 * string are removed. For example, translate("--aaa--","abc-","ABC")
9327 * returns "AAA". If a character occurs more than once in second
9328 * argument string, then the first occurrence determines the replacement
9329 * character. If the third argument string is longer than the second
9330 * argument string, then excess characters are ignored.
9333 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9334 xmlXPathObjectPtr str
;
9335 xmlXPathObjectPtr from
;
9336 xmlXPathObjectPtr to
;
9340 const xmlChar
*point
;
9346 to
= valuePop(ctxt
);
9348 from
= valuePop(ctxt
);
9350 str
= valuePop(ctxt
);
9352 target
= xmlBufCreate();
9354 max
= xmlUTF8Strlen(to
->stringval
);
9355 for (cptr
= str
->stringval
; (ch
=*cptr
); ) {
9356 offset
= xmlUTF8Strloc(from
->stringval
, cptr
);
9359 point
= xmlUTF8Strpos(to
->stringval
, offset
);
9361 xmlBufAdd(target
, point
, xmlUTF8Strsize(point
, 1));
9364 xmlBufAdd(target
, cptr
, xmlUTF8Strsize(cptr
, 1));
9366 /* Step to next character in input */
9369 /* if not simple ascii, verify proper format */
9370 if ( (ch
& 0xc0) != 0xc0 ) {
9371 xmlGenericError(xmlGenericErrorContext
,
9372 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9373 /* not asserting an XPath error is probably better */
9376 /* then skip over remaining bytes for this char */
9377 while ( (ch
<<= 1) & 0x80 )
9378 if ( (*cptr
++ & 0xc0) != 0x80 ) {
9379 xmlGenericError(xmlGenericErrorContext
,
9380 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9381 /* not asserting an XPath error is probably better */
9384 if (ch
& 0x80) /* must have had error encountered */
9389 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9390 xmlBufContent(target
)));
9392 xmlXPathReleaseObject(ctxt
->context
, str
);
9393 xmlXPathReleaseObject(ctxt
->context
, from
);
9394 xmlXPathReleaseObject(ctxt
->context
, to
);
9398 * xmlXPathBooleanFunction:
9399 * @ctxt: the XPath Parser context
9400 * @nargs: the number of arguments
9402 * Implement the boolean() XPath function
9403 * boolean boolean(object)
9404 * The boolean function converts its argument to a boolean as follows:
9405 * - a number is true if and only if it is neither positive or
9406 * negative zero nor NaN
9407 * - a node-set is true if and only if it is non-empty
9408 * - a string is true if and only if its length is non-zero
9411 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9412 xmlXPathObjectPtr cur
;
9415 cur
= valuePop(ctxt
);
9416 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
9417 cur
= xmlXPathCacheConvertBoolean(ctxt
->context
, cur
);
9418 valuePush(ctxt
, cur
);
9422 * xmlXPathNotFunction:
9423 * @ctxt: the XPath Parser context
9424 * @nargs: the number of arguments
9426 * Implement the not() XPath function
9427 * boolean not(boolean)
9428 * The not function returns true if its argument is false,
9429 * and false otherwise.
9432 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9435 CHECK_TYPE(XPATH_BOOLEAN
);
9436 ctxt
->value
->boolval
= ! ctxt
->value
->boolval
;
9440 * xmlXPathTrueFunction:
9441 * @ctxt: the XPath Parser context
9442 * @nargs: the number of arguments
9444 * Implement the true() XPath function
9448 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9450 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9454 * xmlXPathFalseFunction:
9455 * @ctxt: the XPath Parser context
9456 * @nargs: the number of arguments
9458 * Implement the false() XPath function
9462 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9464 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9468 * xmlXPathLangFunction:
9469 * @ctxt: the XPath Parser context
9470 * @nargs: the number of arguments
9472 * Implement the lang() XPath function
9473 * boolean lang(string)
9474 * The lang function returns true or false depending on whether the
9475 * language of the context node as specified by xml:lang attributes
9476 * is the same as or is a sublanguage of the language specified by
9477 * the argument string. The language of the context node is determined
9478 * by the value of the xml:lang attribute on the context node, or, if
9479 * the context node has no xml:lang attribute, by the value of the
9480 * xml:lang attribute on the nearest ancestor of the context node that
9481 * has an xml:lang attribute. If there is no such attribute, then lang
9482 * returns false. If there is such an attribute, then lang returns
9483 * true if the attribute value is equal to the argument ignoring case,
9484 * or if there is some suffix starting with - such that the attribute
9485 * value is equal to the argument ignoring that suffix of the attribute
9486 * value and ignoring case.
9489 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9490 xmlXPathObjectPtr val
= NULL
;
9491 const xmlChar
*theLang
= NULL
;
9492 const xmlChar
*lang
;
9498 CHECK_TYPE(XPATH_STRING
);
9499 val
= valuePop(ctxt
);
9500 lang
= val
->stringval
;
9501 theLang
= xmlNodeGetLang(ctxt
->context
->node
);
9502 if ((theLang
!= NULL
) && (lang
!= NULL
)) {
9503 for (i
= 0;lang
[i
] != 0;i
++)
9504 if (toupper(lang
[i
]) != toupper(theLang
[i
]))
9506 if ((theLang
[i
] == 0) || (theLang
[i
] == '-'))
9510 if (theLang
!= NULL
)
9511 xmlFree((void *)theLang
);
9513 xmlXPathReleaseObject(ctxt
->context
, val
);
9514 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
9518 * xmlXPathNumberFunction:
9519 * @ctxt: the XPath Parser context
9520 * @nargs: the number of arguments
9522 * Implement the number() XPath function
9523 * number number(object?)
9526 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9527 xmlXPathObjectPtr cur
;
9530 if (ctxt
== NULL
) return;
9532 if (ctxt
->context
->node
== NULL
) {
9533 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0.0));
9535 xmlChar
* content
= xmlNodeGetContent(ctxt
->context
->node
);
9537 res
= xmlXPathStringEvalNumber(content
);
9538 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9545 cur
= valuePop(ctxt
);
9546 valuePush(ctxt
, xmlXPathCacheConvertNumber(ctxt
->context
, cur
));
9550 * xmlXPathSumFunction:
9551 * @ctxt: the XPath Parser context
9552 * @nargs: the number of arguments
9554 * Implement the sum() XPath function
9555 * number sum(node-set)
9556 * The sum function returns the sum of the values of the nodes in
9557 * the argument node-set.
9560 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9561 xmlXPathObjectPtr cur
;
9566 if ((ctxt
->value
== NULL
) ||
9567 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
9568 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
9569 XP_ERROR(XPATH_INVALID_TYPE
);
9570 cur
= valuePop(ctxt
);
9572 if ((cur
->nodesetval
!= NULL
) && (cur
->nodesetval
->nodeNr
!= 0)) {
9573 for (i
= 0; i
< cur
->nodesetval
->nodeNr
; i
++) {
9574 res
+= xmlXPathCastNodeToNumber(cur
->nodesetval
->nodeTab
[i
]);
9577 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9578 xmlXPathReleaseObject(ctxt
->context
, cur
);
9582 * xmlXPathFloorFunction:
9583 * @ctxt: the XPath Parser context
9584 * @nargs: the number of arguments
9586 * Implement the floor() XPath function
9587 * number floor(number)
9588 * The floor function returns the largest (closest to positive infinity)
9589 * number that is not greater than the argument and that is an integer.
9592 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9595 CHECK_TYPE(XPATH_NUMBER
);
9597 ctxt
->value
->floatval
= floor(ctxt
->value
->floatval
);
9601 * xmlXPathCeilingFunction:
9602 * @ctxt: the XPath Parser context
9603 * @nargs: the number of arguments
9605 * Implement the ceiling() XPath function
9606 * number ceiling(number)
9607 * The ceiling function returns the smallest (closest to negative infinity)
9608 * number that is not less than the argument and that is an integer.
9611 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9614 CHECK_TYPE(XPATH_NUMBER
);
9617 /* Work around buggy ceil() function on AIX */
9618 ctxt
->value
->floatval
= copysign(ceil(ctxt
->value
->floatval
), ctxt
->value
->floatval
);
9620 ctxt
->value
->floatval
= ceil(ctxt
->value
->floatval
);
9625 * xmlXPathRoundFunction:
9626 * @ctxt: the XPath Parser context
9627 * @nargs: the number of arguments
9629 * Implement the round() XPath function
9630 * number round(number)
9631 * The round function returns the number that is closest to the
9632 * argument and that is an integer. If there are two such numbers,
9633 * then the one that is closest to positive infinity is returned.
9636 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9641 CHECK_TYPE(XPATH_NUMBER
);
9643 f
= ctxt
->value
->floatval
;
9645 if ((f
>= -0.5) && (f
< 0.5)) {
9646 /* Handles negative zero. */
9647 ctxt
->value
->floatval
*= 0.0;
9650 double rounded
= floor(f
);
9651 if (f
- rounded
>= 0.5)
9653 ctxt
->value
->floatval
= rounded
;
9657 /************************************************************************
9661 ************************************************************************/
9664 * a few forward declarations since we use a recursive call based
9667 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
);
9668 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
);
9669 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
);
9670 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt
);
9671 static xmlChar
* xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
,
9675 * xmlXPathCurrentChar:
9676 * @ctxt: the XPath parser context
9677 * @cur: pointer to the beginning of the char
9678 * @len: pointer to the length of the char read
9680 * The current char value, if using UTF-8 this may actually span multiple
9681 * bytes in the input buffer.
9683 * Returns the current char value and its length
9687 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt
, int *len
) {
9697 * We are supposed to handle UTF8, check it's valid
9698 * From rfc2044: encoding of the Unicode values on UTF-8:
9700 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9701 * 0000 0000-0000 007F 0xxxxxxx
9702 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9703 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9705 * Check for the 0x110000 limit too
9709 if ((cur
[1] & 0xc0) != 0x80)
9710 goto encoding_error
;
9711 if ((c
& 0xe0) == 0xe0) {
9713 if ((cur
[2] & 0xc0) != 0x80)
9714 goto encoding_error
;
9715 if ((c
& 0xf0) == 0xf0) {
9716 if (((c
& 0xf8) != 0xf0) ||
9717 ((cur
[3] & 0xc0) != 0x80))
9718 goto encoding_error
;
9721 val
= (cur
[0] & 0x7) << 18;
9722 val
|= (cur
[1] & 0x3f) << 12;
9723 val
|= (cur
[2] & 0x3f) << 6;
9724 val
|= cur
[3] & 0x3f;
9728 val
= (cur
[0] & 0xf) << 12;
9729 val
|= (cur
[1] & 0x3f) << 6;
9730 val
|= cur
[2] & 0x3f;
9735 val
= (cur
[0] & 0x1f) << 6;
9736 val
|= cur
[1] & 0x3f;
9738 if (!IS_CHAR(val
)) {
9739 XP_ERROR0(XPATH_INVALID_CHAR_ERROR
);
9749 * If we detect an UTF8 error that probably means that the
9750 * input encoding didn't get properly advertised in the
9751 * declaration header. Report the error and switch the encoding
9752 * to ISO-Latin-1 (if you don't like this policy, just declare the
9756 XP_ERROR0(XPATH_ENCODING_ERROR
);
9760 * xmlXPathParseNCName:
9761 * @ctxt: the XPath Parser context
9763 * parse an XML namespace non qualified name.
9765 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9767 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9768 * CombiningChar | Extender
9770 * Returns the namespace name or NULL
9774 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt
) {
9779 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9781 * Accelerator for simple ASCII names
9784 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9785 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9788 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9789 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9790 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9791 (*in
== '_') || (*in
== '.') ||
9794 if ((*in
== ' ') || (*in
== '>') || (*in
== '/') ||
9795 (*in
== '[') || (*in
== ']') || (*in
== ':') ||
9796 (*in
== '@') || (*in
== '*')) {
9797 count
= in
- ctxt
->cur
;
9800 ret
= xmlStrndup(ctxt
->cur
, count
);
9805 return(xmlXPathParseNameComplex(ctxt
, 0));
9810 * xmlXPathParseQName:
9811 * @ctxt: the XPath Parser context
9812 * @prefix: a xmlChar **
9814 * parse an XML qualified name
9816 * [NS 5] QName ::= (Prefix ':')? LocalPart
9818 * [NS 6] Prefix ::= NCName
9820 * [NS 7] LocalPart ::= NCName
9822 * Returns the function returns the local part, and prefix is updated
9823 * to get the Prefix if any.
9827 xmlXPathParseQName(xmlXPathParserContextPtr ctxt
, xmlChar
**prefix
) {
9828 xmlChar
*ret
= NULL
;
9831 ret
= xmlXPathParseNCName(ctxt
);
9832 if (ret
&& CUR
== ':') {
9835 ret
= xmlXPathParseNCName(ctxt
);
9841 * xmlXPathParseName:
9842 * @ctxt: the XPath Parser context
9846 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9847 * CombiningChar | Extender
9849 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9851 * Returns the namespace name or NULL
9855 xmlXPathParseName(xmlXPathParserContextPtr ctxt
) {
9860 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9862 * Accelerator for simple ASCII names
9865 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9866 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9867 (*in
== '_') || (*in
== ':')) {
9869 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9870 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9871 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9872 (*in
== '_') || (*in
== '-') ||
9873 (*in
== ':') || (*in
== '.'))
9875 if ((*in
> 0) && (*in
< 0x80)) {
9876 count
= in
- ctxt
->cur
;
9877 if (count
> XML_MAX_NAME_LENGTH
) {
9879 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9881 ret
= xmlStrndup(ctxt
->cur
, count
);
9886 return(xmlXPathParseNameComplex(ctxt
, 1));
9890 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
, int qualified
) {
9891 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
9896 * Handler for more complex cases
9899 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
9900 (c
== '[') || (c
== ']') || (c
== '@') || /* accelerators */
9901 (c
== '*') || /* accelerators */
9902 (!IS_LETTER(c
) && (c
!= '_') &&
9903 ((!qualified
) || (c
!= ':')))) {
9907 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
9908 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
9909 (c
== '.') || (c
== '-') ||
9910 (c
== '_') || ((qualified
) && (c
== ':')) ||
9911 (IS_COMBINING(c
)) ||
9912 (IS_EXTENDER(c
)))) {
9913 COPY_BUF(l
,buf
,len
,c
);
9916 if (len
>= XML_MAX_NAMELEN
) {
9918 * Okay someone managed to make a huge name, so he's ready to pay
9919 * for the processing speed.
9924 if (len
> XML_MAX_NAME_LENGTH
) {
9925 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9927 buffer
= (xmlChar
*) xmlMallocAtomic(max
* sizeof(xmlChar
));
9928 if (buffer
== NULL
) {
9929 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
9931 memcpy(buffer
, buf
, len
);
9932 while ((IS_LETTER(c
)) || (IS_DIGIT(c
)) || /* test bigname.xml */
9933 (c
== '.') || (c
== '-') ||
9934 (c
== '_') || ((qualified
) && (c
== ':')) ||
9935 (IS_COMBINING(c
)) ||
9937 if (len
+ 10 > max
) {
9939 if (max
> XML_MAX_NAME_LENGTH
) {
9941 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9944 tmp
= (xmlChar
*) xmlRealloc(buffer
,
9945 max
* sizeof(xmlChar
));
9948 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
9952 COPY_BUF(l
,buffer
,len
,c
);
9962 return(xmlStrndup(buf
, len
));
9968 * xmlXPathStringEvalNumber:
9969 * @str: A string to scan
9971 * [30a] Float ::= Number ('e' Digits?)?
9973 * [30] Number ::= Digits ('.' Digits?)?
9975 * [31] Digits ::= [0-9]+
9977 * Compile a Number in the string
9978 * In complement of the Number expression, this function also handles
9979 * negative values : '-' Number.
9981 * Returns the double value.
9984 xmlXPathStringEvalNumber(const xmlChar
*str
) {
9985 const xmlChar
*cur
= str
;
9990 int is_exponent_negative
= 0;
9992 unsigned long tmp
= 0;
9995 if (cur
== NULL
) return(0);
9996 while (IS_BLANK_CH(*cur
)) cur
++;
9997 if ((*cur
!= '.') && ((*cur
< '0') || (*cur
> '9')) && (*cur
!= '-')) {
9998 return(xmlXPathNAN
);
10007 * tmp/temp is a workaround against a gcc compiler bug
10008 * http://veillard.com/gcc.bug
10011 while ((*cur
>= '0') && (*cur
<= '9')) {
10013 tmp
= (*cur
- '0');
10016 temp
= (double) tmp
;
10021 while ((*cur
>= '0') && (*cur
<= '9')) {
10022 ret
= ret
* 10 + (*cur
- '0');
10029 int v
, frac
= 0, max
;
10030 double fraction
= 0;
10033 if (((*cur
< '0') || (*cur
> '9')) && (!ok
)) {
10034 return(xmlXPathNAN
);
10036 while (*cur
== '0') {
10040 max
= frac
+ MAX_FRAC
;
10041 while (((*cur
>= '0') && (*cur
<= '9')) && (frac
< max
)) {
10043 fraction
= fraction
* 10 + v
;
10047 fraction
/= pow(10.0, frac
);
10048 ret
= ret
+ fraction
;
10049 while ((*cur
>= '0') && (*cur
<= '9'))
10052 if ((*cur
== 'e') || (*cur
== 'E')) {
10055 is_exponent_negative
= 1;
10057 } else if (*cur
== '+') {
10060 while ((*cur
>= '0') && (*cur
<= '9')) {
10061 if (exponent
< 1000000)
10062 exponent
= exponent
* 10 + (*cur
- '0');
10066 while (IS_BLANK_CH(*cur
)) cur
++;
10067 if (*cur
!= 0) return(xmlXPathNAN
);
10068 if (isneg
) ret
= -ret
;
10069 if (is_exponent_negative
) exponent
= -exponent
;
10070 ret
*= pow(10.0, (double)exponent
);
10075 * xmlXPathCompNumber:
10076 * @ctxt: the XPath Parser context
10078 * [30] Number ::= Digits ('.' Digits?)?
10080 * [31] Digits ::= [0-9]+
10082 * Compile a Number, then push it on the stack
10086 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt
)
10091 int is_exponent_negative
= 0;
10092 xmlXPathObjectPtr num
;
10094 unsigned long tmp
= 0;
10099 if ((CUR
!= '.') && ((CUR
< '0') || (CUR
> '9'))) {
10100 XP_ERROR(XPATH_NUMBER_ERROR
);
10104 * tmp/temp is a workaround against a gcc compiler bug
10105 * http://veillard.com/gcc.bug
10108 while ((CUR
>= '0') && (CUR
<= '9')) {
10113 temp
= (double) tmp
;
10118 while ((CUR
>= '0') && (CUR
<= '9')) {
10119 ret
= ret
* 10 + (CUR
- '0');
10125 int v
, frac
= 0, max
;
10126 double fraction
= 0;
10129 if (((CUR
< '0') || (CUR
> '9')) && (!ok
)) {
10130 XP_ERROR(XPATH_NUMBER_ERROR
);
10132 while (CUR
== '0') {
10136 max
= frac
+ MAX_FRAC
;
10137 while ((CUR
>= '0') && (CUR
<= '9') && (frac
< max
)) {
10139 fraction
= fraction
* 10 + v
;
10143 fraction
/= pow(10.0, frac
);
10144 ret
= ret
+ fraction
;
10145 while ((CUR
>= '0') && (CUR
<= '9'))
10148 if ((CUR
== 'e') || (CUR
== 'E')) {
10151 is_exponent_negative
= 1;
10153 } else if (CUR
== '+') {
10156 while ((CUR
>= '0') && (CUR
<= '9')) {
10157 if (exponent
< 1000000)
10158 exponent
= exponent
* 10 + (CUR
- '0');
10161 if (is_exponent_negative
)
10162 exponent
= -exponent
;
10163 ret
*= pow(10.0, (double) exponent
);
10165 num
= xmlXPathCacheNewFloat(ctxt
->context
, ret
);
10167 ctxt
->error
= XPATH_MEMORY_ERROR
;
10168 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_NUMBER
, 0, 0, num
,
10170 xmlXPathReleaseObject(ctxt
->context
, num
);
10175 * xmlXPathParseLiteral:
10176 * @ctxt: the XPath Parser context
10180 * [29] Literal ::= '"' [^"]* '"'
10183 * Returns the value found or NULL in case of error
10186 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt
) {
10188 xmlChar
*ret
= NULL
;
10193 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10195 if (!IS_CHAR_CH(CUR
)) {
10196 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10198 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10201 } else if (CUR
== '\'') {
10204 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10206 if (!IS_CHAR_CH(CUR
)) {
10207 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10209 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10213 XP_ERRORNULL(XPATH_START_LITERAL_ERROR
);
10219 * xmlXPathCompLiteral:
10220 * @ctxt: the XPath Parser context
10222 * Parse a Literal and push it on the stack.
10224 * [29] Literal ::= '"' [^"]* '"'
10227 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10230 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt
) {
10232 xmlChar
*ret
= NULL
;
10233 xmlXPathObjectPtr lit
;
10238 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10240 if (!IS_CHAR_CH(CUR
)) {
10241 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10243 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10246 } else if (CUR
== '\'') {
10249 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10251 if (!IS_CHAR_CH(CUR
)) {
10252 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10254 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10258 XP_ERROR(XPATH_START_LITERAL_ERROR
);
10260 if (ret
== NULL
) return;
10261 lit
= xmlXPathCacheNewString(ctxt
->context
, ret
);
10263 ctxt
->error
= XPATH_MEMORY_ERROR
;
10264 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_STRING
, 0, 0, lit
,
10266 xmlXPathReleaseObject(ctxt
->context
, lit
);
10272 * xmlXPathCompVariableReference:
10273 * @ctxt: the XPath Parser context
10275 * Parse a VariableReference, evaluate it and push it on the stack.
10277 * The variable bindings consist of a mapping from variable names
10278 * to variable values. The value of a variable is an object, which can be
10279 * of any of the types that are possible for the value of an expression,
10280 * and may also be of additional types not specified here.
10282 * Early evaluation is possible since:
10283 * The variable bindings [...] used to evaluate a subexpression are
10284 * always the same as those used to evaluate the containing expression.
10286 * [36] VariableReference ::= '$' QName
10289 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt
) {
10295 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10298 name
= xmlXPathParseQName(ctxt
, &prefix
);
10299 if (name
== NULL
) {
10301 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10303 ctxt
->comp
->last
= -1;
10304 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE
, 0, 0, 0, name
, prefix
) == -1) {
10309 if ((ctxt
->context
!= NULL
) && (ctxt
->context
->flags
& XML_XPATH_NOVAR
)) {
10310 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR
);
10315 * xmlXPathIsNodeType:
10316 * @name: a name string
10318 * Is the name given a NodeType one.
10320 * [38] NodeType ::= 'comment'
10322 * | 'processing-instruction'
10325 * Returns 1 if true 0 otherwise
10328 xmlXPathIsNodeType(const xmlChar
*name
) {
10332 if (xmlStrEqual(name
, BAD_CAST
"node"))
10334 if (xmlStrEqual(name
, BAD_CAST
"text"))
10336 if (xmlStrEqual(name
, BAD_CAST
"comment"))
10338 if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
10344 * xmlXPathCompFunctionCall:
10345 * @ctxt: the XPath Parser context
10347 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10348 * [17] Argument ::= Expr
10350 * Compile a function call, the evaluation of all arguments are
10351 * pushed on the stack
10354 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt
) {
10360 name
= xmlXPathParseQName(ctxt
, &prefix
);
10361 if (name
== NULL
) {
10363 XP_ERROR(XPATH_EXPR_ERROR
);
10367 if (prefix
== NULL
)
10368 xmlGenericError(xmlGenericErrorContext
, "Calling function %s\n",
10371 xmlGenericError(xmlGenericErrorContext
, "Calling function %s:%s\n",
10378 XP_ERROR(XPATH_EXPR_ERROR
);
10384 * Optimization for count(): we don't need the node-set to be sorted.
10386 if ((prefix
== NULL
) && (name
[0] == 'c') &&
10387 xmlStrEqual(name
, BAD_CAST
"count"))
10391 ctxt
->comp
->last
= -1;
10394 int op1
= ctxt
->comp
->last
;
10395 ctxt
->comp
->last
= -1;
10396 xmlXPathCompileExpr(ctxt
, sort
);
10397 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
10402 PUSH_BINARY_EXPR(XPATH_OP_ARG
, op1
, ctxt
->comp
->last
, 0, 0);
10404 if (CUR
== ')') break;
10408 XP_ERROR(XPATH_EXPR_ERROR
);
10414 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION
, nbargs
, 0, 0, name
, prefix
) == -1) {
10423 * xmlXPathCompPrimaryExpr:
10424 * @ctxt: the XPath Parser context
10426 * [15] PrimaryExpr ::= VariableReference
10432 * Compile a primary expression.
10435 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt
) {
10437 if (CUR
== '$') xmlXPathCompVariableReference(ctxt
);
10438 else if (CUR
== '(') {
10441 xmlXPathCompileExpr(ctxt
, 1);
10444 XP_ERROR(XPATH_EXPR_ERROR
);
10448 } else if (IS_ASCII_DIGIT(CUR
) || (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10449 xmlXPathCompNumber(ctxt
);
10450 } else if ((CUR
== '\'') || (CUR
== '"')) {
10451 xmlXPathCompLiteral(ctxt
);
10453 xmlXPathCompFunctionCall(ctxt
);
10459 * xmlXPathCompFilterExpr:
10460 * @ctxt: the XPath Parser context
10462 * [20] FilterExpr ::= PrimaryExpr
10463 * | FilterExpr Predicate
10465 * Compile a filter expression.
10466 * Square brackets are used to filter expressions in the same way that
10467 * they are used in location paths. It is an error if the expression to
10468 * be filtered does not evaluate to a node-set. The context node list
10469 * used for evaluating the expression in square brackets is the node-set
10470 * to be filtered listed in document order.
10474 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt
) {
10475 xmlXPathCompPrimaryExpr(ctxt
);
10479 while (CUR
== '[') {
10480 xmlXPathCompPredicate(ctxt
, 1);
10488 * xmlXPathScanName:
10489 * @ctxt: the XPath Parser context
10491 * Trickery: parse an XML name but without consuming the input flow
10492 * Needed to avoid insanity in the parser state.
10494 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10495 * CombiningChar | Extender
10497 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10499 * [6] Names ::= Name (S Name)*
10501 * Returns the Name parsed or NULL
10505 xmlXPathScanName(xmlXPathParserContextPtr ctxt
) {
10508 const xmlChar
*cur
;
10514 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
10515 (!IS_LETTER(c
) && (c
!= '_') &&
10520 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
10521 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
10522 (c
== '.') || (c
== '-') ||
10523 (c
== '_') || (c
== ':') ||
10524 (IS_COMBINING(c
)) ||
10525 (IS_EXTENDER(c
)))) {
10529 ret
= xmlStrndup(cur
, ctxt
->cur
- cur
);
10535 * xmlXPathCompPathExpr:
10536 * @ctxt: the XPath Parser context
10538 * [19] PathExpr ::= LocationPath
10540 * | FilterExpr '/' RelativeLocationPath
10541 * | FilterExpr '//' RelativeLocationPath
10543 * Compile a path expression.
10544 * The / operator and // operators combine an arbitrary expression
10545 * and a relative location path. It is an error if the expression
10546 * does not evaluate to a node-set.
10547 * The / operator does composition in the same way as when / is
10548 * used in a location path. As in location paths, // is short for
10549 * /descendant-or-self::node()/.
10553 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt
) {
10554 int lc
= 1; /* Should we branch to LocationPath ? */
10555 xmlChar
*name
= NULL
; /* we may have to preparse a name to find out */
10558 if ((CUR
== '$') || (CUR
== '(') ||
10559 (IS_ASCII_DIGIT(CUR
)) ||
10560 (CUR
== '\'') || (CUR
== '"') ||
10561 (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10563 } else if (CUR
== '*') {
10564 /* relative or absolute location path */
10566 } else if (CUR
== '/') {
10567 /* relative or absolute location path */
10569 } else if (CUR
== '@') {
10570 /* relative abbreviated attribute location path */
10572 } else if (CUR
== '.') {
10573 /* relative abbreviated attribute location path */
10577 * Problem is finding if we have a name here whether it's:
10579 * - a function call in which case it's followed by '('
10580 * - an axis in which case it's followed by ':'
10582 * We do an a priori analysis here rather than having to
10583 * maintain parsed token content through the recursive function
10584 * calls. This looks uglier but makes the code easier to
10585 * read/write/debug.
10588 name
= xmlXPathScanName(ctxt
);
10589 if ((name
!= NULL
) && (xmlStrstr(name
, (xmlChar
*) "::") != NULL
)) {
10591 xmlGenericError(xmlGenericErrorContext
,
10592 "PathExpr: Axis\n");
10596 } else if (name
!= NULL
) {
10597 int len
=xmlStrlen(name
);
10600 while (NXT(len
) != 0) {
10601 if (NXT(len
) == '/') {
10604 xmlGenericError(xmlGenericErrorContext
,
10605 "PathExpr: AbbrRelLocation\n");
10609 } else if (IS_BLANK_CH(NXT(len
))) {
10610 /* ignore blanks */
10612 } else if (NXT(len
) == ':') {
10614 xmlGenericError(xmlGenericErrorContext
,
10615 "PathExpr: AbbrRelLocation\n");
10619 } else if ((NXT(len
) == '(')) {
10620 /* Node Type or Function */
10621 if (xmlXPathIsNodeType(name
)) {
10623 xmlGenericError(xmlGenericErrorContext
,
10624 "PathExpr: Type search\n");
10627 #ifdef LIBXML_XPTR_LOCS_ENABLED
10628 } else if (ctxt
->xptr
&&
10629 xmlStrEqual(name
, BAD_CAST
"range-to")) {
10634 xmlGenericError(xmlGenericErrorContext
,
10635 "PathExpr: function call\n");
10640 } else if ((NXT(len
) == '[')) {
10643 xmlGenericError(xmlGenericErrorContext
,
10644 "PathExpr: AbbrRelLocation\n");
10648 } else if ((NXT(len
) == '<') || (NXT(len
) == '>') ||
10649 (NXT(len
) == '=')) {
10658 if (NXT(len
) == 0) {
10660 xmlGenericError(xmlGenericErrorContext
,
10661 "PathExpr: AbbrRelLocation\n");
10668 /* make sure all cases are covered explicitly */
10669 XP_ERROR(XPATH_EXPR_ERROR
);
10675 PUSH_LEAVE_EXPR(XPATH_OP_ROOT
, 0, 0);
10677 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10679 xmlXPathCompLocationPath(ctxt
);
10681 xmlXPathCompFilterExpr(ctxt
);
10683 if ((CUR
== '/') && (NXT(1) == '/')) {
10687 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
10688 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
10690 xmlXPathCompRelativeLocationPath(ctxt
);
10691 } else if (CUR
== '/') {
10692 xmlXPathCompRelativeLocationPath(ctxt
);
10699 * xmlXPathCompUnionExpr:
10700 * @ctxt: the XPath Parser context
10702 * [18] UnionExpr ::= PathExpr
10703 * | UnionExpr '|' PathExpr
10705 * Compile an union expression.
10709 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt
) {
10710 xmlXPathCompPathExpr(ctxt
);
10713 while (CUR
== '|') {
10714 int op1
= ctxt
->comp
->last
;
10715 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10719 xmlXPathCompPathExpr(ctxt
);
10721 PUSH_BINARY_EXPR(XPATH_OP_UNION
, op1
, ctxt
->comp
->last
, 0, 0);
10728 * xmlXPathCompUnaryExpr:
10729 * @ctxt: the XPath Parser context
10731 * [27] UnaryExpr ::= UnionExpr
10734 * Compile an unary expression.
10738 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt
) {
10743 while (CUR
== '-') {
10750 xmlXPathCompUnionExpr(ctxt
);
10754 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 2, 0);
10756 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 3, 0);
10761 * xmlXPathCompMultiplicativeExpr:
10762 * @ctxt: the XPath Parser context
10764 * [26] MultiplicativeExpr ::= UnaryExpr
10765 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10766 * | MultiplicativeExpr 'div' UnaryExpr
10767 * | MultiplicativeExpr 'mod' UnaryExpr
10768 * [34] MultiplyOperator ::= '*'
10770 * Compile an Additive expression.
10774 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt
) {
10775 xmlXPathCompUnaryExpr(ctxt
);
10778 while ((CUR
== '*') ||
10779 ((CUR
== 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10780 ((CUR
== 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10782 int op1
= ctxt
->comp
->last
;
10787 } else if (CUR
== 'd') {
10790 } else if (CUR
== 'm') {
10795 xmlXPathCompUnaryExpr(ctxt
);
10797 PUSH_BINARY_EXPR(XPATH_OP_MULT
, op1
, ctxt
->comp
->last
, op
, 0);
10803 * xmlXPathCompAdditiveExpr:
10804 * @ctxt: the XPath Parser context
10806 * [25] AdditiveExpr ::= MultiplicativeExpr
10807 * | AdditiveExpr '+' MultiplicativeExpr
10808 * | AdditiveExpr '-' MultiplicativeExpr
10810 * Compile an Additive expression.
10814 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt
) {
10816 xmlXPathCompMultiplicativeExpr(ctxt
);
10819 while ((CUR
== '+') || (CUR
== '-')) {
10821 int op1
= ctxt
->comp
->last
;
10823 if (CUR
== '+') plus
= 1;
10827 xmlXPathCompMultiplicativeExpr(ctxt
);
10829 PUSH_BINARY_EXPR(XPATH_OP_PLUS
, op1
, ctxt
->comp
->last
, plus
, 0);
10835 * xmlXPathCompRelationalExpr:
10836 * @ctxt: the XPath Parser context
10838 * [24] RelationalExpr ::= AdditiveExpr
10839 * | RelationalExpr '<' AdditiveExpr
10840 * | RelationalExpr '>' AdditiveExpr
10841 * | RelationalExpr '<=' AdditiveExpr
10842 * | RelationalExpr '>=' AdditiveExpr
10844 * A <= B > C is allowed ? Answer from James, yes with
10845 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10846 * which is basically what got implemented.
10848 * Compile a Relational expression, then push the result
10853 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt
) {
10854 xmlXPathCompAdditiveExpr(ctxt
);
10857 while ((CUR
== '<') || (CUR
== '>')) {
10859 int op1
= ctxt
->comp
->last
;
10861 if (CUR
== '<') inf
= 1;
10863 if (NXT(1) == '=') strict
= 0;
10868 xmlXPathCompAdditiveExpr(ctxt
);
10870 PUSH_BINARY_EXPR(XPATH_OP_CMP
, op1
, ctxt
->comp
->last
, inf
, strict
);
10876 * xmlXPathCompEqualityExpr:
10877 * @ctxt: the XPath Parser context
10879 * [23] EqualityExpr ::= RelationalExpr
10880 * | EqualityExpr '=' RelationalExpr
10881 * | EqualityExpr '!=' RelationalExpr
10883 * A != B != C is allowed ? Answer from James, yes with
10884 * (RelationalExpr = RelationalExpr) = RelationalExpr
10885 * (RelationalExpr != RelationalExpr) != RelationalExpr
10886 * which is basically what got implemented.
10888 * Compile an Equality expression.
10892 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt
) {
10893 xmlXPathCompRelationalExpr(ctxt
);
10896 while ((CUR
== '=') || ((CUR
== '!') && (NXT(1) == '='))) {
10898 int op1
= ctxt
->comp
->last
;
10900 if (CUR
== '=') eq
= 1;
10905 xmlXPathCompRelationalExpr(ctxt
);
10907 PUSH_BINARY_EXPR(XPATH_OP_EQUAL
, op1
, ctxt
->comp
->last
, eq
, 0);
10913 * xmlXPathCompAndExpr:
10914 * @ctxt: the XPath Parser context
10916 * [22] AndExpr ::= EqualityExpr
10917 * | AndExpr 'and' EqualityExpr
10919 * Compile an AND expression.
10923 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt
) {
10924 xmlXPathCompEqualityExpr(ctxt
);
10927 while ((CUR
== 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10928 int op1
= ctxt
->comp
->last
;
10931 xmlXPathCompEqualityExpr(ctxt
);
10933 PUSH_BINARY_EXPR(XPATH_OP_AND
, op1
, ctxt
->comp
->last
, 0, 0);
10939 * xmlXPathCompileExpr:
10940 * @ctxt: the XPath Parser context
10942 * [14] Expr ::= OrExpr
10943 * [21] OrExpr ::= AndExpr
10944 * | OrExpr 'or' AndExpr
10946 * Parse and compile an expression
10949 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
) {
10950 xmlXPathContextPtr xpctxt
= ctxt
->context
;
10952 if (xpctxt
!= NULL
) {
10953 if (xpctxt
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
10954 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED
);
10956 * Parsing a single '(' pushes about 10 functions on the call stack
10957 * before recursing!
10959 xpctxt
->depth
+= 10;
10962 xmlXPathCompAndExpr(ctxt
);
10965 while ((CUR
== 'o') && (NXT(1) == 'r')) {
10966 int op1
= ctxt
->comp
->last
;
10969 xmlXPathCompAndExpr(ctxt
);
10971 PUSH_BINARY_EXPR(XPATH_OP_OR
, op1
, ctxt
->comp
->last
, 0, 0);
10974 if ((sort
) && (ctxt
->comp
->steps
[ctxt
->comp
->last
].op
!= XPATH_OP_VALUE
)) {
10975 /* more ops could be optimized too */
10977 * This is the main place to eliminate sorting for
10978 * operations which don't require a sorted node-set.
10981 PUSH_UNARY_EXPR(XPATH_OP_SORT
, ctxt
->comp
->last
, 0, 0);
10984 if (xpctxt
!= NULL
)
10985 xpctxt
->depth
-= 10;
10989 * xmlXPathCompPredicate:
10990 * @ctxt: the XPath Parser context
10991 * @filter: act as a filter
10993 * [8] Predicate ::= '[' PredicateExpr ']'
10994 * [9] PredicateExpr ::= Expr
10996 * Compile a predicate expression
10999 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
) {
11000 int op1
= ctxt
->comp
->last
;
11004 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11009 ctxt
->comp
->last
= -1;
11011 * This call to xmlXPathCompileExpr() will deactivate sorting
11012 * of the predicate result.
11013 * TODO: Sorting is still activated for filters, since I'm not
11014 * sure if needed. Normally sorting should not be needed, since
11015 * a filter can only diminish the number of items in a sequence,
11016 * but won't change its order; so if the initial sequence is sorted,
11017 * subsequent sorting is not needed.
11020 xmlXPathCompileExpr(ctxt
, 0);
11022 xmlXPathCompileExpr(ctxt
, 1);
11026 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11030 PUSH_BINARY_EXPR(XPATH_OP_FILTER
, op1
, ctxt
->comp
->last
, 0, 0);
11032 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE
, op1
, ctxt
->comp
->last
, 0, 0);
11039 * xmlXPathCompNodeTest:
11040 * @ctxt: the XPath Parser context
11041 * @test: pointer to a xmlXPathTestVal
11042 * @type: pointer to a xmlXPathTypeVal
11043 * @prefix: placeholder for a possible name prefix
11045 * [7] NodeTest ::= NameTest
11046 * | NodeType '(' ')'
11047 * | 'processing-instruction' '(' Literal ')'
11049 * [37] NameTest ::= '*'
11052 * [38] NodeType ::= 'comment'
11054 * | 'processing-instruction'
11057 * Returns the name found and updates @test, @type and @prefix appropriately
11060 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt
, xmlXPathTestVal
*test
,
11061 xmlXPathTypeVal
*type
, xmlChar
**prefix
,
11065 if ((test
== NULL
) || (type
== NULL
) || (prefix
== NULL
)) {
11069 *type
= (xmlXPathTypeVal
) 0;
11070 *test
= (xmlXPathTestVal
) 0;
11074 if ((name
== NULL
) && (CUR
== '*')) {
11079 *test
= NODE_TEST_ALL
;
11084 name
= xmlXPathParseNCName(ctxt
);
11085 if (name
== NULL
) {
11086 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11089 blanks
= IS_BLANK_CH(CUR
);
11094 * NodeType or PI search
11096 if (xmlStrEqual(name
, BAD_CAST
"comment"))
11097 *type
= NODE_TYPE_COMMENT
;
11098 else if (xmlStrEqual(name
, BAD_CAST
"node"))
11099 *type
= NODE_TYPE_NODE
;
11100 else if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
11101 *type
= NODE_TYPE_PI
;
11102 else if (xmlStrEqual(name
, BAD_CAST
"text"))
11103 *type
= NODE_TYPE_TEXT
;
11107 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11110 *test
= NODE_TEST_TYPE
;
11113 if (*type
== NODE_TYPE_PI
) {
11115 * Specific case: search a PI by name.
11121 name
= xmlXPathParseLiteral(ctxt
);
11122 if (name
== NULL
) {
11123 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11125 *test
= NODE_TEST_PI
;
11132 XP_ERRORNULL(XPATH_UNCLOSED_ERROR
);
11137 *test
= NODE_TEST_NAME
;
11138 if ((!blanks
) && (CUR
== ':')) {
11142 * Since currently the parser context don't have a
11143 * namespace list associated:
11144 * The namespace name for this prefix can be computed
11145 * only at evaluation time. The compilation is done
11146 * outside of any context.
11149 *prefix
= xmlXPathNsLookup(ctxt
->context
, name
);
11152 if (*prefix
== NULL
) {
11153 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
11164 *test
= NODE_TEST_ALL
;
11168 name
= xmlXPathParseNCName(ctxt
);
11169 if (name
== NULL
) {
11170 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11177 * xmlXPathIsAxisName:
11178 * @name: a preparsed name token
11180 * [6] AxisName ::= 'ancestor'
11181 * | 'ancestor-or-self'
11185 * | 'descendant-or-self'
11187 * | 'following-sibling'
11191 * | 'preceding-sibling'
11194 * Returns the axis or 0
11196 static xmlXPathAxisVal
11197 xmlXPathIsAxisName(const xmlChar
*name
) {
11198 xmlXPathAxisVal ret
= (xmlXPathAxisVal
) 0;
11201 if (xmlStrEqual(name
, BAD_CAST
"ancestor"))
11202 ret
= AXIS_ANCESTOR
;
11203 if (xmlStrEqual(name
, BAD_CAST
"ancestor-or-self"))
11204 ret
= AXIS_ANCESTOR_OR_SELF
;
11205 if (xmlStrEqual(name
, BAD_CAST
"attribute"))
11206 ret
= AXIS_ATTRIBUTE
;
11209 if (xmlStrEqual(name
, BAD_CAST
"child"))
11213 if (xmlStrEqual(name
, BAD_CAST
"descendant"))
11214 ret
= AXIS_DESCENDANT
;
11215 if (xmlStrEqual(name
, BAD_CAST
"descendant-or-self"))
11216 ret
= AXIS_DESCENDANT_OR_SELF
;
11219 if (xmlStrEqual(name
, BAD_CAST
"following"))
11220 ret
= AXIS_FOLLOWING
;
11221 if (xmlStrEqual(name
, BAD_CAST
"following-sibling"))
11222 ret
= AXIS_FOLLOWING_SIBLING
;
11225 if (xmlStrEqual(name
, BAD_CAST
"namespace"))
11226 ret
= AXIS_NAMESPACE
;
11229 if (xmlStrEqual(name
, BAD_CAST
"parent"))
11231 if (xmlStrEqual(name
, BAD_CAST
"preceding"))
11232 ret
= AXIS_PRECEDING
;
11233 if (xmlStrEqual(name
, BAD_CAST
"preceding-sibling"))
11234 ret
= AXIS_PRECEDING_SIBLING
;
11237 if (xmlStrEqual(name
, BAD_CAST
"self"))
11245 * xmlXPathCompStep:
11246 * @ctxt: the XPath Parser context
11248 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11249 * | AbbreviatedStep
11251 * [12] AbbreviatedStep ::= '.' | '..'
11253 * [5] AxisSpecifier ::= AxisName '::'
11254 * | AbbreviatedAxisSpecifier
11256 * [13] AbbreviatedAxisSpecifier ::= '@'?
11258 * Modified for XPtr range support as:
11260 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11261 * | AbbreviatedStep
11262 * | 'range-to' '(' Expr ')' Predicate*
11264 * Compile one step in a Location Path
11265 * A location step of . is short for self::node(). This is
11266 * particularly useful in conjunction with //. For example, the
11267 * location path .//para is short for
11268 * self::node()/descendant-or-self::node()/child::para
11269 * and so will select all para descendant elements of the context
11271 * Similarly, a location step of .. is short for parent::node().
11272 * For example, ../title is short for parent::node()/child::title
11273 * and so will select the title children of the parent of the context
11277 xmlXPathCompStep(xmlXPathParserContextPtr ctxt
) {
11278 #ifdef LIBXML_XPTR_LOCS_ENABLED
11284 if ((CUR
== '.') && (NXT(1) == '.')) {
11287 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_PARENT
,
11288 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11289 } else if (CUR
== '.') {
11293 xmlChar
*name
= NULL
;
11294 xmlChar
*prefix
= NULL
;
11295 xmlXPathTestVal test
= (xmlXPathTestVal
) 0;
11296 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) 0;
11297 xmlXPathTypeVal type
= (xmlXPathTypeVal
) 0;
11301 * The modification needed for XPointer change to the production
11303 #ifdef LIBXML_XPTR_LOCS_ENABLED
11305 name
= xmlXPathParseNCName(ctxt
);
11306 if ((name
!= NULL
) && (xmlStrEqual(name
, BAD_CAST
"range-to"))) {
11307 op2
= ctxt
->comp
->last
;
11311 XP_ERROR(XPATH_EXPR_ERROR
);
11316 xmlXPathCompileExpr(ctxt
, 1);
11317 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11322 XP_ERROR(XPATH_EXPR_ERROR
);
11326 goto eval_predicates
;
11334 name
= xmlXPathParseNCName(ctxt
);
11335 if (name
!= NULL
) {
11336 axis
= xmlXPathIsAxisName(name
);
11339 if ((CUR
== ':') && (NXT(1) == ':')) {
11344 /* an element name can conflict with an axis one :-\ */
11350 } else if (CUR
== '@') {
11352 axis
= AXIS_ATTRIBUTE
;
11358 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
11363 name
= xmlXPathCompNodeTest(ctxt
, &test
, &type
, &prefix
, name
);
11367 if ((prefix
!= NULL
) && (ctxt
->context
!= NULL
) &&
11368 (ctxt
->context
->flags
& XML_XPATH_CHECKNS
)) {
11369 if (xmlXPathNsLookup(ctxt
->context
, prefix
) == NULL
) {
11370 xmlXPathErr(ctxt
, XPATH_UNDEF_PREFIX_ERROR
);
11374 xmlGenericError(xmlGenericErrorContext
,
11375 "Basis : computing new set\n");
11379 xmlGenericError(xmlGenericErrorContext
, "Basis : ");
11380 if (ctxt
->value
== NULL
)
11381 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11382 else if (ctxt
->value
->nodesetval
== NULL
)
11383 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11385 xmlGenericErrorContextNodeSet(stdout
, ctxt
->value
->nodesetval
);
11388 #ifdef LIBXML_XPTR_LOCS_ENABLED
11391 op1
= ctxt
->comp
->last
;
11392 ctxt
->comp
->last
= -1;
11395 while (CUR
== '[') {
11396 xmlXPathCompPredicate(ctxt
, 0);
11399 #ifdef LIBXML_XPTR_LOCS_ENABLED
11401 PUSH_BINARY_EXPR(XPATH_OP_RANGETO
, op2
, op1
, 0, 0);
11404 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT
, op1
, ctxt
->comp
->last
, axis
,
11405 test
, type
, (void *)prefix
, (void *)name
) == -1) {
11411 xmlGenericError(xmlGenericErrorContext
, "Step : ");
11412 if (ctxt
->value
== NULL
)
11413 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11414 else if (ctxt
->value
->nodesetval
== NULL
)
11415 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11417 xmlGenericErrorContextNodeSet(xmlGenericErrorContext
,
11418 ctxt
->value
->nodesetval
);
11423 * xmlXPathCompRelativeLocationPath:
11424 * @ctxt: the XPath Parser context
11426 * [3] RelativeLocationPath ::= Step
11427 * | RelativeLocationPath '/' Step
11428 * | AbbreviatedRelativeLocationPath
11429 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11431 * Compile a relative location path.
11434 xmlXPathCompRelativeLocationPath
11435 (xmlXPathParserContextPtr ctxt
) {
11437 if ((CUR
== '/') && (NXT(1) == '/')) {
11440 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11441 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11442 } else if (CUR
== '/') {
11446 xmlXPathCompStep(ctxt
);
11449 while (CUR
== '/') {
11450 if ((CUR
== '/') && (NXT(1) == '/')) {
11453 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11454 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11455 xmlXPathCompStep(ctxt
);
11456 } else if (CUR
== '/') {
11459 xmlXPathCompStep(ctxt
);
11466 * xmlXPathCompLocationPath:
11467 * @ctxt: the XPath Parser context
11469 * [1] LocationPath ::= RelativeLocationPath
11470 * | AbsoluteLocationPath
11471 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11472 * | AbbreviatedAbsoluteLocationPath
11473 * [10] AbbreviatedAbsoluteLocationPath ::=
11474 * '//' RelativeLocationPath
11476 * Compile a location path
11478 * // is short for /descendant-or-self::node()/. For example,
11479 * //para is short for /descendant-or-self::node()/child::para and
11480 * so will select any para element in the document (even a para element
11481 * that is a document element will be selected by //para since the
11482 * document element node is a child of the root node); div//para is
11483 * short for div/descendant-or-self::node()/child::para and so will
11484 * select all para descendants of div children.
11487 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
) {
11490 xmlXPathCompRelativeLocationPath(ctxt
);
11492 while (CUR
== '/') {
11493 if ((CUR
== '/') && (NXT(1) == '/')) {
11496 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11497 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11498 xmlXPathCompRelativeLocationPath(ctxt
);
11499 } else if (CUR
== '/') {
11503 ((IS_ASCII_LETTER(CUR
)) || (CUR
== '_') || (CUR
== '.') ||
11504 (CUR
== '@') || (CUR
== '*')))
11505 xmlXPathCompRelativeLocationPath(ctxt
);
11512 /************************************************************************
11514 * XPath precompiled expression evaluation *
11516 ************************************************************************/
11519 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
);
11523 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op
,
11526 xmlGenericError(xmlGenericErrorContext
, "new step : ");
11527 switch (op
->value
) {
11528 case AXIS_ANCESTOR
:
11529 xmlGenericError(xmlGenericErrorContext
, "axis 'ancestors' ");
11531 case AXIS_ANCESTOR_OR_SELF
:
11532 xmlGenericError(xmlGenericErrorContext
,
11533 "axis 'ancestors-or-self' ");
11535 case AXIS_ATTRIBUTE
:
11536 xmlGenericError(xmlGenericErrorContext
, "axis 'attributes' ");
11539 xmlGenericError(xmlGenericErrorContext
, "axis 'child' ");
11541 case AXIS_DESCENDANT
:
11542 xmlGenericError(xmlGenericErrorContext
, "axis 'descendant' ");
11544 case AXIS_DESCENDANT_OR_SELF
:
11545 xmlGenericError(xmlGenericErrorContext
,
11546 "axis 'descendant-or-self' ");
11548 case AXIS_FOLLOWING
:
11549 xmlGenericError(xmlGenericErrorContext
, "axis 'following' ");
11551 case AXIS_FOLLOWING_SIBLING
:
11552 xmlGenericError(xmlGenericErrorContext
,
11553 "axis 'following-siblings' ");
11555 case AXIS_NAMESPACE
:
11556 xmlGenericError(xmlGenericErrorContext
, "axis 'namespace' ");
11559 xmlGenericError(xmlGenericErrorContext
, "axis 'parent' ");
11561 case AXIS_PRECEDING
:
11562 xmlGenericError(xmlGenericErrorContext
, "axis 'preceding' ");
11564 case AXIS_PRECEDING_SIBLING
:
11565 xmlGenericError(xmlGenericErrorContext
,
11566 "axis 'preceding-sibling' ");
11569 xmlGenericError(xmlGenericErrorContext
, "axis 'self' ");
11572 xmlGenericError(xmlGenericErrorContext
,
11573 " context contains %d nodes\n", nbNodes
);
11574 switch (op
->value2
) {
11575 case NODE_TEST_NONE
:
11576 xmlGenericError(xmlGenericErrorContext
,
11577 " searching for none !!!\n");
11579 case NODE_TEST_TYPE
:
11580 xmlGenericError(xmlGenericErrorContext
,
11581 " searching for type %d\n", op
->value3
);
11584 xmlGenericError(xmlGenericErrorContext
,
11585 " searching for PI !!!\n");
11587 case NODE_TEST_ALL
:
11588 xmlGenericError(xmlGenericErrorContext
,
11589 " searching for *\n");
11592 xmlGenericError(xmlGenericErrorContext
,
11593 " searching for namespace %s\n",
11596 case NODE_TEST_NAME
:
11597 xmlGenericError(xmlGenericErrorContext
,
11598 " searching for name %s\n", op
->value5
);
11600 xmlGenericError(xmlGenericErrorContext
,
11601 " with namespace %s\n", op
->value4
);
11604 xmlGenericError(xmlGenericErrorContext
, "Testing : ");
11606 #endif /* DEBUG_STEP */
11609 * xmlXPathNodeSetFilter:
11610 * @ctxt: the XPath Parser context
11611 * @set: the node set to filter
11612 * @filterOpIndex: the index of the predicate/filter op
11613 * @minPos: minimum position in the filtered set (1-based)
11614 * @maxPos: maximum position in the filtered set (1-based)
11615 * @hasNsNodes: true if the node set may contain namespace nodes
11617 * Filter a node set, keeping only nodes for which the predicate expression
11618 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11622 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt
,
11625 int minPos
, int maxPos
,
11628 xmlXPathContextPtr xpctxt
;
11629 xmlNodePtr oldnode
;
11631 xmlXPathStepOpPtr filterOp
;
11635 if ((set
== NULL
) || (set
->nodeNr
== 0))
11639 * Check if the node set contains a sufficient number of nodes for
11640 * the requested range.
11642 if (set
->nodeNr
< minPos
) {
11643 xmlXPathNodeSetClear(set
, hasNsNodes
);
11647 xpctxt
= ctxt
->context
;
11648 oldnode
= xpctxt
->node
;
11649 olddoc
= xpctxt
->doc
;
11650 oldcs
= xpctxt
->contextSize
;
11651 oldpp
= xpctxt
->proximityPosition
;
11652 filterOp
= &ctxt
->comp
->steps
[filterOpIndex
];
11654 xpctxt
->contextSize
= set
->nodeNr
;
11656 for (i
= 0, j
= 0, pos
= 1; i
< set
->nodeNr
; i
++) {
11657 xmlNodePtr node
= set
->nodeTab
[i
];
11660 xpctxt
->node
= node
;
11661 xpctxt
->proximityPosition
= i
+ 1;
11664 * Also set the xpath document in case things like
11665 * key() are evaluated in the predicate.
11667 * TODO: Get real doc for namespace nodes.
11669 if ((node
->type
!= XML_NAMESPACE_DECL
) &&
11670 (node
->doc
!= NULL
))
11671 xpctxt
->doc
= node
->doc
;
11673 res
= xmlXPathCompOpEvalToBoolean(ctxt
, filterOp
, 1);
11675 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
11678 /* Shouldn't happen */
11679 xmlXPathErr(ctxt
, XPATH_EXPR_ERROR
);
11683 if ((res
!= 0) && ((pos
>= minPos
) && (pos
<= maxPos
))) {
11685 set
->nodeTab
[j
] = node
;
11686 set
->nodeTab
[i
] = NULL
;
11691 /* Remove the entry from the initial node set. */
11692 set
->nodeTab
[i
] = NULL
;
11693 if (node
->type
== XML_NAMESPACE_DECL
)
11694 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
11698 if (pos
== maxPos
) {
11707 /* Free remaining nodes. */
11709 for (; i
< set
->nodeNr
; i
++) {
11710 xmlNodePtr node
= set
->nodeTab
[i
];
11711 if ((node
!= NULL
) && (node
->type
== XML_NAMESPACE_DECL
))
11712 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
11718 /* If too many elements were removed, shrink table to preserve memory. */
11719 if ((set
->nodeMax
> XML_NODESET_DEFAULT
) &&
11720 (set
->nodeNr
< set
->nodeMax
/ 2)) {
11722 int nodeMax
= set
->nodeNr
;
11724 if (nodeMax
< XML_NODESET_DEFAULT
)
11725 nodeMax
= XML_NODESET_DEFAULT
;
11726 tmp
= (xmlNodePtr
*) xmlRealloc(set
->nodeTab
,
11727 nodeMax
* sizeof(xmlNodePtr
));
11729 xmlXPathPErrMemory(ctxt
, "shrinking nodeset\n");
11731 set
->nodeTab
= tmp
;
11732 set
->nodeMax
= nodeMax
;
11736 xpctxt
->node
= oldnode
;
11737 xpctxt
->doc
= olddoc
;
11738 xpctxt
->contextSize
= oldcs
;
11739 xpctxt
->proximityPosition
= oldpp
;
11742 #ifdef LIBXML_XPTR_LOCS_ENABLED
11744 * xmlXPathLocationSetFilter:
11745 * @ctxt: the XPath Parser context
11746 * @locset: the location set to filter
11747 * @filterOpIndex: the index of the predicate/filter op
11748 * @minPos: minimum position in the filtered set (1-based)
11749 * @maxPos: maximum position in the filtered set (1-based)
11751 * Filter a location set, keeping only nodes for which the predicate
11752 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11753 * in the filtered result.
11756 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt
,
11757 xmlLocationSetPtr locset
,
11759 int minPos
, int maxPos
)
11761 xmlXPathContextPtr xpctxt
;
11762 xmlNodePtr oldnode
;
11764 xmlXPathStepOpPtr filterOp
;
11768 if ((locset
== NULL
) || (locset
->locNr
== 0) || (filterOpIndex
== -1))
11771 xpctxt
= ctxt
->context
;
11772 oldnode
= xpctxt
->node
;
11773 olddoc
= xpctxt
->doc
;
11774 oldcs
= xpctxt
->contextSize
;
11775 oldpp
= xpctxt
->proximityPosition
;
11776 filterOp
= &ctxt
->comp
->steps
[filterOpIndex
];
11778 xpctxt
->contextSize
= locset
->locNr
;
11780 for (i
= 0, j
= 0, pos
= 1; i
< locset
->locNr
; i
++) {
11781 xmlNodePtr contextNode
= locset
->locTab
[i
]->user
;
11784 xpctxt
->node
= contextNode
;
11785 xpctxt
->proximityPosition
= i
+ 1;
11788 * Also set the xpath document in case things like
11789 * key() are evaluated in the predicate.
11791 * TODO: Get real doc for namespace nodes.
11793 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11794 (contextNode
->doc
!= NULL
))
11795 xpctxt
->doc
= contextNode
->doc
;
11797 res
= xmlXPathCompOpEvalToBoolean(ctxt
, filterOp
, 1);
11799 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
11802 /* Shouldn't happen */
11803 xmlXPathErr(ctxt
, XPATH_EXPR_ERROR
);
11807 if ((res
!= 0) && ((pos
>= minPos
) && (pos
<= maxPos
))) {
11809 locset
->locTab
[j
] = locset
->locTab
[i
];
11810 locset
->locTab
[i
] = NULL
;
11815 /* Remove the entry from the initial location set. */
11816 xmlXPathFreeObject(locset
->locTab
[i
]);
11817 locset
->locTab
[i
] = NULL
;
11821 if (pos
== maxPos
) {
11830 /* Free remaining nodes. */
11831 for (; i
< locset
->locNr
; i
++)
11832 xmlXPathFreeObject(locset
->locTab
[i
]);
11836 /* If too many elements were removed, shrink table to preserve memory. */
11837 if ((locset
->locMax
> XML_NODESET_DEFAULT
) &&
11838 (locset
->locNr
< locset
->locMax
/ 2)) {
11839 xmlXPathObjectPtr
*tmp
;
11840 int locMax
= locset
->locNr
;
11842 if (locMax
< XML_NODESET_DEFAULT
)
11843 locMax
= XML_NODESET_DEFAULT
;
11844 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(locset
->locTab
,
11845 locMax
* sizeof(xmlXPathObjectPtr
));
11847 xmlXPathPErrMemory(ctxt
, "shrinking locset\n");
11849 locset
->locTab
= tmp
;
11850 locset
->locMax
= locMax
;
11854 xpctxt
->node
= oldnode
;
11855 xpctxt
->doc
= olddoc
;
11856 xpctxt
->contextSize
= oldcs
;
11857 xpctxt
->proximityPosition
= oldpp
;
11859 #endif /* LIBXML_XPTR_LOCS_ENABLED */
11862 * xmlXPathCompOpEvalPredicate:
11863 * @ctxt: the XPath Parser context
11864 * @op: the predicate op
11865 * @set: the node set to filter
11866 * @minPos: minimum position in the filtered set (1-based)
11867 * @maxPos: maximum position in the filtered set (1-based)
11868 * @hasNsNodes: true if the node set may contain namespace nodes
11870 * Filter a node set, keeping only nodes for which the sequence of predicate
11871 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11872 * in the filtered result.
11875 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt
,
11876 xmlXPathStepOpPtr op
,
11878 int minPos
, int maxPos
,
11881 if (op
->ch1
!= -1) {
11882 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11884 * Process inner predicates first.
11886 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11887 xmlGenericError(xmlGenericErrorContext
,
11888 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11889 XP_ERROR(XPATH_INVALID_OPERAND
);
11891 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
11892 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED
);
11893 ctxt
->context
->depth
+= 1;
11894 xmlXPathCompOpEvalPredicate(ctxt
, &comp
->steps
[op
->ch1
], set
,
11895 1, set
->nodeNr
, hasNsNodes
);
11896 ctxt
->context
->depth
-= 1;
11901 xmlXPathNodeSetFilter(ctxt
, set
, op
->ch2
, minPos
, maxPos
, hasNsNodes
);
11905 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt
,
11906 xmlXPathStepOpPtr op
,
11910 xmlXPathStepOpPtr exprOp
;
11913 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11917 * If not -1, then ch1 will point to:
11918 * 1) For predicates (XPATH_OP_PREDICATE):
11919 * - an inner predicate operator
11920 * 2) For filters (XPATH_OP_FILTER):
11921 * - an inner filter operator OR
11922 * - an expression selecting the node set.
11923 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11925 if ((op
->op
!= XPATH_OP_PREDICATE
) && (op
->op
!= XPATH_OP_FILTER
))
11928 if (op
->ch2
!= -1) {
11929 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11933 if ((exprOp
!= NULL
) &&
11934 (exprOp
->op
== XPATH_OP_VALUE
) &&
11935 (exprOp
->value4
!= NULL
) &&
11936 (((xmlXPathObjectPtr
) exprOp
->value4
)->type
== XPATH_NUMBER
))
11938 double floatval
= ((xmlXPathObjectPtr
) exprOp
->value4
)->floatval
;
11941 * We have a "[n]" predicate here.
11942 * TODO: Unfortunately this simplistic test here is not
11943 * able to detect a position() predicate in compound
11944 * expressions like "[@attr = 'a" and position() = 1],
11945 * and even not the usage of position() in
11946 * "[position() = 1]"; thus - obviously - a position-range,
11947 * like it "[position() < 5]", is also not detected.
11948 * Maybe we could rewrite the AST to ease the optimization.
11951 if ((floatval
> INT_MIN
) && (floatval
< INT_MAX
)) {
11952 *maxPos
= (int) floatval
;
11953 if (floatval
== (double) *maxPos
)
11961 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt
,
11962 xmlXPathStepOpPtr op
,
11963 xmlNodePtr
* first
, xmlNodePtr
* last
,
11967 #define XP_TEST_HIT \
11968 if (hasAxisRange != 0) { \
11969 if (++pos == maxPos) { \
11970 if (addNode(seq, cur) < 0) \
11971 ctxt->error = XPATH_MEMORY_ERROR; \
11972 goto axis_range_end; } \
11974 if (addNode(seq, cur) < 0) \
11975 ctxt->error = XPATH_MEMORY_ERROR; \
11976 if (breakOnFirstHit) goto first_hit; }
11978 #define XP_TEST_HIT_NS \
11979 if (hasAxisRange != 0) { \
11980 if (++pos == maxPos) { \
11982 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11983 ctxt->error = XPATH_MEMORY_ERROR; \
11984 goto axis_range_end; } \
11987 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11988 ctxt->error = XPATH_MEMORY_ERROR; \
11989 if (breakOnFirstHit) goto first_hit; }
11991 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) op
->value
;
11992 xmlXPathTestVal test
= (xmlXPathTestVal
) op
->value2
;
11993 xmlXPathTypeVal type
= (xmlXPathTypeVal
) op
->value3
;
11994 const xmlChar
*prefix
= op
->value4
;
11995 const xmlChar
*name
= op
->value5
;
11996 const xmlChar
*URI
= NULL
;
11999 int nbMatches
= 0, prevMatches
= 0;
12001 int total
= 0, hasNsNodes
= 0;
12002 /* The popped object holding the context nodes */
12003 xmlXPathObjectPtr obj
;
12004 /* The set of context nodes for the node tests */
12005 xmlNodeSetPtr contextSeq
;
12007 xmlNodePtr contextNode
;
12008 /* The final resulting node set wrt to all context nodes */
12009 xmlNodeSetPtr outSeq
;
12011 * The temporary resulting node set wrt 1 context node.
12012 * Used to feed predicate evaluation.
12016 /* First predicate operator */
12017 xmlXPathStepOpPtr predOp
;
12018 int maxPos
; /* The requested position() (when a "[n]" predicate) */
12019 int hasPredicateRange
, hasAxisRange
, pos
;
12020 int breakOnFirstHit
;
12022 xmlXPathTraversalFunction next
= NULL
;
12023 int (*addNode
) (xmlNodeSetPtr
, xmlNodePtr
);
12024 xmlXPathNodeSetMergeFunction mergeAndClear
;
12025 xmlNodePtr oldContextNode
;
12026 xmlXPathContextPtr xpctxt
= ctxt
->context
;
12029 CHECK_TYPE0(XPATH_NODESET
);
12030 obj
= valuePop(ctxt
);
12032 * Setup namespaces.
12034 if (prefix
!= NULL
) {
12035 URI
= xmlXPathNsLookup(xpctxt
, prefix
);
12037 xmlXPathReleaseObject(xpctxt
, obj
);
12038 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
12044 * MAYBE FUTURE TODO: merging optimizations:
12045 * - If the nodes to be traversed wrt to the initial nodes and
12046 * the current axis cannot overlap, then we could avoid searching
12047 * for duplicates during the merge.
12048 * But the question is how/when to evaluate if they cannot overlap.
12049 * Example: if we know that for two initial nodes, the one is
12050 * not in the ancestor-or-self axis of the other, then we could safely
12051 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12052 * the descendant-or-self axis.
12054 mergeAndClear
= xmlXPathNodeSetMergeAndClear
;
12056 case AXIS_ANCESTOR
:
12058 next
= xmlXPathNextAncestor
;
12060 case AXIS_ANCESTOR_OR_SELF
:
12062 next
= xmlXPathNextAncestorOrSelf
;
12064 case AXIS_ATTRIBUTE
:
12067 next
= xmlXPathNextAttribute
;
12068 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12072 if (((test
== NODE_TEST_NAME
) || (test
== NODE_TEST_ALL
)) &&
12073 (type
== NODE_TYPE_NODE
))
12076 * Optimization if an element node type is 'element'.
12078 next
= xmlXPathNextChildElement
;
12080 next
= xmlXPathNextChild
;
12081 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12083 case AXIS_DESCENDANT
:
12085 next
= xmlXPathNextDescendant
;
12087 case AXIS_DESCENDANT_OR_SELF
:
12089 next
= xmlXPathNextDescendantOrSelf
;
12091 case AXIS_FOLLOWING
:
12093 next
= xmlXPathNextFollowing
;
12095 case AXIS_FOLLOWING_SIBLING
:
12097 next
= xmlXPathNextFollowingSibling
;
12099 case AXIS_NAMESPACE
:
12102 next
= (xmlXPathTraversalFunction
) xmlXPathNextNamespace
;
12103 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12107 next
= xmlXPathNextParent
;
12109 case AXIS_PRECEDING
:
12111 next
= xmlXPathNextPrecedingInternal
;
12113 case AXIS_PRECEDING_SIBLING
:
12115 next
= xmlXPathNextPrecedingSibling
;
12120 next
= xmlXPathNextSelf
;
12121 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12126 xmlXPathDebugDumpStepAxis(op
,
12127 (obj
->nodesetval
!= NULL
) ? obj
->nodesetval
->nodeNr
: 0);
12130 if (next
== NULL
) {
12131 xmlXPathReleaseObject(xpctxt
, obj
);
12134 contextSeq
= obj
->nodesetval
;
12135 if ((contextSeq
== NULL
) || (contextSeq
->nodeNr
<= 0)) {
12136 xmlXPathReleaseObject(xpctxt
, obj
);
12137 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, NULL
));
12141 * Predicate optimization ---------------------------------------------
12142 * If this step has a last predicate, which contains a position(),
12143 * then we'll optimize (although not exactly "position()", but only
12144 * the short-hand form, i.e., "[n]".
12146 * Example - expression "/foo[parent::bar][1]":
12148 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12150 * PREDICATE -- op->ch2 (predOp)
12151 * PREDICATE -- predOp->ch1 = [parent::bar]
12153 * COLLECT 'parent' 'name' 'node' bar
12155 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12160 hasPredicateRange
= 0;
12162 if (op
->ch2
!= -1) {
12164 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12166 predOp
= &ctxt
->comp
->steps
[op
->ch2
];
12167 if (xmlXPathIsPositionalPredicate(ctxt
, predOp
, &maxPos
)) {
12168 if (predOp
->ch1
!= -1) {
12170 * Use the next inner predicate operator.
12172 predOp
= &ctxt
->comp
->steps
[predOp
->ch1
];
12173 hasPredicateRange
= 1;
12176 * There's no other predicate than the [n] predicate.
12183 breakOnFirstHit
= ((toBool
) && (predOp
== NULL
)) ? 1 : 0;
12185 * Axis traversal -----------------------------------------------------
12189 * - For the attribute axis, the principal node type is attribute.
12190 * - For the namespace axis, the principal node type is namespace.
12191 * - For other axes, the principal node type is element.
12193 * A node test * is true for any node of the
12194 * principal node type. For example, child::* will
12195 * select all element children of the context node
12197 oldContextNode
= xpctxt
->node
;
12198 addNode
= xmlXPathNodeSetAddUnique
;
12201 contextNode
= NULL
;
12205 while (((contextIdx
< contextSeq
->nodeNr
) || (contextNode
!= NULL
)) &&
12206 (ctxt
->error
== XPATH_EXPRESSION_OK
)) {
12207 xpctxt
->node
= contextSeq
->nodeTab
[contextIdx
++];
12210 seq
= xmlXPathNodeSetCreate(NULL
);
12212 /* TODO: Propagate memory error. */
12218 * Traverse the axis and test the nodes.
12224 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12227 cur
= next(ctxt
, cur
);
12232 * QUESTION TODO: What does the "first" and "last" stuff do?
12234 if ((first
!= NULL
) && (*first
!= NULL
)) {
12237 if (((total
% 256) == 0) &&
12238 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12239 (xmlXPathCmpNodesExt(*first
, cur
) >= 0))
12241 (xmlXPathCmpNodes(*first
, cur
) >= 0))
12247 if ((last
!= NULL
) && (*last
!= NULL
)) {
12250 if (((total
% 256) == 0) &&
12251 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12252 (xmlXPathCmpNodesExt(cur
, *last
) >= 0))
12254 (xmlXPathCmpNodes(cur
, *last
) >= 0))
12264 xmlGenericError(xmlGenericErrorContext
, " %s", cur
->name
);
12268 case NODE_TEST_NONE
:
12272 case NODE_TEST_TYPE
:
12273 if (type
== NODE_TYPE_NODE
) {
12274 switch (cur
->type
) {
12275 case XML_DOCUMENT_NODE
:
12276 case XML_HTML_DOCUMENT_NODE
:
12277 case XML_ELEMENT_NODE
:
12278 case XML_ATTRIBUTE_NODE
:
12280 case XML_COMMENT_NODE
:
12281 case XML_CDATA_SECTION_NODE
:
12282 case XML_TEXT_NODE
:
12285 case XML_NAMESPACE_DECL
: {
12286 if (axis
== AXIS_NAMESPACE
) {
12297 } else if (cur
->type
== (xmlElementType
) type
) {
12298 if (cur
->type
== XML_NAMESPACE_DECL
)
12302 } else if ((type
== NODE_TYPE_TEXT
) &&
12303 (cur
->type
== XML_CDATA_SECTION_NODE
))
12309 if ((cur
->type
== XML_PI_NODE
) &&
12310 ((name
== NULL
) || xmlStrEqual(name
, cur
->name
)))
12315 case NODE_TEST_ALL
:
12316 if (axis
== AXIS_ATTRIBUTE
) {
12317 if (cur
->type
== XML_ATTRIBUTE_NODE
)
12319 if (prefix
== NULL
)
12322 } else if ((cur
->ns
!= NULL
) &&
12323 (xmlStrEqual(URI
, cur
->ns
->href
)))
12328 } else if (axis
== AXIS_NAMESPACE
) {
12329 if (cur
->type
== XML_NAMESPACE_DECL
)
12334 if (cur
->type
== XML_ELEMENT_NODE
) {
12335 if (prefix
== NULL
)
12339 } else if ((cur
->ns
!= NULL
) &&
12340 (xmlStrEqual(URI
, cur
->ns
->href
)))
12347 case NODE_TEST_NS
:{
12351 case NODE_TEST_NAME
:
12352 if (axis
== AXIS_ATTRIBUTE
) {
12353 if (cur
->type
!= XML_ATTRIBUTE_NODE
)
12355 } else if (axis
== AXIS_NAMESPACE
) {
12356 if (cur
->type
!= XML_NAMESPACE_DECL
)
12359 if (cur
->type
!= XML_ELEMENT_NODE
)
12362 switch (cur
->type
) {
12363 case XML_ELEMENT_NODE
:
12364 if (xmlStrEqual(name
, cur
->name
)) {
12365 if (prefix
== NULL
) {
12366 if (cur
->ns
== NULL
)
12371 if ((cur
->ns
!= NULL
) &&
12372 (xmlStrEqual(URI
, cur
->ns
->href
)))
12379 case XML_ATTRIBUTE_NODE
:{
12380 xmlAttrPtr attr
= (xmlAttrPtr
) cur
;
12382 if (xmlStrEqual(name
, attr
->name
)) {
12383 if (prefix
== NULL
) {
12384 if ((attr
->ns
== NULL
) ||
12385 (attr
->ns
->prefix
== NULL
))
12390 if ((attr
->ns
!= NULL
) &&
12400 case XML_NAMESPACE_DECL
:
12401 if (cur
->type
== XML_NAMESPACE_DECL
) {
12402 xmlNsPtr ns
= (xmlNsPtr
) cur
;
12404 if ((ns
->prefix
!= NULL
) && (name
!= NULL
)
12405 && (xmlStrEqual(ns
->prefix
, name
)))
12415 } /* switch(test) */
12416 } while ((cur
!= NULL
) && (ctxt
->error
== XPATH_EXPRESSION_OK
));
12418 goto apply_predicates
;
12420 axis_range_end
: /* ----------------------------------------------------- */
12422 * We have a "/foo[n]", and position() = n was reached.
12423 * Note that we can have as well "/foo/::parent::foo[1]", so
12424 * a duplicate-aware merge is still needed.
12425 * Merge with the result.
12427 if (outSeq
== NULL
) {
12431 /* TODO: Check memory error. */
12432 outSeq
= mergeAndClear(outSeq
, seq
);
12434 * Break if only a true/false result was requested.
12440 first_hit
: /* ---------------------------------------------------------- */
12442 * Break if only a true/false result was requested and
12443 * no predicates existed and a node test succeeded.
12445 if (outSeq
== NULL
) {
12449 /* TODO: Check memory error. */
12450 outSeq
= mergeAndClear(outSeq
, seq
);
12455 nbMatches
+= seq
->nodeNr
;
12458 apply_predicates
: /* --------------------------------------------------- */
12459 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
12463 * Apply predicates.
12465 if ((predOp
!= NULL
) && (seq
->nodeNr
> 0)) {
12467 * E.g. when we have a "/foo[some expression][n]".
12470 * QUESTION TODO: The old predicate evaluation took into
12471 * account location-sets.
12472 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12473 * Do we expect such a set here?
12474 * All what I learned now from the evaluation semantics
12475 * does not indicate that a location-set will be processed
12476 * here, so this looks OK.
12479 * Iterate over all predicates, starting with the outermost
12481 * TODO: Problem: we cannot execute the inner predicates first
12482 * since we cannot go back *up* the operator tree!
12484 * 1) Use of recursive functions (like is it currently done
12485 * via xmlXPathCompOpEval())
12486 * 2) Add a predicate evaluation information stack to the
12488 * 3) Change the way the operators are linked; we need a
12489 * "parent" field on xmlXPathStepOp
12491 * For the moment, I'll try to solve this with a recursive
12492 * function: xmlXPathCompOpEvalPredicate().
12494 if (hasPredicateRange
!= 0)
12495 xmlXPathCompOpEvalPredicate(ctxt
, predOp
, seq
, maxPos
, maxPos
,
12498 xmlXPathCompOpEvalPredicate(ctxt
, predOp
, seq
, 1, seq
->nodeNr
,
12501 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
12507 if (seq
->nodeNr
> 0) {
12509 * Add to result set.
12511 if (outSeq
== NULL
) {
12515 /* TODO: Check memory error. */
12516 outSeq
= mergeAndClear(outSeq
, seq
);
12525 if ((obj
->boolval
) && (obj
->user
!= NULL
)) {
12527 * QUESTION TODO: What does this do and why?
12528 * TODO: Do we have to do this also for the "error"
12529 * cleanup further down?
12531 ctxt
->value
->boolval
= 1;
12532 ctxt
->value
->user
= obj
->user
;
12536 xmlXPathReleaseObject(xpctxt
, obj
);
12539 * Ensure we return at least an empty set.
12541 if (outSeq
== NULL
) {
12542 if ((seq
!= NULL
) && (seq
->nodeNr
== 0))
12545 /* TODO: Check memory error. */
12546 outSeq
= xmlXPathNodeSetCreate(NULL
);
12548 if ((seq
!= NULL
) && (seq
!= outSeq
)) {
12549 xmlXPathFreeNodeSet(seq
);
12552 * Hand over the result. Better to push the set also in
12555 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, outSeq
));
12557 * Reset the context node.
12559 xpctxt
->node
= oldContextNode
;
12561 * When traversing the namespace axis in "toBool" mode, it's
12562 * possible that tmpNsList wasn't freed.
12564 if (xpctxt
->tmpNsList
!= NULL
) {
12565 xmlFree(xpctxt
->tmpNsList
);
12566 xpctxt
->tmpNsList
= NULL
;
12570 xmlGenericError(xmlGenericErrorContext
,
12571 "\nExamined %d nodes, found %d nodes at that step\n",
12579 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12580 xmlXPathStepOpPtr op
, xmlNodePtr
* first
);
12583 * xmlXPathCompOpEvalFirst:
12584 * @ctxt: the XPath parser context with the compiled expression
12585 * @op: an XPath compiled operation
12586 * @first: the first elem found so far
12588 * Evaluate the Precompiled XPath operation searching only the first
12589 * element in document order
12591 * Returns the number of examined objects.
12594 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
12595 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12597 int total
= 0, cur
;
12598 xmlXPathCompExprPtr comp
;
12599 xmlXPathObjectPtr arg1
, arg2
;
12602 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12604 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
12605 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED
);
12606 ctxt
->context
->depth
+= 1;
12611 case XPATH_OP_UNION
:
12613 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12616 if ((ctxt
->value
!= NULL
)
12617 && (ctxt
->value
->type
== XPATH_NODESET
)
12618 && (ctxt
->value
->nodesetval
!= NULL
)
12619 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12621 * limit tree traversing to first node in the result
12624 * OPTIMIZE TODO: This implicitly sorts
12625 * the result, even if not needed. E.g. if the argument
12626 * of the count() function, no sorting is needed.
12627 * OPTIMIZE TODO: How do we know if the node-list wasn't
12630 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12631 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12632 *first
= ctxt
->value
->nodesetval
->nodeTab
[0];
12635 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch2
],
12639 arg2
= valuePop(ctxt
);
12640 arg1
= valuePop(ctxt
);
12641 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12642 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12643 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12644 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12645 XP_ERROR0(XPATH_INVALID_TYPE
);
12647 if ((ctxt
->context
->opLimit
!= 0) &&
12648 (((arg1
->nodesetval
!= NULL
) &&
12649 (xmlXPathCheckOpLimit(ctxt
,
12650 arg1
->nodesetval
->nodeNr
) < 0)) ||
12651 ((arg2
->nodesetval
!= NULL
) &&
12652 (xmlXPathCheckOpLimit(ctxt
,
12653 arg2
->nodesetval
->nodeNr
) < 0)))) {
12654 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12655 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12659 /* TODO: Check memory error. */
12660 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12662 valuePush(ctxt
, arg1
);
12663 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12666 xmlXPathCompSwap(op
);
12669 case XPATH_OP_ROOT
:
12670 xmlXPathRoot(ctxt
);
12672 case XPATH_OP_NODE
:
12674 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12677 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12679 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12680 ctxt
->context
->node
));
12682 case XPATH_OP_COLLECT
:{
12686 total
= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12689 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, first
, NULL
, 0);
12692 case XPATH_OP_VALUE
:
12694 xmlXPathCacheObjectCopy(ctxt
->context
,
12695 (xmlXPathObjectPtr
) op
->value4
));
12697 case XPATH_OP_SORT
:
12700 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12703 if ((ctxt
->value
!= NULL
)
12704 && (ctxt
->value
->type
== XPATH_NODESET
)
12705 && (ctxt
->value
->nodesetval
!= NULL
)
12706 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12707 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12709 #ifdef XP_OPTIMIZED_FILTER_FIRST
12710 case XPATH_OP_FILTER
:
12711 total
+= xmlXPathCompOpEvalFilterFirst(ctxt
, op
, first
);
12715 total
+= xmlXPathCompOpEval(ctxt
, op
);
12719 ctxt
->context
->depth
-= 1;
12724 * xmlXPathCompOpEvalLast:
12725 * @ctxt: the XPath parser context with the compiled expression
12726 * @op: an XPath compiled operation
12727 * @last: the last elem found so far
12729 * Evaluate the Precompiled XPath operation searching only the last
12730 * element in document order
12732 * Returns the number of nodes traversed
12735 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
,
12738 int total
= 0, cur
;
12739 xmlXPathCompExprPtr comp
;
12740 xmlXPathObjectPtr arg1
, arg2
;
12743 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12745 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
12746 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED
);
12747 ctxt
->context
->depth
+= 1;
12752 case XPATH_OP_UNION
:
12754 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
], last
);
12756 if ((ctxt
->value
!= NULL
)
12757 && (ctxt
->value
->type
== XPATH_NODESET
)
12758 && (ctxt
->value
->nodesetval
!= NULL
)
12759 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12761 * limit tree traversing to first node in the result
12763 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12764 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12766 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->value
->
12767 nodesetval
->nodeNr
-
12771 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch2
], last
);
12773 if ((ctxt
->value
!= NULL
)
12774 && (ctxt
->value
->type
== XPATH_NODESET
)
12775 && (ctxt
->value
->nodesetval
!= NULL
)
12776 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) { /* TODO: NOP ? */
12779 arg2
= valuePop(ctxt
);
12780 arg1
= valuePop(ctxt
);
12781 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12782 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12783 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12784 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12785 XP_ERROR0(XPATH_INVALID_TYPE
);
12787 if ((ctxt
->context
->opLimit
!= 0) &&
12788 (((arg1
->nodesetval
!= NULL
) &&
12789 (xmlXPathCheckOpLimit(ctxt
,
12790 arg1
->nodesetval
->nodeNr
) < 0)) ||
12791 ((arg2
->nodesetval
!= NULL
) &&
12792 (xmlXPathCheckOpLimit(ctxt
,
12793 arg2
->nodesetval
->nodeNr
) < 0)))) {
12794 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12795 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12799 /* TODO: Check memory error. */
12800 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12802 valuePush(ctxt
, arg1
);
12803 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12806 xmlXPathCompSwap(op
);
12809 case XPATH_OP_ROOT
:
12810 xmlXPathRoot(ctxt
);
12812 case XPATH_OP_NODE
:
12814 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12817 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12819 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12820 ctxt
->context
->node
));
12822 case XPATH_OP_COLLECT
:{
12826 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12829 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, last
, 0);
12832 case XPATH_OP_VALUE
:
12834 xmlXPathCacheObjectCopy(ctxt
->context
,
12835 (xmlXPathObjectPtr
) op
->value4
));
12837 case XPATH_OP_SORT
:
12840 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
],
12843 if ((ctxt
->value
!= NULL
)
12844 && (ctxt
->value
->type
== XPATH_NODESET
)
12845 && (ctxt
->value
->nodesetval
!= NULL
)
12846 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12847 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12850 total
+= xmlXPathCompOpEval(ctxt
, op
);
12854 ctxt
->context
->depth
-= 1;
12858 #ifdef XP_OPTIMIZED_FILTER_FIRST
12860 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12861 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12864 xmlXPathCompExprPtr comp
;
12870 * Optimization for ()[last()] selection i.e. the last elem
12872 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
12873 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
12874 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
12875 int f
= comp
->steps
[op
->ch2
].ch1
;
12878 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
12879 (comp
->steps
[f
].value5
== NULL
) &&
12880 (comp
->steps
[f
].value
== 0) &&
12881 (comp
->steps
[f
].value4
!= NULL
) &&
12883 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
12884 xmlNodePtr last
= NULL
;
12887 xmlXPathCompOpEvalLast(ctxt
,
12888 &comp
->steps
[op
->ch1
],
12892 * The nodeset should be in document order,
12893 * Keep only the last value
12895 if ((ctxt
->value
!= NULL
) &&
12896 (ctxt
->value
->type
== XPATH_NODESET
) &&
12897 (ctxt
->value
->nodesetval
!= NULL
) &&
12898 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
12899 (ctxt
->value
->nodesetval
->nodeNr
> 1)) {
12900 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
12901 *first
= *(ctxt
->value
->nodesetval
->nodeTab
);
12908 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12912 if (ctxt
->value
== NULL
)
12915 #ifdef LIBXML_XPTR_LOCS_ENABLED
12917 * Hum are we filtering the result of an XPointer expression
12919 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
12920 xmlLocationSetPtr locset
= ctxt
->value
->user
;
12922 if (locset
!= NULL
) {
12923 xmlXPathLocationSetFilter(ctxt
, locset
, op
->ch2
, 1, 1);
12924 if (locset
->locNr
> 0)
12925 *first
= (xmlNodePtr
) locset
->locTab
[0]->user
;
12930 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12932 CHECK_TYPE0(XPATH_NODESET
);
12933 set
= ctxt
->value
->nodesetval
;
12935 xmlXPathNodeSetFilter(ctxt
, set
, op
->ch2
, 1, 1, 1);
12936 if (set
->nodeNr
> 0)
12937 *first
= set
->nodeTab
[0];
12942 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12945 * xmlXPathCompOpEval:
12946 * @ctxt: the XPath parser context with the compiled expression
12947 * @op: an XPath compiled operation
12949 * Evaluate the Precompiled XPath operation
12950 * Returns the number of nodes traversed
12953 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
)
12957 xmlXPathCompExprPtr comp
;
12958 xmlXPathObjectPtr arg1
, arg2
;
12961 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12963 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
12964 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED
);
12965 ctxt
->context
->depth
+= 1;
12971 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12973 xmlXPathBooleanFunction(ctxt
, 1);
12974 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 0))
12976 arg2
= valuePop(ctxt
);
12977 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12979 xmlXPathFreeObject(arg2
);
12982 xmlXPathBooleanFunction(ctxt
, 1);
12983 if (ctxt
->value
!= NULL
)
12984 ctxt
->value
->boolval
&= arg2
->boolval
;
12985 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12988 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12990 xmlXPathBooleanFunction(ctxt
, 1);
12991 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 1))
12993 arg2
= valuePop(ctxt
);
12994 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12996 xmlXPathFreeObject(arg2
);
12999 xmlXPathBooleanFunction(ctxt
, 1);
13000 if (ctxt
->value
!= NULL
)
13001 ctxt
->value
->boolval
|= arg2
->boolval
;
13002 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13004 case XPATH_OP_EQUAL
:
13005 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13007 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13010 equal
= xmlXPathEqualValues(ctxt
);
13012 equal
= xmlXPathNotEqualValues(ctxt
);
13013 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, equal
));
13016 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13018 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13020 ret
= xmlXPathCompareValues(ctxt
, op
->value
, op
->value2
);
13021 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
13023 case XPATH_OP_PLUS
:
13024 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13026 if (op
->ch2
!= -1) {
13027 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13030 if (op
->value
== 0)
13031 xmlXPathSubValues(ctxt
);
13032 else if (op
->value
== 1)
13033 xmlXPathAddValues(ctxt
);
13034 else if (op
->value
== 2)
13035 xmlXPathValueFlipSign(ctxt
);
13036 else if (op
->value
== 3) {
13038 CHECK_TYPE0(XPATH_NUMBER
);
13041 case XPATH_OP_MULT
:
13042 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13044 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13046 if (op
->value
== 0)
13047 xmlXPathMultValues(ctxt
);
13048 else if (op
->value
== 1)
13049 xmlXPathDivValues(ctxt
);
13050 else if (op
->value
== 2)
13051 xmlXPathModValues(ctxt
);
13053 case XPATH_OP_UNION
:
13054 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13056 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13059 arg2
= valuePop(ctxt
);
13060 arg1
= valuePop(ctxt
);
13061 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
13062 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
13063 xmlXPathReleaseObject(ctxt
->context
, arg1
);
13064 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13065 XP_ERROR0(XPATH_INVALID_TYPE
);
13067 if ((ctxt
->context
->opLimit
!= 0) &&
13068 (((arg1
->nodesetval
!= NULL
) &&
13069 (xmlXPathCheckOpLimit(ctxt
,
13070 arg1
->nodesetval
->nodeNr
) < 0)) ||
13071 ((arg2
->nodesetval
!= NULL
) &&
13072 (xmlXPathCheckOpLimit(ctxt
,
13073 arg2
->nodesetval
->nodeNr
) < 0)))) {
13074 xmlXPathReleaseObject(ctxt
->context
, arg1
);
13075 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13079 if ((arg1
->nodesetval
== NULL
) ||
13080 ((arg2
->nodesetval
!= NULL
) &&
13081 (arg2
->nodesetval
->nodeNr
!= 0)))
13083 /* TODO: Check memory error. */
13084 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
13088 valuePush(ctxt
, arg1
);
13089 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13091 case XPATH_OP_ROOT
:
13092 xmlXPathRoot(ctxt
);
13094 case XPATH_OP_NODE
:
13096 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13099 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13101 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
13102 ctxt
->context
->node
));
13104 case XPATH_OP_COLLECT
:{
13108 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13111 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 0);
13114 case XPATH_OP_VALUE
:
13116 xmlXPathCacheObjectCopy(ctxt
->context
,
13117 (xmlXPathObjectPtr
) op
->value4
));
13119 case XPATH_OP_VARIABLE
:{
13120 xmlXPathObjectPtr val
;
13124 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13125 if (op
->value5
== NULL
) {
13126 val
= xmlXPathVariableLookup(ctxt
->context
, op
->value4
);
13128 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13129 valuePush(ctxt
, val
);
13131 const xmlChar
*URI
;
13133 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13135 xmlGenericError(xmlGenericErrorContext
,
13136 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13137 (char *) op
->value4
, (char *)op
->value5
);
13138 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13141 val
= xmlXPathVariableLookupNS(ctxt
->context
,
13144 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13145 valuePush(ctxt
, val
);
13149 case XPATH_OP_FUNCTION
:{
13150 xmlXPathFunction func
;
13151 const xmlChar
*oldFunc
, *oldFuncURI
;
13155 frame
= xmlXPathSetFrame(ctxt
);
13156 if (op
->ch1
!= -1) {
13158 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13159 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13160 xmlXPathPopFrame(ctxt
, frame
);
13164 if (ctxt
->valueNr
< ctxt
->valueFrame
+ op
->value
) {
13165 xmlGenericError(xmlGenericErrorContext
,
13166 "xmlXPathCompOpEval: parameter error\n");
13167 ctxt
->error
= XPATH_INVALID_OPERAND
;
13168 xmlXPathPopFrame(ctxt
, frame
);
13171 for (i
= 0; i
< op
->value
; i
++) {
13172 if (ctxt
->valueTab
[(ctxt
->valueNr
- 1) - i
] == NULL
) {
13173 xmlGenericError(xmlGenericErrorContext
,
13174 "xmlXPathCompOpEval: parameter error\n");
13175 ctxt
->error
= XPATH_INVALID_OPERAND
;
13176 xmlXPathPopFrame(ctxt
, frame
);
13180 if (op
->cache
!= NULL
)
13183 const xmlChar
*URI
= NULL
;
13185 if (op
->value5
== NULL
)
13187 xmlXPathFunctionLookup(ctxt
->context
,
13190 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13192 xmlGenericError(xmlGenericErrorContext
,
13193 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13194 (char *)op
->value4
, (char *)op
->value5
);
13195 xmlXPathPopFrame(ctxt
, frame
);
13196 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13199 func
= xmlXPathFunctionLookupNS(ctxt
->context
,
13202 if (func
== NULL
) {
13203 xmlGenericError(xmlGenericErrorContext
,
13204 "xmlXPathCompOpEval: function %s not found\n",
13205 (char *)op
->value4
);
13206 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR
);
13209 op
->cacheURI
= (void *) URI
;
13211 oldFunc
= ctxt
->context
->function
;
13212 oldFuncURI
= ctxt
->context
->functionURI
;
13213 ctxt
->context
->function
= op
->value4
;
13214 ctxt
->context
->functionURI
= op
->cacheURI
;
13215 func(ctxt
, op
->value
);
13216 ctxt
->context
->function
= oldFunc
;
13217 ctxt
->context
->functionURI
= oldFuncURI
;
13218 if ((ctxt
->error
== XPATH_EXPRESSION_OK
) &&
13219 (ctxt
->valueNr
!= ctxt
->valueFrame
+ 1))
13220 XP_ERROR0(XPATH_STACK_ERROR
);
13221 xmlXPathPopFrame(ctxt
, frame
);
13225 if (op
->ch1
!= -1) {
13226 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13229 if (op
->ch2
!= -1) {
13230 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13234 case XPATH_OP_PREDICATE
:
13235 case XPATH_OP_FILTER
:{
13239 * Optimization for ()[1] selection i.e. the first elem
13241 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13242 #ifdef XP_OPTIMIZED_FILTER_FIRST
13244 * FILTER TODO: Can we assume that the inner processing
13245 * will result in an ordered list if we have an
13247 * What about an additional field or flag on
13248 * xmlXPathObject like @sorted ? This way we wouldn't need
13249 * to assume anything, so it would be more robust and
13250 * easier to optimize.
13252 ((comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) || /* 18 */
13253 (comp
->steps
[op
->ch1
].op
== XPATH_OP_FILTER
)) && /* 17 */
13255 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13257 (comp
->steps
[op
->ch2
].op
== XPATH_OP_VALUE
)) { /* 12 */
13258 xmlXPathObjectPtr val
;
13260 val
= comp
->steps
[op
->ch2
].value4
;
13261 if ((val
!= NULL
) && (val
->type
== XPATH_NUMBER
) &&
13262 (val
->floatval
== 1.0)) {
13263 xmlNodePtr first
= NULL
;
13266 xmlXPathCompOpEvalFirst(ctxt
,
13267 &comp
->steps
[op
->ch1
],
13271 * The nodeset should be in document order,
13272 * Keep only the first value
13274 if ((ctxt
->value
!= NULL
) &&
13275 (ctxt
->value
->type
== XPATH_NODESET
) &&
13276 (ctxt
->value
->nodesetval
!= NULL
) &&
13277 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13278 xmlXPathNodeSetClearFromPos(ctxt
->value
->nodesetval
,
13284 * Optimization for ()[last()] selection i.e. the last elem
13286 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13287 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13288 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
13289 int f
= comp
->steps
[op
->ch2
].ch1
;
13292 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
13293 (comp
->steps
[f
].value5
== NULL
) &&
13294 (comp
->steps
[f
].value
== 0) &&
13295 (comp
->steps
[f
].value4
!= NULL
) &&
13297 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
13298 xmlNodePtr last
= NULL
;
13301 xmlXPathCompOpEvalLast(ctxt
,
13302 &comp
->steps
[op
->ch1
],
13306 * The nodeset should be in document order,
13307 * Keep only the last value
13309 if ((ctxt
->value
!= NULL
) &&
13310 (ctxt
->value
->type
== XPATH_NODESET
) &&
13311 (ctxt
->value
->nodesetval
!= NULL
) &&
13312 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
13313 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13314 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
13319 * Process inner predicates first.
13320 * Example "index[parent::book][1]":
13322 * PREDICATE <-- we are here "[1]"
13323 * PREDICATE <-- process "[parent::book]" first
13325 * COLLECT 'parent' 'name' 'node' book
13327 * ELEM Object is a number : 1
13331 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13335 if (ctxt
->value
== NULL
)
13338 #ifdef LIBXML_XPTR_LOCS_ENABLED
13340 * Hum are we filtering the result of an XPointer expression
13342 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13343 xmlLocationSetPtr locset
= ctxt
->value
->user
;
13344 xmlXPathLocationSetFilter(ctxt
, locset
, op
->ch2
,
13348 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13350 CHECK_TYPE0(XPATH_NODESET
);
13351 set
= ctxt
->value
->nodesetval
;
13353 xmlXPathNodeSetFilter(ctxt
, set
, op
->ch2
,
13354 1, set
->nodeNr
, 1);
13357 case XPATH_OP_SORT
:
13359 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13361 if ((ctxt
->value
!= NULL
) &&
13362 (ctxt
->value
->type
== XPATH_NODESET
) &&
13363 (ctxt
->value
->nodesetval
!= NULL
) &&
13364 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13366 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
13369 #ifdef LIBXML_XPTR_LOCS_ENABLED
13370 case XPATH_OP_RANGETO
:{
13371 xmlXPathObjectPtr range
;
13372 xmlXPathObjectPtr res
, obj
;
13373 xmlXPathObjectPtr tmp
;
13374 xmlLocationSetPtr newlocset
= NULL
;
13375 xmlLocationSetPtr oldlocset
;
13376 xmlNodeSetPtr oldset
;
13377 xmlNodePtr oldnode
= ctxt
->context
->node
;
13378 int oldcs
= ctxt
->context
->contextSize
;
13379 int oldpp
= ctxt
->context
->proximityPosition
;
13382 if (op
->ch1
!= -1) {
13384 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13387 if (ctxt
->value
== NULL
) {
13388 XP_ERROR0(XPATH_INVALID_OPERAND
);
13393 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13395 * Extract the old locset, and then evaluate the result of the
13396 * expression for all the element in the locset. use it to grow
13399 CHECK_TYPE0(XPATH_LOCATIONSET
);
13401 if ((ctxt
->value
->user
== NULL
) ||
13402 (((xmlLocationSetPtr
) ctxt
->value
->user
)->locNr
== 0))
13405 obj
= valuePop(ctxt
);
13406 oldlocset
= obj
->user
;
13408 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13410 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13412 * Run the evaluation with a node list made of a
13413 * single item in the nodelocset.
13415 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13416 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13417 ctxt
->context
->proximityPosition
= i
+ 1;
13418 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13419 ctxt
->context
->node
);
13420 valuePush(ctxt
, tmp
);
13424 xmlXPathCompOpEval(ctxt
,
13425 &comp
->steps
[op
->ch2
]);
13426 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13427 xmlXPtrFreeLocationSet(newlocset
);
13428 goto rangeto_error
;
13431 res
= valuePop(ctxt
);
13432 if (res
->type
== XPATH_LOCATIONSET
) {
13433 xmlLocationSetPtr rloc
=
13434 (xmlLocationSetPtr
)res
->user
;
13435 for (j
=0; j
<rloc
->locNr
; j
++) {
13436 range
= xmlXPtrNewRange(
13437 oldlocset
->locTab
[i
]->user
,
13438 oldlocset
->locTab
[i
]->index
,
13439 rloc
->locTab
[j
]->user2
,
13440 rloc
->locTab
[j
]->index2
);
13441 if (range
!= NULL
) {
13442 xmlXPtrLocationSetAdd(newlocset
, range
);
13446 range
= xmlXPtrNewRangeNodeObject(
13447 (xmlNodePtr
)oldlocset
->locTab
[i
]->user
, res
);
13448 if (range
!= NULL
) {
13449 xmlXPtrLocationSetAdd(newlocset
,range
);
13457 xmlXPathReleaseObject(ctxt
->context
, res
);
13459 if (ctxt
->value
== tmp
) {
13460 res
= valuePop(ctxt
);
13461 xmlXPathReleaseObject(ctxt
->context
, res
);
13464 } else { /* Not a location set */
13465 CHECK_TYPE0(XPATH_NODESET
);
13466 obj
= valuePop(ctxt
);
13467 oldset
= obj
->nodesetval
;
13469 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13471 if (oldset
!= NULL
) {
13472 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13474 * Run the evaluation with a node list made of a single item
13477 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13479 * OPTIMIZE TODO: Avoid recreation for every iteration.
13481 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13482 ctxt
->context
->node
);
13483 valuePush(ctxt
, tmp
);
13487 xmlXPathCompOpEval(ctxt
,
13488 &comp
->steps
[op
->ch2
]);
13489 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13490 xmlXPtrFreeLocationSet(newlocset
);
13491 goto rangeto_error
;
13494 res
= valuePop(ctxt
);
13496 xmlXPtrNewRangeNodeObject(oldset
->nodeTab
[i
],
13498 if (range
!= NULL
) {
13499 xmlXPtrLocationSetAdd(newlocset
, range
);
13506 xmlXPathReleaseObject(ctxt
->context
, res
);
13508 if (ctxt
->value
== tmp
) {
13509 res
= valuePop(ctxt
);
13510 xmlXPathReleaseObject(ctxt
->context
, res
);
13517 * The result is used as the new evaluation set.
13519 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13521 xmlXPathReleaseObject(ctxt
->context
, obj
);
13522 ctxt
->context
->node
= oldnode
;
13523 ctxt
->context
->contextSize
= oldcs
;
13524 ctxt
->context
->proximityPosition
= oldpp
;
13527 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13529 xmlGenericError(xmlGenericErrorContext
,
13530 "XPath: unknown precompiled operation %d\n", op
->op
);
13531 ctxt
->error
= XPATH_INVALID_OPERAND
;
13535 ctxt
->context
->depth
-= 1;
13540 * xmlXPathCompOpEvalToBoolean:
13541 * @ctxt: the XPath parser context
13543 * Evaluates if the expression evaluates to true.
13545 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13548 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
13549 xmlXPathStepOpPtr op
,
13552 xmlXPathObjectPtr resObj
= NULL
;
13555 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
13557 /* comp = ctxt->comp; */
13561 case XPATH_OP_VALUE
:
13562 resObj
= (xmlXPathObjectPtr
) op
->value4
;
13564 return(xmlXPathEvaluatePredicateResult(ctxt
, resObj
));
13565 return(xmlXPathCastToBoolean(resObj
));
13566 case XPATH_OP_SORT
:
13568 * We don't need sorting for boolean results. Skip this one.
13570 if (op
->ch1
!= -1) {
13571 op
= &ctxt
->comp
->steps
[op
->ch1
];
13575 case XPATH_OP_COLLECT
:
13579 xmlXPathCompOpEval(ctxt
, &ctxt
->comp
->steps
[op
->ch1
]);
13580 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13583 xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 1);
13584 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13587 resObj
= valuePop(ctxt
);
13588 if (resObj
== NULL
)
13593 * Fallback to call xmlXPathCompOpEval().
13595 xmlXPathCompOpEval(ctxt
, op
);
13596 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13599 resObj
= valuePop(ctxt
);
13600 if (resObj
== NULL
)
13608 if (resObj
->type
== XPATH_BOOLEAN
) {
13609 res
= resObj
->boolval
;
13610 } else if (isPredicate
) {
13612 * For predicates a result of type "number" is handled
13615 * "If the result is a number, the result will be converted
13616 * to true if the number is equal to the context position
13617 * and will be converted to false otherwise;"
13619 res
= xmlXPathEvaluatePredicateResult(ctxt
, resObj
);
13621 res
= xmlXPathCastToBoolean(resObj
);
13623 xmlXPathReleaseObject(ctxt
->context
, resObj
);
13630 #ifdef XPATH_STREAMING
13632 * xmlXPathRunStreamEval:
13633 * @ctxt: the XPath parser context with the compiled expression
13635 * Evaluate the Precompiled Streamable XPath expression in the given context.
13638 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt
, xmlPatternPtr comp
,
13639 xmlXPathObjectPtr
*resultSeq
, int toBool
)
13641 int max_depth
, min_depth
;
13644 int eval_all_nodes
;
13645 xmlNodePtr cur
= NULL
, limit
= NULL
;
13646 xmlStreamCtxtPtr patstream
= NULL
;
13650 if ((ctxt
== NULL
) || (comp
== NULL
))
13652 max_depth
= xmlPatternMaxDepth(comp
);
13653 if (max_depth
== -1)
13655 if (max_depth
== -2)
13657 min_depth
= xmlPatternMinDepth(comp
);
13658 if (min_depth
== -1)
13660 from_root
= xmlPatternFromRoot(comp
);
13664 printf("stream eval: depth %d from root %d\n", max_depth
, from_root
);
13668 if (resultSeq
== NULL
)
13670 *resultSeq
= xmlXPathCacheNewNodeSet(ctxt
, NULL
);
13671 if (*resultSeq
== NULL
)
13676 * handle the special cases of "/" amd "." being matched
13678 if (min_depth
== 0) {
13683 /* TODO: Check memory error. */
13684 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
,
13685 (xmlNodePtr
) ctxt
->doc
);
13687 /* Select "self::node()" */
13690 /* TODO: Check memory error. */
13691 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, ctxt
->node
);
13694 if (max_depth
== 0) {
13699 cur
= (xmlNodePtr
)ctxt
->doc
;
13700 } else if (ctxt
->node
!= NULL
) {
13701 switch (ctxt
->node
->type
) {
13702 case XML_ELEMENT_NODE
:
13703 case XML_DOCUMENT_NODE
:
13704 case XML_DOCUMENT_FRAG_NODE
:
13705 case XML_HTML_DOCUMENT_NODE
:
13708 case XML_ATTRIBUTE_NODE
:
13709 case XML_TEXT_NODE
:
13710 case XML_CDATA_SECTION_NODE
:
13711 case XML_ENTITY_REF_NODE
:
13712 case XML_ENTITY_NODE
:
13714 case XML_COMMENT_NODE
:
13715 case XML_NOTATION_NODE
:
13717 case XML_DOCUMENT_TYPE_NODE
:
13718 case XML_ELEMENT_DECL
:
13719 case XML_ATTRIBUTE_DECL
:
13720 case XML_ENTITY_DECL
:
13721 case XML_NAMESPACE_DECL
:
13722 case XML_XINCLUDE_START
:
13723 case XML_XINCLUDE_END
:
13732 patstream
= xmlPatternGetStreamCtxt(comp
);
13733 if (patstream
== NULL
) {
13735 * QUESTION TODO: Is this an error?
13740 eval_all_nodes
= xmlStreamWantsAnyNode(patstream
);
13743 ret
= xmlStreamPush(patstream
, NULL
, NULL
);
13745 } else if (ret
== 1) {
13748 /* TODO: Check memory error. */
13749 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
);
13753 goto scan_children
;
13756 if (ctxt
->opLimit
!= 0) {
13757 if (ctxt
->opCount
>= ctxt
->opLimit
) {
13758 xmlGenericError(xmlGenericErrorContext
,
13759 "XPath operation limit exceeded\n");
13760 xmlFreeStreamCtxt(patstream
);
13768 switch (cur
->type
) {
13769 case XML_ELEMENT_NODE
:
13770 case XML_TEXT_NODE
:
13771 case XML_CDATA_SECTION_NODE
:
13772 case XML_COMMENT_NODE
:
13774 if (cur
->type
== XML_ELEMENT_NODE
) {
13775 ret
= xmlStreamPush(patstream
, cur
->name
,
13776 (cur
->ns
? cur
->ns
->href
: NULL
));
13777 } else if (eval_all_nodes
)
13778 ret
= xmlStreamPushNode(patstream
, NULL
, NULL
, cur
->type
);
13784 } else if (ret
== 1) {
13787 if (xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
)
13789 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
13790 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
13793 if ((cur
->children
== NULL
) || (depth
>= max_depth
)) {
13794 ret
= xmlStreamPop(patstream
);
13795 while (cur
->next
!= NULL
) {
13797 if ((cur
->type
!= XML_ENTITY_DECL
) &&
13798 (cur
->type
!= XML_DTD_NODE
))
13807 if (cur
->type
== XML_NAMESPACE_DECL
) break;
13808 if ((cur
->children
!= NULL
) && (depth
< max_depth
)) {
13810 * Do not descend on entities declarations
13812 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
13813 cur
= cur
->children
;
13818 if (cur
->type
!= XML_DTD_NODE
)
13826 while (cur
->next
!= NULL
) {
13828 if ((cur
->type
!= XML_ENTITY_DECL
) &&
13829 (cur
->type
!= XML_DTD_NODE
))
13836 if ((cur
== NULL
) || (cur
== limit
) ||
13837 (cur
->type
== XML_DOCUMENT_NODE
))
13839 if (cur
->type
== XML_ELEMENT_NODE
) {
13840 ret
= xmlStreamPop(patstream
);
13841 } else if ((eval_all_nodes
) &&
13842 ((cur
->type
== XML_TEXT_NODE
) ||
13843 (cur
->type
== XML_CDATA_SECTION_NODE
) ||
13844 (cur
->type
== XML_COMMENT_NODE
) ||
13845 (cur
->type
== XML_PI_NODE
)))
13847 ret
= xmlStreamPop(patstream
);
13849 if (cur
->next
!= NULL
) {
13853 } while (cur
!= NULL
);
13855 } while ((cur
!= NULL
) && (depth
>= 0));
13860 printf("stream eval: checked %d nodes selected %d\n",
13861 nb_nodes
, retObj
->nodesetval
->nodeNr
);
13865 xmlFreeStreamCtxt(patstream
);
13870 xmlFreeStreamCtxt(patstream
);
13873 #endif /* XPATH_STREAMING */
13877 * @ctxt: the XPath parser context with the compiled expression
13878 * @toBool: evaluate to a boolean result
13880 * Evaluate the Precompiled XPath expression in the given context.
13883 xmlXPathRunEval(xmlXPathParserContextPtr ctxt
, int toBool
)
13885 xmlXPathCompExprPtr comp
;
13888 if ((ctxt
== NULL
) || (ctxt
->comp
== NULL
))
13891 if (ctxt
->valueTab
== NULL
) {
13892 /* Allocate the value stack */
13893 ctxt
->valueTab
= (xmlXPathObjectPtr
*)
13894 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
13895 if (ctxt
->valueTab
== NULL
) {
13896 xmlXPathPErrMemory(ctxt
, "creating evaluation context\n");
13900 ctxt
->valueMax
= 10;
13901 ctxt
->value
= NULL
;
13902 ctxt
->valueFrame
= 0;
13904 #ifdef XPATH_STREAMING
13905 if (ctxt
->comp
->stream
) {
13910 * Evaluation to boolean result.
13912 res
= xmlXPathRunStreamEval(ctxt
->context
,
13913 ctxt
->comp
->stream
, NULL
, 1);
13917 xmlXPathObjectPtr resObj
= NULL
;
13920 * Evaluation to a sequence.
13922 res
= xmlXPathRunStreamEval(ctxt
->context
,
13923 ctxt
->comp
->stream
, &resObj
, 0);
13925 if ((res
!= -1) && (resObj
!= NULL
)) {
13926 valuePush(ctxt
, resObj
);
13929 if (resObj
!= NULL
)
13930 xmlXPathReleaseObject(ctxt
->context
, resObj
);
13933 * QUESTION TODO: This falls back to normal XPath evaluation
13934 * if res == -1. Is this intended?
13939 if (comp
->last
< 0) {
13940 xmlGenericError(xmlGenericErrorContext
,
13941 "xmlXPathRunEval: last is less than zero\n");
13944 oldDepth
= ctxt
->context
->depth
;
13946 return(xmlXPathCompOpEvalToBoolean(ctxt
,
13947 &comp
->steps
[comp
->last
], 0));
13949 xmlXPathCompOpEval(ctxt
, &comp
->steps
[comp
->last
]);
13950 ctxt
->context
->depth
= oldDepth
;
13955 /************************************************************************
13957 * Public interfaces *
13959 ************************************************************************/
13962 * xmlXPathEvalPredicate:
13963 * @ctxt: the XPath context
13964 * @res: the Predicate Expression evaluation result
13966 * Evaluate a predicate result for the current node.
13967 * A PredicateExpr is evaluated by evaluating the Expr and converting
13968 * the result to a boolean. If the result is a number, the result will
13969 * be converted to true if the number is equal to the position of the
13970 * context node in the context node list (as returned by the position
13971 * function) and will be converted to false otherwise; if the result
13972 * is not a number, then the result will be converted as if by a call
13973 * to the boolean function.
13975 * Returns 1 if predicate is true, 0 otherwise
13978 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr res
) {
13979 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
13980 switch (res
->type
) {
13981 case XPATH_BOOLEAN
:
13982 return(res
->boolval
);
13984 return(res
->floatval
== ctxt
->proximityPosition
);
13985 case XPATH_NODESET
:
13986 case XPATH_XSLT_TREE
:
13987 if (res
->nodesetval
== NULL
)
13989 return(res
->nodesetval
->nodeNr
!= 0);
13991 return((res
->stringval
!= NULL
) &&
13992 (xmlStrlen(res
->stringval
) != 0));
14000 * xmlXPathEvaluatePredicateResult:
14001 * @ctxt: the XPath Parser context
14002 * @res: the Predicate Expression evaluation result
14004 * Evaluate a predicate result for the current node.
14005 * A PredicateExpr is evaluated by evaluating the Expr and converting
14006 * the result to a boolean. If the result is a number, the result will
14007 * be converted to true if the number is equal to the position of the
14008 * context node in the context node list (as returned by the position
14009 * function) and will be converted to false otherwise; if the result
14010 * is not a number, then the result will be converted as if by a call
14011 * to the boolean function.
14013 * Returns 1 if predicate is true, 0 otherwise
14016 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt
,
14017 xmlXPathObjectPtr res
) {
14018 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14019 switch (res
->type
) {
14020 case XPATH_BOOLEAN
:
14021 return(res
->boolval
);
14023 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14024 return((res
->floatval
== ctxt
->context
->proximityPosition
) &&
14025 (!xmlXPathIsNaN(res
->floatval
))); /* MSC pbm Mark Vakoc !*/
14027 return(res
->floatval
== ctxt
->context
->proximityPosition
);
14029 case XPATH_NODESET
:
14030 case XPATH_XSLT_TREE
:
14031 if (res
->nodesetval
== NULL
)
14033 return(res
->nodesetval
->nodeNr
!= 0);
14035 return((res
->stringval
!= NULL
) && (res
->stringval
[0] != 0));
14036 #ifdef LIBXML_XPTR_LOCS_ENABLED
14037 case XPATH_LOCATIONSET
:{
14038 xmlLocationSetPtr ptr
= res
->user
;
14041 return (ptr
->locNr
!= 0);
14050 #ifdef XPATH_STREAMING
14052 * xmlXPathTryStreamCompile:
14053 * @ctxt: an XPath context
14054 * @str: the XPath expression
14056 * Try to compile the XPath expression as a streamable subset.
14058 * Returns the compiled expression or NULL if failed to compile.
14060 static xmlXPathCompExprPtr
14061 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14063 * Optimization: use streaming patterns when the XPath expression can
14064 * be compiled to a stream lookup
14066 xmlPatternPtr stream
;
14067 xmlXPathCompExprPtr comp
;
14068 xmlDictPtr dict
= NULL
;
14069 const xmlChar
**namespaces
= NULL
;
14073 if ((!xmlStrchr(str
, '[')) && (!xmlStrchr(str
, '(')) &&
14074 (!xmlStrchr(str
, '@'))) {
14075 const xmlChar
*tmp
;
14078 * We don't try to handle expressions using the verbose axis
14079 * specifiers ("::"), just the simplified form at this point.
14080 * Additionally, if there is no list of namespaces available and
14081 * there's a ":" in the expression, indicating a prefixed QName,
14082 * then we won't try to compile either. xmlPatterncompile() needs
14083 * to have a list of namespaces at compilation time in order to
14084 * compile prefixed name tests.
14086 tmp
= xmlStrchr(str
, ':');
14087 if ((tmp
!= NULL
) &&
14088 ((ctxt
== NULL
) || (ctxt
->nsNr
== 0) || (tmp
[1] == ':')))
14091 if (ctxt
!= NULL
) {
14093 if (ctxt
->nsNr
> 0) {
14094 namespaces
= xmlMalloc(2 * (ctxt
->nsNr
+ 1) * sizeof(xmlChar
*));
14095 if (namespaces
== NULL
) {
14096 xmlXPathErrMemory(ctxt
, "allocating namespaces array\n");
14099 for (i
= 0, j
= 0; (j
< ctxt
->nsNr
); j
++) {
14100 ns
= ctxt
->namespaces
[j
];
14101 namespaces
[i
++] = ns
->href
;
14102 namespaces
[i
++] = ns
->prefix
;
14104 namespaces
[i
++] = NULL
;
14105 namespaces
[i
] = NULL
;
14109 stream
= xmlPatterncompile(str
, dict
, XML_PATTERN_XPATH
, namespaces
);
14110 if (namespaces
!= NULL
) {
14111 xmlFree((xmlChar
**)namespaces
);
14113 if ((stream
!= NULL
) && (xmlPatternStreamable(stream
) == 1)) {
14114 comp
= xmlXPathNewCompExpr();
14115 if (comp
== NULL
) {
14116 xmlXPathErrMemory(ctxt
, "allocating streamable expression\n");
14119 comp
->stream
= stream
;
14122 xmlDictReference(comp
->dict
);
14125 xmlFreePattern(stream
);
14129 #endif /* XPATH_STREAMING */
14132 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt
,
14133 xmlXPathStepOpPtr op
)
14135 xmlXPathCompExprPtr comp
= pctxt
->comp
;
14136 xmlXPathContextPtr ctxt
;
14139 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14140 * internal representation.
14143 if ((op
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14145 (op
->ch2
== -1 /* no predicate */))
14147 xmlXPathStepOpPtr prevop
= &comp
->steps
[op
->ch1
];
14149 if ((prevop
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14150 ((xmlXPathAxisVal
) prevop
->value
==
14151 AXIS_DESCENDANT_OR_SELF
) &&
14152 (prevop
->ch2
== -1) &&
14153 ((xmlXPathTestVal
) prevop
->value2
== NODE_TEST_TYPE
) &&
14154 ((xmlXPathTypeVal
) prevop
->value3
== NODE_TYPE_NODE
))
14157 * This is a "descendant-or-self::node()" without predicates.
14158 * Try to eliminate it.
14161 switch ((xmlXPathAxisVal
) op
->value
) {
14163 case AXIS_DESCENDANT
:
14165 * Convert "descendant-or-self::node()/child::" or
14166 * "descendant-or-self::node()/descendant::" to
14169 op
->ch1
= prevop
->ch1
;
14170 op
->value
= AXIS_DESCENDANT
;
14173 case AXIS_DESCENDANT_OR_SELF
:
14175 * Convert "descendant-or-self::node()/self::" or
14176 * "descendant-or-self::node()/descendant-or-self::" to
14177 * to "descendant-or-self::"
14179 op
->ch1
= prevop
->ch1
;
14180 op
->value
= AXIS_DESCENDANT_OR_SELF
;
14188 /* OP_VALUE has invalid ch1. */
14189 if (op
->op
== XPATH_OP_VALUE
)
14193 ctxt
= pctxt
->context
;
14194 if (ctxt
!= NULL
) {
14195 if (ctxt
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
14200 xmlXPathOptimizeExpression(pctxt
, &comp
->steps
[op
->ch1
]);
14202 xmlXPathOptimizeExpression(pctxt
, &comp
->steps
[op
->ch2
]);
14208 * xmlXPathCtxtCompile:
14209 * @ctxt: an XPath context
14210 * @str: the XPath expression
14212 * Compile an XPath expression
14214 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14215 * the caller has to free the object.
14217 xmlXPathCompExprPtr
14218 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14219 xmlXPathParserContextPtr pctxt
;
14220 xmlXPathCompExprPtr comp
;
14223 #ifdef XPATH_STREAMING
14224 comp
= xmlXPathTryStreamCompile(ctxt
, str
);
14231 pctxt
= xmlXPathNewParserContext(str
, ctxt
);
14235 oldDepth
= ctxt
->depth
;
14236 xmlXPathCompileExpr(pctxt
, 1);
14238 ctxt
->depth
= oldDepth
;
14240 if( pctxt
->error
!= XPATH_EXPRESSION_OK
)
14242 xmlXPathFreeParserContext(pctxt
);
14246 if (*pctxt
->cur
!= 0) {
14248 * aleksey: in some cases this line prints *second* error message
14249 * (see bug #78858) and probably this should be fixed.
14250 * However, we are not sure that all error messages are printed
14251 * out in other places. It's not critical so we leave it as-is for now
14253 xmlXPatherror(pctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
14256 comp
= pctxt
->comp
;
14257 if ((comp
->nbStep
> 1) && (comp
->last
>= 0)) {
14259 oldDepth
= ctxt
->depth
;
14260 xmlXPathOptimizeExpression(pctxt
, &comp
->steps
[comp
->last
]);
14262 ctxt
->depth
= oldDepth
;
14264 pctxt
->comp
= NULL
;
14266 xmlXPathFreeParserContext(pctxt
);
14268 if (comp
!= NULL
) {
14269 comp
->expr
= xmlStrdup(str
);
14270 #ifdef DEBUG_EVAL_COUNTS
14271 comp
->string
= xmlStrdup(str
);
14280 * @str: the XPath expression
14282 * Compile an XPath expression
14284 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14285 * the caller has to free the object.
14287 xmlXPathCompExprPtr
14288 xmlXPathCompile(const xmlChar
*str
) {
14289 return(xmlXPathCtxtCompile(NULL
, str
));
14293 * xmlXPathCompiledEvalInternal:
14294 * @comp: the compiled XPath expression
14295 * @ctxt: the XPath context
14296 * @resObj: the resulting XPath object or NULL
14297 * @toBool: 1 if only a boolean result is requested
14299 * Evaluate the Precompiled XPath expression in the given context.
14300 * The caller has to free @resObj.
14302 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14303 * the caller has to free the object.
14306 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp
,
14307 xmlXPathContextPtr ctxt
,
14308 xmlXPathObjectPtr
*resObjPtr
,
14311 xmlXPathParserContextPtr pctxt
;
14312 xmlXPathObjectPtr resObj
;
14313 #ifndef LIBXML_THREAD_ENABLED
14314 static int reentance
= 0;
14318 CHECK_CTXT_NEG(ctxt
)
14324 #ifndef LIBXML_THREAD_ENABLED
14327 xmlXPathDisableOptimizer
= 1;
14330 #ifdef DEBUG_EVAL_COUNTS
14332 if ((comp
->string
!= NULL
) && (comp
->nb
> 100)) {
14333 fprintf(stderr
, "100 x %s\n", comp
->string
);
14337 pctxt
= xmlXPathCompParserContext(comp
, ctxt
);
14338 res
= xmlXPathRunEval(pctxt
, toBool
);
14340 if (pctxt
->error
!= XPATH_EXPRESSION_OK
) {
14343 resObj
= valuePop(pctxt
);
14344 if (resObj
== NULL
) {
14346 xmlGenericError(xmlGenericErrorContext
,
14347 "xmlXPathCompiledEval: No result on the stack.\n");
14348 } else if (pctxt
->valueNr
> 0) {
14349 xmlGenericError(xmlGenericErrorContext
,
14350 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14356 *resObjPtr
= resObj
;
14358 xmlXPathReleaseObject(ctxt
, resObj
);
14360 pctxt
->comp
= NULL
;
14361 xmlXPathFreeParserContext(pctxt
);
14362 #ifndef LIBXML_THREAD_ENABLED
14370 * xmlXPathCompiledEval:
14371 * @comp: the compiled XPath expression
14372 * @ctx: the XPath context
14374 * Evaluate the Precompiled XPath expression in the given context.
14376 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14377 * the caller has to free the object.
14380 xmlXPathCompiledEval(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctx
)
14382 xmlXPathObjectPtr res
= NULL
;
14384 xmlXPathCompiledEvalInternal(comp
, ctx
, &res
, 0);
14389 * xmlXPathCompiledEvalToBoolean:
14390 * @comp: the compiled XPath expression
14391 * @ctxt: the XPath context
14393 * Applies the XPath boolean() function on the result of the given
14394 * compiled expression.
14396 * Returns 1 if the expression evaluated to true, 0 if to false and
14397 * -1 in API and internal errors.
14400 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp
,
14401 xmlXPathContextPtr ctxt
)
14403 return(xmlXPathCompiledEvalInternal(comp
, ctxt
, NULL
, 1));
14407 * xmlXPathEvalExpr:
14408 * @ctxt: the XPath Parser context
14410 * Parse and evaluate an XPath expression in the given context,
14411 * then push the result on the context stack
14414 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt
) {
14415 #ifdef XPATH_STREAMING
14416 xmlXPathCompExprPtr comp
;
14420 if (ctxt
== NULL
) return;
14422 #ifdef XPATH_STREAMING
14423 comp
= xmlXPathTryStreamCompile(ctxt
->context
, ctxt
->base
);
14424 if (comp
!= NULL
) {
14425 if (ctxt
->comp
!= NULL
)
14426 xmlXPathFreeCompExpr(ctxt
->comp
);
14431 if (ctxt
->context
!= NULL
)
14432 oldDepth
= ctxt
->context
->depth
;
14433 xmlXPathCompileExpr(ctxt
, 1);
14434 if (ctxt
->context
!= NULL
)
14435 ctxt
->context
->depth
= oldDepth
;
14438 /* Check for trailing characters. */
14439 if (*ctxt
->cur
!= 0)
14440 XP_ERROR(XPATH_EXPR_ERROR
);
14442 if ((ctxt
->comp
->nbStep
> 1) && (ctxt
->comp
->last
>= 0)) {
14443 if (ctxt
->context
!= NULL
)
14444 oldDepth
= ctxt
->context
->depth
;
14445 xmlXPathOptimizeExpression(ctxt
,
14446 &ctxt
->comp
->steps
[ctxt
->comp
->last
]);
14447 if (ctxt
->context
!= NULL
)
14448 ctxt
->context
->depth
= oldDepth
;
14452 xmlXPathRunEval(ctxt
, 0);
14457 * @str: the XPath expression
14458 * @ctx: the XPath context
14460 * Evaluate the XPath Location Path in the given context.
14462 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14463 * the caller has to free the object.
14466 xmlXPathEval(const xmlChar
*str
, xmlXPathContextPtr ctx
) {
14467 xmlXPathParserContextPtr ctxt
;
14468 xmlXPathObjectPtr res
;
14474 ctxt
= xmlXPathNewParserContext(str
, ctx
);
14477 xmlXPathEvalExpr(ctxt
);
14479 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14482 res
= valuePop(ctxt
);
14484 xmlGenericError(xmlGenericErrorContext
,
14485 "xmlXPathCompiledEval: No result on the stack.\n");
14486 } else if (ctxt
->valueNr
> 0) {
14487 xmlGenericError(xmlGenericErrorContext
,
14488 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14493 xmlXPathFreeParserContext(ctxt
);
14498 * xmlXPathSetContextNode:
14499 * @node: the node to to use as the context node
14500 * @ctx: the XPath context
14502 * Sets 'node' as the context node. The node must be in the same
14503 * document as that associated with the context.
14505 * Returns -1 in case of error or 0 if successful
14508 xmlXPathSetContextNode(xmlNodePtr node
, xmlXPathContextPtr ctx
) {
14509 if ((node
== NULL
) || (ctx
== NULL
))
14512 if (node
->doc
== ctx
->doc
) {
14520 * xmlXPathNodeEval:
14521 * @node: the node to to use as the context node
14522 * @str: the XPath expression
14523 * @ctx: the XPath context
14525 * Evaluate the XPath Location Path in the given context. The node 'node'
14526 * is set as the context node. The context node is not restored.
14528 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14529 * the caller has to free the object.
14532 xmlXPathNodeEval(xmlNodePtr node
, const xmlChar
*str
, xmlXPathContextPtr ctx
) {
14535 if (xmlXPathSetContextNode(node
, ctx
) < 0)
14537 return(xmlXPathEval(str
, ctx
));
14541 * xmlXPathEvalExpression:
14542 * @str: the XPath expression
14543 * @ctxt: the XPath context
14545 * Alias for xmlXPathEval().
14547 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14548 * the caller has to free the object.
14551 xmlXPathEvalExpression(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
14552 return(xmlXPathEval(str
, ctxt
));
14555 /************************************************************************
14557 * Extra functions not pertaining to the XPath spec *
14559 ************************************************************************/
14561 * xmlXPathEscapeUriFunction:
14562 * @ctxt: the XPath Parser context
14563 * @nargs: the number of arguments
14565 * Implement the escape-uri() XPath function
14566 * string escape-uri(string $str, bool $escape-reserved)
14568 * This function applies the URI escaping rules defined in section 2 of [RFC
14569 * 2396] to the string supplied as $uri-part, which typically represents all
14570 * or part of a URI. The effect of the function is to replace any special
14571 * character in the string by an escape sequence of the form %xx%yy...,
14572 * where xxyy... is the hexadecimal representation of the octets used to
14573 * represent the character in UTF-8.
14575 * The set of characters that are escaped depends on the setting of the
14576 * boolean argument $escape-reserved.
14578 * If $escape-reserved is true, all characters are escaped other than lower
14579 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14580 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14581 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14582 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14585 * If $escape-reserved is false, the behavior differs in that characters
14586 * referred to in [RFC 2396] as reserved characters are not escaped. These
14587 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14589 * [RFC 2396] does not define whether escaped URIs should use lower case or
14590 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14591 * compared using string comparison functions, this function must always use
14592 * the upper-case letters A-F.
14594 * Generally, $escape-reserved should be set to true when escaping a string
14595 * that is to form a single part of a URI, and to false when escaping an
14596 * entire URI or URI reference.
14598 * In the case of non-ascii characters, the string is encoded according to
14599 * utf-8 and then converted according to RFC 2396.
14602 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14603 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14604 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14605 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14609 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
14610 xmlXPathObjectPtr str
;
14611 int escape_reserved
;
14618 escape_reserved
= xmlXPathPopBoolean(ctxt
);
14621 str
= valuePop(ctxt
);
14623 target
= xmlBufCreate();
14629 for (cptr
= str
->stringval
; *cptr
; cptr
++) {
14630 if ((*cptr
>= 'A' && *cptr
<= 'Z') ||
14631 (*cptr
>= 'a' && *cptr
<= 'z') ||
14632 (*cptr
>= '0' && *cptr
<= '9') ||
14633 *cptr
== '-' || *cptr
== '_' || *cptr
== '.' ||
14634 *cptr
== '!' || *cptr
== '~' || *cptr
== '*' ||
14635 *cptr
== '\''|| *cptr
== '(' || *cptr
== ')' ||
14637 ((cptr
[1] >= 'A' && cptr
[1] <= 'F') ||
14638 (cptr
[1] >= 'a' && cptr
[1] <= 'f') ||
14639 (cptr
[1] >= '0' && cptr
[1] <= '9')) &&
14640 ((cptr
[2] >= 'A' && cptr
[2] <= 'F') ||
14641 (cptr
[2] >= 'a' && cptr
[2] <= 'f') ||
14642 (cptr
[2] >= '0' && cptr
[2] <= '9'))) ||
14643 (!escape_reserved
&&
14644 (*cptr
== ';' || *cptr
== '/' || *cptr
== '?' ||
14645 *cptr
== ':' || *cptr
== '@' || *cptr
== '&' ||
14646 *cptr
== '=' || *cptr
== '+' || *cptr
== '$' ||
14648 xmlBufAdd(target
, cptr
, 1);
14650 if ((*cptr
>> 4) < 10)
14651 escape
[1] = '0' + (*cptr
>> 4);
14653 escape
[1] = 'A' - 10 + (*cptr
>> 4);
14654 if ((*cptr
& 0xF) < 10)
14655 escape
[2] = '0' + (*cptr
& 0xF);
14657 escape
[2] = 'A' - 10 + (*cptr
& 0xF);
14659 xmlBufAdd(target
, &escape
[0], 3);
14663 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
14664 xmlBufContent(target
)));
14665 xmlBufFree(target
);
14666 xmlXPathReleaseObject(ctxt
->context
, str
);
14670 * xmlXPathRegisterAllFunctions:
14671 * @ctxt: the XPath context
14673 * Registers all default XPath functions in this context
14676 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt
)
14678 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"boolean",
14679 xmlXPathBooleanFunction
);
14680 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"ceiling",
14681 xmlXPathCeilingFunction
);
14682 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"count",
14683 xmlXPathCountFunction
);
14684 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"concat",
14685 xmlXPathConcatFunction
);
14686 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"contains",
14687 xmlXPathContainsFunction
);
14688 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"id",
14689 xmlXPathIdFunction
);
14690 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"false",
14691 xmlXPathFalseFunction
);
14692 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"floor",
14693 xmlXPathFloorFunction
);
14694 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"last",
14695 xmlXPathLastFunction
);
14696 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"lang",
14697 xmlXPathLangFunction
);
14698 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"local-name",
14699 xmlXPathLocalNameFunction
);
14700 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"not",
14701 xmlXPathNotFunction
);
14702 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"name",
14703 xmlXPathNameFunction
);
14704 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"namespace-uri",
14705 xmlXPathNamespaceURIFunction
);
14706 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"normalize-space",
14707 xmlXPathNormalizeFunction
);
14708 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"number",
14709 xmlXPathNumberFunction
);
14710 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"position",
14711 xmlXPathPositionFunction
);
14712 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"round",
14713 xmlXPathRoundFunction
);
14714 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string",
14715 xmlXPathStringFunction
);
14716 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string-length",
14717 xmlXPathStringLengthFunction
);
14718 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"starts-with",
14719 xmlXPathStartsWithFunction
);
14720 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring",
14721 xmlXPathSubstringFunction
);
14722 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-before",
14723 xmlXPathSubstringBeforeFunction
);
14724 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-after",
14725 xmlXPathSubstringAfterFunction
);
14726 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"sum",
14727 xmlXPathSumFunction
);
14728 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"true",
14729 xmlXPathTrueFunction
);
14730 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"translate",
14731 xmlXPathTranslateFunction
);
14733 xmlXPathRegisterFuncNS(ctxt
, (const xmlChar
*)"escape-uri",
14734 (const xmlChar
*)"http://www.w3.org/2002/08/xquery-functions",
14735 xmlXPathEscapeUriFunction
);
14738 #endif /* LIBXML_XPATH_ENABLED */