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>
52 #include "private/buf.h"
53 #include "private/error.h"
54 #include "private/xpath.h"
56 #ifdef LIBXML_PATTERN_ENABLED
57 #define XPATH_STREAMING
61 xmlGenericError(xmlGenericErrorContext, \
62 "Unimplemented block at %s:%d\n", \
68 * Use the Timsort algorithm provided in timsort.h to sort
69 * nodeset as this is a great improvement over the old Shell sort
70 * used in xmlXPathNodeSetSort()
75 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
76 * If defined, this will use xmlXPathCmpNodesExt() instead of
77 * xmlXPathCmpNodes(). The new function is optimized comparison of
78 * non-element nodes; actually it will speed up comparison only if
79 * xmlXPathOrderDocElems() was called in order to index the elements of
80 * a tree in document order; Libxslt does such an indexing, thus it will
81 * benefit from this optimization.
83 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
86 * XP_OPTIMIZED_FILTER_FIRST:
87 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
88 * in a way, that it stop evaluation at the first node.
90 #define XP_OPTIMIZED_FILTER_FIRST
94 * Internal flag to enable tracking of how much XPath objects have been
97 /* #define XP_DEBUG_OBJ_USAGE */
101 * when compiling an XPath expression we arbitrary limit the maximum
102 * number of step operation in the compiled expression. 1000000 is
103 * an insanely large value which should never be reached under normal
106 #define XPATH_MAX_STEPS 1000000
109 * XPATH_MAX_STACK_DEPTH:
110 * when evaluating an XPath expression we arbitrary limit the maximum
111 * number of object allowed to be pushed on the stack. 1000000 is
112 * an insanely large value which should never be reached under normal
115 #define XPATH_MAX_STACK_DEPTH 1000000
118 * XPATH_MAX_NODESET_LENGTH:
119 * when evaluating an XPath expression nodesets are created and we
120 * arbitrary limit the maximum length of those node set. 10000000 is
121 * an insanely large value which should never be reached under normal
122 * circumstances, one would first need to construct an in memory tree
123 * with more than 10 millions nodes.
125 #define XPATH_MAX_NODESET_LENGTH 10000000
128 * XPATH_MAX_RECRUSION_DEPTH:
129 * Maximum amount of nested functions calls when parsing or evaluating
132 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
133 #define XPATH_MAX_RECURSION_DEPTH 500
134 #elif defined(_WIN32)
135 /* Windows typically limits stack size to 1MB. */
136 #define XPATH_MAX_RECURSION_DEPTH 1000
138 #define XPATH_MAX_RECURSION_DEPTH 5000
143 * There are a few spots where some tests are done which depend upon ascii
144 * data. These should be enhanced for full UTF8 support (see particularly
145 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
148 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
150 /************************************************************************
152 * Floating point stuff *
154 ************************************************************************/
156 double xmlXPathNAN
= 0.0;
157 double xmlXPathPINF
= 0.0;
158 double xmlXPathNINF
= 0.0;
163 * DEPRECATED: Alias for xmlInitParser.
171 * xmlInitXPathInternal:
173 * Initialize the XPath environment
175 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
177 xmlInitXPathInternal(void) {
178 #if defined(NAN) && defined(INFINITY)
180 xmlXPathPINF
= INFINITY
;
181 xmlXPathNINF
= -INFINITY
;
183 /* MSVC doesn't allow division by zero in constant expressions. */
185 xmlXPathNAN
= 0.0 / zero
;
186 xmlXPathPINF
= 1.0 / zero
;
187 xmlXPathNINF
= -xmlXPathPINF
;
193 * @val: a double value
195 * Returns 1 if the value is a NaN, 0 otherwise
198 xmlXPathIsNaN(double val
) {
202 return !(val
== val
);
208 * @val: a double value
210 * Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
213 xmlXPathIsInf(double val
) {
215 return isinf(val
) ? (val
> 0 ? 1 : -1) : 0;
217 if (val
>= xmlXPathPINF
)
219 if (val
<= -xmlXPathPINF
)
225 #endif /* SCHEMAS or XPATH */
227 #ifdef LIBXML_XPATH_ENABLED
230 * TODO: when compatibility allows remove all "fake node libxslt" strings
231 * the test should just be name[0] = ' '
233 #ifdef DEBUG_XPATH_EXPRESSION
236 #define DEBUG_EVAL_COUNTS
239 static xmlNs xmlXPathXMLNamespaceStruct
= {
247 static xmlNsPtr xmlXPathXMLNamespace
= &xmlXPathXMLNamespaceStruct
;
248 #ifndef LIBXML_THREAD_ENABLED
250 * Optimizer is disabled only when threaded apps are detected while
251 * the library ain't compiled for thread safety.
253 static int xmlXPathDisableOptimizer
= 0;
257 xmlXPathNodeSetClear(xmlNodeSetPtr set
, int hasNsNodes
);
259 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
261 * xmlXPathCmpNodesExt:
262 * @node1: the first node
263 * @node2: the second node
265 * Compare two nodes w.r.t document order.
266 * This one is optimized for handling of non-element nodes.
268 * Returns -2 in case of error 1 if first point < second point, 0 if
269 * it's the same node, -1 otherwise
272 xmlXPathCmpNodesExt(xmlNodePtr node1
, xmlNodePtr node2
) {
274 int misc
= 0, precedence1
= 0, precedence2
= 0;
275 xmlNodePtr miscNode1
= NULL
, miscNode2
= NULL
;
276 xmlNodePtr cur
, root
;
279 if ((node1
== NULL
) || (node2
== NULL
))
286 * a couple of optimizations which will avoid computations in most cases
288 switch (node1
->type
) {
289 case XML_ELEMENT_NODE
:
290 if (node2
->type
== XML_ELEMENT_NODE
) {
291 if ((0 > (ptrdiff_t) node1
->content
) &&
292 (0 > (ptrdiff_t) node2
->content
) &&
293 (node1
->doc
== node2
->doc
))
295 l1
= -((ptrdiff_t) node1
->content
);
296 l2
= -((ptrdiff_t) node2
->content
);
302 goto turtle_comparison
;
305 case XML_ATTRIBUTE_NODE
:
306 precedence1
= 1; /* element is owner */
308 node1
= node1
->parent
;
312 case XML_CDATA_SECTION_NODE
:
313 case XML_COMMENT_NODE
:
317 * Find nearest element node.
319 if (node1
->prev
!= NULL
) {
322 if (node1
->type
== XML_ELEMENT_NODE
) {
323 precedence1
= 3; /* element in prev-sibl axis */
326 if (node1
->prev
== NULL
) {
327 precedence1
= 2; /* element is parent */
329 * URGENT TODO: Are there any cases, where the
330 * parent of such a node is not an element node?
332 node1
= node1
->parent
;
337 precedence1
= 2; /* element is parent */
338 node1
= node1
->parent
;
340 if ((node1
== NULL
) || (node1
->type
!= XML_ELEMENT_NODE
) ||
341 (0 <= (ptrdiff_t) node1
->content
)) {
343 * Fallback for whatever case.
351 case XML_NAMESPACE_DECL
:
353 * TODO: why do we return 1 for namespace nodes?
359 switch (node2
->type
) {
360 case XML_ELEMENT_NODE
:
362 case XML_ATTRIBUTE_NODE
:
363 precedence2
= 1; /* element is owner */
365 node2
= node2
->parent
;
369 case XML_CDATA_SECTION_NODE
:
370 case XML_COMMENT_NODE
:
373 if (node2
->prev
!= NULL
) {
376 if (node2
->type
== XML_ELEMENT_NODE
) {
377 precedence2
= 3; /* element in prev-sibl axis */
380 if (node2
->prev
== NULL
) {
381 precedence2
= 2; /* element is parent */
382 node2
= node2
->parent
;
387 precedence2
= 2; /* element is parent */
388 node2
= node2
->parent
;
390 if ((node2
== NULL
) || (node2
->type
!= XML_ELEMENT_NODE
) ||
391 (0 <= (ptrdiff_t) node2
->content
))
399 case XML_NAMESPACE_DECL
:
405 if (node1
== node2
) {
406 if (precedence1
== precedence2
) {
408 * The ugly case; but normally there aren't many
409 * adjacent non-element nodes around.
411 cur
= miscNode2
->prev
;
412 while (cur
!= NULL
) {
413 if (cur
== miscNode1
)
415 if (cur
->type
== XML_ELEMENT_NODE
)
422 * Evaluate based on higher precedence wrt to the element.
423 * TODO: This assumes attributes are sorted before content.
424 * Is this 100% correct?
426 if (precedence1
< precedence2
)
433 * Special case: One of the helper-elements is contained by the other.
436 * <node1>Text-1(precedence1 == 2)</node1>
438 * Text-6(precedence2 == 3)
441 if ((precedence2
== 3) && (precedence1
> 1)) {
449 if ((precedence1
== 3) && (precedence2
> 1)) {
460 * Speedup using document order if available.
462 if ((node1
->type
== XML_ELEMENT_NODE
) &&
463 (node2
->type
== XML_ELEMENT_NODE
) &&
464 (0 > (ptrdiff_t) node1
->content
) &&
465 (0 > (ptrdiff_t) node2
->content
) &&
466 (node1
->doc
== node2
->doc
)) {
468 l1
= -((ptrdiff_t) node1
->content
);
469 l2
= -((ptrdiff_t) node2
->content
);
478 if (node1
== node2
->prev
)
480 if (node1
== node2
->next
)
483 * compute depth to root
485 for (depth2
= 0, cur
= node2
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
486 if (cur
->parent
== node1
)
491 for (depth1
= 0, cur
= node1
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
492 if (cur
->parent
== node2
)
497 * Distinct document (or distinct entities :-( ) case.
503 * get the nearest common ancestor.
505 while (depth1
> depth2
) {
507 node1
= node1
->parent
;
509 while (depth2
> depth1
) {
511 node2
= node2
->parent
;
513 while (node1
->parent
!= node2
->parent
) {
514 node1
= node1
->parent
;
515 node2
= node2
->parent
;
516 /* should not happen but just in case ... */
517 if ((node1
== NULL
) || (node2
== NULL
))
523 if (node1
== node2
->prev
)
525 if (node1
== node2
->next
)
528 * Speedup using document order if available.
530 if ((node1
->type
== XML_ELEMENT_NODE
) &&
531 (node2
->type
== XML_ELEMENT_NODE
) &&
532 (0 > (ptrdiff_t) node1
->content
) &&
533 (0 > (ptrdiff_t) node2
->content
) &&
534 (node1
->doc
== node2
->doc
)) {
536 l1
= -((ptrdiff_t) node1
->content
);
537 l2
= -((ptrdiff_t) node2
->content
);
544 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
547 return(-1); /* assume there is no sibling list corruption */
549 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
552 * Wrapper for the Timsort algorithm from timsort.h
555 #define SORT_NAME libxml_domnode
556 #define SORT_TYPE xmlNodePtr
562 * Comparison function for the Timsort implementation
564 * Returns -2 in case of error -1 if first point < second point, 0 if
565 * it's the same node, +1 otherwise
568 int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
);
569 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
570 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
572 int res
= xmlXPathCmpNodesExt(x
, y
);
573 return res
== -2 ? res
: -res
;
576 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
578 int res
= xmlXPathCmpNodes(x
, y
);
579 return res
== -2 ? res
: -res
;
582 #define SORT_CMP(x, y) (wrap_cmp(x, y))
584 #endif /* WITH_TIM_SORT */
586 /************************************************************************
588 * Error handling routines *
590 ************************************************************************/
596 * Macro to raise an XPath error and return NULL.
598 #define XP_ERRORNULL(X) \
599 { xmlXPathErr(ctxt, X); return(NULL); }
602 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
604 static const char* const xmlXPathErrorMessages
[] = {
607 "Unfinished literal\n",
608 "Start of literal\n",
609 "Expected $ for variable reference\n",
610 "Undefined variable\n",
611 "Invalid predicate\n",
612 "Invalid expression\n",
613 "Missing closing curly brace\n",
614 "Unregistered function\n",
617 "Invalid number of arguments\n",
618 "Invalid context size\n",
619 "Invalid context position\n",
620 "Memory allocation error\n",
623 "Sub resource error\n",
624 "Undefined namespace prefix\n",
626 "Char out of XML range\n",
627 "Invalid or incomplete context\n",
628 "Stack usage error\n",
629 "Forbidden variable\n",
630 "Operation limit exceeded\n",
631 "Recursion limit exceeded\n",
632 "?? Unknown error ??\n" /* Must be last in the list! */
634 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
635 sizeof(xmlXPathErrorMessages[0])) - 1)
638 * @ctxt: an XPath context
639 * @extra: extra information
641 * Handle a redefinition of attribute error
644 xmlXPathErrMemory(xmlXPathContextPtr ctxt
, const char *extra
)
647 xmlResetError(&ctxt
->lastError
);
651 xmlStrPrintf(buf
, 200,
652 "Memory allocation failed : %s\n",
654 ctxt
->lastError
.message
= (char *) xmlStrdup(buf
);
656 ctxt
->lastError
.message
= (char *)
657 xmlStrdup(BAD_CAST
"Memory allocation failed\n");
659 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
660 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
661 if (ctxt
->error
!= NULL
)
662 ctxt
->error(ctxt
->userData
, &ctxt
->lastError
);
665 __xmlRaiseError(NULL
, NULL
, NULL
,
666 NULL
, NULL
, XML_FROM_XPATH
,
667 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
668 extra
, NULL
, NULL
, 0, 0,
669 "Memory allocation failed : %s\n", extra
);
671 __xmlRaiseError(NULL
, NULL
, NULL
,
672 NULL
, NULL
, XML_FROM_XPATH
,
673 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
674 NULL
, NULL
, NULL
, 0, 0,
675 "Memory allocation failed\n");
680 * xmlXPathPErrMemory:
681 * @ctxt: an XPath parser context
682 * @extra: extra information
684 * Handle a redefinition of attribute error
687 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt
, const char *extra
)
690 xmlXPathErrMemory(NULL
, extra
);
692 ctxt
->error
= XPATH_MEMORY_ERROR
;
693 xmlXPathErrMemory(ctxt
->context
, extra
);
699 * @ctxt: a XPath parser context
700 * @error: the error code
702 * Handle an XPath error
705 xmlXPathErr(xmlXPathParserContextPtr ctxt
, int error
)
707 if ((error
< 0) || (error
> MAXERRNO
))
710 __xmlRaiseError(NULL
, NULL
, NULL
,
711 NULL
, NULL
, XML_FROM_XPATH
,
712 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
713 XML_ERR_ERROR
, NULL
, 0,
714 NULL
, NULL
, NULL
, 0, 0,
715 "%s", xmlXPathErrorMessages
[error
]);
718 /* Only report the first error */
719 if (ctxt
->error
!= 0)
722 if (ctxt
->context
== NULL
) {
723 __xmlRaiseError(NULL
, NULL
, NULL
,
724 NULL
, NULL
, XML_FROM_XPATH
,
725 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
726 XML_ERR_ERROR
, NULL
, 0,
727 (const char *) ctxt
->base
, NULL
, NULL
,
728 ctxt
->cur
- ctxt
->base
, 0,
729 "%s", xmlXPathErrorMessages
[error
]);
733 /* cleanup current last error */
734 xmlResetError(&ctxt
->context
->lastError
);
736 ctxt
->context
->lastError
.domain
= XML_FROM_XPATH
;
737 ctxt
->context
->lastError
.code
= error
+ XML_XPATH_EXPRESSION_OK
-
739 ctxt
->context
->lastError
.level
= XML_ERR_ERROR
;
740 ctxt
->context
->lastError
.str1
= (char *) xmlStrdup(ctxt
->base
);
741 ctxt
->context
->lastError
.int1
= ctxt
->cur
- ctxt
->base
;
742 ctxt
->context
->lastError
.node
= ctxt
->context
->debugNode
;
743 if (ctxt
->context
->error
!= NULL
) {
744 ctxt
->context
->error(ctxt
->context
->userData
,
745 &ctxt
->context
->lastError
);
747 __xmlRaiseError(NULL
, NULL
, NULL
,
748 NULL
, ctxt
->context
->debugNode
, XML_FROM_XPATH
,
749 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
750 XML_ERR_ERROR
, NULL
, 0,
751 (const char *) ctxt
->base
, NULL
, NULL
,
752 ctxt
->cur
- ctxt
->base
, 0,
753 "%s", xmlXPathErrorMessages
[error
]);
760 * @ctxt: the XPath Parser context
761 * @file: the file name
762 * @line: the line number
763 * @no: the error number
765 * Formats an error message.
768 xmlXPatherror(xmlXPathParserContextPtr ctxt
, const char *file ATTRIBUTE_UNUSED
,
769 int line ATTRIBUTE_UNUSED
, int no
) {
770 xmlXPathErr(ctxt
, no
);
774 * xmlXPathCheckOpLimit:
775 * @ctxt: the XPath Parser context
776 * @opCount: the number of operations to be added
778 * Adds opCount to the running total of operations and returns -1 if the
779 * operation limit is exceeded. Returns 0 otherwise.
782 xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt
, unsigned long opCount
) {
783 xmlXPathContextPtr xpctxt
= ctxt
->context
;
785 if ((opCount
> xpctxt
->opLimit
) ||
786 (xpctxt
->opCount
> xpctxt
->opLimit
- opCount
)) {
787 xpctxt
->opCount
= xpctxt
->opLimit
;
788 xmlXPathErr(ctxt
, XPATH_OP_LIMIT_EXCEEDED
);
792 xpctxt
->opCount
+= opCount
;
796 #define OP_LIMIT_EXCEEDED(ctxt, n) \
797 ((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
799 /************************************************************************
803 ************************************************************************/
808 * Pointer-list for various purposes.
810 typedef struct _xmlPointerList xmlPointerList
;
811 typedef xmlPointerList
*xmlPointerListPtr
;
812 struct _xmlPointerList
{
818 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
819 * and here, we should make the functions public.
822 xmlPointerListAddSize(xmlPointerListPtr list
,
826 if (list
->size
<= list
->number
) {
830 if (list
->size
== 0) {
831 if (initialSize
<= 0)
833 newSize
= initialSize
;
835 if (list
->size
> 50000000) {
836 xmlXPathErrMemory(NULL
,
837 "xmlPointerListAddSize: re-allocating item\n");
840 newSize
= list
->size
* 2;
842 tmp
= (void **) xmlRealloc(list
->items
, newSize
* sizeof(void *));
844 xmlXPathErrMemory(NULL
,
845 "xmlPointerListAddSize: re-allocating item\n");
849 list
->size
= newSize
;
851 list
->items
[list
->number
++] = item
;
856 * xsltPointerListCreate:
858 * Creates an xsltPointerList structure.
860 * Returns a xsltPointerList structure or NULL in case of an error.
862 static xmlPointerListPtr
863 xmlPointerListCreate(int initialSize
)
865 xmlPointerListPtr ret
;
867 ret
= xmlMalloc(sizeof(xmlPointerList
));
869 xmlXPathErrMemory(NULL
,
870 "xmlPointerListCreate: allocating item\n");
873 memset(ret
, 0, sizeof(xmlPointerList
));
874 if (initialSize
> 0) {
875 xmlPointerListAddSize(ret
, NULL
, initialSize
);
882 * xsltPointerListFree:
884 * Frees the xsltPointerList structure. This does not free
885 * the content of the list.
888 xmlPointerListFree(xmlPointerListPtr list
)
892 if (list
->items
!= NULL
)
893 xmlFree(list
->items
);
897 /************************************************************************
901 ************************************************************************/
919 XPATH_OP_VALUE
, /* 11 */
924 XPATH_OP_FILTER
, /* 16 */
925 XPATH_OP_SORT
/* 17 */
926 #ifdef LIBXML_XPTR_LOCS_ENABLED
933 AXIS_ANCESTOR_OR_SELF
,
937 AXIS_DESCENDANT_OR_SELF
,
939 AXIS_FOLLOWING_SIBLING
,
943 AXIS_PRECEDING_SIBLING
,
958 NODE_TYPE_COMMENT
= XML_COMMENT_NODE
,
959 NODE_TYPE_TEXT
= XML_TEXT_NODE
,
960 NODE_TYPE_PI
= XML_PI_NODE
963 typedef struct _xmlXPathStepOp xmlXPathStepOp
;
964 typedef xmlXPathStepOp
*xmlXPathStepOpPtr
;
965 struct _xmlXPathStepOp
{
966 xmlXPathOp op
; /* The identifier of the operation */
967 int ch1
; /* First child */
968 int ch2
; /* Second child */
974 xmlXPathFunction cache
;
978 struct _xmlXPathCompExpr
{
979 int nbStep
; /* Number of steps in this expression */
980 int maxStep
; /* Maximum number of steps allocated */
981 xmlXPathStepOp
*steps
; /* ops for computation of this expression */
982 int last
; /* index of last step in expression */
983 xmlChar
*expr
; /* the expression being computed */
984 xmlDictPtr dict
; /* the dictionary to use if any */
985 #ifdef DEBUG_EVAL_COUNTS
989 #ifdef XPATH_STREAMING
990 xmlPatternPtr stream
;
994 /************************************************************************
996 * Forward declarations *
998 ************************************************************************/
1000 xmlXPathFreeValueTree(xmlNodeSetPtr obj
);
1002 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
);
1004 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
1005 xmlXPathStepOpPtr op
, xmlNodePtr
*first
);
1007 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
1008 xmlXPathStepOpPtr op
,
1011 xmlXPathFreeObjectEntry(void *obj
, const xmlChar
*name
);
1013 /************************************************************************
1015 * Parser Type functions *
1017 ************************************************************************/
1020 * xmlXPathNewCompExpr:
1022 * Create a new Xpath component
1024 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1026 static xmlXPathCompExprPtr
1027 xmlXPathNewCompExpr(void) {
1028 xmlXPathCompExprPtr cur
;
1030 cur
= (xmlXPathCompExprPtr
) xmlMalloc(sizeof(xmlXPathCompExpr
));
1032 xmlXPathErrMemory(NULL
, "allocating component\n");
1035 memset(cur
, 0, sizeof(xmlXPathCompExpr
));
1038 cur
->steps
= (xmlXPathStepOp
*) xmlMalloc(cur
->maxStep
*
1039 sizeof(xmlXPathStepOp
));
1040 if (cur
->steps
== NULL
) {
1041 xmlXPathErrMemory(NULL
, "allocating steps\n");
1045 memset(cur
->steps
, 0, cur
->maxStep
* sizeof(xmlXPathStepOp
));
1047 #ifdef DEBUG_EVAL_COUNTS
1054 * xmlXPathFreeCompExpr:
1055 * @comp: an XPATH comp
1057 * Free up the memory allocated by @comp
1060 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp
)
1062 xmlXPathStepOpPtr op
;
1067 if (comp
->dict
== NULL
) {
1068 for (i
= 0; i
< comp
->nbStep
; i
++) {
1069 op
= &comp
->steps
[i
];
1070 if (op
->value4
!= NULL
) {
1071 if (op
->op
== XPATH_OP_VALUE
)
1072 xmlXPathFreeObject(op
->value4
);
1074 xmlFree(op
->value4
);
1076 if (op
->value5
!= NULL
)
1077 xmlFree(op
->value5
);
1080 for (i
= 0; i
< comp
->nbStep
; i
++) {
1081 op
= &comp
->steps
[i
];
1082 if (op
->value4
!= NULL
) {
1083 if (op
->op
== XPATH_OP_VALUE
)
1084 xmlXPathFreeObject(op
->value4
);
1087 xmlDictFree(comp
->dict
);
1089 if (comp
->steps
!= NULL
) {
1090 xmlFree(comp
->steps
);
1092 #ifdef DEBUG_EVAL_COUNTS
1093 if (comp
->string
!= NULL
) {
1094 xmlFree(comp
->string
);
1097 #ifdef XPATH_STREAMING
1098 if (comp
->stream
!= NULL
) {
1099 xmlFreePatternList(comp
->stream
);
1102 if (comp
->expr
!= NULL
) {
1103 xmlFree(comp
->expr
);
1110 * xmlXPathCompExprAdd:
1111 * @comp: the compiled expression
1112 * @ch1: first child index
1113 * @ch2: second child index
1115 * @value: the first int value
1116 * @value2: the second int value
1117 * @value3: the third int value
1118 * @value4: the first string value
1119 * @value5: the second string value
1121 * Add a step to an XPath Compiled Expression
1123 * Returns -1 in case of failure, the index otherwise
1126 xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt
, int ch1
, int ch2
,
1127 xmlXPathOp op
, int value
,
1128 int value2
, int value3
, void *value4
, void *value5
) {
1129 xmlXPathCompExprPtr comp
= ctxt
->comp
;
1130 if (comp
->nbStep
>= comp
->maxStep
) {
1131 xmlXPathStepOp
*real
;
1133 if (comp
->maxStep
>= XPATH_MAX_STEPS
) {
1134 xmlXPathPErrMemory(ctxt
, "adding step\n");
1138 real
= (xmlXPathStepOp
*) xmlRealloc(comp
->steps
,
1139 comp
->maxStep
* sizeof(xmlXPathStepOp
));
1142 xmlXPathPErrMemory(ctxt
, "adding step\n");
1147 comp
->last
= comp
->nbStep
;
1148 comp
->steps
[comp
->nbStep
].ch1
= ch1
;
1149 comp
->steps
[comp
->nbStep
].ch2
= ch2
;
1150 comp
->steps
[comp
->nbStep
].op
= op
;
1151 comp
->steps
[comp
->nbStep
].value
= value
;
1152 comp
->steps
[comp
->nbStep
].value2
= value2
;
1153 comp
->steps
[comp
->nbStep
].value3
= value3
;
1154 if ((comp
->dict
!= NULL
) &&
1155 ((op
== XPATH_OP_FUNCTION
) || (op
== XPATH_OP_VARIABLE
) ||
1156 (op
== XPATH_OP_COLLECT
))) {
1157 if (value4
!= NULL
) {
1158 comp
->steps
[comp
->nbStep
].value4
= (xmlChar
*)
1159 (void *)xmlDictLookup(comp
->dict
, value4
, -1);
1162 comp
->steps
[comp
->nbStep
].value4
= NULL
;
1163 if (value5
!= NULL
) {
1164 comp
->steps
[comp
->nbStep
].value5
= (xmlChar
*)
1165 (void *)xmlDictLookup(comp
->dict
, value5
, -1);
1168 comp
->steps
[comp
->nbStep
].value5
= NULL
;
1170 comp
->steps
[comp
->nbStep
].value4
= value4
;
1171 comp
->steps
[comp
->nbStep
].value5
= value5
;
1173 comp
->steps
[comp
->nbStep
].cache
= NULL
;
1174 return(comp
->nbStep
++);
1179 * @comp: the compiled expression
1180 * @op: operation index
1182 * Swaps 2 operations in the compiled expression
1185 xmlXPathCompSwap(xmlXPathStepOpPtr op
) {
1188 #ifndef LIBXML_THREAD_ENABLED
1190 * Since this manipulates possibly shared variables, this is
1191 * disabled if one detects that the library is used in a multithreaded
1194 if (xmlXPathDisableOptimizer
)
1203 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1204 xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1205 (op), (val), (val2), (val3), (val4), (val5))
1206 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1207 xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1208 (op), (val), (val2), (val3), (val4), (val5))
1210 #define PUSH_LEAVE_EXPR(op, val, val2) \
1211 xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1213 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1214 xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1216 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1217 xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1218 (val), (val2), 0 ,NULL ,NULL)
1220 /************************************************************************
1222 * XPath object cache structures *
1224 ************************************************************************/
1226 /* #define XP_DEFAULT_CACHE_ON */
1228 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1230 typedef struct _xmlXPathContextCache xmlXPathContextCache
;
1231 typedef xmlXPathContextCache
*xmlXPathContextCachePtr
;
1232 struct _xmlXPathContextCache
{
1233 xmlPointerListPtr nodesetObjs
; /* contains xmlXPathObjectPtr */
1234 xmlPointerListPtr stringObjs
; /* contains xmlXPathObjectPtr */
1235 xmlPointerListPtr booleanObjs
; /* contains xmlXPathObjectPtr */
1236 xmlPointerListPtr numberObjs
; /* contains xmlXPathObjectPtr */
1237 xmlPointerListPtr miscObjs
; /* contains xmlXPathObjectPtr */
1243 #ifdef XP_DEBUG_OBJ_USAGE
1245 int dbgCachedNodeset
;
1246 int dbgCachedString
;
1248 int dbgCachedNumber
;
1251 int dbgCachedLocset
;
1253 int dbgCachedXSLTTree
;
1254 int dbgCachedUndefined
;
1258 int dbgReusedNodeset
;
1259 int dbgReusedString
;
1261 int dbgReusedNumber
;
1264 int dbgReusedLocset
;
1266 int dbgReusedXSLTTree
;
1267 int dbgReusedUndefined
;
1272 /************************************************************************
1274 * Debugging related functions *
1276 ************************************************************************/
1279 xmlGenericError(xmlGenericErrorContext, \
1280 "Internal error at %s:%d\n", \
1281 __FILE__, __LINE__);
1283 #ifdef LIBXML_DEBUG_ENABLED
1285 xmlXPathDebugDumpNode(FILE *output
, xmlNodePtr cur
, int depth
) {
1289 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1290 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1291 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1293 fprintf(output
, "%s", shift
);
1294 fprintf(output
, "Node is NULL !\n");
1299 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
1300 (cur
->type
== XML_HTML_DOCUMENT_NODE
)) {
1301 fprintf(output
, "%s", shift
);
1302 fprintf(output
, " /\n");
1303 } else if (cur
->type
== XML_ATTRIBUTE_NODE
)
1304 xmlDebugDumpAttr(output
, (xmlAttrPtr
)cur
, depth
);
1306 xmlDebugDumpOneNode(output
, cur
, depth
);
1309 xmlXPathDebugDumpNodeList(FILE *output
, xmlNodePtr cur
, int depth
) {
1314 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1315 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1316 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1318 fprintf(output
, "%s", shift
);
1319 fprintf(output
, "Node is NULL !\n");
1324 while (cur
!= NULL
) {
1327 xmlDebugDumpOneNode(output
, tmp
, depth
);
1332 xmlXPathDebugDumpNodeSet(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1336 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1337 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1338 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1341 fprintf(output
, "%s", shift
);
1342 fprintf(output
, "NodeSet is NULL !\n");
1348 fprintf(output
, "Set contains %d nodes:\n", cur
->nodeNr
);
1349 for (i
= 0;i
< cur
->nodeNr
;i
++) {
1350 fprintf(output
, "%s", shift
);
1351 fprintf(output
, "%d", i
+ 1);
1352 xmlXPathDebugDumpNode(output
, cur
->nodeTab
[i
], depth
+ 1);
1358 xmlXPathDebugDumpValueTree(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1362 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1363 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1364 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1366 if ((cur
== NULL
) || (cur
->nodeNr
== 0) || (cur
->nodeTab
[0] == NULL
)) {
1367 fprintf(output
, "%s", shift
);
1368 fprintf(output
, "Value Tree is NULL !\n");
1373 fprintf(output
, "%s", shift
);
1374 fprintf(output
, "%d", i
+ 1);
1375 xmlXPathDebugDumpNodeList(output
, cur
->nodeTab
[0]->children
, depth
+ 1);
1377 #if defined(LIBXML_XPTR_LOCS_ENABLED)
1379 xmlXPathDebugDumpLocationSet(FILE *output
, xmlLocationSetPtr cur
, int depth
) {
1383 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1384 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1385 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1388 fprintf(output
, "%s", shift
);
1389 fprintf(output
, "LocationSet is NULL !\n");
1394 for (i
= 0;i
< cur
->locNr
;i
++) {
1395 fprintf(output
, "%s", shift
);
1396 fprintf(output
, "%d : ", i
+ 1);
1397 xmlXPathDebugDumpObject(output
, cur
->locTab
[i
], depth
+ 1);
1400 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1403 * xmlXPathDebugDumpObject:
1404 * @output: the FILE * to dump the output
1405 * @cur: the object to inspect
1406 * @depth: indentation level
1408 * Dump the content of the object for debugging purposes
1411 xmlXPathDebugDumpObject(FILE *output
, xmlXPathObjectPtr cur
, int depth
) {
1415 if (output
== NULL
) return;
1417 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1418 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1419 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1422 fprintf(output
, "%s", shift
);
1425 fprintf(output
, "Object is empty (NULL)\n");
1429 case XPATH_UNDEFINED
:
1430 fprintf(output
, "Object is uninitialized\n");
1433 fprintf(output
, "Object is a Node Set :\n");
1434 xmlXPathDebugDumpNodeSet(output
, cur
->nodesetval
, depth
);
1436 case XPATH_XSLT_TREE
:
1437 fprintf(output
, "Object is an XSLT value tree :\n");
1438 xmlXPathDebugDumpValueTree(output
, cur
->nodesetval
, depth
);
1441 fprintf(output
, "Object is a Boolean : ");
1442 if (cur
->boolval
) fprintf(output
, "true\n");
1443 else fprintf(output
, "false\n");
1446 switch (xmlXPathIsInf(cur
->floatval
)) {
1448 fprintf(output
, "Object is a number : Infinity\n");
1451 fprintf(output
, "Object is a number : -Infinity\n");
1454 if (xmlXPathIsNaN(cur
->floatval
)) {
1455 fprintf(output
, "Object is a number : NaN\n");
1456 } else if (cur
->floatval
== 0) {
1457 /* Omit sign for negative zero. */
1458 fprintf(output
, "Object is a number : 0\n");
1460 fprintf(output
, "Object is a number : %0g\n", cur
->floatval
);
1465 fprintf(output
, "Object is a string : ");
1466 xmlDebugDumpString(output
, cur
->stringval
);
1467 fprintf(output
, "\n");
1469 #ifdef LIBXML_XPTR_LOCS_ENABLED
1471 fprintf(output
, "Object is a point : index %d in node", cur
->index
);
1472 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
, depth
+ 1);
1473 fprintf(output
, "\n");
1476 if ((cur
->user2
== NULL
) ||
1477 ((cur
->user2
== cur
->user
) && (cur
->index
== cur
->index2
))) {
1478 fprintf(output
, "Object is a collapsed range :\n");
1479 fprintf(output
, "%s", shift
);
1480 if (cur
->index
>= 0)
1481 fprintf(output
, "index %d in ", cur
->index
);
1482 fprintf(output
, "node\n");
1483 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1486 fprintf(output
, "Object is a range :\n");
1487 fprintf(output
, "%s", shift
);
1488 fprintf(output
, "From ");
1489 if (cur
->index
>= 0)
1490 fprintf(output
, "index %d in ", cur
->index
);
1491 fprintf(output
, "node\n");
1492 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1494 fprintf(output
, "%s", shift
);
1495 fprintf(output
, "To ");
1496 if (cur
->index2
>= 0)
1497 fprintf(output
, "index %d in ", cur
->index2
);
1498 fprintf(output
, "node\n");
1499 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user2
,
1501 fprintf(output
, "\n");
1504 case XPATH_LOCATIONSET
:
1505 fprintf(output
, "Object is a Location Set:\n");
1506 xmlXPathDebugDumpLocationSet(output
,
1507 (xmlLocationSetPtr
) cur
->user
, depth
);
1509 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1511 fprintf(output
, "Object is user defined\n");
1517 xmlXPathDebugDumpStepOp(FILE *output
, xmlXPathCompExprPtr comp
,
1518 xmlXPathStepOpPtr op
, int depth
) {
1522 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1523 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1524 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1526 fprintf(output
, "%s", shift
);
1528 fprintf(output
, "Step is NULL\n");
1533 fprintf(output
, "END"); break;
1535 fprintf(output
, "AND"); break;
1537 fprintf(output
, "OR"); break;
1538 case XPATH_OP_EQUAL
:
1540 fprintf(output
, "EQUAL =");
1542 fprintf(output
, "EQUAL !=");
1546 fprintf(output
, "CMP <");
1548 fprintf(output
, "CMP >");
1550 fprintf(output
, "=");
1554 fprintf(output
, "PLUS -");
1555 else if (op
->value
== 1)
1556 fprintf(output
, "PLUS +");
1557 else if (op
->value
== 2)
1558 fprintf(output
, "PLUS unary -");
1559 else if (op
->value
== 3)
1560 fprintf(output
, "PLUS unary - -");
1564 fprintf(output
, "MULT *");
1565 else if (op
->value
== 1)
1566 fprintf(output
, "MULT div");
1568 fprintf(output
, "MULT mod");
1570 case XPATH_OP_UNION
:
1571 fprintf(output
, "UNION"); break;
1573 fprintf(output
, "ROOT"); break;
1575 fprintf(output
, "NODE"); break;
1577 fprintf(output
, "SORT"); break;
1578 case XPATH_OP_COLLECT
: {
1579 xmlXPathAxisVal axis
= (xmlXPathAxisVal
)op
->value
;
1580 xmlXPathTestVal test
= (xmlXPathTestVal
)op
->value2
;
1581 xmlXPathTypeVal type
= (xmlXPathTypeVal
)op
->value3
;
1582 const xmlChar
*prefix
= op
->value4
;
1583 const xmlChar
*name
= op
->value5
;
1585 fprintf(output
, "COLLECT ");
1588 fprintf(output
, " 'ancestors' "); break;
1589 case AXIS_ANCESTOR_OR_SELF
:
1590 fprintf(output
, " 'ancestors-or-self' "); break;
1591 case AXIS_ATTRIBUTE
:
1592 fprintf(output
, " 'attributes' "); break;
1594 fprintf(output
, " 'child' "); break;
1595 case AXIS_DESCENDANT
:
1596 fprintf(output
, " 'descendant' "); break;
1597 case AXIS_DESCENDANT_OR_SELF
:
1598 fprintf(output
, " 'descendant-or-self' "); break;
1599 case AXIS_FOLLOWING
:
1600 fprintf(output
, " 'following' "); break;
1601 case AXIS_FOLLOWING_SIBLING
:
1602 fprintf(output
, " 'following-siblings' "); break;
1603 case AXIS_NAMESPACE
:
1604 fprintf(output
, " 'namespace' "); break;
1606 fprintf(output
, " 'parent' "); break;
1607 case AXIS_PRECEDING
:
1608 fprintf(output
, " 'preceding' "); break;
1609 case AXIS_PRECEDING_SIBLING
:
1610 fprintf(output
, " 'preceding-sibling' "); break;
1612 fprintf(output
, " 'self' "); break;
1615 case NODE_TEST_NONE
:
1616 fprintf(output
, "'none' "); break;
1617 case NODE_TEST_TYPE
:
1618 fprintf(output
, "'type' "); break;
1620 fprintf(output
, "'PI' "); break;
1622 fprintf(output
, "'all' "); break;
1624 fprintf(output
, "'namespace' "); break;
1625 case NODE_TEST_NAME
:
1626 fprintf(output
, "'name' "); break;
1629 case NODE_TYPE_NODE
:
1630 fprintf(output
, "'node' "); break;
1631 case NODE_TYPE_COMMENT
:
1632 fprintf(output
, "'comment' "); break;
1633 case NODE_TYPE_TEXT
:
1634 fprintf(output
, "'text' "); break;
1636 fprintf(output
, "'PI' "); break;
1639 fprintf(output
, "%s:", prefix
);
1641 fprintf(output
, "%s", (const char *) name
);
1645 case XPATH_OP_VALUE
: {
1646 xmlXPathObjectPtr object
= (xmlXPathObjectPtr
) op
->value4
;
1648 fprintf(output
, "ELEM ");
1649 xmlXPathDebugDumpObject(output
, object
, 0);
1652 case XPATH_OP_VARIABLE
: {
1653 const xmlChar
*prefix
= op
->value5
;
1654 const xmlChar
*name
= op
->value4
;
1657 fprintf(output
, "VARIABLE %s:%s", prefix
, name
);
1659 fprintf(output
, "VARIABLE %s", name
);
1662 case XPATH_OP_FUNCTION
: {
1663 int nbargs
= op
->value
;
1664 const xmlChar
*prefix
= op
->value5
;
1665 const xmlChar
*name
= op
->value4
;
1668 fprintf(output
, "FUNCTION %s:%s(%d args)",
1669 prefix
, name
, nbargs
);
1671 fprintf(output
, "FUNCTION %s(%d args)", name
, nbargs
);
1674 case XPATH_OP_ARG
: fprintf(output
, "ARG"); break;
1675 case XPATH_OP_PREDICATE
: fprintf(output
, "PREDICATE"); break;
1676 case XPATH_OP_FILTER
: fprintf(output
, "FILTER"); break;
1677 #ifdef LIBXML_XPTR_LOCS_ENABLED
1678 case XPATH_OP_RANGETO
: fprintf(output
, "RANGETO"); break;
1681 fprintf(output
, "UNKNOWN %d\n", op
->op
); return;
1683 fprintf(output
, "\n");
1686 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch1
], depth
+ 1);
1688 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch2
], depth
+ 1);
1692 * xmlXPathDebugDumpCompExpr:
1693 * @output: the FILE * for the output
1694 * @comp: the precompiled XPath expression
1695 * @depth: the indentation level.
1697 * Dumps the tree of the compiled XPath expression.
1700 xmlXPathDebugDumpCompExpr(FILE *output
, xmlXPathCompExprPtr comp
,
1705 if ((output
== NULL
) || (comp
== NULL
)) return;
1707 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1708 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1709 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1711 fprintf(output
, "%s", shift
);
1713 #ifdef XPATH_STREAMING
1715 fprintf(output
, "Streaming Expression\n");
1719 fprintf(output
, "Compiled Expression : %d elements\n",
1722 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[i
], depth
+ 1);
1726 #ifdef XP_DEBUG_OBJ_USAGE
1729 * XPath object usage related debugging variables.
1731 static int xmlXPathDebugObjCounterUndefined
= 0;
1732 static int xmlXPathDebugObjCounterNodeset
= 0;
1733 static int xmlXPathDebugObjCounterBool
= 0;
1734 static int xmlXPathDebugObjCounterNumber
= 0;
1735 static int xmlXPathDebugObjCounterString
= 0;
1736 static int xmlXPathDebugObjCounterPoint
= 0;
1737 static int xmlXPathDebugObjCounterRange
= 0;
1738 static int xmlXPathDebugObjCounterLocset
= 0;
1739 static int xmlXPathDebugObjCounterUsers
= 0;
1740 static int xmlXPathDebugObjCounterXSLTTree
= 0;
1741 static int xmlXPathDebugObjCounterAll
= 0;
1743 static int xmlXPathDebugObjTotalUndefined
= 0;
1744 static int xmlXPathDebugObjTotalNodeset
= 0;
1745 static int xmlXPathDebugObjTotalBool
= 0;
1746 static int xmlXPathDebugObjTotalNumber
= 0;
1747 static int xmlXPathDebugObjTotalString
= 0;
1748 static int xmlXPathDebugObjTotalPoint
= 0;
1749 static int xmlXPathDebugObjTotalRange
= 0;
1750 static int xmlXPathDebugObjTotalLocset
= 0;
1751 static int xmlXPathDebugObjTotalUsers
= 0;
1752 static int xmlXPathDebugObjTotalXSLTTree
= 0;
1753 static int xmlXPathDebugObjTotalAll
= 0;
1755 static int xmlXPathDebugObjMaxUndefined
= 0;
1756 static int xmlXPathDebugObjMaxNodeset
= 0;
1757 static int xmlXPathDebugObjMaxBool
= 0;
1758 static int xmlXPathDebugObjMaxNumber
= 0;
1759 static int xmlXPathDebugObjMaxString
= 0;
1760 static int xmlXPathDebugObjMaxPoint
= 0;
1761 static int xmlXPathDebugObjMaxRange
= 0;
1762 static int xmlXPathDebugObjMaxLocset
= 0;
1763 static int xmlXPathDebugObjMaxUsers
= 0;
1764 static int xmlXPathDebugObjMaxXSLTTree
= 0;
1765 static int xmlXPathDebugObjMaxAll
= 0;
1768 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt
)
1771 if (ctxt
->cache
!= NULL
) {
1772 xmlXPathContextCachePtr cache
=
1773 (xmlXPathContextCachePtr
) ctxt
->cache
;
1775 cache
->dbgCachedAll
= 0;
1776 cache
->dbgCachedNodeset
= 0;
1777 cache
->dbgCachedString
= 0;
1778 cache
->dbgCachedBool
= 0;
1779 cache
->dbgCachedNumber
= 0;
1780 cache
->dbgCachedPoint
= 0;
1781 cache
->dbgCachedRange
= 0;
1782 cache
->dbgCachedLocset
= 0;
1783 cache
->dbgCachedUsers
= 0;
1784 cache
->dbgCachedXSLTTree
= 0;
1785 cache
->dbgCachedUndefined
= 0;
1787 cache
->dbgReusedAll
= 0;
1788 cache
->dbgReusedNodeset
= 0;
1789 cache
->dbgReusedString
= 0;
1790 cache
->dbgReusedBool
= 0;
1791 cache
->dbgReusedNumber
= 0;
1792 cache
->dbgReusedPoint
= 0;
1793 cache
->dbgReusedRange
= 0;
1794 cache
->dbgReusedLocset
= 0;
1795 cache
->dbgReusedUsers
= 0;
1796 cache
->dbgReusedXSLTTree
= 0;
1797 cache
->dbgReusedUndefined
= 0;
1801 xmlXPathDebugObjCounterUndefined
= 0;
1802 xmlXPathDebugObjCounterNodeset
= 0;
1803 xmlXPathDebugObjCounterBool
= 0;
1804 xmlXPathDebugObjCounterNumber
= 0;
1805 xmlXPathDebugObjCounterString
= 0;
1806 xmlXPathDebugObjCounterPoint
= 0;
1807 xmlXPathDebugObjCounterRange
= 0;
1808 xmlXPathDebugObjCounterLocset
= 0;
1809 xmlXPathDebugObjCounterUsers
= 0;
1810 xmlXPathDebugObjCounterXSLTTree
= 0;
1811 xmlXPathDebugObjCounterAll
= 0;
1813 xmlXPathDebugObjTotalUndefined
= 0;
1814 xmlXPathDebugObjTotalNodeset
= 0;
1815 xmlXPathDebugObjTotalBool
= 0;
1816 xmlXPathDebugObjTotalNumber
= 0;
1817 xmlXPathDebugObjTotalString
= 0;
1818 xmlXPathDebugObjTotalPoint
= 0;
1819 xmlXPathDebugObjTotalRange
= 0;
1820 xmlXPathDebugObjTotalLocset
= 0;
1821 xmlXPathDebugObjTotalUsers
= 0;
1822 xmlXPathDebugObjTotalXSLTTree
= 0;
1823 xmlXPathDebugObjTotalAll
= 0;
1825 xmlXPathDebugObjMaxUndefined
= 0;
1826 xmlXPathDebugObjMaxNodeset
= 0;
1827 xmlXPathDebugObjMaxBool
= 0;
1828 xmlXPathDebugObjMaxNumber
= 0;
1829 xmlXPathDebugObjMaxString
= 0;
1830 xmlXPathDebugObjMaxPoint
= 0;
1831 xmlXPathDebugObjMaxRange
= 0;
1832 xmlXPathDebugObjMaxLocset
= 0;
1833 xmlXPathDebugObjMaxUsers
= 0;
1834 xmlXPathDebugObjMaxXSLTTree
= 0;
1835 xmlXPathDebugObjMaxAll
= 0;
1840 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt
,
1841 xmlXPathObjectType objType
)
1846 if (ctxt
->cache
!= NULL
) {
1847 xmlXPathContextCachePtr cache
=
1848 (xmlXPathContextCachePtr
) ctxt
->cache
;
1852 cache
->dbgReusedAll
++;
1854 case XPATH_UNDEFINED
:
1855 cache
->dbgReusedUndefined
++;
1858 cache
->dbgReusedNodeset
++;
1861 cache
->dbgReusedBool
++;
1864 cache
->dbgReusedNumber
++;
1867 cache
->dbgReusedString
++;
1869 #ifdef LIBXML_XPTR_LOCS_ENABLED
1871 cache
->dbgReusedPoint
++;
1874 cache
->dbgReusedRange
++;
1876 case XPATH_LOCATIONSET
:
1877 cache
->dbgReusedLocset
++;
1879 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1881 cache
->dbgReusedUsers
++;
1883 case XPATH_XSLT_TREE
:
1884 cache
->dbgReusedXSLTTree
++;
1893 case XPATH_UNDEFINED
:
1895 xmlXPathDebugObjTotalUndefined
++;
1896 xmlXPathDebugObjCounterUndefined
++;
1897 if (xmlXPathDebugObjCounterUndefined
>
1898 xmlXPathDebugObjMaxUndefined
)
1899 xmlXPathDebugObjMaxUndefined
=
1900 xmlXPathDebugObjCounterUndefined
;
1904 xmlXPathDebugObjTotalNodeset
++;
1905 xmlXPathDebugObjCounterNodeset
++;
1906 if (xmlXPathDebugObjCounterNodeset
>
1907 xmlXPathDebugObjMaxNodeset
)
1908 xmlXPathDebugObjMaxNodeset
=
1909 xmlXPathDebugObjCounterNodeset
;
1913 xmlXPathDebugObjTotalBool
++;
1914 xmlXPathDebugObjCounterBool
++;
1915 if (xmlXPathDebugObjCounterBool
>
1916 xmlXPathDebugObjMaxBool
)
1917 xmlXPathDebugObjMaxBool
=
1918 xmlXPathDebugObjCounterBool
;
1922 xmlXPathDebugObjTotalNumber
++;
1923 xmlXPathDebugObjCounterNumber
++;
1924 if (xmlXPathDebugObjCounterNumber
>
1925 xmlXPathDebugObjMaxNumber
)
1926 xmlXPathDebugObjMaxNumber
=
1927 xmlXPathDebugObjCounterNumber
;
1931 xmlXPathDebugObjTotalString
++;
1932 xmlXPathDebugObjCounterString
++;
1933 if (xmlXPathDebugObjCounterString
>
1934 xmlXPathDebugObjMaxString
)
1935 xmlXPathDebugObjMaxString
=
1936 xmlXPathDebugObjCounterString
;
1938 #ifdef LIBXML_XPTR_LOCS_ENABLED
1941 xmlXPathDebugObjTotalPoint
++;
1942 xmlXPathDebugObjCounterPoint
++;
1943 if (xmlXPathDebugObjCounterPoint
>
1944 xmlXPathDebugObjMaxPoint
)
1945 xmlXPathDebugObjMaxPoint
=
1946 xmlXPathDebugObjCounterPoint
;
1950 xmlXPathDebugObjTotalRange
++;
1951 xmlXPathDebugObjCounterRange
++;
1952 if (xmlXPathDebugObjCounterRange
>
1953 xmlXPathDebugObjMaxRange
)
1954 xmlXPathDebugObjMaxRange
=
1955 xmlXPathDebugObjCounterRange
;
1957 case XPATH_LOCATIONSET
:
1959 xmlXPathDebugObjTotalLocset
++;
1960 xmlXPathDebugObjCounterLocset
++;
1961 if (xmlXPathDebugObjCounterLocset
>
1962 xmlXPathDebugObjMaxLocset
)
1963 xmlXPathDebugObjMaxLocset
=
1964 xmlXPathDebugObjCounterLocset
;
1966 #endif /* LIBXML_XPTR_LOCS_ENABLED */
1969 xmlXPathDebugObjTotalUsers
++;
1970 xmlXPathDebugObjCounterUsers
++;
1971 if (xmlXPathDebugObjCounterUsers
>
1972 xmlXPathDebugObjMaxUsers
)
1973 xmlXPathDebugObjMaxUsers
=
1974 xmlXPathDebugObjCounterUsers
;
1976 case XPATH_XSLT_TREE
:
1978 xmlXPathDebugObjTotalXSLTTree
++;
1979 xmlXPathDebugObjCounterXSLTTree
++;
1980 if (xmlXPathDebugObjCounterXSLTTree
>
1981 xmlXPathDebugObjMaxXSLTTree
)
1982 xmlXPathDebugObjMaxXSLTTree
=
1983 xmlXPathDebugObjCounterXSLTTree
;
1989 xmlXPathDebugObjTotalAll
++;
1990 xmlXPathDebugObjCounterAll
++;
1991 if (xmlXPathDebugObjCounterAll
>
1992 xmlXPathDebugObjMaxAll
)
1993 xmlXPathDebugObjMaxAll
=
1994 xmlXPathDebugObjCounterAll
;
1998 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt
,
1999 xmlXPathObjectType objType
)
2004 if (ctxt
->cache
!= NULL
) {
2005 xmlXPathContextCachePtr cache
=
2006 (xmlXPathContextCachePtr
) ctxt
->cache
;
2010 cache
->dbgCachedAll
++;
2012 case XPATH_UNDEFINED
:
2013 cache
->dbgCachedUndefined
++;
2016 cache
->dbgCachedNodeset
++;
2019 cache
->dbgCachedBool
++;
2022 cache
->dbgCachedNumber
++;
2025 cache
->dbgCachedString
++;
2027 #ifdef LIBXML_XPTR_LOCS_ENABLED
2029 cache
->dbgCachedPoint
++;
2032 cache
->dbgCachedRange
++;
2034 case XPATH_LOCATIONSET
:
2035 cache
->dbgCachedLocset
++;
2037 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2039 cache
->dbgCachedUsers
++;
2041 case XPATH_XSLT_TREE
:
2042 cache
->dbgCachedXSLTTree
++;
2051 case XPATH_UNDEFINED
:
2052 xmlXPathDebugObjCounterUndefined
--;
2055 xmlXPathDebugObjCounterNodeset
--;
2058 xmlXPathDebugObjCounterBool
--;
2061 xmlXPathDebugObjCounterNumber
--;
2064 xmlXPathDebugObjCounterString
--;
2066 #ifdef LIBXML_XPTR_LOCS_ENABLED
2068 xmlXPathDebugObjCounterPoint
--;
2071 xmlXPathDebugObjCounterRange
--;
2073 case XPATH_LOCATIONSET
:
2074 xmlXPathDebugObjCounterLocset
--;
2076 #endif /* LIBXML_XPTR_LOCS_ENABLED */
2078 xmlXPathDebugObjCounterUsers
--;
2080 case XPATH_XSLT_TREE
:
2081 xmlXPathDebugObjCounterXSLTTree
--;
2086 xmlXPathDebugObjCounterAll
--;
2090 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt
)
2092 int reqAll
, reqNodeset
, reqString
, reqBool
, reqNumber
,
2093 reqXSLTTree
, reqUndefined
;
2094 int caAll
= 0, caNodeset
= 0, caString
= 0, caBool
= 0,
2095 caNumber
= 0, caXSLTTree
= 0, caUndefined
= 0;
2096 int reAll
= 0, reNodeset
= 0, reString
= 0, reBool
= 0,
2097 reNumber
= 0, reXSLTTree
= 0, reUndefined
= 0;
2098 int leftObjs
= xmlXPathDebugObjCounterAll
;
2100 reqAll
= xmlXPathDebugObjTotalAll
;
2101 reqNodeset
= xmlXPathDebugObjTotalNodeset
;
2102 reqString
= xmlXPathDebugObjTotalString
;
2103 reqBool
= xmlXPathDebugObjTotalBool
;
2104 reqNumber
= xmlXPathDebugObjTotalNumber
;
2105 reqXSLTTree
= xmlXPathDebugObjTotalXSLTTree
;
2106 reqUndefined
= xmlXPathDebugObjTotalUndefined
;
2108 printf("# XPath object usage:\n");
2111 if (ctxt
->cache
!= NULL
) {
2112 xmlXPathContextCachePtr cache
=
2113 (xmlXPathContextCachePtr
) ctxt
->cache
;
2115 reAll
= cache
->dbgReusedAll
;
2117 reNodeset
= cache
->dbgReusedNodeset
;
2118 reqNodeset
+= reNodeset
;
2119 reString
= cache
->dbgReusedString
;
2120 reqString
+= reString
;
2121 reBool
= cache
->dbgReusedBool
;
2123 reNumber
= cache
->dbgReusedNumber
;
2124 reqNumber
+= reNumber
;
2125 reXSLTTree
= cache
->dbgReusedXSLTTree
;
2126 reqXSLTTree
+= reXSLTTree
;
2127 reUndefined
= cache
->dbgReusedUndefined
;
2128 reqUndefined
+= reUndefined
;
2130 caAll
= cache
->dbgCachedAll
;
2131 caBool
= cache
->dbgCachedBool
;
2132 caNodeset
= cache
->dbgCachedNodeset
;
2133 caString
= cache
->dbgCachedString
;
2134 caNumber
= cache
->dbgCachedNumber
;
2135 caXSLTTree
= cache
->dbgCachedXSLTTree
;
2136 caUndefined
= cache
->dbgCachedUndefined
;
2138 if (cache
->nodesetObjs
)
2139 leftObjs
-= cache
->nodesetObjs
->number
;
2140 if (cache
->stringObjs
)
2141 leftObjs
-= cache
->stringObjs
->number
;
2142 if (cache
->booleanObjs
)
2143 leftObjs
-= cache
->booleanObjs
->number
;
2144 if (cache
->numberObjs
)
2145 leftObjs
-= cache
->numberObjs
->number
;
2146 if (cache
->miscObjs
)
2147 leftObjs
-= cache
->miscObjs
->number
;
2152 printf("# total : %d\n", reqAll
);
2153 printf("# left : %d\n", leftObjs
);
2154 printf("# created: %d\n", xmlXPathDebugObjTotalAll
);
2155 printf("# reused : %d\n", reAll
);
2156 printf("# max : %d\n", xmlXPathDebugObjMaxAll
);
2158 printf("# node-sets\n");
2159 printf("# total : %d\n", reqNodeset
);
2160 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset
);
2161 printf("# reused : %d\n", reNodeset
);
2162 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset
);
2164 printf("# strings\n");
2165 printf("# total : %d\n", reqString
);
2166 printf("# created: %d\n", xmlXPathDebugObjTotalString
);
2167 printf("# reused : %d\n", reString
);
2168 printf("# max : %d\n", xmlXPathDebugObjMaxString
);
2170 printf("# booleans\n");
2171 printf("# total : %d\n", reqBool
);
2172 printf("# created: %d\n", xmlXPathDebugObjTotalBool
);
2173 printf("# reused : %d\n", reBool
);
2174 printf("# max : %d\n", xmlXPathDebugObjMaxBool
);
2176 printf("# numbers\n");
2177 printf("# total : %d\n", reqNumber
);
2178 printf("# created: %d\n", xmlXPathDebugObjTotalNumber
);
2179 printf("# reused : %d\n", reNumber
);
2180 printf("# max : %d\n", xmlXPathDebugObjMaxNumber
);
2182 printf("# XSLT result tree fragments\n");
2183 printf("# total : %d\n", reqXSLTTree
);
2184 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree
);
2185 printf("# reused : %d\n", reXSLTTree
);
2186 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree
);
2188 printf("# undefined\n");
2189 printf("# total : %d\n", reqUndefined
);
2190 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined
);
2191 printf("# reused : %d\n", reUndefined
);
2192 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined
);
2196 #endif /* XP_DEBUG_OBJ_USAGE */
2198 #endif /* LIBXML_DEBUG_ENABLED */
2200 /************************************************************************
2202 * XPath object caching *
2204 ************************************************************************/
2209 * Create a new object cache
2211 * Returns the xmlXPathCache just allocated.
2213 static xmlXPathContextCachePtr
2214 xmlXPathNewCache(void)
2216 xmlXPathContextCachePtr ret
;
2218 ret
= (xmlXPathContextCachePtr
) xmlMalloc(sizeof(xmlXPathContextCache
));
2220 xmlXPathErrMemory(NULL
, "creating object cache\n");
2223 memset(ret
, 0 , sizeof(xmlXPathContextCache
));
2224 ret
->maxNodeset
= 100;
2225 ret
->maxString
= 100;
2226 ret
->maxBoolean
= 100;
2227 ret
->maxNumber
= 100;
2233 xmlXPathCacheFreeObjectList(xmlPointerListPtr list
)
2236 xmlXPathObjectPtr obj
;
2241 for (i
= 0; i
< list
->number
; i
++) {
2242 obj
= list
->items
[i
];
2244 * Note that it is already assured that we don't need to
2245 * look out for namespace nodes in the node-set.
2247 if (obj
->nodesetval
!= NULL
) {
2248 if (obj
->nodesetval
->nodeTab
!= NULL
)
2249 xmlFree(obj
->nodesetval
->nodeTab
);
2250 xmlFree(obj
->nodesetval
);
2253 #ifdef XP_DEBUG_OBJ_USAGE
2254 xmlXPathDebugObjCounterAll
--;
2257 xmlPointerListFree(list
);
2261 xmlXPathFreeCache(xmlXPathContextCachePtr cache
)
2265 if (cache
->nodesetObjs
)
2266 xmlXPathCacheFreeObjectList(cache
->nodesetObjs
);
2267 if (cache
->stringObjs
)
2268 xmlXPathCacheFreeObjectList(cache
->stringObjs
);
2269 if (cache
->booleanObjs
)
2270 xmlXPathCacheFreeObjectList(cache
->booleanObjs
);
2271 if (cache
->numberObjs
)
2272 xmlXPathCacheFreeObjectList(cache
->numberObjs
);
2273 if (cache
->miscObjs
)
2274 xmlXPathCacheFreeObjectList(cache
->miscObjs
);
2279 * xmlXPathContextSetCache:
2281 * @ctxt: the XPath context
2282 * @active: enables/disables (creates/frees) the cache
2283 * @value: a value with semantics dependent on @options
2284 * @options: options (currently only the value 0 is used)
2286 * Creates/frees an object cache on the XPath context.
2287 * If activates XPath objects (xmlXPathObject) will be cached internally
2290 * 0: This will set the XPath object caching:
2292 * This will set the maximum number of XPath objects
2293 * to be cached per slot
2294 * There are 5 slots for: node-set, string, number, boolean, and
2295 * misc objects. Use <0 for the default number (100).
2296 * Other values for @options have currently no effect.
2298 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2301 xmlXPathContextSetCache(xmlXPathContextPtr ctxt
,
2309 xmlXPathContextCachePtr cache
;
2311 if (ctxt
->cache
== NULL
) {
2312 ctxt
->cache
= xmlXPathNewCache();
2313 if (ctxt
->cache
== NULL
)
2316 cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2320 cache
->maxNodeset
= value
;
2321 cache
->maxString
= value
;
2322 cache
->maxNumber
= value
;
2323 cache
->maxBoolean
= value
;
2324 cache
->maxMisc
= value
;
2326 } else if (ctxt
->cache
!= NULL
) {
2327 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
2334 * xmlXPathCacheWrapNodeSet:
2335 * @ctxt: the XPath context
2336 * @val: the NodePtr value
2338 * This is the cached version of xmlXPathWrapNodeSet().
2339 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2341 * Returns the created or reused object.
2343 * In case of error the node set is destroyed and NULL is returned.
2345 static xmlXPathObjectPtr
2346 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt
, xmlNodeSetPtr val
)
2348 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2349 xmlXPathContextCachePtr cache
=
2350 (xmlXPathContextCachePtr
) ctxt
->cache
;
2352 if ((cache
->miscObjs
!= NULL
) &&
2353 (cache
->miscObjs
->number
!= 0))
2355 xmlXPathObjectPtr ret
;
2357 ret
= (xmlXPathObjectPtr
)
2358 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2359 ret
->type
= XPATH_NODESET
;
2360 ret
->nodesetval
= val
;
2361 #ifdef XP_DEBUG_OBJ_USAGE
2362 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2368 return(xmlXPathWrapNodeSet(val
));
2373 * xmlXPathCacheWrapString:
2374 * @ctxt: the XPath context
2375 * @val: the xmlChar * value
2377 * This is the cached version of xmlXPathWrapString().
2378 * Wraps the @val string into an XPath object.
2380 * Returns the created or reused object.
2382 static xmlXPathObjectPtr
2383 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt
, xmlChar
*val
)
2385 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2386 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2388 if ((cache
->stringObjs
!= NULL
) &&
2389 (cache
->stringObjs
->number
!= 0))
2392 xmlXPathObjectPtr ret
;
2394 ret
= (xmlXPathObjectPtr
)
2395 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2396 ret
->type
= XPATH_STRING
;
2397 ret
->stringval
= val
;
2398 #ifdef XP_DEBUG_OBJ_USAGE
2399 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2402 } else if ((cache
->miscObjs
!= NULL
) &&
2403 (cache
->miscObjs
->number
!= 0))
2405 xmlXPathObjectPtr ret
;
2407 * Fallback to misc-cache.
2409 ret
= (xmlXPathObjectPtr
)
2410 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2412 ret
->type
= XPATH_STRING
;
2413 ret
->stringval
= val
;
2414 #ifdef XP_DEBUG_OBJ_USAGE
2415 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2420 return(xmlXPathWrapString(val
));
2424 * xmlXPathCacheNewNodeSet:
2425 * @ctxt: the XPath context
2426 * @val: the NodePtr value
2428 * This is the cached version of xmlXPathNewNodeSet().
2429 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2430 * it with the single Node @val
2432 * Returns the created or reused object.
2434 static xmlXPathObjectPtr
2435 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt
, xmlNodePtr val
)
2437 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2438 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2440 if ((cache
->nodesetObjs
!= NULL
) &&
2441 (cache
->nodesetObjs
->number
!= 0))
2443 xmlXPathObjectPtr ret
;
2445 * Use the nodeset-cache.
2447 ret
= (xmlXPathObjectPtr
)
2448 cache
->nodesetObjs
->items
[--cache
->nodesetObjs
->number
];
2449 ret
->type
= XPATH_NODESET
;
2452 if ((ret
->nodesetval
->nodeMax
== 0) ||
2453 (val
->type
== XML_NAMESPACE_DECL
))
2455 /* TODO: Check memory error. */
2456 xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
);
2458 ret
->nodesetval
->nodeTab
[0] = val
;
2459 ret
->nodesetval
->nodeNr
= 1;
2462 #ifdef XP_DEBUG_OBJ_USAGE
2463 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2466 } else if ((cache
->miscObjs
!= NULL
) &&
2467 (cache
->miscObjs
->number
!= 0))
2469 xmlXPathObjectPtr ret
;
2472 * Fallback to misc-cache.
2475 set
= xmlXPathNodeSetCreate(val
);
2477 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
2478 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
2482 ret
= (xmlXPathObjectPtr
)
2483 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2485 ret
->type
= XPATH_NODESET
;
2487 ret
->nodesetval
= set
;
2488 #ifdef XP_DEBUG_OBJ_USAGE
2489 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2494 return(xmlXPathNewNodeSet(val
));
2498 * xmlXPathCacheNewString:
2499 * @ctxt: the XPath context
2500 * @val: the xmlChar * value
2502 * This is the cached version of xmlXPathNewString().
2503 * Acquire an xmlXPathObjectPtr of type string and of value @val
2505 * Returns the created or reused object.
2507 static xmlXPathObjectPtr
2508 xmlXPathCacheNewString(xmlXPathContextPtr ctxt
, const xmlChar
*val
)
2510 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2511 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2513 if ((cache
->stringObjs
!= NULL
) &&
2514 (cache
->stringObjs
->number
!= 0))
2516 xmlXPathObjectPtr ret
;
2521 copy
= xmlStrdup(val
);
2523 xmlXPathErrMemory(ctxt
, NULL
);
2527 ret
= (xmlXPathObjectPtr
)
2528 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2529 ret
->type
= XPATH_STRING
;
2530 ret
->stringval
= copy
;
2531 #ifdef XP_DEBUG_OBJ_USAGE
2532 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2535 } else if ((cache
->miscObjs
!= NULL
) &&
2536 (cache
->miscObjs
->number
!= 0))
2538 xmlXPathObjectPtr ret
;
2543 copy
= xmlStrdup(val
);
2545 xmlXPathErrMemory(ctxt
, NULL
);
2549 ret
= (xmlXPathObjectPtr
)
2550 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2552 ret
->type
= XPATH_STRING
;
2553 ret
->stringval
= copy
;
2554 #ifdef XP_DEBUG_OBJ_USAGE
2555 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2560 return(xmlXPathNewString(val
));
2564 * xmlXPathCacheNewCString:
2565 * @ctxt: the XPath context
2566 * @val: the char * value
2568 * This is the cached version of xmlXPathNewCString().
2569 * Acquire an xmlXPathObjectPtr of type string and of value @val
2571 * Returns the created or reused object.
2573 static xmlXPathObjectPtr
2574 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt
, const char *val
)
2576 return xmlXPathCacheNewString(ctxt
, BAD_CAST 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 evaluation context
2819 * Pops the top XPath object from the value stack
2821 * Returns the XPath object just removed
2824 valuePop(xmlXPathParserContextPtr ctxt
)
2826 xmlXPathObjectPtr ret
;
2828 if ((ctxt
== NULL
) || (ctxt
->valueNr
<= 0))
2832 if (ctxt
->valueNr
> 0)
2833 ctxt
->value
= ctxt
->valueTab
[ctxt
->valueNr
- 1];
2836 ret
= ctxt
->valueTab
[ctxt
->valueNr
];
2837 ctxt
->valueTab
[ctxt
->valueNr
] = NULL
;
2842 * @ctxt: an XPath evaluation context
2843 * @value: the XPath object
2845 * Pushes a new XPath object on top of the value stack. If value is NULL,
2846 * a memory error is recorded in the parser context.
2848 * Returns the number of items on the value stack, or -1 in case of error.
2850 * The object is destroyed in case of error.
2853 valuePush(xmlXPathParserContextPtr ctxt
, xmlXPathObjectPtr value
)
2855 if (ctxt
== NULL
) return(-1);
2856 if (value
== NULL
) {
2858 * A NULL value typically indicates that a memory allocation failed,
2859 * so we set ctxt->error here to propagate the error.
2861 ctxt
->error
= XPATH_MEMORY_ERROR
;
2864 if (ctxt
->valueNr
>= ctxt
->valueMax
) {
2865 xmlXPathObjectPtr
*tmp
;
2867 if (ctxt
->valueMax
>= XPATH_MAX_STACK_DEPTH
) {
2868 xmlXPathPErrMemory(ctxt
, "XPath stack depth limit reached\n");
2869 xmlXPathFreeObject(value
);
2872 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(ctxt
->valueTab
,
2873 2 * ctxt
->valueMax
*
2874 sizeof(ctxt
->valueTab
[0]));
2876 xmlXPathPErrMemory(ctxt
, "pushing value\n");
2877 xmlXPathFreeObject(value
);
2880 ctxt
->valueMax
*= 2;
2881 ctxt
->valueTab
= tmp
;
2883 ctxt
->valueTab
[ctxt
->valueNr
] = value
;
2884 ctxt
->value
= value
;
2885 return (ctxt
->valueNr
++);
2889 * xmlXPathPopBoolean:
2890 * @ctxt: an XPath parser context
2892 * Pops a boolean from the stack, handling conversion if needed.
2893 * Check error with #xmlXPathCheckError.
2895 * Returns the boolean
2898 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt
) {
2899 xmlXPathObjectPtr obj
;
2902 obj
= valuePop(ctxt
);
2904 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2907 if (obj
->type
!= XPATH_BOOLEAN
)
2908 ret
= xmlXPathCastToBoolean(obj
);
2911 xmlXPathReleaseObject(ctxt
->context
, obj
);
2916 * xmlXPathPopNumber:
2917 * @ctxt: an XPath parser context
2919 * Pops a number from the stack, handling conversion if needed.
2920 * Check error with #xmlXPathCheckError.
2922 * Returns the number
2925 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt
) {
2926 xmlXPathObjectPtr obj
;
2929 obj
= valuePop(ctxt
);
2931 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2934 if (obj
->type
!= XPATH_NUMBER
)
2935 ret
= xmlXPathCastToNumber(obj
);
2937 ret
= obj
->floatval
;
2938 xmlXPathReleaseObject(ctxt
->context
, obj
);
2943 * xmlXPathPopString:
2944 * @ctxt: an XPath parser context
2946 * Pops a string from the stack, handling conversion if needed.
2947 * Check error with #xmlXPathCheckError.
2949 * Returns the string
2952 xmlXPathPopString (xmlXPathParserContextPtr ctxt
) {
2953 xmlXPathObjectPtr obj
;
2956 obj
= valuePop(ctxt
);
2958 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2961 ret
= xmlXPathCastToString(obj
); /* this does required strdup */
2962 /* TODO: needs refactoring somewhere else */
2963 if (obj
->stringval
== ret
)
2964 obj
->stringval
= NULL
;
2965 xmlXPathReleaseObject(ctxt
->context
, obj
);
2970 * xmlXPathPopNodeSet:
2971 * @ctxt: an XPath parser context
2973 * Pops a node-set from the stack, handling conversion if needed.
2974 * Check error with #xmlXPathCheckError.
2976 * Returns the node-set
2979 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt
) {
2980 xmlXPathObjectPtr obj
;
2983 if (ctxt
== NULL
) return(NULL
);
2984 if (ctxt
->value
== NULL
) {
2985 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2988 if (!xmlXPathStackIsNodeSet(ctxt
)) {
2989 xmlXPathSetTypeError(ctxt
);
2992 obj
= valuePop(ctxt
);
2993 ret
= obj
->nodesetval
;
2995 /* to fix memory leak of not clearing obj->user */
2996 if (obj
->boolval
&& obj
->user
!= NULL
)
2997 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
2999 obj
->nodesetval
= NULL
;
3000 xmlXPathReleaseObject(ctxt
->context
, obj
);
3005 * xmlXPathPopExternal:
3006 * @ctxt: an XPath parser context
3008 * Pops an external object from the stack, handling conversion if needed.
3009 * Check error with #xmlXPathCheckError.
3011 * Returns the object
3014 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt
) {
3015 xmlXPathObjectPtr obj
;
3018 if ((ctxt
== NULL
) || (ctxt
->value
== NULL
)) {
3019 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
3022 if (ctxt
->value
->type
!= XPATH_USERS
) {
3023 xmlXPathSetTypeError(ctxt
);
3026 obj
= valuePop(ctxt
);
3029 xmlXPathReleaseObject(ctxt
->context
, obj
);
3034 * Macros for accessing the content. Those should be used only by the parser,
3037 * Dirty macros, i.e. one need to make assumption on the context to use them
3039 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3040 * CUR returns the current xmlChar value, i.e. a 8 bit value
3041 * in ISO-Latin or UTF-8.
3042 * This should be used internally by the parser
3043 * only to compare to ASCII values otherwise it would break when
3044 * running with UTF-8 encoding.
3045 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3046 * to compare on ASCII based substring.
3047 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3048 * strings within the parser.
3049 * CURRENT Returns the current char value, with the full decoding of
3050 * UTF-8 if we are using this mode. It returns an int.
3051 * NEXT Skip to the next character, this does the proper decoding
3052 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3053 * It returns the pointer to the current xmlChar.
3056 #define CUR (*ctxt->cur)
3057 #define SKIP(val) ctxt->cur += (val)
3058 #define NXT(val) ctxt->cur[(val)]
3059 #define CUR_PTR ctxt->cur
3060 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3062 #define COPY_BUF(l,b,i,v) \
3063 if (l == 1) b[i++] = v; \
3064 else i += xmlCopyChar(l,&b[i],v)
3066 #define NEXTL(l) ctxt->cur += l
3068 #define SKIP_BLANKS \
3069 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3071 #define CURRENT (*ctxt->cur)
3072 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3079 #define DBL_EPSILON 1E-9
3082 #define UPPER_DOUBLE 1E9
3083 #define LOWER_DOUBLE 1E-5
3084 #define LOWER_DOUBLE_EXP 5
3086 #define INTEGER_DIGITS DBL_DIG
3087 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3088 #define EXPONENT_DIGITS (3 + 2)
3091 * xmlXPathFormatNumber:
3092 * @number: number to format
3093 * @buffer: output buffer
3094 * @buffersize: size of output buffer
3096 * Convert the number into a string representation.
3099 xmlXPathFormatNumber(double number
, char buffer
[], int buffersize
)
3101 switch (xmlXPathIsInf(number
)) {
3103 if (buffersize
> (int)sizeof("Infinity"))
3104 snprintf(buffer
, buffersize
, "Infinity");
3107 if (buffersize
> (int)sizeof("-Infinity"))
3108 snprintf(buffer
, buffersize
, "-Infinity");
3111 if (xmlXPathIsNaN(number
)) {
3112 if (buffersize
> (int)sizeof("NaN"))
3113 snprintf(buffer
, buffersize
, "NaN");
3114 } else if (number
== 0) {
3115 /* Omit sign for negative zero. */
3116 snprintf(buffer
, buffersize
, "0");
3117 } else if ((number
> INT_MIN
) && (number
< INT_MAX
) &&
3118 (number
== (int) number
)) {
3121 int value
= (int) number
;
3127 snprintf(work
, 29, "%d", value
);
3129 while ((*cur
) && (ptr
- buffer
< buffersize
)) {
3133 if (ptr
- buffer
< buffersize
) {
3135 } else if (buffersize
> 0) {
3141 For the dimension of work,
3142 DBL_DIG is number of significant digits
3143 EXPONENT is only needed for "scientific notation"
3144 3 is sign, decimal point, and terminating zero
3145 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3146 Note that this dimension is slightly (a few characters)
3147 larger than actually necessary.
3149 char work
[DBL_DIG
+ EXPONENT_DIGITS
+ 3 + LOWER_DOUBLE_EXP
];
3150 int integer_place
, fraction_place
;
3152 char *after_fraction
;
3153 double absolute_value
;
3156 absolute_value
= fabs(number
);
3159 * First choose format - scientific or regular floating point.
3160 * In either case, result is in work, and after_fraction points
3161 * just past the fractional part.
3163 if ( ((absolute_value
> UPPER_DOUBLE
) ||
3164 (absolute_value
< LOWER_DOUBLE
)) &&
3165 (absolute_value
!= 0.0) ) {
3166 /* Use scientific notation */
3167 integer_place
= DBL_DIG
+ EXPONENT_DIGITS
+ 1;
3168 fraction_place
= DBL_DIG
- 1;
3169 size
= snprintf(work
, sizeof(work
),"%*.*e",
3170 integer_place
, fraction_place
, number
);
3171 while ((size
> 0) && (work
[size
] != 'e')) size
--;
3175 /* Use regular notation */
3176 if (absolute_value
> 0.0) {
3177 integer_place
= (int)log10(absolute_value
);
3178 if (integer_place
> 0)
3179 fraction_place
= DBL_DIG
- integer_place
- 1;
3181 fraction_place
= DBL_DIG
- integer_place
;
3185 size
= snprintf(work
, sizeof(work
), "%0.*f",
3186 fraction_place
, number
);
3189 /* Remove leading spaces sometimes inserted by snprintf */
3190 while (work
[0] == ' ') {
3191 for (ptr
= &work
[0];(ptr
[0] = ptr
[1]);ptr
++);
3195 /* Remove fractional trailing zeroes */
3196 after_fraction
= work
+ size
;
3197 ptr
= after_fraction
;
3198 while (*(--ptr
) == '0')
3202 while ((*ptr
++ = *after_fraction
++) != 0);
3204 /* Finally copy result back to caller */
3205 size
= strlen(work
) + 1;
3206 if (size
> buffersize
) {
3207 work
[buffersize
- 1] = 0;
3210 memmove(buffer
, work
, size
);
3217 /************************************************************************
3219 * Routines to handle NodeSets *
3221 ************************************************************************/
3224 * xmlXPathOrderDocElems:
3225 * @doc: an input document
3227 * Call this routine to speed up XPath computation on static documents.
3228 * This stamps all the element nodes with the document order
3229 * Like for line information, the order is kept in the element->content
3230 * field, the value stored is actually - the node number (starting at -1)
3231 * to be able to differentiate from line numbers.
3233 * Returns the number of elements found in the document or -1 in case
3237 xmlXPathOrderDocElems(xmlDocPtr doc
) {
3238 ptrdiff_t count
= 0;
3243 cur
= doc
->children
;
3244 while (cur
!= NULL
) {
3245 if (cur
->type
== XML_ELEMENT_NODE
) {
3246 cur
->content
= (void *) (-(++count
));
3247 if (cur
->children
!= NULL
) {
3248 cur
= cur
->children
;
3252 if (cur
->next
!= NULL
) {
3260 if (cur
== (xmlNodePtr
) doc
) {
3264 if (cur
->next
!= NULL
) {
3268 } while (cur
!= NULL
);
3275 * @node1: the first node
3276 * @node2: the second node
3278 * Compare two nodes w.r.t document order
3280 * Returns -2 in case of error 1 if first point < second point, 0 if
3281 * it's the same node, -1 otherwise
3284 xmlXPathCmpNodes(xmlNodePtr node1
, xmlNodePtr node2
) {
3286 int attr1
= 0, attr2
= 0;
3287 xmlNodePtr attrNode1
= NULL
, attrNode2
= NULL
;
3288 xmlNodePtr cur
, root
;
3290 if ((node1
== NULL
) || (node2
== NULL
))
3293 * a couple of optimizations which will avoid computations in most cases
3295 if (node1
== node2
) /* trivial case */
3297 if (node1
->type
== XML_ATTRIBUTE_NODE
) {
3300 node1
= node1
->parent
;
3302 if (node2
->type
== XML_ATTRIBUTE_NODE
) {
3305 node2
= node2
->parent
;
3307 if (node1
== node2
) {
3308 if (attr1
== attr2
) {
3309 /* not required, but we keep attributes in order */
3311 cur
= attrNode2
->prev
;
3312 while (cur
!= NULL
) {
3313 if (cur
== attrNode1
)
3325 if ((node1
->type
== XML_NAMESPACE_DECL
) ||
3326 (node2
->type
== XML_NAMESPACE_DECL
))
3328 if (node1
== node2
->prev
)
3330 if (node1
== node2
->next
)
3334 * Speedup using document order if available.
3336 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3337 (node2
->type
== XML_ELEMENT_NODE
) &&
3338 (0 > (ptrdiff_t) node1
->content
) &&
3339 (0 > (ptrdiff_t) node2
->content
) &&
3340 (node1
->doc
== node2
->doc
)) {
3343 l1
= -((ptrdiff_t) node1
->content
);
3344 l2
= -((ptrdiff_t) node2
->content
);
3352 * compute depth to root
3354 for (depth2
= 0, cur
= node2
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3355 if (cur
->parent
== node1
)
3360 for (depth1
= 0, cur
= node1
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3361 if (cur
->parent
== node2
)
3366 * Distinct document (or distinct entities :-( ) case.
3372 * get the nearest common ancestor.
3374 while (depth1
> depth2
) {
3376 node1
= node1
->parent
;
3378 while (depth2
> depth1
) {
3380 node2
= node2
->parent
;
3382 while (node1
->parent
!= node2
->parent
) {
3383 node1
= node1
->parent
;
3384 node2
= node2
->parent
;
3385 /* should not happen but just in case ... */
3386 if ((node1
== NULL
) || (node2
== NULL
))
3392 if (node1
== node2
->prev
)
3394 if (node1
== node2
->next
)
3397 * Speedup using document order if available.
3399 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3400 (node2
->type
== XML_ELEMENT_NODE
) &&
3401 (0 > (ptrdiff_t) node1
->content
) &&
3402 (0 > (ptrdiff_t) node2
->content
) &&
3403 (node1
->doc
== node2
->doc
)) {
3406 l1
= -((ptrdiff_t) node1
->content
);
3407 l2
= -((ptrdiff_t) node2
->content
);
3414 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
3417 return(-1); /* assume there is no sibling list corruption */
3421 * xmlXPathNodeSetSort:
3422 * @set: the node set
3424 * Sort the node set in document order
3427 xmlXPathNodeSetSort(xmlNodeSetPtr set
) {
3428 #ifndef WITH_TIM_SORT
3429 int i
, j
, incr
, len
;
3436 #ifndef WITH_TIM_SORT
3438 * Use the old Shell's sort implementation to sort the node-set
3439 * Timsort ought to be quite faster
3442 for (incr
= len
/ 2; incr
> 0; incr
/= 2) {
3443 for (i
= incr
; i
< len
; i
++) {
3446 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3447 if (xmlXPathCmpNodesExt(set
->nodeTab
[j
],
3448 set
->nodeTab
[j
+ incr
]) == -1)
3450 if (xmlXPathCmpNodes(set
->nodeTab
[j
],
3451 set
->nodeTab
[j
+ incr
]) == -1)
3454 tmp
= set
->nodeTab
[j
];
3455 set
->nodeTab
[j
] = set
->nodeTab
[j
+ incr
];
3456 set
->nodeTab
[j
+ incr
] = tmp
;
3463 #else /* WITH_TIM_SORT */
3464 libxml_domnode_tim_sort(set
->nodeTab
, set
->nodeNr
);
3465 #endif /* WITH_TIM_SORT */
3468 #define XML_NODESET_DEFAULT 10
3470 * xmlXPathNodeSetDupNs:
3471 * @node: the parent node of the namespace XPath node
3472 * @ns: the libxml namespace declaration node.
3474 * Namespace node in libxml don't match the XPath semantic. In a node set
3475 * the namespace nodes are duplicated and the next pointer is set to the
3476 * parent node in the XPath semantic.
3478 * Returns the newly created object.
3481 xmlXPathNodeSetDupNs(xmlNodePtr node
, xmlNsPtr ns
) {
3484 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3486 if ((node
== NULL
) || (node
->type
== XML_NAMESPACE_DECL
))
3487 return((xmlNodePtr
) ns
);
3490 * Allocate a new Namespace and fill the fields.
3492 cur
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
3494 xmlXPathErrMemory(NULL
, "duplicating namespace\n");
3497 memset(cur
, 0, sizeof(xmlNs
));
3498 cur
->type
= XML_NAMESPACE_DECL
;
3499 if (ns
->href
!= NULL
)
3500 cur
->href
= xmlStrdup(ns
->href
);
3501 if (ns
->prefix
!= NULL
)
3502 cur
->prefix
= xmlStrdup(ns
->prefix
);
3503 cur
->next
= (xmlNsPtr
) node
;
3504 return((xmlNodePtr
) cur
);
3508 * xmlXPathNodeSetFreeNs:
3509 * @ns: the XPath namespace node found in a nodeset.
3511 * Namespace nodes 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. Check if such a node needs to be freed
3516 xmlXPathNodeSetFreeNs(xmlNsPtr ns
) {
3517 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3520 if ((ns
->next
!= NULL
) && (ns
->next
->type
!= XML_NAMESPACE_DECL
)) {
3521 if (ns
->href
!= NULL
)
3522 xmlFree((xmlChar
*)ns
->href
);
3523 if (ns
->prefix
!= NULL
)
3524 xmlFree((xmlChar
*)ns
->prefix
);
3530 * xmlXPathNodeSetCreate:
3531 * @val: an initial xmlNodePtr, or NULL
3533 * Create a new xmlNodeSetPtr of type double and of value @val
3535 * Returns the newly created object.
3538 xmlXPathNodeSetCreate(xmlNodePtr val
) {
3541 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3543 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3546 memset(ret
, 0 , sizeof(xmlNodeSet
));
3548 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3549 sizeof(xmlNodePtr
));
3550 if (ret
->nodeTab
== NULL
) {
3551 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3555 memset(ret
->nodeTab
, 0 ,
3556 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3557 ret
->nodeMax
= XML_NODESET_DEFAULT
;
3558 if (val
->type
== XML_NAMESPACE_DECL
) {
3559 xmlNsPtr ns
= (xmlNsPtr
) val
;
3560 xmlNodePtr nsNode
= xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3562 if (nsNode
== NULL
) {
3563 xmlXPathFreeNodeSet(ret
);
3566 ret
->nodeTab
[ret
->nodeNr
++] = nsNode
;
3568 ret
->nodeTab
[ret
->nodeNr
++] = val
;
3574 * xmlXPathNodeSetContains:
3575 * @cur: the node-set
3578 * checks whether @cur contains @val
3580 * Returns true (1) if @cur contains @val, false (0) otherwise
3583 xmlXPathNodeSetContains (xmlNodeSetPtr cur
, xmlNodePtr val
) {
3586 if ((cur
== NULL
) || (val
== NULL
)) return(0);
3587 if (val
->type
== XML_NAMESPACE_DECL
) {
3588 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3589 if (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
3592 ns1
= (xmlNsPtr
) val
;
3593 ns2
= (xmlNsPtr
) cur
->nodeTab
[i
];
3596 if ((ns1
->next
!= NULL
) && (ns2
->next
== ns1
->next
) &&
3597 (xmlStrEqual(ns1
->prefix
, ns2
->prefix
)))
3602 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3603 if (cur
->nodeTab
[i
] == val
)
3611 * xmlXPathNodeSetAddNs:
3612 * @cur: the initial node set
3613 * @node: the hosting node
3614 * @ns: a the namespace node
3616 * add a new namespace node to an existing NodeSet
3618 * Returns 0 in case of success and -1 in case of error
3621 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur
, xmlNodePtr node
, xmlNsPtr ns
) {
3625 if ((cur
== NULL
) || (ns
== NULL
) || (node
== NULL
) ||
3626 (ns
->type
!= XML_NAMESPACE_DECL
) ||
3627 (node
->type
!= XML_ELEMENT_NODE
))
3630 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3632 * prevent duplicates
3634 for (i
= 0;i
< cur
->nodeNr
;i
++) {
3635 if ((cur
->nodeTab
[i
] != NULL
) &&
3636 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) &&
3637 (((xmlNsPtr
)cur
->nodeTab
[i
])->next
== (xmlNsPtr
) node
) &&
3638 (xmlStrEqual(ns
->prefix
, ((xmlNsPtr
)cur
->nodeTab
[i
])->prefix
)))
3643 * grow the nodeTab if needed
3645 if (cur
->nodeMax
== 0) {
3646 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3647 sizeof(xmlNodePtr
));
3648 if (cur
->nodeTab
== NULL
) {
3649 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3652 memset(cur
->nodeTab
, 0 ,
3653 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3654 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3655 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3658 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3659 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3662 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3663 sizeof(xmlNodePtr
));
3665 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3669 cur
->nodeTab
= temp
;
3671 nsNode
= xmlXPathNodeSetDupNs(node
, ns
);
3674 cur
->nodeTab
[cur
->nodeNr
++] = nsNode
;
3679 * xmlXPathNodeSetAdd:
3680 * @cur: the initial node set
3681 * @val: a new xmlNodePtr
3683 * add a new xmlNodePtr to an existing NodeSet
3685 * Returns 0 in case of success, and -1 in case of error
3688 xmlXPathNodeSetAdd(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3691 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3693 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3695 * prevent duplicates
3697 for (i
= 0;i
< cur
->nodeNr
;i
++)
3698 if (cur
->nodeTab
[i
] == val
) return(0);
3701 * grow the nodeTab if needed
3703 if (cur
->nodeMax
== 0) {
3704 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3705 sizeof(xmlNodePtr
));
3706 if (cur
->nodeTab
== NULL
) {
3707 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3710 memset(cur
->nodeTab
, 0 ,
3711 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3712 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3713 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3716 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3717 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3720 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3721 sizeof(xmlNodePtr
));
3723 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3727 cur
->nodeTab
= temp
;
3729 if (val
->type
== XML_NAMESPACE_DECL
) {
3730 xmlNsPtr ns
= (xmlNsPtr
) val
;
3731 xmlNodePtr nsNode
= xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3735 cur
->nodeTab
[cur
->nodeNr
++] = nsNode
;
3737 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3742 * xmlXPathNodeSetAddUnique:
3743 * @cur: the initial node set
3744 * @val: a new xmlNodePtr
3746 * add a new xmlNodePtr to an existing NodeSet, optimized version
3747 * when we are sure the node is not already in the set.
3749 * Returns 0 in case of success and -1 in case of failure
3752 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3753 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3755 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3757 * grow the nodeTab if needed
3759 if (cur
->nodeMax
== 0) {
3760 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3761 sizeof(xmlNodePtr
));
3762 if (cur
->nodeTab
== NULL
) {
3763 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3766 memset(cur
->nodeTab
, 0 ,
3767 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3768 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3769 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3772 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3773 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3776 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3777 sizeof(xmlNodePtr
));
3779 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3782 cur
->nodeTab
= temp
;
3785 if (val
->type
== XML_NAMESPACE_DECL
) {
3786 xmlNsPtr ns
= (xmlNsPtr
) val
;
3787 xmlNodePtr nsNode
= xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3791 cur
->nodeTab
[cur
->nodeNr
++] = nsNode
;
3793 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3798 * xmlXPathNodeSetMerge:
3799 * @val1: the first NodeSet or NULL
3800 * @val2: the second NodeSet
3802 * Merges two nodesets, all nodes from @val2 are added to @val1
3803 * if @val1 is NULL, a new set is created and copied from @val2
3805 * Returns @val1 once extended or NULL in case of error.
3807 * Frees @val1 in case of error.
3810 xmlXPathNodeSetMerge(xmlNodeSetPtr val1
, xmlNodeSetPtr val2
) {
3811 int i
, j
, initNr
, skip
;
3814 if (val2
== NULL
) return(val1
);
3816 val1
= xmlXPathNodeSetCreate(NULL
);
3821 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3822 initNr
= val1
->nodeNr
;
3824 for (i
= 0;i
< val2
->nodeNr
;i
++) {
3825 n2
= val2
->nodeTab
[i
];
3827 * check against duplicates
3830 for (j
= 0; j
< initNr
; j
++) {
3831 n1
= val1
->nodeTab
[j
];
3835 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3836 (n2
->type
== XML_NAMESPACE_DECL
)) {
3837 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3838 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3839 ((xmlNsPtr
) n2
)->prefix
)))
3850 * grow the nodeTab if needed
3852 if (val1
->nodeMax
== 0) {
3853 val1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3854 sizeof(xmlNodePtr
));
3855 if (val1
->nodeTab
== NULL
) {
3856 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3859 memset(val1
->nodeTab
, 0 ,
3860 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3861 val1
->nodeMax
= XML_NODESET_DEFAULT
;
3862 } else if (val1
->nodeNr
== val1
->nodeMax
) {
3865 if (val1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3866 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
3869 temp
= (xmlNodePtr
*) xmlRealloc(val1
->nodeTab
, val1
->nodeMax
* 2 *
3870 sizeof(xmlNodePtr
));
3872 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3875 val1
->nodeTab
= temp
;
3878 if (n2
->type
== XML_NAMESPACE_DECL
) {
3879 xmlNsPtr ns
= (xmlNsPtr
) n2
;
3880 xmlNodePtr nsNode
= xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3884 val1
->nodeTab
[val1
->nodeNr
++] = nsNode
;
3886 val1
->nodeTab
[val1
->nodeNr
++] = n2
;
3892 xmlXPathFreeNodeSet(val1
);
3898 * xmlXPathNodeSetMergeAndClear:
3899 * @set1: the first NodeSet or NULL
3900 * @set2: the second NodeSet
3902 * Merges two nodesets, all nodes from @set2 are added to @set1.
3903 * Checks for duplicate nodes. Clears set2.
3905 * Returns @set1 once extended or NULL in case of error.
3907 * Frees @set1 in case of error.
3909 static xmlNodeSetPtr
3910 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
)
3913 int i
, j
, initNbSet1
;
3916 initNbSet1
= set1
->nodeNr
;
3917 for (i
= 0;i
< set2
->nodeNr
;i
++) {
3918 n2
= set2
->nodeTab
[i
];
3922 for (j
= 0; j
< initNbSet1
; j
++) {
3923 n1
= set1
->nodeTab
[j
];
3926 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3927 (n2
->type
== XML_NAMESPACE_DECL
))
3929 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3930 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3931 ((xmlNsPtr
) n2
)->prefix
)))
3934 * Free the namespace node.
3936 xmlXPathNodeSetFreeNs((xmlNsPtr
) n2
);
3942 * grow the nodeTab if needed
3944 if (set1
->nodeMax
== 0) {
3945 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
3946 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3947 if (set1
->nodeTab
== NULL
) {
3948 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3951 memset(set1
->nodeTab
, 0,
3952 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3953 set1
->nodeMax
= XML_NODESET_DEFAULT
;
3954 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
3957 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3958 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
3961 temp
= (xmlNodePtr
*) xmlRealloc(
3962 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
3964 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3967 set1
->nodeTab
= temp
;
3970 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
3972 set2
->nodeTab
[i
] = NULL
;
3979 xmlXPathFreeNodeSet(set1
);
3980 xmlXPathNodeSetClear(set2
, 1);
3985 * xmlXPathNodeSetMergeAndClearNoDupls:
3986 * @set1: the first NodeSet or NULL
3987 * @set2: the second NodeSet
3989 * Merges two nodesets, all nodes from @set2 are added to @set1.
3990 * Doesn't check for duplicate nodes. Clears set2.
3992 * Returns @set1 once extended or NULL in case of error.
3994 * Frees @set1 in case of error.
3996 static xmlNodeSetPtr
3997 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
)
4003 for (i
= 0;i
< set2
->nodeNr
;i
++) {
4004 n2
= set2
->nodeTab
[i
];
4005 if (set1
->nodeMax
== 0) {
4006 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
4007 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4008 if (set1
->nodeTab
== NULL
) {
4009 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4012 memset(set1
->nodeTab
, 0,
4013 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4014 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4015 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4018 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4019 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4022 temp
= (xmlNodePtr
*) xmlRealloc(
4023 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4025 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4028 set1
->nodeTab
= temp
;
4031 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4032 set2
->nodeTab
[i
] = NULL
;
4039 xmlXPathFreeNodeSet(set1
);
4040 xmlXPathNodeSetClear(set2
, 1);
4045 * xmlXPathNodeSetDel:
4046 * @cur: the initial node set
4047 * @val: an xmlNodePtr
4049 * Removes an xmlNodePtr from an existing NodeSet
4052 xmlXPathNodeSetDel(xmlNodeSetPtr cur
, xmlNodePtr val
) {
4055 if (cur
== NULL
) return;
4056 if (val
== NULL
) return;
4059 * find node in nodeTab
4061 for (i
= 0;i
< cur
->nodeNr
;i
++)
4062 if (cur
->nodeTab
[i
] == val
) break;
4064 if (i
>= cur
->nodeNr
) { /* not found */
4066 xmlGenericError(xmlGenericErrorContext
,
4067 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4072 if ((cur
->nodeTab
[i
] != NULL
) &&
4073 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4074 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[i
]);
4076 for (;i
< cur
->nodeNr
;i
++)
4077 cur
->nodeTab
[i
] = cur
->nodeTab
[i
+ 1];
4078 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4082 * xmlXPathNodeSetRemove:
4083 * @cur: the initial node set
4084 * @val: the index to remove
4086 * Removes an entry from an existing NodeSet list.
4089 xmlXPathNodeSetRemove(xmlNodeSetPtr cur
, int val
) {
4090 if (cur
== NULL
) return;
4091 if (val
>= cur
->nodeNr
) return;
4092 if ((cur
->nodeTab
[val
] != NULL
) &&
4093 (cur
->nodeTab
[val
]->type
== XML_NAMESPACE_DECL
))
4094 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[val
]);
4096 for (;val
< cur
->nodeNr
;val
++)
4097 cur
->nodeTab
[val
] = cur
->nodeTab
[val
+ 1];
4098 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4102 * xmlXPathFreeNodeSet:
4103 * @obj: the xmlNodeSetPtr to free
4105 * Free the NodeSet compound (not the actual nodes !).
4108 xmlXPathFreeNodeSet(xmlNodeSetPtr obj
) {
4109 if (obj
== NULL
) return;
4110 if (obj
->nodeTab
!= NULL
) {
4113 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4114 for (i
= 0;i
< obj
->nodeNr
;i
++)
4115 if ((obj
->nodeTab
[i
] != NULL
) &&
4116 (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4117 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4118 xmlFree(obj
->nodeTab
);
4124 * xmlXPathNodeSetClearFromPos:
4125 * @set: the node set to be cleared
4126 * @pos: the start position to clear from
4128 * Clears the list from temporary XPath objects (e.g. namespace nodes
4129 * are feed) starting with the entry at @pos, but does *not* free the list
4130 * itself. Sets the length of the list to @pos.
4133 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set
, int pos
, int hasNsNodes
)
4135 if ((set
== NULL
) || (pos
>= set
->nodeNr
))
4137 else if ((hasNsNodes
)) {
4141 for (i
= pos
; i
< set
->nodeNr
; i
++) {
4142 node
= set
->nodeTab
[i
];
4143 if ((node
!= NULL
) &&
4144 (node
->type
== XML_NAMESPACE_DECL
))
4145 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4152 * xmlXPathNodeSetClear:
4153 * @set: the node set to clear
4155 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4156 * are feed), but does *not* free the list itself. Sets the length of the
4160 xmlXPathNodeSetClear(xmlNodeSetPtr set
, int hasNsNodes
)
4162 xmlXPathNodeSetClearFromPos(set
, 0, hasNsNodes
);
4166 * xmlXPathNodeSetKeepLast:
4167 * @set: the node set to be cleared
4169 * Move the last node to the first position and clear temporary XPath objects
4170 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4174 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set
)
4179 if ((set
== NULL
) || (set
->nodeNr
<= 1))
4181 for (i
= 0; i
< set
->nodeNr
- 1; i
++) {
4182 node
= set
->nodeTab
[i
];
4183 if ((node
!= NULL
) &&
4184 (node
->type
== XML_NAMESPACE_DECL
))
4185 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4187 set
->nodeTab
[0] = set
->nodeTab
[set
->nodeNr
-1];
4192 * xmlXPathFreeValueTree:
4193 * @obj: the xmlNodeSetPtr to free
4195 * Free the NodeSet compound and the actual tree, this is different
4196 * from xmlXPathFreeNodeSet()
4199 xmlXPathFreeValueTree(xmlNodeSetPtr obj
) {
4202 if (obj
== NULL
) return;
4204 if (obj
->nodeTab
!= NULL
) {
4205 for (i
= 0;i
< obj
->nodeNr
;i
++) {
4206 if (obj
->nodeTab
[i
] != NULL
) {
4207 if (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
4208 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4210 xmlFreeNodeList(obj
->nodeTab
[i
]);
4214 xmlFree(obj
->nodeTab
);
4219 #if defined(DEBUG) || defined(DEBUG_STEP)
4221 * xmlGenericErrorContextNodeSet:
4222 * @output: a FILE * for the output
4223 * @obj: the xmlNodeSetPtr to display
4225 * Quick display of a NodeSet
4228 xmlGenericErrorContextNodeSet(FILE *output
, xmlNodeSetPtr obj
) {
4231 if (output
== NULL
) output
= xmlGenericErrorContext
;
4233 fprintf(output
, "NodeSet == NULL !\n");
4236 if (obj
->nodeNr
== 0) {
4237 fprintf(output
, "NodeSet is empty\n");
4240 if (obj
->nodeTab
== NULL
) {
4241 fprintf(output
, " nodeTab == NULL !\n");
4244 for (i
= 0; i
< obj
->nodeNr
; i
++) {
4245 if (obj
->nodeTab
[i
] == NULL
) {
4246 fprintf(output
, " NULL !\n");
4249 if ((obj
->nodeTab
[i
]->type
== XML_DOCUMENT_NODE
) ||
4250 (obj
->nodeTab
[i
]->type
== XML_HTML_DOCUMENT_NODE
))
4251 fprintf(output
, " /");
4252 else if (obj
->nodeTab
[i
]->name
== NULL
)
4253 fprintf(output
, " noname!");
4254 else fprintf(output
, " %s", obj
->nodeTab
[i
]->name
);
4256 fprintf(output
, "\n");
4261 * xmlXPathNewNodeSet:
4262 * @val: the NodePtr value
4264 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4265 * it with the single Node @val
4267 * Returns the newly created object.
4270 xmlXPathNewNodeSet(xmlNodePtr val
) {
4271 xmlXPathObjectPtr ret
;
4273 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4275 xmlXPathErrMemory(NULL
, "creating nodeset\n");
4278 memset(ret
, 0 , sizeof(xmlXPathObject
));
4279 ret
->type
= XPATH_NODESET
;
4281 /* TODO: Check memory error. */
4282 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4283 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4284 #ifdef XP_DEBUG_OBJ_USAGE
4285 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4291 * xmlXPathNewValueTree:
4292 * @val: the NodePtr value
4294 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4295 * it with the tree root @val
4297 * Returns the newly created object.
4300 xmlXPathNewValueTree(xmlNodePtr val
) {
4301 xmlXPathObjectPtr ret
;
4303 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4305 xmlXPathErrMemory(NULL
, "creating result value tree\n");
4308 memset(ret
, 0 , sizeof(xmlXPathObject
));
4309 ret
->type
= XPATH_XSLT_TREE
;
4311 ret
->user
= (void *) val
;
4312 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4313 #ifdef XP_DEBUG_OBJ_USAGE
4314 xmlXPathDebugObjUsageRequested(NULL
, XPATH_XSLT_TREE
);
4320 * xmlXPathNewNodeSetList:
4321 * @val: an existing NodeSet
4323 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4324 * it with the Nodeset @val
4326 * Returns the newly created object.
4329 xmlXPathNewNodeSetList(xmlNodeSetPtr val
)
4331 xmlXPathObjectPtr ret
;
4336 else if (val
->nodeTab
== NULL
)
4337 ret
= xmlXPathNewNodeSet(NULL
);
4339 ret
= xmlXPathNewNodeSet(val
->nodeTab
[0]);
4341 for (i
= 1; i
< val
->nodeNr
; ++i
) {
4342 /* TODO: Propagate memory error. */
4343 if (xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
->nodeTab
[i
])
4353 * xmlXPathWrapNodeSet:
4354 * @val: the NodePtr value
4356 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4358 * Returns the newly created object.
4360 * In case of error the node set is destroyed and NULL is returned.
4363 xmlXPathWrapNodeSet(xmlNodeSetPtr val
) {
4364 xmlXPathObjectPtr ret
;
4366 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4368 xmlXPathErrMemory(NULL
, "creating node set object\n");
4369 xmlXPathFreeNodeSet(val
);
4372 memset(ret
, 0 , sizeof(xmlXPathObject
));
4373 ret
->type
= XPATH_NODESET
;
4374 ret
->nodesetval
= val
;
4375 #ifdef XP_DEBUG_OBJ_USAGE
4376 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4382 * xmlXPathFreeNodeSetList:
4383 * @obj: an existing NodeSetList object
4385 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4386 * the list contrary to xmlXPathFreeObject().
4389 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj
) {
4390 if (obj
== NULL
) return;
4391 #ifdef XP_DEBUG_OBJ_USAGE
4392 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
4398 * xmlXPathDifference:
4399 * @nodes1: a node-set
4400 * @nodes2: a node-set
4402 * Implements the EXSLT - Sets difference() function:
4403 * node-set set:difference (node-set, node-set)
4405 * Returns the difference between the two node sets, or nodes1 if
4409 xmlXPathDifference (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4414 if (xmlXPathNodeSetIsEmpty(nodes2
))
4417 /* TODO: Check memory error. */
4418 ret
= xmlXPathNodeSetCreate(NULL
);
4419 if (xmlXPathNodeSetIsEmpty(nodes1
))
4422 l1
= xmlXPathNodeSetGetLength(nodes1
);
4424 for (i
= 0; i
< l1
; i
++) {
4425 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4426 if (!xmlXPathNodeSetContains(nodes2
, cur
)) {
4427 /* TODO: Propagate memory error. */
4428 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4436 * xmlXPathIntersection:
4437 * @nodes1: a node-set
4438 * @nodes2: a node-set
4440 * Implements the EXSLT - Sets intersection() function:
4441 * node-set set:intersection (node-set, node-set)
4443 * Returns a node set comprising the nodes that are within both the
4444 * node sets passed as arguments
4447 xmlXPathIntersection (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4448 xmlNodeSetPtr ret
= xmlXPathNodeSetCreate(NULL
);
4454 if (xmlXPathNodeSetIsEmpty(nodes1
))
4456 if (xmlXPathNodeSetIsEmpty(nodes2
))
4459 l1
= xmlXPathNodeSetGetLength(nodes1
);
4461 for (i
= 0; i
< l1
; i
++) {
4462 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4463 if (xmlXPathNodeSetContains(nodes2
, cur
)) {
4464 /* TODO: Propagate memory error. */
4465 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4473 * xmlXPathDistinctSorted:
4474 * @nodes: a node-set, sorted by document order
4476 * Implements the EXSLT - Sets distinct() function:
4477 * node-set set:distinct (node-set)
4479 * Returns a subset of the nodes contained in @nodes, or @nodes if
4483 xmlXPathDistinctSorted (xmlNodeSetPtr nodes
) {
4485 xmlHashTablePtr hash
;
4490 if (xmlXPathNodeSetIsEmpty(nodes
))
4493 ret
= xmlXPathNodeSetCreate(NULL
);
4496 l
= xmlXPathNodeSetGetLength(nodes
);
4497 hash
= xmlHashCreate (l
);
4498 for (i
= 0; i
< l
; i
++) {
4499 cur
= xmlXPathNodeSetItem(nodes
, i
);
4500 strval
= xmlXPathCastNodeToString(cur
);
4501 if (xmlHashLookup(hash
, strval
) == NULL
) {
4502 if (xmlHashAddEntry(hash
, strval
, strval
) < 0) {
4506 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4512 xmlHashFree(hash
, xmlHashDefaultDeallocator
);
4516 xmlHashFree(hash
, xmlHashDefaultDeallocator
);
4517 xmlXPathFreeNodeSet(ret
);
4523 * @nodes: a node-set
4525 * Implements the EXSLT - Sets distinct() function:
4526 * node-set set:distinct (node-set)
4527 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4528 * is called with the sorted node-set
4530 * Returns a subset of the nodes contained in @nodes, or @nodes if
4534 xmlXPathDistinct (xmlNodeSetPtr nodes
) {
4535 if (xmlXPathNodeSetIsEmpty(nodes
))
4538 xmlXPathNodeSetSort(nodes
);
4539 return(xmlXPathDistinctSorted(nodes
));
4543 * xmlXPathHasSameNodes:
4544 * @nodes1: a node-set
4545 * @nodes2: a node-set
4547 * Implements the EXSLT - Sets has-same-nodes function:
4548 * boolean set:has-same-node(node-set, node-set)
4550 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4554 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4558 if (xmlXPathNodeSetIsEmpty(nodes1
) ||
4559 xmlXPathNodeSetIsEmpty(nodes2
))
4562 l
= xmlXPathNodeSetGetLength(nodes1
);
4563 for (i
= 0; i
< l
; i
++) {
4564 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4565 if (xmlXPathNodeSetContains(nodes2
, cur
))
4572 * xmlXPathNodeLeadingSorted:
4573 * @nodes: a node-set, sorted by document order
4576 * Implements the EXSLT - Sets leading() function:
4577 * node-set set:leading (node-set, node-set)
4579 * Returns the nodes in @nodes that precede @node in document order,
4580 * @nodes if @node is NULL or an empty node-set if @nodes
4581 * doesn't contain @node
4584 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4592 ret
= xmlXPathNodeSetCreate(NULL
);
4595 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4596 (!xmlXPathNodeSetContains(nodes
, node
)))
4599 l
= xmlXPathNodeSetGetLength(nodes
);
4600 for (i
= 0; i
< l
; i
++) {
4601 cur
= xmlXPathNodeSetItem(nodes
, i
);
4604 /* TODO: Propagate memory error. */
4605 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4612 * xmlXPathNodeLeading:
4613 * @nodes: a node-set
4616 * Implements the EXSLT - Sets leading() function:
4617 * node-set set:leading (node-set, node-set)
4618 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4621 * Returns the nodes in @nodes that precede @node in document order,
4622 * @nodes if @node is NULL or an empty node-set if @nodes
4623 * doesn't contain @node
4626 xmlXPathNodeLeading (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4627 xmlXPathNodeSetSort(nodes
);
4628 return(xmlXPathNodeLeadingSorted(nodes
, node
));
4632 * xmlXPathLeadingSorted:
4633 * @nodes1: a node-set, sorted by document order
4634 * @nodes2: a node-set, sorted by document order
4636 * Implements the EXSLT - Sets leading() function:
4637 * node-set set:leading (node-set, node-set)
4639 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4640 * in document order, @nodes1 if @nodes2 is NULL or empty or
4641 * an empty node-set if @nodes1 doesn't contain @nodes2
4644 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4645 if (xmlXPathNodeSetIsEmpty(nodes2
))
4647 return(xmlXPathNodeLeadingSorted(nodes1
,
4648 xmlXPathNodeSetItem(nodes2
, 1)));
4653 * @nodes1: a node-set
4654 * @nodes2: a node-set
4656 * Implements the EXSLT - Sets leading() function:
4657 * node-set set:leading (node-set, node-set)
4658 * @nodes1 and @nodes2 are sorted by document order, then
4659 * #exslSetsLeadingSorted is called.
4661 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4662 * in document order, @nodes1 if @nodes2 is NULL or empty or
4663 * an empty node-set if @nodes1 doesn't contain @nodes2
4666 xmlXPathLeading (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4667 if (xmlXPathNodeSetIsEmpty(nodes2
))
4669 if (xmlXPathNodeSetIsEmpty(nodes1
))
4670 return(xmlXPathNodeSetCreate(NULL
));
4671 xmlXPathNodeSetSort(nodes1
);
4672 xmlXPathNodeSetSort(nodes2
);
4673 return(xmlXPathNodeLeadingSorted(nodes1
,
4674 xmlXPathNodeSetItem(nodes2
, 1)));
4678 * xmlXPathNodeTrailingSorted:
4679 * @nodes: a node-set, sorted by document order
4682 * Implements the EXSLT - Sets trailing() function:
4683 * node-set set:trailing (node-set, node-set)
4685 * Returns the nodes in @nodes that follow @node in document order,
4686 * @nodes if @node is NULL or an empty node-set if @nodes
4687 * doesn't contain @node
4690 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4698 ret
= xmlXPathNodeSetCreate(NULL
);
4701 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4702 (!xmlXPathNodeSetContains(nodes
, node
)))
4705 l
= xmlXPathNodeSetGetLength(nodes
);
4706 for (i
= l
- 1; i
>= 0; i
--) {
4707 cur
= xmlXPathNodeSetItem(nodes
, i
);
4710 /* TODO: Propagate memory error. */
4711 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4714 xmlXPathNodeSetSort(ret
); /* bug 413451 */
4719 * xmlXPathNodeTrailing:
4720 * @nodes: a node-set
4723 * Implements the EXSLT - Sets trailing() function:
4724 * node-set set:trailing (node-set, node-set)
4725 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4728 * Returns the nodes in @nodes that follow @node in document order,
4729 * @nodes if @node is NULL or an empty node-set if @nodes
4730 * doesn't contain @node
4733 xmlXPathNodeTrailing (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4734 xmlXPathNodeSetSort(nodes
);
4735 return(xmlXPathNodeTrailingSorted(nodes
, node
));
4739 * xmlXPathTrailingSorted:
4740 * @nodes1: a node-set, sorted by document order
4741 * @nodes2: a node-set, sorted by document order
4743 * Implements the EXSLT - Sets trailing() function:
4744 * node-set set:trailing (node-set, node-set)
4746 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4747 * in document order, @nodes1 if @nodes2 is NULL or empty or
4748 * an empty node-set if @nodes1 doesn't contain @nodes2
4751 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4752 if (xmlXPathNodeSetIsEmpty(nodes2
))
4754 return(xmlXPathNodeTrailingSorted(nodes1
,
4755 xmlXPathNodeSetItem(nodes2
, 0)));
4760 * @nodes1: a node-set
4761 * @nodes2: a node-set
4763 * Implements the EXSLT - Sets trailing() function:
4764 * node-set set:trailing (node-set, node-set)
4765 * @nodes1 and @nodes2 are sorted by document order, then
4766 * #xmlXPathTrailingSorted is called.
4768 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4769 * in document order, @nodes1 if @nodes2 is NULL or empty or
4770 * an empty node-set if @nodes1 doesn't contain @nodes2
4773 xmlXPathTrailing (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4774 if (xmlXPathNodeSetIsEmpty(nodes2
))
4776 if (xmlXPathNodeSetIsEmpty(nodes1
))
4777 return(xmlXPathNodeSetCreate(NULL
));
4778 xmlXPathNodeSetSort(nodes1
);
4779 xmlXPathNodeSetSort(nodes2
);
4780 return(xmlXPathNodeTrailingSorted(nodes1
,
4781 xmlXPathNodeSetItem(nodes2
, 0)));
4784 /************************************************************************
4786 * Routines to handle extra functions *
4788 ************************************************************************/
4791 * xmlXPathRegisterFunc:
4792 * @ctxt: the XPath context
4793 * @name: the function name
4794 * @f: the function implementation or NULL
4796 * Register a new function. If @f is NULL it unregisters the function
4798 * Returns 0 in case of success, -1 in case of error
4801 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4802 xmlXPathFunction f
) {
4803 return(xmlXPathRegisterFuncNS(ctxt
, name
, NULL
, f
));
4807 * xmlXPathRegisterFuncNS:
4808 * @ctxt: the XPath context
4809 * @name: the function name
4810 * @ns_uri: the function namespace URI
4811 * @f: the function implementation or NULL
4813 * Register a new function. If @f is NULL it unregisters the function
4815 * Returns 0 in case of success, -1 in case of error
4818 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4819 const xmlChar
*ns_uri
, xmlXPathFunction f
) {
4825 if (ctxt
->funcHash
== NULL
)
4826 ctxt
->funcHash
= xmlHashCreate(0);
4827 if (ctxt
->funcHash
== NULL
)
4830 return(xmlHashRemoveEntry2(ctxt
->funcHash
, name
, ns_uri
, NULL
));
4831 XML_IGNORE_FPTR_CAST_WARNINGS
4832 return(xmlHashAddEntry2(ctxt
->funcHash
, name
, ns_uri
, (void *) f
));
4837 * xmlXPathRegisterFuncLookup:
4838 * @ctxt: the XPath context
4839 * @f: the lookup function
4840 * @funcCtxt: the lookup data
4842 * Registers an external mechanism to do function lookup.
4845 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt
,
4846 xmlXPathFuncLookupFunc f
,
4850 ctxt
->funcLookupFunc
= f
;
4851 ctxt
->funcLookupData
= funcCtxt
;
4855 * xmlXPathFunctionLookup:
4856 * @ctxt: the XPath context
4857 * @name: the function name
4859 * Search in the Function array of the context for the given
4862 * Returns the xmlXPathFunction or NULL if not found
4865 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
4869 if (ctxt
->funcLookupFunc
!= NULL
) {
4870 xmlXPathFunction ret
;
4871 xmlXPathFuncLookupFunc f
;
4873 f
= ctxt
->funcLookupFunc
;
4874 ret
= f(ctxt
->funcLookupData
, name
, NULL
);
4878 return(xmlXPathFunctionLookupNS(ctxt
, name
, NULL
));
4882 * xmlXPathFunctionLookupNS:
4883 * @ctxt: the XPath context
4884 * @name: the function name
4885 * @ns_uri: the function namespace URI
4887 * Search in the Function array of the context for the given
4890 * Returns the xmlXPathFunction or NULL if not found
4893 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4894 const xmlChar
*ns_uri
) {
4895 xmlXPathFunction ret
;
4902 if (ctxt
->funcLookupFunc
!= NULL
) {
4903 xmlXPathFuncLookupFunc f
;
4905 f
= ctxt
->funcLookupFunc
;
4906 ret
= f(ctxt
->funcLookupData
, name
, ns_uri
);
4911 if (ctxt
->funcHash
== NULL
)
4914 XML_IGNORE_FPTR_CAST_WARNINGS
4915 ret
= (xmlXPathFunction
) xmlHashLookup2(ctxt
->funcHash
, name
, ns_uri
);
4921 * xmlXPathRegisteredFuncsCleanup:
4922 * @ctxt: the XPath context
4924 * Cleanup the XPath context data associated to registered functions
4927 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt
) {
4931 xmlHashFree(ctxt
->funcHash
, NULL
);
4932 ctxt
->funcHash
= NULL
;
4935 /************************************************************************
4937 * Routines to handle Variables *
4939 ************************************************************************/
4942 * xmlXPathRegisterVariable:
4943 * @ctxt: the XPath context
4944 * @name: the variable name
4945 * @value: the variable value or NULL
4947 * Register a new variable value. If @value is NULL it unregisters
4950 * Returns 0 in case of success, -1 in case of error
4953 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4954 xmlXPathObjectPtr value
) {
4955 return(xmlXPathRegisterVariableNS(ctxt
, name
, NULL
, value
));
4959 * xmlXPathRegisterVariableNS:
4960 * @ctxt: the XPath context
4961 * @name: the variable name
4962 * @ns_uri: the variable namespace URI
4963 * @value: the variable value or NULL
4965 * Register a new variable value. If @value is NULL it unregisters
4968 * Returns 0 in case of success, -1 in case of error
4971 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4972 const xmlChar
*ns_uri
,
4973 xmlXPathObjectPtr value
) {
4979 if (ctxt
->varHash
== NULL
)
4980 ctxt
->varHash
= xmlHashCreate(0);
4981 if (ctxt
->varHash
== NULL
)
4984 return(xmlHashRemoveEntry2(ctxt
->varHash
, name
, ns_uri
,
4985 xmlXPathFreeObjectEntry
));
4986 return(xmlHashUpdateEntry2(ctxt
->varHash
, name
, ns_uri
,
4987 (void *) value
, xmlXPathFreeObjectEntry
));
4991 * xmlXPathRegisterVariableLookup:
4992 * @ctxt: the XPath context
4993 * @f: the lookup function
4994 * @data: the lookup data
4996 * register an external mechanism to do variable lookup
4999 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt
,
5000 xmlXPathVariableLookupFunc f
, void *data
) {
5003 ctxt
->varLookupFunc
= f
;
5004 ctxt
->varLookupData
= data
;
5008 * xmlXPathVariableLookup:
5009 * @ctxt: the XPath context
5010 * @name: the variable name
5012 * Search in the Variable array of the context for the given
5015 * Returns a copy of the value or NULL if not found
5018 xmlXPathVariableLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
5022 if (ctxt
->varLookupFunc
!= NULL
) {
5023 xmlXPathObjectPtr ret
;
5025 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5026 (ctxt
->varLookupData
, name
, NULL
);
5029 return(xmlXPathVariableLookupNS(ctxt
, name
, NULL
));
5033 * xmlXPathVariableLookupNS:
5034 * @ctxt: the XPath context
5035 * @name: the variable name
5036 * @ns_uri: the variable namespace URI
5038 * Search in the Variable array of the context for the given
5041 * Returns the a copy of the value or NULL if not found
5044 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5045 const xmlChar
*ns_uri
) {
5049 if (ctxt
->varLookupFunc
!= NULL
) {
5050 xmlXPathObjectPtr ret
;
5052 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5053 (ctxt
->varLookupData
, name
, ns_uri
);
5054 if (ret
!= NULL
) return(ret
);
5057 if (ctxt
->varHash
== NULL
)
5062 return(xmlXPathCacheObjectCopy(ctxt
, (xmlXPathObjectPtr
)
5063 xmlHashLookup2(ctxt
->varHash
, name
, ns_uri
)));
5067 * xmlXPathRegisteredVariablesCleanup:
5068 * @ctxt: the XPath context
5070 * Cleanup the XPath context data associated to registered variables
5073 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt
) {
5077 xmlHashFree(ctxt
->varHash
, xmlXPathFreeObjectEntry
);
5078 ctxt
->varHash
= NULL
;
5082 * xmlXPathRegisterNs:
5083 * @ctxt: the XPath context
5084 * @prefix: the namespace prefix cannot be NULL or empty string
5085 * @ns_uri: the namespace name
5087 * Register a new namespace. If @ns_uri is NULL it unregisters
5090 * Returns 0 in case of success, -1 in case of error
5093 xmlXPathRegisterNs(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
,
5094 const xmlChar
*ns_uri
) {
5104 if (ctxt
->nsHash
== NULL
)
5105 ctxt
->nsHash
= xmlHashCreate(10);
5106 if (ctxt
->nsHash
== NULL
)
5109 return(xmlHashRemoveEntry(ctxt
->nsHash
, prefix
,
5110 xmlHashDefaultDeallocator
));
5112 copy
= xmlStrdup(ns_uri
);
5115 if (xmlHashUpdateEntry(ctxt
->nsHash
, prefix
, copy
,
5116 xmlHashDefaultDeallocator
) < 0) {
5126 * @ctxt: the XPath context
5127 * @prefix: the namespace prefix value
5129 * Search in the namespace declaration array of the context for the given
5130 * namespace name associated to the given prefix
5132 * Returns the value or NULL if not found
5135 xmlXPathNsLookup(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
) {
5141 #ifdef XML_XML_NAMESPACE
5142 if (xmlStrEqual(prefix
, (const xmlChar
*) "xml"))
5143 return(XML_XML_NAMESPACE
);
5146 if (ctxt
->namespaces
!= NULL
) {
5149 for (i
= 0;i
< ctxt
->nsNr
;i
++) {
5150 if ((ctxt
->namespaces
[i
] != NULL
) &&
5151 (xmlStrEqual(ctxt
->namespaces
[i
]->prefix
, prefix
)))
5152 return(ctxt
->namespaces
[i
]->href
);
5156 return((const xmlChar
*) xmlHashLookup(ctxt
->nsHash
, prefix
));
5160 * xmlXPathRegisteredNsCleanup:
5161 * @ctxt: the XPath context
5163 * Cleanup the XPath context data associated to registered variables
5166 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt
) {
5170 xmlHashFree(ctxt
->nsHash
, xmlHashDefaultDeallocator
);
5171 ctxt
->nsHash
= NULL
;
5174 /************************************************************************
5176 * Routines to handle Values *
5178 ************************************************************************/
5180 /* Allocations are terrible, one needs to optimize all this !!! */
5184 * @val: the double value
5186 * Create a new xmlXPathObjectPtr of type double and of value @val
5188 * Returns the newly created object.
5191 xmlXPathNewFloat(double val
) {
5192 xmlXPathObjectPtr ret
;
5194 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5196 xmlXPathErrMemory(NULL
, "creating float object\n");
5199 memset(ret
, 0 , sizeof(xmlXPathObject
));
5200 ret
->type
= XPATH_NUMBER
;
5201 ret
->floatval
= val
;
5202 #ifdef XP_DEBUG_OBJ_USAGE
5203 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NUMBER
);
5209 * xmlXPathNewBoolean:
5210 * @val: the boolean value
5212 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5214 * Returns the newly created object.
5217 xmlXPathNewBoolean(int val
) {
5218 xmlXPathObjectPtr ret
;
5220 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5222 xmlXPathErrMemory(NULL
, "creating boolean object\n");
5225 memset(ret
, 0 , sizeof(xmlXPathObject
));
5226 ret
->type
= XPATH_BOOLEAN
;
5227 ret
->boolval
= (val
!= 0);
5228 #ifdef XP_DEBUG_OBJ_USAGE
5229 xmlXPathDebugObjUsageRequested(NULL
, XPATH_BOOLEAN
);
5235 * xmlXPathNewString:
5236 * @val: the xmlChar * value
5238 * Create a new xmlXPathObjectPtr of type string and of value @val
5240 * Returns the newly created object.
5243 xmlXPathNewString(const xmlChar
*val
) {
5244 xmlXPathObjectPtr ret
;
5246 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5248 xmlXPathErrMemory(NULL
, "creating string object\n");
5251 memset(ret
, 0 , sizeof(xmlXPathObject
));
5252 ret
->type
= XPATH_STRING
;
5255 ret
->stringval
= xmlStrdup(val
);
5256 if (ret
->stringval
== NULL
) {
5260 #ifdef XP_DEBUG_OBJ_USAGE
5261 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5267 * xmlXPathWrapString:
5268 * @val: the xmlChar * value
5270 * Wraps the @val string into an XPath object.
5272 * Returns the newly created object.
5274 * Frees @val in case of error.
5277 xmlXPathWrapString (xmlChar
*val
) {
5278 xmlXPathObjectPtr ret
;
5280 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5282 xmlXPathErrMemory(NULL
, "creating string object\n");
5286 memset(ret
, 0 , sizeof(xmlXPathObject
));
5287 ret
->type
= XPATH_STRING
;
5288 ret
->stringval
= val
;
5289 #ifdef XP_DEBUG_OBJ_USAGE
5290 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5296 * xmlXPathNewCString:
5297 * @val: the char * value
5299 * Create a new xmlXPathObjectPtr of type string and of value @val
5301 * Returns the newly created object.
5304 xmlXPathNewCString(const char *val
) {
5305 return(xmlXPathNewString(BAD_CAST val
));
5309 * xmlXPathWrapCString:
5310 * @val: the char * value
5312 * Wraps a string into an XPath object.
5314 * Returns the newly created object.
5317 xmlXPathWrapCString (char * val
) {
5318 return(xmlXPathWrapString((xmlChar
*)(val
)));
5322 * xmlXPathWrapExternal:
5323 * @val: the user data
5325 * Wraps the @val data into an XPath object.
5327 * Returns the newly created object.
5330 xmlXPathWrapExternal (void *val
) {
5331 xmlXPathObjectPtr ret
;
5333 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5335 xmlXPathErrMemory(NULL
, "creating user object\n");
5338 memset(ret
, 0 , sizeof(xmlXPathObject
));
5339 ret
->type
= XPATH_USERS
;
5341 #ifdef XP_DEBUG_OBJ_USAGE
5342 xmlXPathDebugObjUsageRequested(NULL
, XPATH_USERS
);
5348 * xmlXPathObjectCopy:
5349 * @val: the original object
5351 * allocate a new copy of a given object
5353 * Returns the newly created object.
5356 xmlXPathObjectCopy(xmlXPathObjectPtr val
) {
5357 xmlXPathObjectPtr ret
;
5362 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5364 xmlXPathErrMemory(NULL
, "copying object\n");
5367 memcpy(ret
, val
, sizeof(xmlXPathObject
));
5368 #ifdef XP_DEBUG_OBJ_USAGE
5369 xmlXPathDebugObjUsageRequested(NULL
, val
->type
);
5371 switch (val
->type
) {
5374 #ifdef LIBXML_XPTR_LOCS_ENABLED
5377 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5380 ret
->stringval
= xmlStrdup(val
->stringval
);
5381 if (ret
->stringval
== NULL
) {
5386 case XPATH_XSLT_TREE
:
5389 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5390 this previous handling is no longer correct, and can cause some serious
5391 problems (ref. bug 145547)
5393 if ((val
->nodesetval
!= NULL
) &&
5394 (val
->nodesetval
->nodeTab
!= NULL
)) {
5395 xmlNodePtr cur
, tmp
;
5399 top
= xmlNewDoc(NULL
);
5400 top
->name
= (char *)
5401 xmlStrdup(val
->nodesetval
->nodeTab
[0]->name
);
5405 cur
= val
->nodesetval
->nodeTab
[0]->children
;
5406 while (cur
!= NULL
) {
5407 tmp
= xmlDocCopyNode(cur
, top
, 1);
5408 xmlAddChild((xmlNodePtr
) top
, tmp
);
5413 ret
->nodesetval
= xmlXPathNodeSetCreate((xmlNodePtr
) top
);
5415 ret
->nodesetval
= xmlXPathNodeSetCreate(NULL
);
5416 /* Deallocate the copied tree value */
5420 /* TODO: Check memory error. */
5421 ret
->nodesetval
= xmlXPathNodeSetMerge(NULL
, val
->nodesetval
);
5422 /* Do not deallocate the copied tree value */
5425 #ifdef LIBXML_XPTR_LOCS_ENABLED
5426 case XPATH_LOCATIONSET
:
5428 xmlLocationSetPtr loc
= val
->user
;
5429 ret
->user
= (void *) xmlXPtrLocationSetMerge(NULL
, loc
);
5434 ret
->user
= val
->user
;
5436 case XPATH_UNDEFINED
:
5437 xmlGenericError(xmlGenericErrorContext
,
5438 "xmlXPathObjectCopy: unsupported type %d\n",
5446 * xmlXPathFreeObject:
5447 * @obj: the object to free
5449 * Free up an xmlXPathObjectPtr object.
5452 xmlXPathFreeObject(xmlXPathObjectPtr obj
) {
5453 if (obj
== NULL
) return;
5454 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
5457 if (obj
->user
!= NULL
) {
5458 xmlXPathFreeNodeSet(obj
->nodesetval
);
5459 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
5462 obj
->type
= XPATH_XSLT_TREE
; /* TODO: Just for debugging. */
5463 if (obj
->nodesetval
!= NULL
)
5464 xmlXPathFreeValueTree(obj
->nodesetval
);
5466 if (obj
->nodesetval
!= NULL
)
5467 xmlXPathFreeNodeSet(obj
->nodesetval
);
5469 #ifdef LIBXML_XPTR_LOCS_ENABLED
5470 } else if (obj
->type
== XPATH_LOCATIONSET
) {
5471 if (obj
->user
!= NULL
)
5472 xmlXPtrFreeLocationSet(obj
->user
);
5474 } else if (obj
->type
== XPATH_STRING
) {
5475 if (obj
->stringval
!= NULL
)
5476 xmlFree(obj
->stringval
);
5478 #ifdef XP_DEBUG_OBJ_USAGE
5479 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5485 xmlXPathFreeObjectEntry(void *obj
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
5486 xmlXPathFreeObject((xmlXPathObjectPtr
) obj
);
5490 * xmlXPathReleaseObject:
5491 * @obj: the xmlXPathObjectPtr to free or to cache
5493 * Depending on the state of the cache this frees the given
5494 * XPath object or stores it in the cache.
5497 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
)
5499 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5500 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5501 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5503 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5507 if ((ctxt
== NULL
) || (ctxt
->cache
== NULL
)) {
5508 xmlXPathFreeObject(obj
);
5510 xmlXPathContextCachePtr cache
=
5511 (xmlXPathContextCachePtr
) ctxt
->cache
;
5513 switch (obj
->type
) {
5515 case XPATH_XSLT_TREE
:
5516 if (obj
->nodesetval
!= NULL
) {
5519 * It looks like the @boolval is used for
5520 * evaluation if this an XSLT Result Tree Fragment.
5521 * TODO: Check if this assumption is correct.
5523 obj
->type
= XPATH_XSLT_TREE
; /* just for debugging */
5524 xmlXPathFreeValueTree(obj
->nodesetval
);
5525 obj
->nodesetval
= NULL
;
5526 } else if ((obj
->nodesetval
->nodeMax
<= 40) &&
5527 (XP_CACHE_WANTS(cache
->nodesetObjs
,
5528 cache
->maxNodeset
)))
5530 XP_CACHE_ADD(cache
->nodesetObjs
, obj
);
5533 xmlXPathFreeNodeSet(obj
->nodesetval
);
5534 obj
->nodesetval
= NULL
;
5539 if (obj
->stringval
!= NULL
)
5540 xmlFree(obj
->stringval
);
5542 if (XP_CACHE_WANTS(cache
->stringObjs
, cache
->maxString
)) {
5543 XP_CACHE_ADD(cache
->stringObjs
, obj
);
5548 if (XP_CACHE_WANTS(cache
->booleanObjs
, cache
->maxBoolean
)) {
5549 XP_CACHE_ADD(cache
->booleanObjs
, obj
);
5554 if (XP_CACHE_WANTS(cache
->numberObjs
, cache
->maxNumber
)) {
5555 XP_CACHE_ADD(cache
->numberObjs
, obj
);
5559 #ifdef LIBXML_XPTR_LOCS_ENABLED
5560 case XPATH_LOCATIONSET
:
5561 if (obj
->user
!= NULL
) {
5562 xmlXPtrFreeLocationSet(obj
->user
);
5571 * Fallback to adding to the misc-objects slot.
5573 if (XP_CACHE_WANTS(cache
->miscObjs
, cache
->maxMisc
)) {
5574 XP_CACHE_ADD(cache
->miscObjs
, obj
);
5580 #ifdef XP_DEBUG_OBJ_USAGE
5581 xmlXPathDebugObjUsageReleased(ctxt
, obj
->type
);
5584 if (obj
->nodesetval
!= NULL
) {
5585 xmlNodeSetPtr tmpset
= obj
->nodesetval
;
5588 * TODO: Due to those nasty ns-nodes, we need to traverse
5589 * the list and free the ns-nodes.
5590 * URGENT TODO: Check if it's actually slowing things down.
5591 * Maybe we shouldn't try to preserve the list.
5593 if (tmpset
->nodeNr
> 1) {
5597 for (i
= 0; i
< tmpset
->nodeNr
; i
++) {
5598 node
= tmpset
->nodeTab
[i
];
5599 if ((node
!= NULL
) &&
5600 (node
->type
== XML_NAMESPACE_DECL
))
5602 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
5605 } else if (tmpset
->nodeNr
== 1) {
5606 if ((tmpset
->nodeTab
[0] != NULL
) &&
5607 (tmpset
->nodeTab
[0]->type
== XML_NAMESPACE_DECL
))
5608 xmlXPathNodeSetFreeNs((xmlNsPtr
) tmpset
->nodeTab
[0]);
5611 memset(obj
, 0, sizeof(xmlXPathObject
));
5612 obj
->nodesetval
= tmpset
;
5614 memset(obj
, 0, sizeof(xmlXPathObject
));
5620 * Cache is full; free the object.
5622 if (obj
->nodesetval
!= NULL
)
5623 xmlXPathFreeNodeSet(obj
->nodesetval
);
5624 #ifdef XP_DEBUG_OBJ_USAGE
5625 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5633 /************************************************************************
5635 * Type Casting Routines *
5637 ************************************************************************/
5640 * xmlXPathCastBooleanToString:
5643 * Converts a boolean to its string value.
5645 * Returns a newly allocated string.
5648 xmlXPathCastBooleanToString (int val
) {
5651 ret
= xmlStrdup((const xmlChar
*) "true");
5653 ret
= xmlStrdup((const xmlChar
*) "false");
5658 * xmlXPathCastNumberToString:
5661 * Converts a number to its string value.
5663 * Returns a newly allocated string.
5666 xmlXPathCastNumberToString (double val
) {
5668 switch (xmlXPathIsInf(val
)) {
5670 ret
= xmlStrdup((const xmlChar
*) "Infinity");
5673 ret
= xmlStrdup((const xmlChar
*) "-Infinity");
5676 if (xmlXPathIsNaN(val
)) {
5677 ret
= xmlStrdup((const xmlChar
*) "NaN");
5678 } else if (val
== 0) {
5679 /* Omit sign for negative zero. */
5680 ret
= xmlStrdup((const xmlChar
*) "0");
5682 /* could be improved */
5684 xmlXPathFormatNumber(val
, buf
, 99);
5686 ret
= xmlStrdup((const xmlChar
*) buf
);
5693 * xmlXPathCastNodeToString:
5696 * Converts a node to its string value.
5698 * Returns a newly allocated string.
5701 xmlXPathCastNodeToString (xmlNodePtr node
) {
5703 if ((ret
= xmlNodeGetContent(node
)) == NULL
)
5704 ret
= xmlStrdup((const xmlChar
*) "");
5709 * xmlXPathCastNodeSetToString:
5712 * Converts a node-set to its string value.
5714 * Returns a newly allocated string.
5717 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns
) {
5718 if ((ns
== NULL
) || (ns
->nodeNr
== 0) || (ns
->nodeTab
== NULL
))
5719 return(xmlStrdup((const xmlChar
*) ""));
5722 xmlXPathNodeSetSort(ns
);
5723 return(xmlXPathCastNodeToString(ns
->nodeTab
[0]));
5727 * xmlXPathCastToString:
5728 * @val: an XPath object
5730 * Converts an existing object to its string() equivalent
5732 * Returns the allocated string value of the object, NULL in case of error.
5733 * It's up to the caller to free the string memory with xmlFree().
5736 xmlXPathCastToString(xmlXPathObjectPtr val
) {
5737 xmlChar
*ret
= NULL
;
5740 return(xmlStrdup((const xmlChar
*) ""));
5741 switch (val
->type
) {
5742 case XPATH_UNDEFINED
:
5744 xmlGenericError(xmlGenericErrorContext
, "String: undefined\n");
5746 ret
= xmlStrdup((const xmlChar
*) "");
5749 case XPATH_XSLT_TREE
:
5750 ret
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5753 return(xmlStrdup(val
->stringval
));
5755 ret
= xmlXPathCastBooleanToString(val
->boolval
);
5757 case XPATH_NUMBER
: {
5758 ret
= xmlXPathCastNumberToString(val
->floatval
);
5762 #ifdef LIBXML_XPTR_LOCS_ENABLED
5765 case XPATH_LOCATIONSET
:
5766 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5768 ret
= xmlStrdup((const xmlChar
*) "");
5775 * xmlXPathConvertString:
5776 * @val: an XPath object
5778 * Converts an existing object to its string() equivalent
5780 * Returns the new object, the old one is freed (or the operation
5781 * is done directly on @val)
5784 xmlXPathConvertString(xmlXPathObjectPtr val
) {
5785 xmlChar
*res
= NULL
;
5788 return(xmlXPathNewCString(""));
5790 switch (val
->type
) {
5791 case XPATH_UNDEFINED
:
5793 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
5797 case XPATH_XSLT_TREE
:
5798 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5803 res
= xmlXPathCastBooleanToString(val
->boolval
);
5806 res
= xmlXPathCastNumberToString(val
->floatval
);
5809 #ifdef LIBXML_XPTR_LOCS_ENABLED
5812 case XPATH_LOCATIONSET
:
5813 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5817 xmlXPathFreeObject(val
);
5819 return(xmlXPathNewCString(""));
5820 return(xmlXPathWrapString(res
));
5824 * xmlXPathCastBooleanToNumber:
5827 * Converts a boolean to its number value
5829 * Returns the number value
5832 xmlXPathCastBooleanToNumber(int val
) {
5839 * xmlXPathCastStringToNumber:
5842 * Converts a string to its number value
5844 * Returns the number value
5847 xmlXPathCastStringToNumber(const xmlChar
* val
) {
5848 return(xmlXPathStringEvalNumber(val
));
5852 * xmlXPathCastNodeToNumber:
5855 * Converts a node to its number value
5857 * Returns the number value
5860 xmlXPathCastNodeToNumber (xmlNodePtr node
) {
5865 return(xmlXPathNAN
);
5866 strval
= xmlXPathCastNodeToString(node
);
5868 return(xmlXPathNAN
);
5869 ret
= xmlXPathCastStringToNumber(strval
);
5876 * xmlXPathCastNodeSetToNumber:
5879 * Converts a node-set to its number value
5881 * Returns the number value
5884 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns
) {
5889 return(xmlXPathNAN
);
5890 str
= xmlXPathCastNodeSetToString(ns
);
5891 ret
= xmlXPathCastStringToNumber(str
);
5897 * xmlXPathCastToNumber:
5898 * @val: an XPath object
5900 * Converts an XPath object to its number value
5902 * Returns the number value
5905 xmlXPathCastToNumber(xmlXPathObjectPtr val
) {
5909 return(xmlXPathNAN
);
5910 switch (val
->type
) {
5911 case XPATH_UNDEFINED
:
5913 xmlGenericError(xmlGenericErrorContext
, "NUMBER: undefined\n");
5918 case XPATH_XSLT_TREE
:
5919 ret
= xmlXPathCastNodeSetToNumber(val
->nodesetval
);
5922 ret
= xmlXPathCastStringToNumber(val
->stringval
);
5925 ret
= val
->floatval
;
5928 ret
= xmlXPathCastBooleanToNumber(val
->boolval
);
5931 #ifdef LIBXML_XPTR_LOCS_ENABLED
5934 case XPATH_LOCATIONSET
:
5935 #endif /* LIBXML_XPTR_LOCS_ENABLED */
5944 * xmlXPathConvertNumber:
5945 * @val: an XPath object
5947 * Converts an existing object to its number() equivalent
5949 * Returns the new object, the old one is freed (or the operation
5950 * is done directly on @val)
5953 xmlXPathConvertNumber(xmlXPathObjectPtr val
) {
5954 xmlXPathObjectPtr ret
;
5957 return(xmlXPathNewFloat(0.0));
5958 if (val
->type
== XPATH_NUMBER
)
5960 ret
= xmlXPathNewFloat(xmlXPathCastToNumber(val
));
5961 xmlXPathFreeObject(val
);
5966 * xmlXPathCastNumberToBoolean:
5969 * Converts a number to its boolean value
5971 * Returns the boolean value
5974 xmlXPathCastNumberToBoolean (double val
) {
5975 if (xmlXPathIsNaN(val
) || (val
== 0.0))
5981 * xmlXPathCastStringToBoolean:
5984 * Converts a string to its boolean value
5986 * Returns the boolean value
5989 xmlXPathCastStringToBoolean (const xmlChar
*val
) {
5990 if ((val
== NULL
) || (xmlStrlen(val
) == 0))
5996 * xmlXPathCastNodeSetToBoolean:
5999 * Converts a node-set to its boolean value
6001 * Returns the boolean value
6004 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns
) {
6005 if ((ns
== NULL
) || (ns
->nodeNr
== 0))
6011 * xmlXPathCastToBoolean:
6012 * @val: an XPath object
6014 * Converts an XPath object to its boolean value
6016 * Returns the boolean value
6019 xmlXPathCastToBoolean (xmlXPathObjectPtr val
) {
6024 switch (val
->type
) {
6025 case XPATH_UNDEFINED
:
6027 xmlGenericError(xmlGenericErrorContext
, "BOOLEAN: undefined\n");
6032 case XPATH_XSLT_TREE
:
6033 ret
= xmlXPathCastNodeSetToBoolean(val
->nodesetval
);
6036 ret
= xmlXPathCastStringToBoolean(val
->stringval
);
6039 ret
= xmlXPathCastNumberToBoolean(val
->floatval
);
6045 #ifdef LIBXML_XPTR_LOCS_ENABLED
6048 case XPATH_LOCATIONSET
:
6049 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6059 * xmlXPathConvertBoolean:
6060 * @val: an XPath object
6062 * Converts an existing object to its boolean() equivalent
6064 * Returns the new object, the old one is freed (or the operation
6065 * is done directly on @val)
6068 xmlXPathConvertBoolean(xmlXPathObjectPtr val
) {
6069 xmlXPathObjectPtr ret
;
6072 return(xmlXPathNewBoolean(0));
6073 if (val
->type
== XPATH_BOOLEAN
)
6075 ret
= xmlXPathNewBoolean(xmlXPathCastToBoolean(val
));
6076 xmlXPathFreeObject(val
);
6080 /************************************************************************
6082 * Routines to handle XPath contexts *
6084 ************************************************************************/
6087 * xmlXPathNewContext:
6088 * @doc: the XML document
6090 * Create a new xmlXPathContext
6092 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6095 xmlXPathNewContext(xmlDocPtr doc
) {
6096 xmlXPathContextPtr ret
;
6098 ret
= (xmlXPathContextPtr
) xmlMalloc(sizeof(xmlXPathContext
));
6100 xmlXPathErrMemory(NULL
, "creating context\n");
6103 memset(ret
, 0 , sizeof(xmlXPathContext
));
6107 ret
->varHash
= NULL
;
6113 ret
->funcHash
= xmlHashCreate(0);
6122 ret
->contextSize
= -1;
6123 ret
->proximityPosition
= -1;
6125 #ifdef XP_DEFAULT_CACHE_ON
6126 if (xmlXPathContextSetCache(ret
, 1, -1, 0) == -1) {
6127 xmlXPathFreeContext(ret
);
6132 xmlXPathRegisterAllFunctions(ret
);
6138 * xmlXPathFreeContext:
6139 * @ctxt: the context to free
6141 * Free up an xmlXPathContext
6144 xmlXPathFreeContext(xmlXPathContextPtr ctxt
) {
6145 if (ctxt
== NULL
) return;
6147 if (ctxt
->cache
!= NULL
)
6148 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
6149 xmlXPathRegisteredNsCleanup(ctxt
);
6150 xmlXPathRegisteredFuncsCleanup(ctxt
);
6151 xmlXPathRegisteredVariablesCleanup(ctxt
);
6152 xmlResetError(&ctxt
->lastError
);
6156 /************************************************************************
6158 * Routines to handle XPath parser contexts *
6160 ************************************************************************/
6162 #define CHECK_CTXT(ctxt) \
6163 if (ctxt == NULL) { \
6164 __xmlRaiseError(NULL, NULL, NULL, \
6165 NULL, NULL, XML_FROM_XPATH, \
6166 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6167 __FILE__, __LINE__, \
6168 NULL, NULL, NULL, 0, 0, \
6169 "NULL context pointer\n"); \
6173 #define CHECK_CTXT_NEG(ctxt) \
6174 if (ctxt == NULL) { \
6175 __xmlRaiseError(NULL, NULL, NULL, \
6176 NULL, NULL, XML_FROM_XPATH, \
6177 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6178 __FILE__, __LINE__, \
6179 NULL, NULL, NULL, 0, 0, \
6180 "NULL context pointer\n"); \
6185 #define CHECK_CONTEXT(ctxt) \
6186 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6187 (ctxt->doc->children == NULL)) { \
6188 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6194 * xmlXPathNewParserContext:
6195 * @str: the XPath expression
6196 * @ctxt: the XPath context
6198 * Create a new xmlXPathParserContext
6200 * Returns the xmlXPathParserContext just allocated.
6202 xmlXPathParserContextPtr
6203 xmlXPathNewParserContext(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
6204 xmlXPathParserContextPtr ret
;
6206 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6208 xmlXPathErrMemory(ctxt
, "creating parser context\n");
6211 memset(ret
, 0 , sizeof(xmlXPathParserContext
));
6212 ret
->cur
= ret
->base
= str
;
6213 ret
->context
= ctxt
;
6215 ret
->comp
= xmlXPathNewCompExpr();
6216 if (ret
->comp
== NULL
) {
6217 xmlFree(ret
->valueTab
);
6221 if ((ctxt
!= NULL
) && (ctxt
->dict
!= NULL
)) {
6222 ret
->comp
->dict
= ctxt
->dict
;
6223 xmlDictReference(ret
->comp
->dict
);
6230 * xmlXPathCompParserContext:
6231 * @comp: the XPath compiled expression
6232 * @ctxt: the XPath context
6234 * Create a new xmlXPathParserContext when processing a compiled expression
6236 * Returns the xmlXPathParserContext just allocated.
6238 static xmlXPathParserContextPtr
6239 xmlXPathCompParserContext(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctxt
) {
6240 xmlXPathParserContextPtr ret
;
6242 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6244 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6247 memset(ret
, 0 , sizeof(xmlXPathParserContext
));
6249 /* Allocate the value stack */
6250 ret
->valueTab
= (xmlXPathObjectPtr
*)
6251 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
6252 if (ret
->valueTab
== NULL
) {
6254 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6261 ret
->context
= ctxt
;
6268 * xmlXPathFreeParserContext:
6269 * @ctxt: the context to free
6271 * Free up an xmlXPathParserContext
6274 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt
) {
6277 if (ctxt
->valueTab
!= NULL
) {
6278 for (i
= 0; i
< ctxt
->valueNr
; i
++) {
6280 xmlXPathReleaseObject(ctxt
->context
, ctxt
->valueTab
[i
]);
6282 xmlXPathFreeObject(ctxt
->valueTab
[i
]);
6284 xmlFree(ctxt
->valueTab
);
6286 if (ctxt
->comp
!= NULL
) {
6287 #ifdef XPATH_STREAMING
6288 if (ctxt
->comp
->stream
!= NULL
) {
6289 xmlFreePatternList(ctxt
->comp
->stream
);
6290 ctxt
->comp
->stream
= NULL
;
6293 xmlXPathFreeCompExpr(ctxt
->comp
);
6298 /************************************************************************
6300 * The implicit core function library *
6302 ************************************************************************/
6305 * xmlXPathNodeValHash:
6306 * @node: a node pointer
6308 * Function computing the beginning of the string value of the node,
6309 * used to speed up comparisons
6311 * Returns an int usable as a hash
6314 xmlXPathNodeValHash(xmlNodePtr node
) {
6316 const xmlChar
* string
= NULL
;
6317 xmlNodePtr tmp
= NULL
;
6318 unsigned int ret
= 0;
6323 if (node
->type
== XML_DOCUMENT_NODE
) {
6324 tmp
= xmlDocGetRootElement((xmlDocPtr
) node
);
6326 node
= node
->children
;
6334 switch (node
->type
) {
6335 case XML_COMMENT_NODE
:
6337 case XML_CDATA_SECTION_NODE
:
6339 string
= node
->content
;
6344 return(string
[0] + (string
[1] << 8));
6345 case XML_NAMESPACE_DECL
:
6346 string
= ((xmlNsPtr
)node
)->href
;
6351 return(string
[0] + (string
[1] << 8));
6352 case XML_ATTRIBUTE_NODE
:
6353 tmp
= ((xmlAttrPtr
) node
)->children
;
6355 case XML_ELEMENT_NODE
:
6356 tmp
= node
->children
;
6361 while (tmp
!= NULL
) {
6362 switch (tmp
->type
) {
6363 case XML_CDATA_SECTION_NODE
:
6365 string
= tmp
->content
;
6371 if ((string
!= NULL
) && (string
[0] != 0)) {
6373 return(ret
+ (string
[0] << 8));
6375 if (string
[1] == 0) {
6379 return(string
[0] + (string
[1] << 8));
6385 if ((tmp
->children
!= NULL
) && (tmp
->type
!= XML_DTD_NODE
)) {
6386 if (tmp
->children
->type
!= XML_ENTITY_DECL
) {
6387 tmp
= tmp
->children
;
6394 if (tmp
->next
!= NULL
) {
6407 if (tmp
->next
!= NULL
) {
6411 } while (tmp
!= NULL
);
6417 * xmlXPathStringHash:
6420 * Function computing the beginning of the string value of the node,
6421 * used to speed up comparisons
6423 * Returns an int usable as a hash
6426 xmlXPathStringHash(const xmlChar
* string
) {
6431 return(string
[0] + (string
[1] << 8));
6435 * xmlXPathCompareNodeSetFloat:
6436 * @ctxt: the XPath Parser context
6437 * @inf: less than (1) or greater than (0)
6438 * @strict: is the comparison strict
6439 * @arg: the node set
6442 * Implement the compare operation between a nodeset and a number
6443 * @ns < @val (1, 1, ...
6444 * @ns <= @val (1, 0, ...
6445 * @ns > @val (0, 1, ...
6446 * @ns >= @val (0, 0, ...
6448 * If one object to be compared is a node-set and the other is a number,
6449 * then the comparison will be true if and only if there is a node in the
6450 * node-set such that the result of performing the comparison on the number
6451 * to be compared and on the result of converting the string-value of that
6452 * node to a number using the number function is true.
6454 * Returns 0 or 1 depending on the results of the test.
6457 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6458 xmlXPathObjectPtr arg
, xmlXPathObjectPtr f
) {
6463 if ((f
== NULL
) || (arg
== NULL
) ||
6464 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6465 xmlXPathReleaseObject(ctxt
->context
, arg
);
6466 xmlXPathReleaseObject(ctxt
->context
, f
);
6469 ns
= arg
->nodesetval
;
6471 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6472 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6475 xmlXPathCacheNewString(ctxt
->context
, str2
));
6477 xmlXPathNumberFunction(ctxt
, 1);
6478 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, f
));
6479 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6485 xmlXPathReleaseObject(ctxt
->context
, arg
);
6486 xmlXPathReleaseObject(ctxt
->context
, f
);
6491 * xmlXPathCompareNodeSetString:
6492 * @ctxt: the XPath Parser context
6493 * @inf: less than (1) or greater than (0)
6494 * @strict: is the comparison strict
6495 * @arg: the node set
6498 * Implement the compare operation between a nodeset and a string
6499 * @ns < @val (1, 1, ...
6500 * @ns <= @val (1, 0, ...
6501 * @ns > @val (0, 1, ...
6502 * @ns >= @val (0, 0, ...
6504 * If one object to be compared is a node-set and the other is a string,
6505 * then the comparison will be true if and only if there is a node in
6506 * the node-set such that the result of performing the comparison on the
6507 * string-value of the node and the other string is true.
6509 * Returns 0 or 1 depending on the results of the test.
6512 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6513 xmlXPathObjectPtr arg
, xmlXPathObjectPtr s
) {
6518 if ((s
== NULL
) || (arg
== NULL
) ||
6519 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6520 xmlXPathReleaseObject(ctxt
->context
, arg
);
6521 xmlXPathReleaseObject(ctxt
->context
, s
);
6524 ns
= arg
->nodesetval
;
6526 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6527 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6530 xmlXPathCacheNewString(ctxt
->context
, str2
));
6532 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, s
));
6533 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6539 xmlXPathReleaseObject(ctxt
->context
, arg
);
6540 xmlXPathReleaseObject(ctxt
->context
, s
);
6545 * xmlXPathCompareNodeSets:
6546 * @inf: less than (1) or greater than (0)
6547 * @strict: is the comparison strict
6548 * @arg1: the first node set object
6549 * @arg2: the second node set object
6551 * Implement the compare operation on nodesets:
6553 * If both objects to be compared are node-sets, then the comparison
6554 * will be true if and only if there is a node in the first node-set
6555 * and a node in the second node-set such that the result of performing
6556 * the comparison on the string-values of the two nodes is true.
6558 * When neither object to be compared is a node-set and the operator
6559 * is <=, <, >= or >, then the objects are compared by converting both
6560 * objects to numbers and comparing the numbers according to IEEE 754.
6562 * The number function converts its argument to a number as follows:
6563 * - a string that consists of optional whitespace followed by an
6564 * optional minus sign followed by a Number followed by whitespace
6565 * is converted to the IEEE 754 number that is nearest (according
6566 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6567 * represented by the string; any other string is converted to NaN
6569 * Conclusion all nodes need to be converted first to their string value
6570 * and then the comparison must be done when possible
6573 xmlXPathCompareNodeSets(int inf
, int strict
,
6574 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6582 if ((arg1
== NULL
) ||
6583 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
))) {
6584 xmlXPathFreeObject(arg2
);
6587 if ((arg2
== NULL
) ||
6588 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
))) {
6589 xmlXPathFreeObject(arg1
);
6590 xmlXPathFreeObject(arg2
);
6594 ns1
= arg1
->nodesetval
;
6595 ns2
= arg2
->nodesetval
;
6597 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0)) {
6598 xmlXPathFreeObject(arg1
);
6599 xmlXPathFreeObject(arg2
);
6602 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0)) {
6603 xmlXPathFreeObject(arg1
);
6604 xmlXPathFreeObject(arg2
);
6608 values2
= (double *) xmlMalloc(ns2
->nodeNr
* sizeof(double));
6609 if (values2
== NULL
) {
6610 /* TODO: Propagate memory error. */
6611 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6612 xmlXPathFreeObject(arg1
);
6613 xmlXPathFreeObject(arg2
);
6616 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6617 val1
= xmlXPathCastNodeToNumber(ns1
->nodeTab
[i
]);
6618 if (xmlXPathIsNaN(val1
))
6620 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6622 values2
[j
] = xmlXPathCastNodeToNumber(ns2
->nodeTab
[j
]);
6624 if (xmlXPathIsNaN(values2
[j
]))
6627 ret
= (val1
< values2
[j
]);
6628 else if (inf
&& !strict
)
6629 ret
= (val1
<= values2
[j
]);
6630 else if (!inf
&& strict
)
6631 ret
= (val1
> values2
[j
]);
6632 else if (!inf
&& !strict
)
6633 ret
= (val1
>= values2
[j
]);
6642 xmlXPathFreeObject(arg1
);
6643 xmlXPathFreeObject(arg2
);
6648 * xmlXPathCompareNodeSetValue:
6649 * @ctxt: the XPath Parser context
6650 * @inf: less than (1) or greater than (0)
6651 * @strict: is the comparison strict
6652 * @arg: the node set
6655 * Implement the compare operation between a nodeset and a value
6656 * @ns < @val (1, 1, ...
6657 * @ns <= @val (1, 0, ...
6658 * @ns > @val (0, 1, ...
6659 * @ns >= @val (0, 0, ...
6661 * If one object to be compared is a node-set and the other is a boolean,
6662 * then the comparison will be true if and only if the result of performing
6663 * the comparison on the boolean and on the result of converting
6664 * the node-set to a boolean using the boolean function is true.
6666 * Returns 0 or 1 depending on the results of the test.
6669 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6670 xmlXPathObjectPtr arg
, xmlXPathObjectPtr val
) {
6671 if ((val
== NULL
) || (arg
== NULL
) ||
6672 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6677 return(xmlXPathCompareNodeSetFloat(ctxt
, inf
, strict
, arg
, val
));
6679 case XPATH_XSLT_TREE
:
6680 return(xmlXPathCompareNodeSets(inf
, strict
, arg
, val
));
6682 return(xmlXPathCompareNodeSetString(ctxt
, inf
, strict
, arg
, val
));
6684 valuePush(ctxt
, arg
);
6685 xmlXPathBooleanFunction(ctxt
, 1);
6686 valuePush(ctxt
, val
);
6687 return(xmlXPathCompareValues(ctxt
, inf
, strict
));
6689 xmlGenericError(xmlGenericErrorContext
,
6690 "xmlXPathCompareNodeSetValue: Can't compare node set "
6691 "and object of type %d\n",
6693 xmlXPathReleaseObject(ctxt
->context
, arg
);
6694 xmlXPathReleaseObject(ctxt
->context
, val
);
6695 XP_ERROR0(XPATH_INVALID_TYPE
);
6701 * xmlXPathEqualNodeSetString:
6702 * @arg: the nodeset object argument
6703 * @str: the string to compare to.
6704 * @neq: flag to show whether for '=' (0) or '!=' (1)
6706 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6707 * If one object to be compared is a node-set and the other is a string,
6708 * then the comparison will be true if and only if there is a node in
6709 * the node-set such that the result of performing the comparison on the
6710 * string-value of the node and the other string is true.
6712 * Returns 0 or 1 depending on the results of the test.
6715 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg
, const xmlChar
* str
, int neq
)
6722 if ((str
== NULL
) || (arg
== NULL
) ||
6723 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6725 ns
= arg
->nodesetval
;
6727 * A NULL nodeset compared with a string is always false
6728 * (since there is no node equal, and no node not equal)
6730 if ((ns
== NULL
) || (ns
->nodeNr
<= 0) )
6732 hash
= xmlXPathStringHash(str
);
6733 for (i
= 0; i
< ns
->nodeNr
; i
++) {
6734 if (xmlXPathNodeValHash(ns
->nodeTab
[i
]) == hash
) {
6735 str2
= xmlNodeGetContent(ns
->nodeTab
[i
]);
6736 if ((str2
!= NULL
) && (xmlStrEqual(str
, str2
))) {
6741 } else if ((str2
== NULL
) && (xmlStrEqual(str
, BAD_CAST
""))) {
6759 * xmlXPathEqualNodeSetFloat:
6760 * @arg: the nodeset object argument
6761 * @f: the float to compare to
6762 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6764 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6765 * If one object to be compared is a node-set and the other is a number,
6766 * then the comparison will be true if and only if there is a node in
6767 * the node-set such that the result of performing the comparison on the
6768 * number to be compared and on the result of converting the string-value
6769 * of that node to a number using the number function is true.
6771 * Returns 0 or 1 depending on the results of the test.
6774 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt
,
6775 xmlXPathObjectPtr arg
, double f
, int neq
) {
6779 xmlXPathObjectPtr val
;
6782 if ((arg
== NULL
) ||
6783 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6786 ns
= arg
->nodesetval
;
6788 for (i
=0;i
<ns
->nodeNr
;i
++) {
6789 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6791 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, str2
));
6793 xmlXPathNumberFunction(ctxt
, 1);
6795 val
= valuePop(ctxt
);
6797 xmlXPathReleaseObject(ctxt
->context
, val
);
6798 if (!xmlXPathIsNaN(v
)) {
6799 if ((!neq
) && (v
==f
)) {
6802 } else if ((neq
) && (v
!=f
)) {
6806 } else { /* NaN is unequal to any value */
6819 * xmlXPathEqualNodeSets:
6820 * @arg1: first nodeset object argument
6821 * @arg2: second nodeset object argument
6822 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6824 * Implement the equal / not equal operation on XPath nodesets:
6825 * @arg1 == @arg2 or @arg1 != @arg2
6826 * If both objects to be compared are node-sets, then the comparison
6827 * will be true if and only if there is a node in the first node-set and
6828 * a node in the second node-set such that the result of performing the
6829 * comparison on the string-values of the two nodes is true.
6831 * (needless to say, this is a costly operation)
6833 * Returns 0 or 1 depending on the results of the test.
6836 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
, int neq
) {
6838 unsigned int *hashs1
;
6839 unsigned int *hashs2
;
6846 if ((arg1
== NULL
) ||
6847 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)))
6849 if ((arg2
== NULL
) ||
6850 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
)))
6853 ns1
= arg1
->nodesetval
;
6854 ns2
= arg2
->nodesetval
;
6856 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0))
6858 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0))
6862 * for equal, check if there is a node pertaining to both sets
6865 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6866 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6867 if (ns1
->nodeTab
[i
] == ns2
->nodeTab
[j
])
6870 values1
= (xmlChar
**) xmlMalloc(ns1
->nodeNr
* sizeof(xmlChar
*));
6871 if (values1
== NULL
) {
6872 /* TODO: Propagate memory error. */
6873 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6876 hashs1
= (unsigned int *) xmlMalloc(ns1
->nodeNr
* sizeof(unsigned int));
6877 if (hashs1
== NULL
) {
6878 /* TODO: Propagate memory error. */
6879 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6883 memset(values1
, 0, ns1
->nodeNr
* sizeof(xmlChar
*));
6884 values2
= (xmlChar
**) xmlMalloc(ns2
->nodeNr
* sizeof(xmlChar
*));
6885 if (values2
== NULL
) {
6886 /* TODO: Propagate memory error. */
6887 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6892 hashs2
= (unsigned int *) xmlMalloc(ns2
->nodeNr
* sizeof(unsigned int));
6893 if (hashs2
== NULL
) {
6894 /* TODO: Propagate memory error. */
6895 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6901 memset(values2
, 0, ns2
->nodeNr
* sizeof(xmlChar
*));
6902 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6903 hashs1
[i
] = xmlXPathNodeValHash(ns1
->nodeTab
[i
]);
6904 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6906 hashs2
[j
] = xmlXPathNodeValHash(ns2
->nodeTab
[j
]);
6907 if (hashs1
[i
] != hashs2
[j
]) {
6914 if (values1
[i
] == NULL
)
6915 values1
[i
] = xmlNodeGetContent(ns1
->nodeTab
[i
]);
6916 if (values2
[j
] == NULL
)
6917 values2
[j
] = xmlNodeGetContent(ns2
->nodeTab
[j
]);
6918 ret
= xmlStrEqual(values1
[i
], values2
[j
]) ^ neq
;
6926 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6927 if (values1
[i
] != NULL
)
6928 xmlFree(values1
[i
]);
6929 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6930 if (values2
[j
] != NULL
)
6931 xmlFree(values2
[j
]);
6940 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt
,
6941 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6944 *At this point we are assured neither arg1 nor arg2
6945 *is a nodeset, so we can just pick the appropriate routine.
6947 switch (arg1
->type
) {
6948 case XPATH_UNDEFINED
:
6950 xmlGenericError(xmlGenericErrorContext
,
6951 "Equal: undefined\n");
6955 switch (arg2
->type
) {
6956 case XPATH_UNDEFINED
:
6958 xmlGenericError(xmlGenericErrorContext
,
6959 "Equal: undefined\n");
6964 xmlGenericError(xmlGenericErrorContext
,
6965 "Equal: %d boolean %d \n",
6966 arg1
->boolval
, arg2
->boolval
);
6968 ret
= (arg1
->boolval
== arg2
->boolval
);
6971 ret
= (arg1
->boolval
==
6972 xmlXPathCastNumberToBoolean(arg2
->floatval
));
6975 if ((arg2
->stringval
== NULL
) ||
6976 (arg2
->stringval
[0] == 0)) ret
= 0;
6979 ret
= (arg1
->boolval
== ret
);
6982 #ifdef LIBXML_XPTR_LOCS_ENABLED
6985 case XPATH_LOCATIONSET
:
6986 #endif /* LIBXML_XPTR_LOCS_ENABLED */
6990 case XPATH_XSLT_TREE
:
6995 switch (arg2
->type
) {
6996 case XPATH_UNDEFINED
:
6998 xmlGenericError(xmlGenericErrorContext
,
6999 "Equal: undefined\n");
7003 ret
= (arg2
->boolval
==
7004 xmlXPathCastNumberToBoolean(arg1
->floatval
));
7007 valuePush(ctxt
, arg2
);
7008 xmlXPathNumberFunction(ctxt
, 1);
7009 arg2
= valuePop(ctxt
);
7012 /* Falls through. */
7014 /* Hand check NaN and Infinity equalities */
7015 if (xmlXPathIsNaN(arg1
->floatval
) ||
7016 xmlXPathIsNaN(arg2
->floatval
)) {
7018 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7019 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7023 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7024 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7028 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7029 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7033 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7034 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7039 ret
= (arg1
->floatval
== arg2
->floatval
);
7043 #ifdef LIBXML_XPTR_LOCS_ENABLED
7046 case XPATH_LOCATIONSET
:
7047 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7051 case XPATH_XSLT_TREE
:
7056 switch (arg2
->type
) {
7057 case XPATH_UNDEFINED
:
7059 xmlGenericError(xmlGenericErrorContext
,
7060 "Equal: undefined\n");
7064 if ((arg1
->stringval
== NULL
) ||
7065 (arg1
->stringval
[0] == 0)) ret
= 0;
7068 ret
= (arg2
->boolval
== ret
);
7071 ret
= xmlStrEqual(arg1
->stringval
, arg2
->stringval
);
7074 valuePush(ctxt
, arg1
);
7075 xmlXPathNumberFunction(ctxt
, 1);
7076 arg1
= valuePop(ctxt
);
7079 /* Hand check NaN and Infinity equalities */
7080 if (xmlXPathIsNaN(arg1
->floatval
) ||
7081 xmlXPathIsNaN(arg2
->floatval
)) {
7083 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7084 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7088 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7089 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7093 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7094 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7098 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7099 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7104 ret
= (arg1
->floatval
== arg2
->floatval
);
7108 #ifdef LIBXML_XPTR_LOCS_ENABLED
7111 case XPATH_LOCATIONSET
:
7112 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7116 case XPATH_XSLT_TREE
:
7121 #ifdef LIBXML_XPTR_LOCS_ENABLED
7124 case XPATH_LOCATIONSET
:
7125 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7129 case XPATH_XSLT_TREE
:
7132 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7133 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7138 * xmlXPathEqualValues:
7139 * @ctxt: the XPath Parser context
7141 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7143 * Returns 0 or 1 depending on the results of the test.
7146 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt
) {
7147 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7150 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7151 arg2
= valuePop(ctxt
);
7152 arg1
= valuePop(ctxt
);
7153 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7155 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7157 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7158 XP_ERROR0(XPATH_INVALID_OPERAND
);
7163 xmlGenericError(xmlGenericErrorContext
,
7164 "Equal: by pointer\n");
7166 xmlXPathFreeObject(arg1
);
7171 *If either argument is a nodeset, it's a 'special case'
7173 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7174 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7176 *Hack it to assure arg1 is the nodeset
7178 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7183 switch (arg2
->type
) {
7184 case XPATH_UNDEFINED
:
7186 xmlGenericError(xmlGenericErrorContext
,
7187 "Equal: undefined\n");
7191 case XPATH_XSLT_TREE
:
7192 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 0);
7195 if ((arg1
->nodesetval
== NULL
) ||
7196 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7199 ret
= (ret
== arg2
->boolval
);
7202 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 0);
7205 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
, 0);
7208 #ifdef LIBXML_XPTR_LOCS_ENABLED
7211 case XPATH_LOCATIONSET
:
7212 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7216 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7217 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7221 return (xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7225 * xmlXPathNotEqualValues:
7226 * @ctxt: the XPath Parser context
7228 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7230 * Returns 0 or 1 depending on the results of the test.
7233 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt
) {
7234 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7237 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7238 arg2
= valuePop(ctxt
);
7239 arg1
= valuePop(ctxt
);
7240 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7242 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7244 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7245 XP_ERROR0(XPATH_INVALID_OPERAND
);
7250 xmlGenericError(xmlGenericErrorContext
,
7251 "NotEqual: by pointer\n");
7253 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7258 *If either argument is a nodeset, it's a 'special case'
7260 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7261 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7263 *Hack it to assure arg1 is the nodeset
7265 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7270 switch (arg2
->type
) {
7271 case XPATH_UNDEFINED
:
7273 xmlGenericError(xmlGenericErrorContext
,
7274 "NotEqual: undefined\n");
7278 case XPATH_XSLT_TREE
:
7279 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 1);
7282 if ((arg1
->nodesetval
== NULL
) ||
7283 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7286 ret
= (ret
!= arg2
->boolval
);
7289 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 1);
7292 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
,1);
7295 #ifdef LIBXML_XPTR_LOCS_ENABLED
7298 case XPATH_LOCATIONSET
:
7299 #endif /* LIBXML_XPTR_LOCS_ENABLED */
7303 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7304 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7308 return (!xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7312 * xmlXPathCompareValues:
7313 * @ctxt: the XPath Parser context
7314 * @inf: less than (1) or greater than (0)
7315 * @strict: is the comparison strict
7317 * Implement the compare operation on XPath objects:
7318 * @arg1 < @arg2 (1, 1, ...
7319 * @arg1 <= @arg2 (1, 0, ...
7320 * @arg1 > @arg2 (0, 1, ...
7321 * @arg1 >= @arg2 (0, 0, ...
7323 * When neither object to be compared is a node-set and the operator is
7324 * <=, <, >=, >, then the objects are compared by converted both objects
7325 * to numbers and comparing the numbers according to IEEE 754. The <
7326 * comparison will be true if and only if the first number is less than the
7327 * second number. The <= comparison will be true if and only if the first
7328 * number is less than or equal to the second number. The > comparison
7329 * will be true if and only if the first number is greater than the second
7330 * number. The >= comparison will be true if and only if the first number
7331 * is greater than or equal to the second number.
7333 * Returns 1 if the comparison succeeded, 0 if it failed
7336 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt
, int inf
, int strict
) {
7337 int ret
= 0, arg1i
= 0, arg2i
= 0;
7338 xmlXPathObjectPtr arg1
, arg2
;
7340 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7341 arg2
= valuePop(ctxt
);
7342 arg1
= valuePop(ctxt
);
7343 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7345 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7347 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7348 XP_ERROR0(XPATH_INVALID_OPERAND
);
7351 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7352 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7354 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7355 * are not freed from within this routine; they will be freed from the
7356 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7358 if (((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
)) &&
7359 ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
))){
7360 ret
= xmlXPathCompareNodeSets(inf
, strict
, arg1
, arg2
);
7362 if ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7363 ret
= xmlXPathCompareNodeSetValue(ctxt
, inf
, strict
,
7366 ret
= xmlXPathCompareNodeSetValue(ctxt
, !inf
, strict
,
7373 if (arg1
->type
!= XPATH_NUMBER
) {
7374 valuePush(ctxt
, arg1
);
7375 xmlXPathNumberFunction(ctxt
, 1);
7376 arg1
= valuePop(ctxt
);
7378 if (arg2
->type
!= XPATH_NUMBER
) {
7379 valuePush(ctxt
, arg2
);
7380 xmlXPathNumberFunction(ctxt
, 1);
7381 arg2
= valuePop(ctxt
);
7386 * Add tests for infinity and nan
7387 * => feedback on 3.4 for Inf and NaN
7389 /* Hand check NaN and Infinity comparisons */
7390 if (xmlXPathIsNaN(arg1
->floatval
) || xmlXPathIsNaN(arg2
->floatval
)) {
7393 arg1i
=xmlXPathIsInf(arg1
->floatval
);
7394 arg2i
=xmlXPathIsInf(arg2
->floatval
);
7395 if (inf
&& strict
) {
7396 if ((arg1i
== -1 && arg2i
!= -1) ||
7397 (arg2i
== 1 && arg1i
!= 1)) {
7399 } else if (arg1i
== 0 && arg2i
== 0) {
7400 ret
= (arg1
->floatval
< arg2
->floatval
);
7405 else if (inf
&& !strict
) {
7406 if (arg1i
== -1 || arg2i
== 1) {
7408 } else if (arg1i
== 0 && arg2i
== 0) {
7409 ret
= (arg1
->floatval
<= arg2
->floatval
);
7414 else if (!inf
&& strict
) {
7415 if ((arg1i
== 1 && arg2i
!= 1) ||
7416 (arg2i
== -1 && arg1i
!= -1)) {
7418 } else if (arg1i
== 0 && arg2i
== 0) {
7419 ret
= (arg1
->floatval
> arg2
->floatval
);
7424 else if (!inf
&& !strict
) {
7425 if (arg1i
== 1 || arg2i
== -1) {
7427 } else if (arg1i
== 0 && arg2i
== 0) {
7428 ret
= (arg1
->floatval
>= arg2
->floatval
);
7435 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7436 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7441 * xmlXPathValueFlipSign:
7442 * @ctxt: the XPath Parser context
7444 * Implement the unary - operation on an XPath object
7445 * The numeric operators convert their operands to numbers as if
7446 * by calling the number function.
7449 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt
) {
7450 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return;
7452 CHECK_TYPE(XPATH_NUMBER
);
7453 ctxt
->value
->floatval
= -ctxt
->value
->floatval
;
7457 * xmlXPathAddValues:
7458 * @ctxt: the XPath Parser context
7460 * Implement the add operation on XPath objects:
7461 * The numeric operators convert their operands to numbers as if
7462 * by calling the number function.
7465 xmlXPathAddValues(xmlXPathParserContextPtr ctxt
) {
7466 xmlXPathObjectPtr arg
;
7469 arg
= valuePop(ctxt
);
7471 XP_ERROR(XPATH_INVALID_OPERAND
);
7472 val
= xmlXPathCastToNumber(arg
);
7473 xmlXPathReleaseObject(ctxt
->context
, arg
);
7475 CHECK_TYPE(XPATH_NUMBER
);
7476 ctxt
->value
->floatval
+= val
;
7480 * xmlXPathSubValues:
7481 * @ctxt: the XPath Parser context
7483 * Implement the subtraction operation on XPath objects:
7484 * The numeric operators convert their operands to numbers as if
7485 * by calling the number function.
7488 xmlXPathSubValues(xmlXPathParserContextPtr ctxt
) {
7489 xmlXPathObjectPtr arg
;
7492 arg
= valuePop(ctxt
);
7494 XP_ERROR(XPATH_INVALID_OPERAND
);
7495 val
= xmlXPathCastToNumber(arg
);
7496 xmlXPathReleaseObject(ctxt
->context
, arg
);
7498 CHECK_TYPE(XPATH_NUMBER
);
7499 ctxt
->value
->floatval
-= val
;
7503 * xmlXPathMultValues:
7504 * @ctxt: the XPath Parser context
7506 * Implement the multiply operation on XPath objects:
7507 * The numeric operators convert their operands to numbers as if
7508 * by calling the number function.
7511 xmlXPathMultValues(xmlXPathParserContextPtr ctxt
) {
7512 xmlXPathObjectPtr arg
;
7515 arg
= valuePop(ctxt
);
7517 XP_ERROR(XPATH_INVALID_OPERAND
);
7518 val
= xmlXPathCastToNumber(arg
);
7519 xmlXPathReleaseObject(ctxt
->context
, arg
);
7521 CHECK_TYPE(XPATH_NUMBER
);
7522 ctxt
->value
->floatval
*= val
;
7526 * xmlXPathDivValues:
7527 * @ctxt: the XPath Parser context
7529 * Implement the div operation on XPath objects @arg1 / @arg2:
7530 * The numeric operators convert their operands to numbers as if
7531 * by calling the number function.
7533 ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
7535 xmlXPathDivValues(xmlXPathParserContextPtr ctxt
) {
7536 xmlXPathObjectPtr arg
;
7539 arg
= valuePop(ctxt
);
7541 XP_ERROR(XPATH_INVALID_OPERAND
);
7542 val
= xmlXPathCastToNumber(arg
);
7543 xmlXPathReleaseObject(ctxt
->context
, arg
);
7545 CHECK_TYPE(XPATH_NUMBER
);
7546 ctxt
->value
->floatval
/= val
;
7550 * xmlXPathModValues:
7551 * @ctxt: the XPath Parser context
7553 * Implement the mod operation on XPath objects: @arg1 / @arg2
7554 * The numeric operators convert their operands to numbers as if
7555 * by calling the number function.
7558 xmlXPathModValues(xmlXPathParserContextPtr ctxt
) {
7559 xmlXPathObjectPtr arg
;
7562 arg
= valuePop(ctxt
);
7564 XP_ERROR(XPATH_INVALID_OPERAND
);
7565 arg2
= xmlXPathCastToNumber(arg
);
7566 xmlXPathReleaseObject(ctxt
->context
, arg
);
7568 CHECK_TYPE(XPATH_NUMBER
);
7569 arg1
= ctxt
->value
->floatval
;
7571 ctxt
->value
->floatval
= xmlXPathNAN
;
7573 ctxt
->value
->floatval
= fmod(arg1
, arg2
);
7577 /************************************************************************
7579 * The traversal functions *
7581 ************************************************************************/
7584 * A traversal function enumerates nodes along an axis.
7585 * Initially it must be called with NULL, and it indicates
7586 * termination on the axis by returning NULL.
7588 typedef xmlNodePtr (*xmlXPathTraversalFunction
)
7589 (xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
);
7592 * xmlXPathTraversalFunctionExt:
7593 * A traversal function enumerates nodes along an axis.
7594 * Initially it must be called with NULL, and it indicates
7595 * termination on the axis by returning NULL.
7596 * The context node of the traversal is specified via @contextNode.
7598 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt
)
7599 (xmlNodePtr cur
, xmlNodePtr contextNode
);
7602 * xmlXPathNodeSetMergeFunction:
7603 * Used for merging node sets in xmlXPathCollectAndTest().
7605 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction
)
7606 (xmlNodeSetPtr
, xmlNodeSetPtr
);
7611 * @ctxt: the XPath Parser context
7612 * @cur: the current node in the traversal
7614 * Traversal function for the "self" direction
7615 * The self axis contains just the context node itself
7617 * Returns the next element following that axis
7620 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7621 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7623 return(ctxt
->context
->node
);
7628 * xmlXPathNextChild:
7629 * @ctxt: the XPath Parser context
7630 * @cur: the current node in the traversal
7632 * Traversal function for the "child" direction
7633 * The child axis contains the children of the context node in document order.
7635 * Returns the next element following that axis
7638 xmlXPathNextChild(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7639 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7641 if (ctxt
->context
->node
== NULL
) return(NULL
);
7642 switch (ctxt
->context
->node
->type
) {
7643 case XML_ELEMENT_NODE
:
7645 case XML_CDATA_SECTION_NODE
:
7646 case XML_ENTITY_REF_NODE
:
7647 case XML_ENTITY_NODE
:
7649 case XML_COMMENT_NODE
:
7650 case XML_NOTATION_NODE
:
7652 return(ctxt
->context
->node
->children
);
7653 case XML_DOCUMENT_NODE
:
7654 case XML_DOCUMENT_TYPE_NODE
:
7655 case XML_DOCUMENT_FRAG_NODE
:
7656 case XML_HTML_DOCUMENT_NODE
:
7657 return(((xmlDocPtr
) ctxt
->context
->node
)->children
);
7658 case XML_ELEMENT_DECL
:
7659 case XML_ATTRIBUTE_DECL
:
7660 case XML_ENTITY_DECL
:
7661 case XML_ATTRIBUTE_NODE
:
7662 case XML_NAMESPACE_DECL
:
7663 case XML_XINCLUDE_START
:
7664 case XML_XINCLUDE_END
:
7669 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
7670 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
7676 * xmlXPathNextChildElement:
7677 * @ctxt: the XPath Parser context
7678 * @cur: the current node in the traversal
7680 * Traversal function for the "child" direction and nodes of type element.
7681 * The child axis contains the children of the context node in document order.
7683 * Returns the next element following that axis
7686 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7687 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7689 cur
= ctxt
->context
->node
;
7690 if (cur
== NULL
) return(NULL
);
7692 * Get the first element child.
7694 switch (cur
->type
) {
7695 case XML_ELEMENT_NODE
:
7696 case XML_DOCUMENT_FRAG_NODE
:
7697 case XML_ENTITY_REF_NODE
: /* URGENT TODO: entify-refs as well? */
7698 case XML_ENTITY_NODE
:
7699 cur
= cur
->children
;
7701 if (cur
->type
== XML_ELEMENT_NODE
)
7705 } while ((cur
!= NULL
) &&
7706 (cur
->type
!= XML_ELEMENT_NODE
));
7710 case XML_DOCUMENT_NODE
:
7711 case XML_HTML_DOCUMENT_NODE
:
7712 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7719 * Get the next sibling element node.
7721 switch (cur
->type
) {
7722 case XML_ELEMENT_NODE
:
7724 case XML_ENTITY_REF_NODE
:
7725 case XML_ENTITY_NODE
:
7726 case XML_CDATA_SECTION_NODE
:
7728 case XML_COMMENT_NODE
:
7729 case XML_XINCLUDE_END
:
7731 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7735 if (cur
->next
!= NULL
) {
7736 if (cur
->next
->type
== XML_ELEMENT_NODE
)
7741 } while ((cur
!= NULL
) && (cur
->type
!= XML_ELEMENT_NODE
));
7749 * xmlXPathNextDescendantOrSelfElemParent:
7750 * @ctxt: the XPath Parser context
7751 * @cur: the current node in the traversal
7753 * Traversal function for the "descendant-or-self" axis.
7754 * Additionally it returns only nodes which can be parents of
7758 * Returns the next element following that axis
7761 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur
,
7762 xmlNodePtr contextNode
)
7765 if (contextNode
== NULL
)
7767 switch (contextNode
->type
) {
7768 case XML_ELEMENT_NODE
:
7769 case XML_XINCLUDE_START
:
7770 case XML_DOCUMENT_FRAG_NODE
:
7771 case XML_DOCUMENT_NODE
:
7772 case XML_HTML_DOCUMENT_NODE
:
7773 return(contextNode
);
7779 xmlNodePtr start
= cur
;
7781 while (cur
!= NULL
) {
7782 switch (cur
->type
) {
7783 case XML_ELEMENT_NODE
:
7784 /* TODO: OK to have XInclude here? */
7785 case XML_XINCLUDE_START
:
7786 case XML_DOCUMENT_FRAG_NODE
:
7789 if (cur
->children
!= NULL
) {
7790 cur
= cur
->children
;
7794 /* Not sure if we need those here. */
7795 case XML_DOCUMENT_NODE
:
7796 case XML_HTML_DOCUMENT_NODE
:
7799 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7805 if ((cur
== NULL
) || (cur
== contextNode
))
7807 if (cur
->next
!= NULL
) {
7820 * xmlXPathNextDescendant:
7821 * @ctxt: the XPath Parser context
7822 * @cur: the current node in the traversal
7824 * Traversal function for the "descendant" direction
7825 * the descendant axis contains the descendants of the context node in document
7826 * order; a descendant is a child or a child of a child and so on.
7828 * Returns the next element following that axis
7831 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7832 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7834 if (ctxt
->context
->node
== NULL
)
7836 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7837 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7840 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
7841 return(ctxt
->context
->doc
->children
);
7842 return(ctxt
->context
->node
->children
);
7845 if (cur
->type
== XML_NAMESPACE_DECL
)
7847 if (cur
->children
!= NULL
) {
7849 * Do not descend on entities declarations
7851 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
7852 cur
= cur
->children
;
7856 if (cur
->type
!= XML_DTD_NODE
)
7861 if (cur
== ctxt
->context
->node
) return(NULL
);
7863 while (cur
->next
!= NULL
) {
7865 if ((cur
->type
!= XML_ENTITY_DECL
) &&
7866 (cur
->type
!= XML_DTD_NODE
))
7872 if (cur
== NULL
) break;
7873 if (cur
== ctxt
->context
->node
) return(NULL
);
7874 if (cur
->next
!= NULL
) {
7878 } while (cur
!= NULL
);
7883 * xmlXPathNextDescendantOrSelf:
7884 * @ctxt: the XPath Parser context
7885 * @cur: the current node in the traversal
7887 * Traversal function for the "descendant-or-self" direction
7888 * the descendant-or-self axis contains the context node and the descendants
7889 * of the context node in document order; thus the context node is the first
7890 * node on the axis, and the first child of the context node is the second node
7893 * Returns the next element following that axis
7896 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7897 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7899 return(ctxt
->context
->node
);
7901 if (ctxt
->context
->node
== NULL
)
7903 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7904 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7907 return(xmlXPathNextDescendant(ctxt
, cur
));
7911 * xmlXPathNextParent:
7912 * @ctxt: the XPath Parser context
7913 * @cur: the current node in the traversal
7915 * Traversal function for the "parent" direction
7916 * The parent axis contains the parent of the context node, if there is one.
7918 * Returns the next element following that axis
7921 xmlXPathNextParent(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7922 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7924 * the parent of an attribute or namespace node is the element
7925 * to which the attribute or namespace node is attached
7926 * Namespace handling !!!
7929 if (ctxt
->context
->node
== NULL
) return(NULL
);
7930 switch (ctxt
->context
->node
->type
) {
7931 case XML_ELEMENT_NODE
:
7933 case XML_CDATA_SECTION_NODE
:
7934 case XML_ENTITY_REF_NODE
:
7935 case XML_ENTITY_NODE
:
7937 case XML_COMMENT_NODE
:
7938 case XML_NOTATION_NODE
:
7940 case XML_ELEMENT_DECL
:
7941 case XML_ATTRIBUTE_DECL
:
7942 case XML_XINCLUDE_START
:
7943 case XML_XINCLUDE_END
:
7944 case XML_ENTITY_DECL
:
7945 if (ctxt
->context
->node
->parent
== NULL
)
7946 return((xmlNodePtr
) ctxt
->context
->doc
);
7947 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
7948 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
7949 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
7950 BAD_CAST
"fake node libxslt"))))
7952 return(ctxt
->context
->node
->parent
);
7953 case XML_ATTRIBUTE_NODE
: {
7954 xmlAttrPtr att
= (xmlAttrPtr
) ctxt
->context
->node
;
7956 return(att
->parent
);
7958 case XML_DOCUMENT_NODE
:
7959 case XML_DOCUMENT_TYPE_NODE
:
7960 case XML_DOCUMENT_FRAG_NODE
:
7961 case XML_HTML_DOCUMENT_NODE
:
7963 case XML_NAMESPACE_DECL
: {
7964 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
7966 if ((ns
->next
!= NULL
) &&
7967 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
7968 return((xmlNodePtr
) ns
->next
);
7977 * xmlXPathNextAncestor:
7978 * @ctxt: the XPath Parser context
7979 * @cur: the current node in the traversal
7981 * Traversal function for the "ancestor" direction
7982 * the ancestor axis contains the ancestors of the context node; the ancestors
7983 * of the context node consist of the parent of context node and the parent's
7984 * parent and so on; the nodes are ordered in reverse document order; thus the
7985 * parent is the first node on the axis, and the parent's parent is the second
7988 * Returns the next element following that axis
7991 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7992 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7994 * the parent of an attribute or namespace node is the element
7995 * to which the attribute or namespace node is attached
7999 if (ctxt
->context
->node
== NULL
) return(NULL
);
8000 switch (ctxt
->context
->node
->type
) {
8001 case XML_ELEMENT_NODE
:
8003 case XML_CDATA_SECTION_NODE
:
8004 case XML_ENTITY_REF_NODE
:
8005 case XML_ENTITY_NODE
:
8007 case XML_COMMENT_NODE
:
8009 case XML_ELEMENT_DECL
:
8010 case XML_ATTRIBUTE_DECL
:
8011 case XML_ENTITY_DECL
:
8012 case XML_NOTATION_NODE
:
8013 case XML_XINCLUDE_START
:
8014 case XML_XINCLUDE_END
:
8015 if (ctxt
->context
->node
->parent
== NULL
)
8016 return((xmlNodePtr
) ctxt
->context
->doc
);
8017 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
8018 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
8019 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
8020 BAD_CAST
"fake node libxslt"))))
8022 return(ctxt
->context
->node
->parent
);
8023 case XML_ATTRIBUTE_NODE
: {
8024 xmlAttrPtr tmp
= (xmlAttrPtr
) ctxt
->context
->node
;
8026 return(tmp
->parent
);
8028 case XML_DOCUMENT_NODE
:
8029 case XML_DOCUMENT_TYPE_NODE
:
8030 case XML_DOCUMENT_FRAG_NODE
:
8031 case XML_HTML_DOCUMENT_NODE
:
8033 case XML_NAMESPACE_DECL
: {
8034 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8036 if ((ns
->next
!= NULL
) &&
8037 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8038 return((xmlNodePtr
) ns
->next
);
8039 /* Bad, how did that namespace end up here ? */
8045 if (cur
== ctxt
->context
->doc
->children
)
8046 return((xmlNodePtr
) ctxt
->context
->doc
);
8047 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8049 switch (cur
->type
) {
8050 case XML_ELEMENT_NODE
:
8052 case XML_CDATA_SECTION_NODE
:
8053 case XML_ENTITY_REF_NODE
:
8054 case XML_ENTITY_NODE
:
8056 case XML_COMMENT_NODE
:
8057 case XML_NOTATION_NODE
:
8059 case XML_ELEMENT_DECL
:
8060 case XML_ATTRIBUTE_DECL
:
8061 case XML_ENTITY_DECL
:
8062 case XML_XINCLUDE_START
:
8063 case XML_XINCLUDE_END
:
8064 if (cur
->parent
== NULL
)
8066 if ((cur
->parent
->type
== XML_ELEMENT_NODE
) &&
8067 ((cur
->parent
->name
[0] == ' ') ||
8068 (xmlStrEqual(cur
->parent
->name
,
8069 BAD_CAST
"fake node libxslt"))))
8071 return(cur
->parent
);
8072 case XML_ATTRIBUTE_NODE
: {
8073 xmlAttrPtr att
= (xmlAttrPtr
) cur
;
8075 return(att
->parent
);
8077 case XML_NAMESPACE_DECL
: {
8078 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8080 if ((ns
->next
!= NULL
) &&
8081 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8082 return((xmlNodePtr
) ns
->next
);
8083 /* Bad, how did that namespace end up here ? */
8086 case XML_DOCUMENT_NODE
:
8087 case XML_DOCUMENT_TYPE_NODE
:
8088 case XML_DOCUMENT_FRAG_NODE
:
8089 case XML_HTML_DOCUMENT_NODE
:
8096 * xmlXPathNextAncestorOrSelf:
8097 * @ctxt: the XPath Parser context
8098 * @cur: the current node in the traversal
8100 * Traversal function for the "ancestor-or-self" direction
8101 * he ancestor-or-self axis contains the context node and ancestors of
8102 * the context node in reverse document order; thus the context node is
8103 * the first node on the axis, and the context node's parent the second;
8104 * parent here is defined the same as with the parent axis.
8106 * Returns the next element following that axis
8109 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8110 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8112 return(ctxt
->context
->node
);
8113 return(xmlXPathNextAncestor(ctxt
, cur
));
8117 * xmlXPathNextFollowingSibling:
8118 * @ctxt: the XPath Parser context
8119 * @cur: the current node in the traversal
8121 * Traversal function for the "following-sibling" direction
8122 * The following-sibling axis contains the following siblings of the context
8123 * node in document order.
8125 * Returns the next element following that axis
8128 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8129 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8130 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8131 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8133 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8136 return(ctxt
->context
->node
->next
);
8141 * xmlXPathNextPrecedingSibling:
8142 * @ctxt: the XPath Parser context
8143 * @cur: the current node in the traversal
8145 * Traversal function for the "preceding-sibling" direction
8146 * The preceding-sibling axis contains the preceding siblings of the context
8147 * node in reverse document order; the first preceding sibling is first on the
8148 * axis; the sibling preceding that node is the second on the axis and so on.
8150 * Returns the next element following that axis
8153 xmlXPathNextPrecedingSibling(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
->prev
);
8162 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
)) {
8165 return(ctxt
->context
->node
->prev
);
8171 * xmlXPathNextFollowing:
8172 * @ctxt: the XPath Parser context
8173 * @cur: the current node in the traversal
8175 * Traversal function for the "following" direction
8176 * The following axis contains all nodes in the same document as the context
8177 * node that are after the context node in document order, excluding any
8178 * descendants and excluding attribute nodes and namespace nodes; the nodes
8179 * are ordered in document order
8181 * Returns the next element following that axis
8184 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8185 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8186 if ((cur
!= NULL
) && (cur
->type
!= XML_ATTRIBUTE_NODE
) &&
8187 (cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->children
!= NULL
))
8188 return(cur
->children
);
8191 cur
= ctxt
->context
->node
;
8192 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8194 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8195 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8197 if ((ns
->next
== NULL
) ||
8198 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8200 cur
= (xmlNodePtr
) ns
->next
;
8203 if (cur
== NULL
) return(NULL
) ; /* ERROR */
8204 if (cur
->next
!= NULL
) return(cur
->next
) ;
8207 if (cur
== NULL
) break;
8208 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
) return(NULL
);
8209 if (cur
->next
!= NULL
) return(cur
->next
);
8210 } while (cur
!= NULL
);
8215 * xmlXPathIsAncestor:
8216 * @ancestor: the ancestor node
8217 * @node: the current node
8219 * Check that @ancestor is a @node's ancestor
8221 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8224 xmlXPathIsAncestor(xmlNodePtr ancestor
, xmlNodePtr node
) {
8225 if ((ancestor
== NULL
) || (node
== NULL
)) return(0);
8226 if (node
->type
== XML_NAMESPACE_DECL
)
8228 if (ancestor
->type
== XML_NAMESPACE_DECL
)
8230 /* nodes need to be in the same document */
8231 if (ancestor
->doc
!= node
->doc
) return(0);
8232 /* avoid searching if ancestor or node is the root node */
8233 if (ancestor
== (xmlNodePtr
) node
->doc
) return(1);
8234 if (node
== (xmlNodePtr
) ancestor
->doc
) return(0);
8235 while (node
->parent
!= NULL
) {
8236 if (node
->parent
== ancestor
)
8238 node
= node
->parent
;
8244 * xmlXPathNextPreceding:
8245 * @ctxt: the XPath Parser context
8246 * @cur: the current node in the traversal
8248 * Traversal function for the "preceding" direction
8249 * the preceding axis contains all nodes in the same document as the context
8250 * node that are before the context node in document order, excluding any
8251 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8252 * ordered in reverse document order
8254 * Returns the next element following that axis
8257 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
)
8259 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8261 cur
= ctxt
->context
->node
;
8262 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8264 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8265 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8267 if ((ns
->next
== NULL
) ||
8268 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8270 cur
= (xmlNodePtr
) ns
->next
;
8273 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
8275 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8278 if (cur
->prev
!= NULL
) {
8279 for (cur
= cur
->prev
; cur
->last
!= NULL
; cur
= cur
->last
) ;
8286 if (cur
== ctxt
->context
->doc
->children
)
8288 } while (xmlXPathIsAncestor(cur
, ctxt
->context
->node
));
8293 * xmlXPathNextPrecedingInternal:
8294 * @ctxt: the XPath Parser context
8295 * @cur: the current node in the traversal
8297 * Traversal function for the "preceding" direction
8298 * the preceding axis contains all nodes in the same document as the context
8299 * node that are before the context node in document order, excluding any
8300 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8301 * ordered in reverse document order
8302 * This is a faster implementation but internal only since it requires a
8303 * state kept in the parser context: ctxt->ancestor.
8305 * Returns the next element following that axis
8308 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt
,
8311 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8313 cur
= ctxt
->context
->node
;
8316 if (cur
->type
== XML_ATTRIBUTE_NODE
) {
8318 } else if (cur
->type
== XML_NAMESPACE_DECL
) {
8319 xmlNsPtr ns
= (xmlNsPtr
) cur
;
8321 if ((ns
->next
== NULL
) ||
8322 (ns
->next
->type
== XML_NAMESPACE_DECL
))
8324 cur
= (xmlNodePtr
) ns
->next
;
8326 ctxt
->ancestor
= cur
->parent
;
8328 if (cur
->type
== XML_NAMESPACE_DECL
)
8330 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8332 while (cur
->prev
== NULL
) {
8336 if (cur
== ctxt
->context
->doc
->children
)
8338 if (cur
!= ctxt
->ancestor
)
8340 ctxt
->ancestor
= cur
->parent
;
8343 while (cur
->last
!= NULL
)
8349 * xmlXPathNextNamespace:
8350 * @ctxt: the XPath Parser context
8351 * @cur: the current attribute in the traversal
8353 * Traversal function for the "namespace" direction
8354 * the namespace axis contains the namespace nodes of the context node;
8355 * the order of nodes on this axis is implementation-defined; the axis will
8356 * be empty unless the context node is an element
8358 * We keep the XML namespace node at the end of the list.
8360 * Returns the next element following that axis
8363 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8364 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8365 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
) return(NULL
);
8367 if (ctxt
->context
->tmpNsList
!= NULL
)
8368 xmlFree(ctxt
->context
->tmpNsList
);
8369 ctxt
->context
->tmpNsList
=
8370 xmlGetNsList(ctxt
->context
->doc
, ctxt
->context
->node
);
8371 ctxt
->context
->tmpNsNr
= 0;
8372 if (ctxt
->context
->tmpNsList
!= NULL
) {
8373 while (ctxt
->context
->tmpNsList
[ctxt
->context
->tmpNsNr
] != NULL
) {
8374 ctxt
->context
->tmpNsNr
++;
8377 return((xmlNodePtr
) xmlXPathXMLNamespace
);
8379 if (ctxt
->context
->tmpNsNr
> 0) {
8380 return (xmlNodePtr
)ctxt
->context
->tmpNsList
[--ctxt
->context
->tmpNsNr
];
8382 if (ctxt
->context
->tmpNsList
!= NULL
)
8383 xmlFree(ctxt
->context
->tmpNsList
);
8384 ctxt
->context
->tmpNsList
= NULL
;
8390 * xmlXPathNextAttribute:
8391 * @ctxt: the XPath Parser context
8392 * @cur: the current attribute in the traversal
8394 * Traversal function for the "attribute" direction
8395 * TODO: support DTD inherited default attributes
8397 * Returns the next element following that axis
8400 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8401 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8402 if (ctxt
->context
->node
== NULL
)
8404 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
)
8407 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
8409 return((xmlNodePtr
)ctxt
->context
->node
->properties
);
8411 return((xmlNodePtr
)cur
->next
);
8414 /************************************************************************
8416 * NodeTest Functions *
8418 ************************************************************************/
8420 #define IS_FUNCTION 200
8423 /************************************************************************
8425 * Implicit tree core function library *
8427 ************************************************************************/
8431 * @ctxt: the XPath Parser context
8433 * Initialize the context to the root of the document
8436 xmlXPathRoot(xmlXPathParserContextPtr ctxt
) {
8437 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8439 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8440 (xmlNodePtr
) ctxt
->context
->doc
));
8443 /************************************************************************
8445 * The explicit core function library *
8446 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8448 ************************************************************************/
8452 * xmlXPathLastFunction:
8453 * @ctxt: the XPath Parser context
8454 * @nargs: the number of arguments
8456 * Implement the last() XPath function
8458 * The last function returns the number of nodes in the context node list.
8461 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8463 if (ctxt
->context
->contextSize
>= 0) {
8465 xmlXPathCacheNewFloat(ctxt
->context
,
8466 (double) ctxt
->context
->contextSize
));
8468 xmlGenericError(xmlGenericErrorContext
,
8469 "last() : %d\n", ctxt
->context
->contextSize
);
8472 XP_ERROR(XPATH_INVALID_CTXT_SIZE
);
8477 * xmlXPathPositionFunction:
8478 * @ctxt: the XPath Parser context
8479 * @nargs: the number of arguments
8481 * Implement the position() XPath function
8483 * The position function returns the position of the context node in the
8484 * context node list. The first position is 1, and so the last position
8485 * will be equal to last().
8488 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8490 if (ctxt
->context
->proximityPosition
>= 0) {
8492 xmlXPathCacheNewFloat(ctxt
->context
,
8493 (double) ctxt
->context
->proximityPosition
));
8495 xmlGenericError(xmlGenericErrorContext
, "position() : %d\n",
8496 ctxt
->context
->proximityPosition
);
8499 XP_ERROR(XPATH_INVALID_CTXT_POSITION
);
8504 * xmlXPathCountFunction:
8505 * @ctxt: the XPath Parser context
8506 * @nargs: the number of arguments
8508 * Implement the count() XPath function
8509 * number count(node-set)
8512 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8513 xmlXPathObjectPtr cur
;
8516 if ((ctxt
->value
== NULL
) ||
8517 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8518 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8519 XP_ERROR(XPATH_INVALID_TYPE
);
8520 cur
= valuePop(ctxt
);
8522 if ((cur
== NULL
) || (cur
->nodesetval
== NULL
))
8523 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8525 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8526 (double) cur
->nodesetval
->nodeNr
));
8527 xmlXPathReleaseObject(ctxt
->context
, cur
);
8531 * xmlXPathGetElementsByIds:
8532 * @doc: the document
8533 * @ids: a whitespace separated list of IDs
8535 * Selects elements by their unique ID.
8537 * Returns a node-set of selected elements.
8539 static xmlNodeSetPtr
8540 xmlXPathGetElementsByIds (xmlDocPtr doc
, const xmlChar
*ids
) {
8542 const xmlChar
*cur
= ids
;
8545 xmlNodePtr elem
= NULL
;
8547 if (ids
== NULL
) return(NULL
);
8549 ret
= xmlXPathNodeSetCreate(NULL
);
8553 while (IS_BLANK_CH(*cur
)) cur
++;
8555 while ((!IS_BLANK_CH(*cur
)) && (*cur
!= 0))
8558 ID
= xmlStrndup(ids
, cur
- ids
);
8561 * We used to check the fact that the value passed
8562 * was an NCName, but this generated much troubles for
8563 * me and Aleksey Sanin, people blatantly violated that
8564 * constraint, like Visa3D spec.
8565 * if (xmlValidateNCName(ID, 1) == 0)
8567 attr
= xmlGetID(doc
, ID
);
8569 if (attr
->type
== XML_ATTRIBUTE_NODE
)
8570 elem
= attr
->parent
;
8571 else if (attr
->type
== XML_ELEMENT_NODE
)
8572 elem
= (xmlNodePtr
) attr
;
8575 /* TODO: Check memory error. */
8577 xmlXPathNodeSetAdd(ret
, elem
);
8582 while (IS_BLANK_CH(*cur
)) cur
++;
8589 * xmlXPathIdFunction:
8590 * @ctxt: the XPath Parser context
8591 * @nargs: the number of arguments
8593 * Implement the id() XPath function
8594 * node-set id(object)
8595 * The id function selects elements by their unique ID
8596 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8597 * then the result is the union of the result of applying id to the
8598 * string value of each of the nodes in the argument node-set. When the
8599 * argument to id is of any other type, the argument is converted to a
8600 * string as if by a call to the string function; the string is split
8601 * into a whitespace-separated list of tokens (whitespace is any sequence
8602 * of characters matching the production S); the result is a node-set
8603 * containing the elements in the same document as the context node that
8604 * have a unique ID equal to any of the tokens in the list.
8607 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8610 xmlXPathObjectPtr obj
;
8613 obj
= valuePop(ctxt
);
8614 if (obj
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8615 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
8619 /* TODO: Check memory error. */
8620 ret
= xmlXPathNodeSetCreate(NULL
);
8622 if (obj
->nodesetval
!= NULL
) {
8623 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
8625 xmlXPathCastNodeToString(obj
->nodesetval
->nodeTab
[i
]);
8626 ns
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, tokens
);
8627 /* TODO: Check memory error. */
8628 ret
= xmlXPathNodeSetMerge(ret
, ns
);
8629 xmlXPathFreeNodeSet(ns
);
8634 xmlXPathReleaseObject(ctxt
->context
, obj
);
8635 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8638 obj
= xmlXPathCacheConvertString(ctxt
->context
, obj
);
8639 if (obj
== NULL
) return;
8640 ret
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, obj
->stringval
);
8641 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8642 xmlXPathReleaseObject(ctxt
->context
, obj
);
8647 * xmlXPathLocalNameFunction:
8648 * @ctxt: the XPath Parser context
8649 * @nargs: the number of arguments
8651 * Implement the local-name() XPath function
8652 * string local-name(node-set?)
8653 * The local-name function returns a string containing the local part
8654 * of the name of the node in the argument node-set that is first in
8655 * document order. If the node-set is empty or the first node has no
8656 * name, an empty string is returned. If the argument is omitted it
8657 * defaults to the context node.
8660 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8661 xmlXPathObjectPtr cur
;
8663 if (ctxt
== NULL
) return;
8666 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8667 ctxt
->context
->node
));
8672 if ((ctxt
->value
== NULL
) ||
8673 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8674 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8675 XP_ERROR(XPATH_INVALID_TYPE
);
8676 cur
= valuePop(ctxt
);
8678 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8679 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8681 int i
= 0; /* Should be first in document order !!!!! */
8682 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8683 case XML_ELEMENT_NODE
:
8684 case XML_ATTRIBUTE_NODE
:
8686 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8687 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8690 xmlXPathCacheNewString(ctxt
->context
,
8691 cur
->nodesetval
->nodeTab
[i
]->name
));
8693 case XML_NAMESPACE_DECL
:
8694 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8695 ((xmlNsPtr
)cur
->nodesetval
->nodeTab
[i
])->prefix
));
8698 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8701 xmlXPathReleaseObject(ctxt
->context
, cur
);
8705 * xmlXPathNamespaceURIFunction:
8706 * @ctxt: the XPath Parser context
8707 * @nargs: the number of arguments
8709 * Implement the namespace-uri() XPath function
8710 * string namespace-uri(node-set?)
8711 * The namespace-uri function returns a string containing the
8712 * namespace URI of the expanded name of the node in the argument
8713 * node-set that is first in document order. If the node-set is empty,
8714 * the first node has no name, or the expanded name has no namespace
8715 * URI, an empty string is returned. If the argument is omitted it
8716 * defaults to the context node.
8719 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8720 xmlXPathObjectPtr cur
;
8722 if (ctxt
== NULL
) return;
8725 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8726 ctxt
->context
->node
));
8730 if ((ctxt
->value
== NULL
) ||
8731 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8732 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8733 XP_ERROR(XPATH_INVALID_TYPE
);
8734 cur
= valuePop(ctxt
);
8736 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8737 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8739 int i
= 0; /* Should be first in document order !!!!! */
8740 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8741 case XML_ELEMENT_NODE
:
8742 case XML_ATTRIBUTE_NODE
:
8743 if (cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
)
8744 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8746 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8747 cur
->nodesetval
->nodeTab
[i
]->ns
->href
));
8750 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8753 xmlXPathReleaseObject(ctxt
->context
, cur
);
8757 * xmlXPathNameFunction:
8758 * @ctxt: the XPath Parser context
8759 * @nargs: the number of arguments
8761 * Implement the name() XPath function
8762 * string name(node-set?)
8763 * The name function returns a string containing a QName representing
8764 * the name of the node in the argument node-set that is first in document
8765 * order. The QName must represent the name with respect to the namespace
8766 * declarations in effect on the node whose name is being represented.
8767 * Typically, this will be the form in which the name occurred in the XML
8768 * source. This need not be the case if there are namespace declarations
8769 * in effect on the node that associate multiple prefixes with the same
8770 * namespace. However, an implementation may include information about
8771 * the original prefix in its representation of nodes; in this case, an
8772 * implementation can ensure that the returned string is always the same
8773 * as the QName used in the XML source. If the argument it omitted it
8774 * defaults to the context node.
8775 * Libxml keep the original prefix so the "real qualified name" used is
8779 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
8781 xmlXPathObjectPtr cur
;
8784 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8785 ctxt
->context
->node
));
8790 if ((ctxt
->value
== NULL
) ||
8791 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8792 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8793 XP_ERROR(XPATH_INVALID_TYPE
);
8794 cur
= valuePop(ctxt
);
8796 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8797 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8799 int i
= 0; /* Should be first in document order !!!!! */
8801 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8802 case XML_ELEMENT_NODE
:
8803 case XML_ATTRIBUTE_NODE
:
8804 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8806 xmlXPathCacheNewCString(ctxt
->context
, ""));
8807 else if ((cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
) ||
8808 (cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
== NULL
)) {
8810 xmlXPathCacheNewString(ctxt
->context
,
8811 cur
->nodesetval
->nodeTab
[i
]->name
));
8815 fullname
= xmlBuildQName(cur
->nodesetval
->nodeTab
[i
]->name
,
8816 cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
,
8818 if (fullname
== cur
->nodesetval
->nodeTab
[i
]->name
)
8819 fullname
= xmlStrdup(cur
->nodesetval
->nodeTab
[i
]->name
);
8820 if (fullname
== NULL
)
8821 xmlXPathPErrMemory(ctxt
, NULL
);
8822 valuePush(ctxt
, xmlXPathCacheWrapString(
8823 ctxt
->context
, fullname
));
8827 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8828 cur
->nodesetval
->nodeTab
[i
]));
8829 xmlXPathLocalNameFunction(ctxt
, 1);
8832 xmlXPathReleaseObject(ctxt
->context
, cur
);
8837 * xmlXPathStringFunction:
8838 * @ctxt: the XPath Parser context
8839 * @nargs: the number of arguments
8841 * Implement the string() XPath function
8842 * string string(object?)
8843 * The string function converts an object to a string as follows:
8844 * - A node-set is converted to a string by returning the value of
8845 * the node in the node-set that is first in document order.
8846 * If the node-set is empty, an empty string is returned.
8847 * - A number is converted to a string as follows
8848 * + NaN is converted to the string NaN
8849 * + positive zero is converted to the string 0
8850 * + negative zero is converted to the string 0
8851 * + positive infinity is converted to the string Infinity
8852 * + negative infinity is converted to the string -Infinity
8853 * + if the number is an integer, the number is represented in
8854 * decimal form as a Number with no decimal point and no leading
8855 * zeros, preceded by a minus sign (-) if the number is negative
8856 * + otherwise, the number is represented in decimal form as a
8857 * Number including a decimal point with at least one digit
8858 * before the decimal point and at least one digit after the
8859 * decimal point, preceded by a minus sign (-) if the number
8860 * is negative; there must be no leading zeros before the decimal
8861 * point apart possibly from the one required digit immediately
8862 * before the decimal point; beyond the one required digit
8863 * after the decimal point there must be as many, but only as
8864 * many, more digits as are needed to uniquely distinguish the
8865 * number from all other IEEE 754 numeric values.
8866 * - The boolean false value is converted to the string false.
8867 * The boolean true value is converted to the string true.
8869 * If the argument is omitted, it defaults to a node-set with the
8870 * context node as its only member.
8873 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8874 xmlXPathObjectPtr cur
;
8876 if (ctxt
== NULL
) return;
8879 xmlXPathCacheWrapString(ctxt
->context
,
8880 xmlXPathCastNodeToString(ctxt
->context
->node
)));
8885 cur
= valuePop(ctxt
);
8886 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8887 valuePush(ctxt
, xmlXPathCacheConvertString(ctxt
->context
, cur
));
8891 * xmlXPathStringLengthFunction:
8892 * @ctxt: the XPath Parser context
8893 * @nargs: the number of arguments
8895 * Implement the string-length() XPath function
8896 * number string-length(string?)
8897 * The string-length returns the number of characters in the string
8898 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8899 * the context node converted to a string, in other words the value
8900 * of the context node.
8903 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8904 xmlXPathObjectPtr cur
;
8907 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8909 if (ctxt
->context
->node
== NULL
) {
8910 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0));
8914 content
= xmlXPathCastNodeToString(ctxt
->context
->node
);
8915 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8916 xmlUTF8Strlen(content
)));
8923 CHECK_TYPE(XPATH_STRING
);
8924 cur
= valuePop(ctxt
);
8925 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8926 xmlUTF8Strlen(cur
->stringval
)));
8927 xmlXPathReleaseObject(ctxt
->context
, cur
);
8931 * xmlXPathConcatFunction:
8932 * @ctxt: the XPath Parser context
8933 * @nargs: the number of arguments
8935 * Implement the concat() XPath function
8936 * string concat(string, string, string*)
8937 * The concat function returns the concatenation of its arguments.
8940 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8941 xmlXPathObjectPtr cur
, newobj
;
8944 if (ctxt
== NULL
) return;
8950 cur
= valuePop(ctxt
);
8951 if ((cur
== NULL
) || (cur
->type
!= XPATH_STRING
)) {
8952 xmlXPathReleaseObject(ctxt
->context
, cur
);
8959 newobj
= valuePop(ctxt
);
8960 if ((newobj
== NULL
) || (newobj
->type
!= XPATH_STRING
)) {
8961 xmlXPathReleaseObject(ctxt
->context
, newobj
);
8962 xmlXPathReleaseObject(ctxt
->context
, cur
);
8963 XP_ERROR(XPATH_INVALID_TYPE
);
8965 tmp
= xmlStrcat(newobj
->stringval
, cur
->stringval
);
8966 newobj
->stringval
= cur
->stringval
;
8967 cur
->stringval
= tmp
;
8968 xmlXPathReleaseObject(ctxt
->context
, newobj
);
8971 valuePush(ctxt
, cur
);
8975 * xmlXPathContainsFunction:
8976 * @ctxt: the XPath Parser context
8977 * @nargs: the number of arguments
8979 * Implement the contains() XPath function
8980 * boolean contains(string, string)
8981 * The contains function returns true if the first argument string
8982 * contains the second argument string, and otherwise returns false.
8985 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8986 xmlXPathObjectPtr hay
, needle
;
8990 CHECK_TYPE(XPATH_STRING
);
8991 needle
= valuePop(ctxt
);
8993 hay
= valuePop(ctxt
);
8995 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
8996 xmlXPathReleaseObject(ctxt
->context
, hay
);
8997 xmlXPathReleaseObject(ctxt
->context
, needle
);
8998 XP_ERROR(XPATH_INVALID_TYPE
);
9000 if (xmlStrstr(hay
->stringval
, needle
->stringval
))
9001 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9003 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9004 xmlXPathReleaseObject(ctxt
->context
, hay
);
9005 xmlXPathReleaseObject(ctxt
->context
, needle
);
9009 * xmlXPathStartsWithFunction:
9010 * @ctxt: the XPath Parser context
9011 * @nargs: the number of arguments
9013 * Implement the starts-with() XPath function
9014 * boolean starts-with(string, string)
9015 * The starts-with function returns true if the first argument string
9016 * starts with the second argument string, and otherwise returns false.
9019 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9020 xmlXPathObjectPtr hay
, needle
;
9025 CHECK_TYPE(XPATH_STRING
);
9026 needle
= valuePop(ctxt
);
9028 hay
= valuePop(ctxt
);
9030 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9031 xmlXPathReleaseObject(ctxt
->context
, hay
);
9032 xmlXPathReleaseObject(ctxt
->context
, needle
);
9033 XP_ERROR(XPATH_INVALID_TYPE
);
9035 n
= xmlStrlen(needle
->stringval
);
9036 if (xmlStrncmp(hay
->stringval
, needle
->stringval
, n
))
9037 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9039 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9040 xmlXPathReleaseObject(ctxt
->context
, hay
);
9041 xmlXPathReleaseObject(ctxt
->context
, needle
);
9045 * xmlXPathSubstringFunction:
9046 * @ctxt: the XPath Parser context
9047 * @nargs: the number of arguments
9049 * Implement the substring() XPath function
9050 * string substring(string, number, number?)
9051 * The substring function returns the substring of the first argument
9052 * starting at the position specified in the second argument with
9053 * length specified in the third argument. For example,
9054 * substring("12345",2,3) returns "234". If the third argument is not
9055 * specified, it returns the substring starting at the position specified
9056 * in the second argument and continuing to the end of the string. For
9057 * example, substring("12345",2) returns "2345". More precisely, each
9058 * character in the string (see [3.6 Strings]) is considered to have a
9059 * numeric position: the position of the first character is 1, the position
9060 * of the second character is 2 and so on. The returned substring contains
9061 * those characters for which the position of the character is greater than
9062 * or equal to the second argument and, if the third argument is specified,
9063 * less than the sum of the second and third arguments; the comparisons
9064 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9065 * - substring("12345", 1.5, 2.6) returns "234"
9066 * - substring("12345", 0, 3) returns "12"
9067 * - substring("12345", 0 div 0, 3) returns ""
9068 * - substring("12345", 1, 0 div 0) returns ""
9069 * - substring("12345", -42, 1 div 0) returns "12345"
9070 * - substring("12345", -1 div 0, 1 div 0) returns ""
9073 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9074 xmlXPathObjectPtr str
, start
, len
;
9076 int i
= 1, j
= INT_MAX
;
9085 * take care of possible last (position) argument
9089 CHECK_TYPE(XPATH_NUMBER
);
9090 len
= valuePop(ctxt
);
9092 xmlXPathReleaseObject(ctxt
->context
, len
);
9096 CHECK_TYPE(XPATH_NUMBER
);
9097 start
= valuePop(ctxt
);
9098 in
= start
->floatval
;
9099 xmlXPathReleaseObject(ctxt
->context
, start
);
9101 CHECK_TYPE(XPATH_STRING
);
9102 str
= valuePop(ctxt
);
9104 if (!(in
< INT_MAX
)) { /* Logical NOT to handle NaNs */
9106 } else if (in
>= 1.0) {
9108 if (in
- floor(in
) >= 0.5)
9113 double rin
, rle
, end
;
9116 if (in
- rin
>= 0.5)
9120 if (le
- rle
>= 0.5)
9124 if (!(end
>= 1.0)) { /* Logical NOT to handle NaNs */
9126 } else if (end
< INT_MAX
) {
9132 xmlChar
*ret
= xmlUTF8Strsub(str
->stringval
, i
- 1, j
- i
);
9133 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, ret
));
9136 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
9139 xmlXPathReleaseObject(ctxt
->context
, str
);
9143 * xmlXPathSubstringBeforeFunction:
9144 * @ctxt: the XPath Parser context
9145 * @nargs: the number of arguments
9147 * Implement the substring-before() XPath function
9148 * string substring-before(string, string)
9149 * The substring-before function returns the substring of the first
9150 * argument string that precedes the first occurrence of the second
9151 * argument string in the first argument string, or the empty string
9152 * if the first argument string does not contain the second argument
9153 * string. For example, substring-before("1999/04/01","/") returns 1999.
9156 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9157 xmlXPathObjectPtr str
;
9158 xmlXPathObjectPtr find
;
9160 const xmlChar
*point
;
9165 find
= valuePop(ctxt
);
9167 str
= valuePop(ctxt
);
9169 target
= xmlBufCreate();
9171 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9173 offset
= point
- str
->stringval
;
9174 xmlBufAdd(target
, str
->stringval
, offset
);
9176 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9177 xmlBufContent(target
)));
9180 xmlXPathReleaseObject(ctxt
->context
, str
);
9181 xmlXPathReleaseObject(ctxt
->context
, find
);
9185 * xmlXPathSubstringAfterFunction:
9186 * @ctxt: the XPath Parser context
9187 * @nargs: the number of arguments
9189 * Implement the substring-after() XPath function
9190 * string substring-after(string, string)
9191 * The substring-after function returns the substring of the first
9192 * argument string that follows the first occurrence of the second
9193 * argument string in the first argument string, or the empty stringi
9194 * if the first argument string does not contain the second argument
9195 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9196 * and substring-after("1999/04/01","19") returns 99/04/01.
9199 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9200 xmlXPathObjectPtr str
;
9201 xmlXPathObjectPtr find
;
9203 const xmlChar
*point
;
9208 find
= valuePop(ctxt
);
9210 str
= valuePop(ctxt
);
9212 target
= xmlBufCreate();
9214 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9216 offset
= point
- str
->stringval
+ xmlStrlen(find
->stringval
);
9217 xmlBufAdd(target
, &str
->stringval
[offset
],
9218 xmlStrlen(str
->stringval
) - offset
);
9220 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9221 xmlBufContent(target
)));
9224 xmlXPathReleaseObject(ctxt
->context
, str
);
9225 xmlXPathReleaseObject(ctxt
->context
, find
);
9229 * xmlXPathNormalizeFunction:
9230 * @ctxt: the XPath Parser context
9231 * @nargs: the number of arguments
9233 * Implement the normalize-space() XPath function
9234 * string normalize-space(string?)
9235 * The normalize-space function returns the argument string with white
9236 * space normalized by stripping leading and trailing whitespace
9237 * and replacing sequences of whitespace characters by a single
9238 * space. Whitespace characters are the same allowed by the S production
9239 * in XML. If the argument is omitted, it defaults to the context
9240 * node converted to a string, in other words the value of the context node.
9243 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9244 xmlChar
*source
, *target
;
9247 if (ctxt
== NULL
) return;
9249 /* Use current context node */
9251 xmlXPathCacheWrapString(ctxt
->context
,
9252 xmlXPathCastNodeToString(ctxt
->context
->node
)));
9258 CHECK_TYPE(XPATH_STRING
);
9259 source
= ctxt
->value
->stringval
;
9264 /* Skip leading whitespaces */
9265 while (IS_BLANK_CH(*source
))
9268 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9271 if (IS_BLANK_CH(*source
)) {
9278 *target
++ = *source
;
9286 * xmlXPathTranslateFunction:
9287 * @ctxt: the XPath Parser context
9288 * @nargs: the number of arguments
9290 * Implement the translate() XPath function
9291 * string translate(string, string, string)
9292 * The translate function returns the first argument string with
9293 * occurrences of characters in the second argument string replaced
9294 * by the character at the corresponding position in the third argument
9295 * string. For example, translate("bar","abc","ABC") returns the string
9296 * BAr. If there is a character in the second argument string with no
9297 * character at a corresponding position in the third argument string
9298 * (because the second argument string is longer than the third argument
9299 * string), then occurrences of that character in the first argument
9300 * string are removed. For example, translate("--aaa--","abc-","ABC")
9301 * returns "AAA". If a character occurs more than once in second
9302 * argument string, then the first occurrence determines the replacement
9303 * character. If the third argument string is longer than the second
9304 * argument string, then excess characters are ignored.
9307 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9308 xmlXPathObjectPtr str
;
9309 xmlXPathObjectPtr from
;
9310 xmlXPathObjectPtr to
;
9314 const xmlChar
*point
;
9320 to
= valuePop(ctxt
);
9322 from
= valuePop(ctxt
);
9324 str
= valuePop(ctxt
);
9326 target
= xmlBufCreate();
9328 max
= xmlUTF8Strlen(to
->stringval
);
9329 for (cptr
= str
->stringval
; (ch
=*cptr
); ) {
9330 offset
= xmlUTF8Strloc(from
->stringval
, cptr
);
9333 point
= xmlUTF8Strpos(to
->stringval
, offset
);
9335 xmlBufAdd(target
, point
, xmlUTF8Strsize(point
, 1));
9338 xmlBufAdd(target
, cptr
, xmlUTF8Strsize(cptr
, 1));
9340 /* Step to next character in input */
9343 /* if not simple ascii, verify proper format */
9344 if ( (ch
& 0xc0) != 0xc0 ) {
9345 xmlGenericError(xmlGenericErrorContext
,
9346 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9347 /* not asserting an XPath error is probably better */
9350 /* then skip over remaining bytes for this char */
9351 while ( (ch
<<= 1) & 0x80 )
9352 if ( (*cptr
++ & 0xc0) != 0x80 ) {
9353 xmlGenericError(xmlGenericErrorContext
,
9354 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9355 /* not asserting an XPath error is probably better */
9358 if (ch
& 0x80) /* must have had error encountered */
9363 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9364 xmlBufContent(target
)));
9366 xmlXPathReleaseObject(ctxt
->context
, str
);
9367 xmlXPathReleaseObject(ctxt
->context
, from
);
9368 xmlXPathReleaseObject(ctxt
->context
, to
);
9372 * xmlXPathBooleanFunction:
9373 * @ctxt: the XPath Parser context
9374 * @nargs: the number of arguments
9376 * Implement the boolean() XPath function
9377 * boolean boolean(object)
9378 * The boolean function converts its argument to a boolean as follows:
9379 * - a number is true if and only if it is neither positive or
9380 * negative zero nor NaN
9381 * - a node-set is true if and only if it is non-empty
9382 * - a string is true if and only if its length is non-zero
9385 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9386 xmlXPathObjectPtr cur
;
9389 cur
= valuePop(ctxt
);
9390 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
9391 cur
= xmlXPathCacheConvertBoolean(ctxt
->context
, cur
);
9392 valuePush(ctxt
, cur
);
9396 * xmlXPathNotFunction:
9397 * @ctxt: the XPath Parser context
9398 * @nargs: the number of arguments
9400 * Implement the not() XPath function
9401 * boolean not(boolean)
9402 * The not function returns true if its argument is false,
9403 * and false otherwise.
9406 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9409 CHECK_TYPE(XPATH_BOOLEAN
);
9410 ctxt
->value
->boolval
= ! ctxt
->value
->boolval
;
9414 * xmlXPathTrueFunction:
9415 * @ctxt: the XPath Parser context
9416 * @nargs: the number of arguments
9418 * Implement the true() XPath function
9422 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9424 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9428 * xmlXPathFalseFunction:
9429 * @ctxt: the XPath Parser context
9430 * @nargs: the number of arguments
9432 * Implement the false() XPath function
9436 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9438 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9442 * xmlXPathLangFunction:
9443 * @ctxt: the XPath Parser context
9444 * @nargs: the number of arguments
9446 * Implement the lang() XPath function
9447 * boolean lang(string)
9448 * The lang function returns true or false depending on whether the
9449 * language of the context node as specified by xml:lang attributes
9450 * is the same as or is a sublanguage of the language specified by
9451 * the argument string. The language of the context node is determined
9452 * by the value of the xml:lang attribute on the context node, or, if
9453 * the context node has no xml:lang attribute, by the value of the
9454 * xml:lang attribute on the nearest ancestor of the context node that
9455 * has an xml:lang attribute. If there is no such attribute, then lang
9456 * returns false. If there is such an attribute, then lang returns
9457 * true if the attribute value is equal to the argument ignoring case,
9458 * or if there is some suffix starting with - such that the attribute
9459 * value is equal to the argument ignoring that suffix of the attribute
9460 * value and ignoring case.
9463 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9464 xmlXPathObjectPtr val
= NULL
;
9465 const xmlChar
*theLang
= NULL
;
9466 const xmlChar
*lang
;
9472 CHECK_TYPE(XPATH_STRING
);
9473 val
= valuePop(ctxt
);
9474 lang
= val
->stringval
;
9475 theLang
= xmlNodeGetLang(ctxt
->context
->node
);
9476 if ((theLang
!= NULL
) && (lang
!= NULL
)) {
9477 for (i
= 0;lang
[i
] != 0;i
++)
9478 if (toupper(lang
[i
]) != toupper(theLang
[i
]))
9480 if ((theLang
[i
] == 0) || (theLang
[i
] == '-'))
9484 if (theLang
!= NULL
)
9485 xmlFree((void *)theLang
);
9487 xmlXPathReleaseObject(ctxt
->context
, val
);
9488 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
9492 * xmlXPathNumberFunction:
9493 * @ctxt: the XPath Parser context
9494 * @nargs: the number of arguments
9496 * Implement the number() XPath function
9497 * number number(object?)
9500 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9501 xmlXPathObjectPtr cur
;
9504 if (ctxt
== NULL
) return;
9506 if (ctxt
->context
->node
== NULL
) {
9507 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0.0));
9509 xmlChar
* content
= xmlNodeGetContent(ctxt
->context
->node
);
9511 res
= xmlXPathStringEvalNumber(content
);
9512 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9519 cur
= valuePop(ctxt
);
9520 valuePush(ctxt
, xmlXPathCacheConvertNumber(ctxt
->context
, cur
));
9524 * xmlXPathSumFunction:
9525 * @ctxt: the XPath Parser context
9526 * @nargs: the number of arguments
9528 * Implement the sum() XPath function
9529 * number sum(node-set)
9530 * The sum function returns the sum of the values of the nodes in
9531 * the argument node-set.
9534 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9535 xmlXPathObjectPtr cur
;
9540 if ((ctxt
->value
== NULL
) ||
9541 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
9542 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
9543 XP_ERROR(XPATH_INVALID_TYPE
);
9544 cur
= valuePop(ctxt
);
9546 if ((cur
->nodesetval
!= NULL
) && (cur
->nodesetval
->nodeNr
!= 0)) {
9547 for (i
= 0; i
< cur
->nodesetval
->nodeNr
; i
++) {
9548 res
+= xmlXPathCastNodeToNumber(cur
->nodesetval
->nodeTab
[i
]);
9551 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9552 xmlXPathReleaseObject(ctxt
->context
, cur
);
9556 * xmlXPathFloorFunction:
9557 * @ctxt: the XPath Parser context
9558 * @nargs: the number of arguments
9560 * Implement the floor() XPath function
9561 * number floor(number)
9562 * The floor function returns the largest (closest to positive infinity)
9563 * number that is not greater than the argument and that is an integer.
9566 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9569 CHECK_TYPE(XPATH_NUMBER
);
9571 ctxt
->value
->floatval
= floor(ctxt
->value
->floatval
);
9575 * xmlXPathCeilingFunction:
9576 * @ctxt: the XPath Parser context
9577 * @nargs: the number of arguments
9579 * Implement the ceiling() XPath function
9580 * number ceiling(number)
9581 * The ceiling function returns the smallest (closest to negative infinity)
9582 * number that is not less than the argument and that is an integer.
9585 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9588 CHECK_TYPE(XPATH_NUMBER
);
9591 /* Work around buggy ceil() function on AIX */
9592 ctxt
->value
->floatval
= copysign(ceil(ctxt
->value
->floatval
), ctxt
->value
->floatval
);
9594 ctxt
->value
->floatval
= ceil(ctxt
->value
->floatval
);
9599 * xmlXPathRoundFunction:
9600 * @ctxt: the XPath Parser context
9601 * @nargs: the number of arguments
9603 * Implement the round() XPath function
9604 * number round(number)
9605 * The round function returns the number that is closest to the
9606 * argument and that is an integer. If there are two such numbers,
9607 * then the one that is closest to positive infinity is returned.
9610 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9615 CHECK_TYPE(XPATH_NUMBER
);
9617 f
= ctxt
->value
->floatval
;
9619 if ((f
>= -0.5) && (f
< 0.5)) {
9620 /* Handles negative zero. */
9621 ctxt
->value
->floatval
*= 0.0;
9624 double rounded
= floor(f
);
9625 if (f
- rounded
>= 0.5)
9627 ctxt
->value
->floatval
= rounded
;
9631 /************************************************************************
9635 ************************************************************************/
9638 * a few forward declarations since we use a recursive call based
9641 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
);
9642 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
);
9643 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
);
9644 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt
);
9645 static xmlChar
* xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
,
9649 * xmlXPathCurrentChar:
9650 * @ctxt: the XPath parser context
9651 * @cur: pointer to the beginning of the char
9652 * @len: pointer to the length of the char read
9654 * The current char value, if using UTF-8 this may actually span multiple
9655 * bytes in the input buffer.
9657 * Returns the current char value and its length
9661 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt
, int *len
) {
9671 * We are supposed to handle UTF8, check it's valid
9672 * From rfc2044: encoding of the Unicode values on UTF-8:
9674 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9675 * 0000 0000-0000 007F 0xxxxxxx
9676 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9677 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9679 * Check for the 0x110000 limit too
9683 if ((cur
[1] & 0xc0) != 0x80)
9684 goto encoding_error
;
9685 if ((c
& 0xe0) == 0xe0) {
9687 if ((cur
[2] & 0xc0) != 0x80)
9688 goto encoding_error
;
9689 if ((c
& 0xf0) == 0xf0) {
9690 if (((c
& 0xf8) != 0xf0) ||
9691 ((cur
[3] & 0xc0) != 0x80))
9692 goto encoding_error
;
9695 val
= (cur
[0] & 0x7) << 18;
9696 val
|= (cur
[1] & 0x3f) << 12;
9697 val
|= (cur
[2] & 0x3f) << 6;
9698 val
|= cur
[3] & 0x3f;
9702 val
= (cur
[0] & 0xf) << 12;
9703 val
|= (cur
[1] & 0x3f) << 6;
9704 val
|= cur
[2] & 0x3f;
9709 val
= (cur
[0] & 0x1f) << 6;
9710 val
|= cur
[1] & 0x3f;
9712 if (!IS_CHAR(val
)) {
9713 XP_ERROR0(XPATH_INVALID_CHAR_ERROR
);
9723 * If we detect an UTF8 error that probably means that the
9724 * input encoding didn't get properly advertised in the
9725 * declaration header. Report the error and switch the encoding
9726 * to ISO-Latin-1 (if you don't like this policy, just declare the
9730 XP_ERROR0(XPATH_ENCODING_ERROR
);
9734 * xmlXPathParseNCName:
9735 * @ctxt: the XPath Parser context
9737 * parse an XML namespace non qualified name.
9739 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9741 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9742 * CombiningChar | Extender
9744 * Returns the namespace name or NULL
9748 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt
) {
9753 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9755 * Accelerator for simple ASCII names
9758 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9759 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9762 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9763 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9764 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9765 (*in
== '_') || (*in
== '.') ||
9768 if ((*in
== ' ') || (*in
== '>') || (*in
== '/') ||
9769 (*in
== '[') || (*in
== ']') || (*in
== ':') ||
9770 (*in
== '@') || (*in
== '*')) {
9771 count
= in
- ctxt
->cur
;
9774 ret
= xmlStrndup(ctxt
->cur
, count
);
9779 return(xmlXPathParseNameComplex(ctxt
, 0));
9784 * xmlXPathParseQName:
9785 * @ctxt: the XPath Parser context
9786 * @prefix: a xmlChar **
9788 * parse an XML qualified name
9790 * [NS 5] QName ::= (Prefix ':')? LocalPart
9792 * [NS 6] Prefix ::= NCName
9794 * [NS 7] LocalPart ::= NCName
9796 * Returns the function returns the local part, and prefix is updated
9797 * to get the Prefix if any.
9801 xmlXPathParseQName(xmlXPathParserContextPtr ctxt
, xmlChar
**prefix
) {
9802 xmlChar
*ret
= NULL
;
9805 ret
= xmlXPathParseNCName(ctxt
);
9806 if (ret
&& CUR
== ':') {
9809 ret
= xmlXPathParseNCName(ctxt
);
9815 * xmlXPathParseName:
9816 * @ctxt: the XPath Parser context
9820 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9821 * CombiningChar | Extender
9823 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9825 * Returns the namespace name or NULL
9829 xmlXPathParseName(xmlXPathParserContextPtr ctxt
) {
9834 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9836 * Accelerator for simple ASCII names
9839 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9840 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9841 (*in
== '_') || (*in
== ':')) {
9843 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9844 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9845 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9846 (*in
== '_') || (*in
== '-') ||
9847 (*in
== ':') || (*in
== '.'))
9849 if ((*in
> 0) && (*in
< 0x80)) {
9850 count
= in
- ctxt
->cur
;
9851 if (count
> XML_MAX_NAME_LENGTH
) {
9853 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9855 ret
= xmlStrndup(ctxt
->cur
, count
);
9860 return(xmlXPathParseNameComplex(ctxt
, 1));
9864 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
, int qualified
) {
9865 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
9870 * Handler for more complex cases
9873 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
9874 (c
== '[') || (c
== ']') || (c
== '@') || /* accelerators */
9875 (c
== '*') || /* accelerators */
9876 (!IS_LETTER(c
) && (c
!= '_') &&
9877 ((!qualified
) || (c
!= ':')))) {
9881 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
9882 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
9883 (c
== '.') || (c
== '-') ||
9884 (c
== '_') || ((qualified
) && (c
== ':')) ||
9885 (IS_COMBINING(c
)) ||
9886 (IS_EXTENDER(c
)))) {
9887 COPY_BUF(l
,buf
,len
,c
);
9890 if (len
>= XML_MAX_NAMELEN
) {
9892 * Okay someone managed to make a huge name, so he's ready to pay
9893 * for the processing speed.
9898 if (len
> XML_MAX_NAME_LENGTH
) {
9899 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9901 buffer
= (xmlChar
*) xmlMallocAtomic(max
);
9902 if (buffer
== NULL
) {
9903 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
9905 memcpy(buffer
, buf
, len
);
9906 while ((IS_LETTER(c
)) || (IS_DIGIT(c
)) || /* test bigname.xml */
9907 (c
== '.') || (c
== '-') ||
9908 (c
== '_') || ((qualified
) && (c
== ':')) ||
9909 (IS_COMBINING(c
)) ||
9911 if (len
+ 10 > max
) {
9913 if (max
> XML_MAX_NAME_LENGTH
) {
9915 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9918 tmp
= (xmlChar
*) xmlRealloc(buffer
, max
);
9921 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
9925 COPY_BUF(l
,buffer
,len
,c
);
9935 return(xmlStrndup(buf
, len
));
9941 * xmlXPathStringEvalNumber:
9942 * @str: A string to scan
9944 * [30a] Float ::= Number ('e' Digits?)?
9946 * [30] Number ::= Digits ('.' Digits?)?
9948 * [31] Digits ::= [0-9]+
9950 * Compile a Number in the string
9951 * In complement of the Number expression, this function also handles
9952 * negative values : '-' Number.
9954 * Returns the double value.
9957 xmlXPathStringEvalNumber(const xmlChar
*str
) {
9958 const xmlChar
*cur
= str
;
9963 int is_exponent_negative
= 0;
9965 unsigned long tmp
= 0;
9968 if (cur
== NULL
) return(0);
9969 while (IS_BLANK_CH(*cur
)) cur
++;
9974 if ((*cur
!= '.') && ((*cur
< '0') || (*cur
> '9'))) {
9975 return(xmlXPathNAN
);
9980 * tmp/temp is a workaround against a gcc compiler bug
9981 * http://veillard.com/gcc.bug
9984 while ((*cur
>= '0') && (*cur
<= '9')) {
9989 temp
= (double) tmp
;
9994 while ((*cur
>= '0') && (*cur
<= '9')) {
9995 ret
= ret
* 10 + (*cur
- '0');
10002 int v
, frac
= 0, max
;
10003 double fraction
= 0;
10006 if (((*cur
< '0') || (*cur
> '9')) && (!ok
)) {
10007 return(xmlXPathNAN
);
10009 while (*cur
== '0') {
10013 max
= frac
+ MAX_FRAC
;
10014 while (((*cur
>= '0') && (*cur
<= '9')) && (frac
< max
)) {
10016 fraction
= fraction
* 10 + v
;
10020 fraction
/= pow(10.0, frac
);
10021 ret
= ret
+ fraction
;
10022 while ((*cur
>= '0') && (*cur
<= '9'))
10025 if ((*cur
== 'e') || (*cur
== 'E')) {
10028 is_exponent_negative
= 1;
10030 } else if (*cur
== '+') {
10033 while ((*cur
>= '0') && (*cur
<= '9')) {
10034 if (exponent
< 1000000)
10035 exponent
= exponent
* 10 + (*cur
- '0');
10039 while (IS_BLANK_CH(*cur
)) cur
++;
10040 if (*cur
!= 0) return(xmlXPathNAN
);
10041 if (isneg
) ret
= -ret
;
10042 if (is_exponent_negative
) exponent
= -exponent
;
10043 ret
*= pow(10.0, (double)exponent
);
10048 * xmlXPathCompNumber:
10049 * @ctxt: the XPath Parser context
10051 * [30] Number ::= Digits ('.' Digits?)?
10053 * [31] Digits ::= [0-9]+
10055 * Compile a Number, then push it on the stack
10059 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt
)
10064 int is_exponent_negative
= 0;
10065 xmlXPathObjectPtr num
;
10067 unsigned long tmp
= 0;
10072 if ((CUR
!= '.') && ((CUR
< '0') || (CUR
> '9'))) {
10073 XP_ERROR(XPATH_NUMBER_ERROR
);
10077 * tmp/temp is a workaround against a gcc compiler bug
10078 * http://veillard.com/gcc.bug
10081 while ((CUR
>= '0') && (CUR
<= '9')) {
10086 temp
= (double) tmp
;
10091 while ((CUR
>= '0') && (CUR
<= '9')) {
10092 ret
= ret
* 10 + (CUR
- '0');
10098 int v
, frac
= 0, max
;
10099 double fraction
= 0;
10102 if (((CUR
< '0') || (CUR
> '9')) && (!ok
)) {
10103 XP_ERROR(XPATH_NUMBER_ERROR
);
10105 while (CUR
== '0') {
10109 max
= frac
+ MAX_FRAC
;
10110 while ((CUR
>= '0') && (CUR
<= '9') && (frac
< max
)) {
10112 fraction
= fraction
* 10 + v
;
10116 fraction
/= pow(10.0, frac
);
10117 ret
= ret
+ fraction
;
10118 while ((CUR
>= '0') && (CUR
<= '9'))
10121 if ((CUR
== 'e') || (CUR
== 'E')) {
10124 is_exponent_negative
= 1;
10126 } else if (CUR
== '+') {
10129 while ((CUR
>= '0') && (CUR
<= '9')) {
10130 if (exponent
< 1000000)
10131 exponent
= exponent
* 10 + (CUR
- '0');
10134 if (is_exponent_negative
)
10135 exponent
= -exponent
;
10136 ret
*= pow(10.0, (double) exponent
);
10138 num
= xmlXPathCacheNewFloat(ctxt
->context
, ret
);
10140 ctxt
->error
= XPATH_MEMORY_ERROR
;
10141 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_NUMBER
, 0, 0, num
,
10143 xmlXPathReleaseObject(ctxt
->context
, num
);
10148 * xmlXPathParseLiteral:
10149 * @ctxt: the XPath Parser context
10153 * [29] Literal ::= '"' [^"]* '"'
10156 * Returns the value found or NULL in case of error
10159 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt
) {
10161 xmlChar
*ret
= NULL
;
10166 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10168 if (!IS_CHAR_CH(CUR
)) {
10169 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10171 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10174 } else if (CUR
== '\'') {
10177 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10179 if (!IS_CHAR_CH(CUR
)) {
10180 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10182 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10186 XP_ERRORNULL(XPATH_START_LITERAL_ERROR
);
10192 * xmlXPathCompLiteral:
10193 * @ctxt: the XPath Parser context
10195 * Parse a Literal and push it on the stack.
10197 * [29] Literal ::= '"' [^"]* '"'
10200 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10203 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt
) {
10205 xmlChar
*ret
= NULL
;
10206 xmlXPathObjectPtr lit
;
10211 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10213 if (!IS_CHAR_CH(CUR
)) {
10214 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10216 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10219 } else if (CUR
== '\'') {
10222 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10224 if (!IS_CHAR_CH(CUR
)) {
10225 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10227 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10231 XP_ERROR(XPATH_START_LITERAL_ERROR
);
10234 xmlXPathPErrMemory(ctxt
, NULL
);
10237 lit
= xmlXPathCacheNewString(ctxt
->context
, ret
);
10239 ctxt
->error
= XPATH_MEMORY_ERROR
;
10240 } else if (PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_STRING
, 0, 0, lit
,
10242 xmlXPathReleaseObject(ctxt
->context
, lit
);
10248 * xmlXPathCompVariableReference:
10249 * @ctxt: the XPath Parser context
10251 * Parse a VariableReference, evaluate it and push it on the stack.
10253 * The variable bindings consist of a mapping from variable names
10254 * to variable values. The value of a variable is an object, which can be
10255 * of any of the types that are possible for the value of an expression,
10256 * and may also be of additional types not specified here.
10258 * Early evaluation is possible since:
10259 * The variable bindings [...] used to evaluate a subexpression are
10260 * always the same as those used to evaluate the containing expression.
10262 * [36] VariableReference ::= '$' QName
10265 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt
) {
10271 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10274 name
= xmlXPathParseQName(ctxt
, &prefix
);
10275 if (name
== NULL
) {
10277 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10279 ctxt
->comp
->last
= -1;
10280 if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE
, 0, 0, 0, name
, prefix
) == -1) {
10285 if ((ctxt
->context
!= NULL
) && (ctxt
->context
->flags
& XML_XPATH_NOVAR
)) {
10286 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR
);
10291 * xmlXPathIsNodeType:
10292 * @name: a name string
10294 * Is the name given a NodeType one.
10296 * [38] NodeType ::= 'comment'
10298 * | 'processing-instruction'
10301 * Returns 1 if true 0 otherwise
10304 xmlXPathIsNodeType(const xmlChar
*name
) {
10308 if (xmlStrEqual(name
, BAD_CAST
"node"))
10310 if (xmlStrEqual(name
, BAD_CAST
"text"))
10312 if (xmlStrEqual(name
, BAD_CAST
"comment"))
10314 if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
10320 * xmlXPathCompFunctionCall:
10321 * @ctxt: the XPath Parser context
10323 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10324 * [17] Argument ::= Expr
10326 * Compile a function call, the evaluation of all arguments are
10327 * pushed on the stack
10330 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt
) {
10336 name
= xmlXPathParseQName(ctxt
, &prefix
);
10337 if (name
== NULL
) {
10339 XP_ERROR(XPATH_EXPR_ERROR
);
10343 if (prefix
== NULL
)
10344 xmlGenericError(xmlGenericErrorContext
, "Calling function %s\n",
10347 xmlGenericError(xmlGenericErrorContext
, "Calling function %s:%s\n",
10354 XP_ERROR(XPATH_EXPR_ERROR
);
10360 * Optimization for count(): we don't need the node-set to be sorted.
10362 if ((prefix
== NULL
) && (name
[0] == 'c') &&
10363 xmlStrEqual(name
, BAD_CAST
"count"))
10367 ctxt
->comp
->last
= -1;
10370 int op1
= ctxt
->comp
->last
;
10371 ctxt
->comp
->last
= -1;
10372 xmlXPathCompileExpr(ctxt
, sort
);
10373 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
10378 PUSH_BINARY_EXPR(XPATH_OP_ARG
, op1
, ctxt
->comp
->last
, 0, 0);
10380 if (CUR
== ')') break;
10384 XP_ERROR(XPATH_EXPR_ERROR
);
10390 if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION
, nbargs
, 0, 0, name
, prefix
) == -1) {
10399 * xmlXPathCompPrimaryExpr:
10400 * @ctxt: the XPath Parser context
10402 * [15] PrimaryExpr ::= VariableReference
10408 * Compile a primary expression.
10411 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt
) {
10413 if (CUR
== '$') xmlXPathCompVariableReference(ctxt
);
10414 else if (CUR
== '(') {
10417 xmlXPathCompileExpr(ctxt
, 1);
10420 XP_ERROR(XPATH_EXPR_ERROR
);
10424 } else if (IS_ASCII_DIGIT(CUR
) || (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10425 xmlXPathCompNumber(ctxt
);
10426 } else if ((CUR
== '\'') || (CUR
== '"')) {
10427 xmlXPathCompLiteral(ctxt
);
10429 xmlXPathCompFunctionCall(ctxt
);
10435 * xmlXPathCompFilterExpr:
10436 * @ctxt: the XPath Parser context
10438 * [20] FilterExpr ::= PrimaryExpr
10439 * | FilterExpr Predicate
10441 * Compile a filter expression.
10442 * Square brackets are used to filter expressions in the same way that
10443 * they are used in location paths. It is an error if the expression to
10444 * be filtered does not evaluate to a node-set. The context node list
10445 * used for evaluating the expression in square brackets is the node-set
10446 * to be filtered listed in document order.
10450 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt
) {
10451 xmlXPathCompPrimaryExpr(ctxt
);
10455 while (CUR
== '[') {
10456 xmlXPathCompPredicate(ctxt
, 1);
10464 * xmlXPathScanName:
10465 * @ctxt: the XPath Parser context
10467 * Trickery: parse an XML name but without consuming the input flow
10468 * Needed to avoid insanity in the parser state.
10470 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10471 * CombiningChar | Extender
10473 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10475 * [6] Names ::= Name (S Name)*
10477 * Returns the Name parsed or NULL
10481 xmlXPathScanName(xmlXPathParserContextPtr ctxt
) {
10484 const xmlChar
*cur
;
10490 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
10491 (!IS_LETTER(c
) && (c
!= '_') &&
10496 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
10497 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
10498 (c
== '.') || (c
== '-') ||
10499 (c
== '_') || (c
== ':') ||
10500 (IS_COMBINING(c
)) ||
10501 (IS_EXTENDER(c
)))) {
10505 ret
= xmlStrndup(cur
, ctxt
->cur
- cur
);
10511 * xmlXPathCompPathExpr:
10512 * @ctxt: the XPath Parser context
10514 * [19] PathExpr ::= LocationPath
10516 * | FilterExpr '/' RelativeLocationPath
10517 * | FilterExpr '//' RelativeLocationPath
10519 * Compile a path expression.
10520 * The / operator and // operators combine an arbitrary expression
10521 * and a relative location path. It is an error if the expression
10522 * does not evaluate to a node-set.
10523 * The / operator does composition in the same way as when / is
10524 * used in a location path. As in location paths, // is short for
10525 * /descendant-or-self::node()/.
10529 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt
) {
10530 int lc
= 1; /* Should we branch to LocationPath ? */
10531 xmlChar
*name
= NULL
; /* we may have to preparse a name to find out */
10534 if ((CUR
== '$') || (CUR
== '(') ||
10535 (IS_ASCII_DIGIT(CUR
)) ||
10536 (CUR
== '\'') || (CUR
== '"') ||
10537 (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10539 } else if (CUR
== '*') {
10540 /* relative or absolute location path */
10542 } else if (CUR
== '/') {
10543 /* relative or absolute location path */
10545 } else if (CUR
== '@') {
10546 /* relative abbreviated attribute location path */
10548 } else if (CUR
== '.') {
10549 /* relative abbreviated attribute location path */
10553 * Problem is finding if we have a name here whether it's:
10555 * - a function call in which case it's followed by '('
10556 * - an axis in which case it's followed by ':'
10558 * We do an a priori analysis here rather than having to
10559 * maintain parsed token content through the recursive function
10560 * calls. This looks uglier but makes the code easier to
10561 * read/write/debug.
10564 name
= xmlXPathScanName(ctxt
);
10565 if ((name
!= NULL
) && (xmlStrstr(name
, (xmlChar
*) "::") != NULL
)) {
10567 xmlGenericError(xmlGenericErrorContext
,
10568 "PathExpr: Axis\n");
10572 } else if (name
!= NULL
) {
10573 int len
=xmlStrlen(name
);
10576 while (NXT(len
) != 0) {
10577 if (NXT(len
) == '/') {
10580 xmlGenericError(xmlGenericErrorContext
,
10581 "PathExpr: AbbrRelLocation\n");
10585 } else if (IS_BLANK_CH(NXT(len
))) {
10586 /* ignore blanks */
10588 } else if (NXT(len
) == ':') {
10590 xmlGenericError(xmlGenericErrorContext
,
10591 "PathExpr: AbbrRelLocation\n");
10595 } else if ((NXT(len
) == '(')) {
10596 /* Node Type or Function */
10597 if (xmlXPathIsNodeType(name
)) {
10599 xmlGenericError(xmlGenericErrorContext
,
10600 "PathExpr: Type search\n");
10603 #ifdef LIBXML_XPTR_LOCS_ENABLED
10604 } else if (ctxt
->xptr
&&
10605 xmlStrEqual(name
, BAD_CAST
"range-to")) {
10610 xmlGenericError(xmlGenericErrorContext
,
10611 "PathExpr: function call\n");
10616 } else if ((NXT(len
) == '[')) {
10619 xmlGenericError(xmlGenericErrorContext
,
10620 "PathExpr: AbbrRelLocation\n");
10624 } else if ((NXT(len
) == '<') || (NXT(len
) == '>') ||
10625 (NXT(len
) == '=')) {
10634 if (NXT(len
) == 0) {
10636 xmlGenericError(xmlGenericErrorContext
,
10637 "PathExpr: AbbrRelLocation\n");
10644 /* make sure all cases are covered explicitly */
10645 XP_ERROR(XPATH_EXPR_ERROR
);
10651 PUSH_LEAVE_EXPR(XPATH_OP_ROOT
, 0, 0);
10653 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10655 xmlXPathCompLocationPath(ctxt
);
10657 xmlXPathCompFilterExpr(ctxt
);
10659 if ((CUR
== '/') && (NXT(1) == '/')) {
10663 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
10664 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
10666 xmlXPathCompRelativeLocationPath(ctxt
);
10667 } else if (CUR
== '/') {
10668 xmlXPathCompRelativeLocationPath(ctxt
);
10675 * xmlXPathCompUnionExpr:
10676 * @ctxt: the XPath Parser context
10678 * [18] UnionExpr ::= PathExpr
10679 * | UnionExpr '|' PathExpr
10681 * Compile an union expression.
10685 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt
) {
10686 xmlXPathCompPathExpr(ctxt
);
10689 while (CUR
== '|') {
10690 int op1
= ctxt
->comp
->last
;
10691 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10695 xmlXPathCompPathExpr(ctxt
);
10697 PUSH_BINARY_EXPR(XPATH_OP_UNION
, op1
, ctxt
->comp
->last
, 0, 0);
10704 * xmlXPathCompUnaryExpr:
10705 * @ctxt: the XPath Parser context
10707 * [27] UnaryExpr ::= UnionExpr
10710 * Compile an unary expression.
10714 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt
) {
10719 while (CUR
== '-') {
10726 xmlXPathCompUnionExpr(ctxt
);
10730 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 2, 0);
10732 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 3, 0);
10737 * xmlXPathCompMultiplicativeExpr:
10738 * @ctxt: the XPath Parser context
10740 * [26] MultiplicativeExpr ::= UnaryExpr
10741 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10742 * | MultiplicativeExpr 'div' UnaryExpr
10743 * | MultiplicativeExpr 'mod' UnaryExpr
10744 * [34] MultiplyOperator ::= '*'
10746 * Compile an Additive expression.
10750 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt
) {
10751 xmlXPathCompUnaryExpr(ctxt
);
10754 while ((CUR
== '*') ||
10755 ((CUR
== 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10756 ((CUR
== 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10758 int op1
= ctxt
->comp
->last
;
10763 } else if (CUR
== 'd') {
10766 } else if (CUR
== 'm') {
10771 xmlXPathCompUnaryExpr(ctxt
);
10773 PUSH_BINARY_EXPR(XPATH_OP_MULT
, op1
, ctxt
->comp
->last
, op
, 0);
10779 * xmlXPathCompAdditiveExpr:
10780 * @ctxt: the XPath Parser context
10782 * [25] AdditiveExpr ::= MultiplicativeExpr
10783 * | AdditiveExpr '+' MultiplicativeExpr
10784 * | AdditiveExpr '-' MultiplicativeExpr
10786 * Compile an Additive expression.
10790 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt
) {
10792 xmlXPathCompMultiplicativeExpr(ctxt
);
10795 while ((CUR
== '+') || (CUR
== '-')) {
10797 int op1
= ctxt
->comp
->last
;
10799 if (CUR
== '+') plus
= 1;
10803 xmlXPathCompMultiplicativeExpr(ctxt
);
10805 PUSH_BINARY_EXPR(XPATH_OP_PLUS
, op1
, ctxt
->comp
->last
, plus
, 0);
10811 * xmlXPathCompRelationalExpr:
10812 * @ctxt: the XPath Parser context
10814 * [24] RelationalExpr ::= AdditiveExpr
10815 * | RelationalExpr '<' AdditiveExpr
10816 * | RelationalExpr '>' AdditiveExpr
10817 * | RelationalExpr '<=' AdditiveExpr
10818 * | RelationalExpr '>=' AdditiveExpr
10820 * A <= B > C is allowed ? Answer from James, yes with
10821 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10822 * which is basically what got implemented.
10824 * Compile a Relational expression, then push the result
10829 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt
) {
10830 xmlXPathCompAdditiveExpr(ctxt
);
10833 while ((CUR
== '<') || (CUR
== '>')) {
10835 int op1
= ctxt
->comp
->last
;
10837 if (CUR
== '<') inf
= 1;
10839 if (NXT(1) == '=') strict
= 0;
10844 xmlXPathCompAdditiveExpr(ctxt
);
10846 PUSH_BINARY_EXPR(XPATH_OP_CMP
, op1
, ctxt
->comp
->last
, inf
, strict
);
10852 * xmlXPathCompEqualityExpr:
10853 * @ctxt: the XPath Parser context
10855 * [23] EqualityExpr ::= RelationalExpr
10856 * | EqualityExpr '=' RelationalExpr
10857 * | EqualityExpr '!=' RelationalExpr
10859 * A != B != C is allowed ? Answer from James, yes with
10860 * (RelationalExpr = RelationalExpr) = RelationalExpr
10861 * (RelationalExpr != RelationalExpr) != RelationalExpr
10862 * which is basically what got implemented.
10864 * Compile an Equality expression.
10868 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt
) {
10869 xmlXPathCompRelationalExpr(ctxt
);
10872 while ((CUR
== '=') || ((CUR
== '!') && (NXT(1) == '='))) {
10874 int op1
= ctxt
->comp
->last
;
10876 if (CUR
== '=') eq
= 1;
10881 xmlXPathCompRelationalExpr(ctxt
);
10883 PUSH_BINARY_EXPR(XPATH_OP_EQUAL
, op1
, ctxt
->comp
->last
, eq
, 0);
10889 * xmlXPathCompAndExpr:
10890 * @ctxt: the XPath Parser context
10892 * [22] AndExpr ::= EqualityExpr
10893 * | AndExpr 'and' EqualityExpr
10895 * Compile an AND expression.
10899 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt
) {
10900 xmlXPathCompEqualityExpr(ctxt
);
10903 while ((CUR
== 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10904 int op1
= ctxt
->comp
->last
;
10907 xmlXPathCompEqualityExpr(ctxt
);
10909 PUSH_BINARY_EXPR(XPATH_OP_AND
, op1
, ctxt
->comp
->last
, 0, 0);
10915 * xmlXPathCompileExpr:
10916 * @ctxt: the XPath Parser context
10918 * [14] Expr ::= OrExpr
10919 * [21] OrExpr ::= AndExpr
10920 * | OrExpr 'or' AndExpr
10922 * Parse and compile an expression
10925 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
) {
10926 xmlXPathContextPtr xpctxt
= ctxt
->context
;
10928 if (xpctxt
!= NULL
) {
10929 if (xpctxt
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
10930 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED
);
10932 * Parsing a single '(' pushes about 10 functions on the call stack
10933 * before recursing!
10935 xpctxt
->depth
+= 10;
10938 xmlXPathCompAndExpr(ctxt
);
10941 while ((CUR
== 'o') && (NXT(1) == 'r')) {
10942 int op1
= ctxt
->comp
->last
;
10945 xmlXPathCompAndExpr(ctxt
);
10947 PUSH_BINARY_EXPR(XPATH_OP_OR
, op1
, ctxt
->comp
->last
, 0, 0);
10950 if ((sort
) && (ctxt
->comp
->steps
[ctxt
->comp
->last
].op
!= XPATH_OP_VALUE
)) {
10951 /* more ops could be optimized too */
10953 * This is the main place to eliminate sorting for
10954 * operations which don't require a sorted node-set.
10957 PUSH_UNARY_EXPR(XPATH_OP_SORT
, ctxt
->comp
->last
, 0, 0);
10960 if (xpctxt
!= NULL
)
10961 xpctxt
->depth
-= 10;
10965 * xmlXPathCompPredicate:
10966 * @ctxt: the XPath Parser context
10967 * @filter: act as a filter
10969 * [8] Predicate ::= '[' PredicateExpr ']'
10970 * [9] PredicateExpr ::= Expr
10972 * Compile a predicate expression
10975 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
) {
10976 int op1
= ctxt
->comp
->last
;
10980 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
10985 ctxt
->comp
->last
= -1;
10987 * This call to xmlXPathCompileExpr() will deactivate sorting
10988 * of the predicate result.
10989 * TODO: Sorting is still activated for filters, since I'm not
10990 * sure if needed. Normally sorting should not be needed, since
10991 * a filter can only diminish the number of items in a sequence,
10992 * but won't change its order; so if the initial sequence is sorted,
10993 * subsequent sorting is not needed.
10996 xmlXPathCompileExpr(ctxt
, 0);
10998 xmlXPathCompileExpr(ctxt
, 1);
11002 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11006 PUSH_BINARY_EXPR(XPATH_OP_FILTER
, op1
, ctxt
->comp
->last
, 0, 0);
11008 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE
, op1
, ctxt
->comp
->last
, 0, 0);
11015 * xmlXPathCompNodeTest:
11016 * @ctxt: the XPath Parser context
11017 * @test: pointer to a xmlXPathTestVal
11018 * @type: pointer to a xmlXPathTypeVal
11019 * @prefix: placeholder for a possible name prefix
11021 * [7] NodeTest ::= NameTest
11022 * | NodeType '(' ')'
11023 * | 'processing-instruction' '(' Literal ')'
11025 * [37] NameTest ::= '*'
11028 * [38] NodeType ::= 'comment'
11030 * | 'processing-instruction'
11033 * Returns the name found and updates @test, @type and @prefix appropriately
11036 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt
, xmlXPathTestVal
*test
,
11037 xmlXPathTypeVal
*type
, xmlChar
**prefix
,
11041 if ((test
== NULL
) || (type
== NULL
) || (prefix
== NULL
)) {
11045 *type
= (xmlXPathTypeVal
) 0;
11046 *test
= (xmlXPathTestVal
) 0;
11050 if ((name
== NULL
) && (CUR
== '*')) {
11055 *test
= NODE_TEST_ALL
;
11060 name
= xmlXPathParseNCName(ctxt
);
11061 if (name
== NULL
) {
11062 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11065 blanks
= IS_BLANK_CH(CUR
);
11070 * NodeType or PI search
11072 if (xmlStrEqual(name
, BAD_CAST
"comment"))
11073 *type
= NODE_TYPE_COMMENT
;
11074 else if (xmlStrEqual(name
, BAD_CAST
"node"))
11075 *type
= NODE_TYPE_NODE
;
11076 else if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
11077 *type
= NODE_TYPE_PI
;
11078 else if (xmlStrEqual(name
, BAD_CAST
"text"))
11079 *type
= NODE_TYPE_TEXT
;
11083 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11086 *test
= NODE_TEST_TYPE
;
11089 if (*type
== NODE_TYPE_PI
) {
11091 * Specific case: search a PI by name.
11097 name
= xmlXPathParseLiteral(ctxt
);
11098 if (name
== NULL
) {
11099 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11101 *test
= NODE_TEST_PI
;
11108 XP_ERRORNULL(XPATH_UNCLOSED_ERROR
);
11113 *test
= NODE_TEST_NAME
;
11114 if ((!blanks
) && (CUR
== ':')) {
11118 * Since currently the parser context don't have a
11119 * namespace list associated:
11120 * The namespace name for this prefix can be computed
11121 * only at evaluation time. The compilation is done
11122 * outside of any context.
11125 *prefix
= xmlXPathNsLookup(ctxt
->context
, name
);
11128 if (*prefix
== NULL
) {
11129 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
11140 *test
= NODE_TEST_ALL
;
11144 name
= xmlXPathParseNCName(ctxt
);
11145 if (name
== NULL
) {
11146 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11153 * xmlXPathIsAxisName:
11154 * @name: a preparsed name token
11156 * [6] AxisName ::= 'ancestor'
11157 * | 'ancestor-or-self'
11161 * | 'descendant-or-self'
11163 * | 'following-sibling'
11167 * | 'preceding-sibling'
11170 * Returns the axis or 0
11172 static xmlXPathAxisVal
11173 xmlXPathIsAxisName(const xmlChar
*name
) {
11174 xmlXPathAxisVal ret
= (xmlXPathAxisVal
) 0;
11177 if (xmlStrEqual(name
, BAD_CAST
"ancestor"))
11178 ret
= AXIS_ANCESTOR
;
11179 if (xmlStrEqual(name
, BAD_CAST
"ancestor-or-self"))
11180 ret
= AXIS_ANCESTOR_OR_SELF
;
11181 if (xmlStrEqual(name
, BAD_CAST
"attribute"))
11182 ret
= AXIS_ATTRIBUTE
;
11185 if (xmlStrEqual(name
, BAD_CAST
"child"))
11189 if (xmlStrEqual(name
, BAD_CAST
"descendant"))
11190 ret
= AXIS_DESCENDANT
;
11191 if (xmlStrEqual(name
, BAD_CAST
"descendant-or-self"))
11192 ret
= AXIS_DESCENDANT_OR_SELF
;
11195 if (xmlStrEqual(name
, BAD_CAST
"following"))
11196 ret
= AXIS_FOLLOWING
;
11197 if (xmlStrEqual(name
, BAD_CAST
"following-sibling"))
11198 ret
= AXIS_FOLLOWING_SIBLING
;
11201 if (xmlStrEqual(name
, BAD_CAST
"namespace"))
11202 ret
= AXIS_NAMESPACE
;
11205 if (xmlStrEqual(name
, BAD_CAST
"parent"))
11207 if (xmlStrEqual(name
, BAD_CAST
"preceding"))
11208 ret
= AXIS_PRECEDING
;
11209 if (xmlStrEqual(name
, BAD_CAST
"preceding-sibling"))
11210 ret
= AXIS_PRECEDING_SIBLING
;
11213 if (xmlStrEqual(name
, BAD_CAST
"self"))
11221 * xmlXPathCompStep:
11222 * @ctxt: the XPath Parser context
11224 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11225 * | AbbreviatedStep
11227 * [12] AbbreviatedStep ::= '.' | '..'
11229 * [5] AxisSpecifier ::= AxisName '::'
11230 * | AbbreviatedAxisSpecifier
11232 * [13] AbbreviatedAxisSpecifier ::= '@'?
11234 * Modified for XPtr range support as:
11236 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11237 * | AbbreviatedStep
11238 * | 'range-to' '(' Expr ')' Predicate*
11240 * Compile one step in a Location Path
11241 * A location step of . is short for self::node(). This is
11242 * particularly useful in conjunction with //. For example, the
11243 * location path .//para is short for
11244 * self::node()/descendant-or-self::node()/child::para
11245 * and so will select all para descendant elements of the context
11247 * Similarly, a location step of .. is short for parent::node().
11248 * For example, ../title is short for parent::node()/child::title
11249 * and so will select the title children of the parent of the context
11253 xmlXPathCompStep(xmlXPathParserContextPtr ctxt
) {
11254 #ifdef LIBXML_XPTR_LOCS_ENABLED
11260 if ((CUR
== '.') && (NXT(1) == '.')) {
11263 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_PARENT
,
11264 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11265 } else if (CUR
== '.') {
11269 xmlChar
*name
= NULL
;
11270 xmlChar
*prefix
= NULL
;
11271 xmlXPathTestVal test
= (xmlXPathTestVal
) 0;
11272 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) 0;
11273 xmlXPathTypeVal type
= (xmlXPathTypeVal
) 0;
11277 * The modification needed for XPointer change to the production
11279 #ifdef LIBXML_XPTR_LOCS_ENABLED
11281 name
= xmlXPathParseNCName(ctxt
);
11282 if ((name
!= NULL
) && (xmlStrEqual(name
, BAD_CAST
"range-to"))) {
11283 op2
= ctxt
->comp
->last
;
11287 XP_ERROR(XPATH_EXPR_ERROR
);
11292 xmlXPathCompileExpr(ctxt
, 1);
11293 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11298 XP_ERROR(XPATH_EXPR_ERROR
);
11302 goto eval_predicates
;
11310 name
= xmlXPathParseNCName(ctxt
);
11311 if (name
!= NULL
) {
11312 axis
= xmlXPathIsAxisName(name
);
11315 if ((CUR
== ':') && (NXT(1) == ':')) {
11320 /* an element name can conflict with an axis one :-\ */
11326 } else if (CUR
== '@') {
11328 axis
= AXIS_ATTRIBUTE
;
11334 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
11339 name
= xmlXPathCompNodeTest(ctxt
, &test
, &type
, &prefix
, name
);
11343 if ((prefix
!= NULL
) && (ctxt
->context
!= NULL
) &&
11344 (ctxt
->context
->flags
& XML_XPATH_CHECKNS
)) {
11345 if (xmlXPathNsLookup(ctxt
->context
, prefix
) == NULL
) {
11346 xmlXPathErr(ctxt
, XPATH_UNDEF_PREFIX_ERROR
);
11350 xmlGenericError(xmlGenericErrorContext
,
11351 "Basis : computing new set\n");
11355 xmlGenericError(xmlGenericErrorContext
, "Basis : ");
11356 if (ctxt
->value
== NULL
)
11357 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11358 else if (ctxt
->value
->nodesetval
== NULL
)
11359 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11361 xmlGenericErrorContextNodeSet(stdout
, ctxt
->value
->nodesetval
);
11364 #ifdef LIBXML_XPTR_LOCS_ENABLED
11367 op1
= ctxt
->comp
->last
;
11368 ctxt
->comp
->last
= -1;
11371 while (CUR
== '[') {
11372 xmlXPathCompPredicate(ctxt
, 0);
11375 #ifdef LIBXML_XPTR_LOCS_ENABLED
11377 PUSH_BINARY_EXPR(XPATH_OP_RANGETO
, op2
, op1
, 0, 0);
11380 if (PUSH_FULL_EXPR(XPATH_OP_COLLECT
, op1
, ctxt
->comp
->last
, axis
,
11381 test
, type
, (void *)prefix
, (void *)name
) == -1) {
11387 xmlGenericError(xmlGenericErrorContext
, "Step : ");
11388 if (ctxt
->value
== NULL
)
11389 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11390 else if (ctxt
->value
->nodesetval
== NULL
)
11391 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11393 xmlGenericErrorContextNodeSet(xmlGenericErrorContext
,
11394 ctxt
->value
->nodesetval
);
11399 * xmlXPathCompRelativeLocationPath:
11400 * @ctxt: the XPath Parser context
11402 * [3] RelativeLocationPath ::= Step
11403 * | RelativeLocationPath '/' Step
11404 * | AbbreviatedRelativeLocationPath
11405 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11407 * Compile a relative location path.
11410 xmlXPathCompRelativeLocationPath
11411 (xmlXPathParserContextPtr ctxt
) {
11413 if ((CUR
== '/') && (NXT(1) == '/')) {
11416 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11417 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11418 } else if (CUR
== '/') {
11422 xmlXPathCompStep(ctxt
);
11425 while (CUR
== '/') {
11426 if ((CUR
== '/') && (NXT(1) == '/')) {
11429 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11430 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11431 xmlXPathCompStep(ctxt
);
11432 } else if (CUR
== '/') {
11435 xmlXPathCompStep(ctxt
);
11442 * xmlXPathCompLocationPath:
11443 * @ctxt: the XPath Parser context
11445 * [1] LocationPath ::= RelativeLocationPath
11446 * | AbsoluteLocationPath
11447 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11448 * | AbbreviatedAbsoluteLocationPath
11449 * [10] AbbreviatedAbsoluteLocationPath ::=
11450 * '//' RelativeLocationPath
11452 * Compile a location path
11454 * // is short for /descendant-or-self::node()/. For example,
11455 * //para is short for /descendant-or-self::node()/child::para and
11456 * so will select any para element in the document (even a para element
11457 * that is a document element will be selected by //para since the
11458 * document element node is a child of the root node); div//para is
11459 * short for div/descendant-or-self::node()/child::para and so will
11460 * select all para descendants of div children.
11463 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
) {
11466 xmlXPathCompRelativeLocationPath(ctxt
);
11468 while (CUR
== '/') {
11469 if ((CUR
== '/') && (NXT(1) == '/')) {
11472 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11473 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11474 xmlXPathCompRelativeLocationPath(ctxt
);
11475 } else if (CUR
== '/') {
11479 ((IS_ASCII_LETTER(CUR
)) || (CUR
== '_') || (CUR
== '.') ||
11480 (CUR
== '@') || (CUR
== '*')))
11481 xmlXPathCompRelativeLocationPath(ctxt
);
11488 /************************************************************************
11490 * XPath precompiled expression evaluation *
11492 ************************************************************************/
11495 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
);
11499 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op
,
11502 xmlGenericError(xmlGenericErrorContext
, "new step : ");
11503 switch (op
->value
) {
11504 case AXIS_ANCESTOR
:
11505 xmlGenericError(xmlGenericErrorContext
, "axis 'ancestors' ");
11507 case AXIS_ANCESTOR_OR_SELF
:
11508 xmlGenericError(xmlGenericErrorContext
,
11509 "axis 'ancestors-or-self' ");
11511 case AXIS_ATTRIBUTE
:
11512 xmlGenericError(xmlGenericErrorContext
, "axis 'attributes' ");
11515 xmlGenericError(xmlGenericErrorContext
, "axis 'child' ");
11517 case AXIS_DESCENDANT
:
11518 xmlGenericError(xmlGenericErrorContext
, "axis 'descendant' ");
11520 case AXIS_DESCENDANT_OR_SELF
:
11521 xmlGenericError(xmlGenericErrorContext
,
11522 "axis 'descendant-or-self' ");
11524 case AXIS_FOLLOWING
:
11525 xmlGenericError(xmlGenericErrorContext
, "axis 'following' ");
11527 case AXIS_FOLLOWING_SIBLING
:
11528 xmlGenericError(xmlGenericErrorContext
,
11529 "axis 'following-siblings' ");
11531 case AXIS_NAMESPACE
:
11532 xmlGenericError(xmlGenericErrorContext
, "axis 'namespace' ");
11535 xmlGenericError(xmlGenericErrorContext
, "axis 'parent' ");
11537 case AXIS_PRECEDING
:
11538 xmlGenericError(xmlGenericErrorContext
, "axis 'preceding' ");
11540 case AXIS_PRECEDING_SIBLING
:
11541 xmlGenericError(xmlGenericErrorContext
,
11542 "axis 'preceding-sibling' ");
11545 xmlGenericError(xmlGenericErrorContext
, "axis 'self' ");
11548 xmlGenericError(xmlGenericErrorContext
,
11549 " context contains %d nodes\n", nbNodes
);
11550 switch (op
->value2
) {
11551 case NODE_TEST_NONE
:
11552 xmlGenericError(xmlGenericErrorContext
,
11553 " searching for none !!!\n");
11555 case NODE_TEST_TYPE
:
11556 xmlGenericError(xmlGenericErrorContext
,
11557 " searching for type %d\n", op
->value3
);
11560 xmlGenericError(xmlGenericErrorContext
,
11561 " searching for PI !!!\n");
11563 case NODE_TEST_ALL
:
11564 xmlGenericError(xmlGenericErrorContext
,
11565 " searching for *\n");
11568 xmlGenericError(xmlGenericErrorContext
,
11569 " searching for namespace %s\n",
11572 case NODE_TEST_NAME
:
11573 xmlGenericError(xmlGenericErrorContext
,
11574 " searching for name %s\n", op
->value5
);
11576 xmlGenericError(xmlGenericErrorContext
,
11577 " with namespace %s\n", op
->value4
);
11580 xmlGenericError(xmlGenericErrorContext
, "Testing : ");
11582 #endif /* DEBUG_STEP */
11585 * xmlXPathNodeSetFilter:
11586 * @ctxt: the XPath Parser context
11587 * @set: the node set to filter
11588 * @filterOpIndex: the index of the predicate/filter op
11589 * @minPos: minimum position in the filtered set (1-based)
11590 * @maxPos: maximum position in the filtered set (1-based)
11591 * @hasNsNodes: true if the node set may contain namespace nodes
11593 * Filter a node set, keeping only nodes for which the predicate expression
11594 * matches. Afterwards, keep only nodes between minPos and maxPos in the
11598 xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt
,
11601 int minPos
, int maxPos
,
11604 xmlXPathContextPtr xpctxt
;
11605 xmlNodePtr oldnode
;
11607 xmlXPathStepOpPtr filterOp
;
11611 if ((set
== NULL
) || (set
->nodeNr
== 0))
11615 * Check if the node set contains a sufficient number of nodes for
11616 * the requested range.
11618 if (set
->nodeNr
< minPos
) {
11619 xmlXPathNodeSetClear(set
, hasNsNodes
);
11623 xpctxt
= ctxt
->context
;
11624 oldnode
= xpctxt
->node
;
11625 olddoc
= xpctxt
->doc
;
11626 oldcs
= xpctxt
->contextSize
;
11627 oldpp
= xpctxt
->proximityPosition
;
11628 filterOp
= &ctxt
->comp
->steps
[filterOpIndex
];
11630 xpctxt
->contextSize
= set
->nodeNr
;
11632 for (i
= 0, j
= 0, pos
= 1; i
< set
->nodeNr
; i
++) {
11633 xmlNodePtr node
= set
->nodeTab
[i
];
11636 xpctxt
->node
= node
;
11637 xpctxt
->proximityPosition
= i
+ 1;
11640 * Also set the xpath document in case things like
11641 * key() are evaluated in the predicate.
11643 * TODO: Get real doc for namespace nodes.
11645 if ((node
->type
!= XML_NAMESPACE_DECL
) &&
11646 (node
->doc
!= NULL
))
11647 xpctxt
->doc
= node
->doc
;
11649 res
= xmlXPathCompOpEvalToBoolean(ctxt
, filterOp
, 1);
11651 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
11654 /* Shouldn't happen */
11655 xmlXPathErr(ctxt
, XPATH_EXPR_ERROR
);
11659 if ((res
!= 0) && ((pos
>= minPos
) && (pos
<= maxPos
))) {
11661 set
->nodeTab
[j
] = node
;
11662 set
->nodeTab
[i
] = NULL
;
11667 /* Remove the entry from the initial node set. */
11668 set
->nodeTab
[i
] = NULL
;
11669 if (node
->type
== XML_NAMESPACE_DECL
)
11670 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
11674 if (pos
== maxPos
) {
11683 /* Free remaining nodes. */
11685 for (; i
< set
->nodeNr
; i
++) {
11686 xmlNodePtr node
= set
->nodeTab
[i
];
11687 if ((node
!= NULL
) && (node
->type
== XML_NAMESPACE_DECL
))
11688 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
11694 /* If too many elements were removed, shrink table to preserve memory. */
11695 if ((set
->nodeMax
> XML_NODESET_DEFAULT
) &&
11696 (set
->nodeNr
< set
->nodeMax
/ 2)) {
11698 int nodeMax
= set
->nodeNr
;
11700 if (nodeMax
< XML_NODESET_DEFAULT
)
11701 nodeMax
= XML_NODESET_DEFAULT
;
11702 tmp
= (xmlNodePtr
*) xmlRealloc(set
->nodeTab
,
11703 nodeMax
* sizeof(xmlNodePtr
));
11705 xmlXPathPErrMemory(ctxt
, "shrinking nodeset\n");
11707 set
->nodeTab
= tmp
;
11708 set
->nodeMax
= nodeMax
;
11712 xpctxt
->node
= oldnode
;
11713 xpctxt
->doc
= olddoc
;
11714 xpctxt
->contextSize
= oldcs
;
11715 xpctxt
->proximityPosition
= oldpp
;
11718 #ifdef LIBXML_XPTR_LOCS_ENABLED
11720 * xmlXPathLocationSetFilter:
11721 * @ctxt: the XPath Parser context
11722 * @locset: the location set to filter
11723 * @filterOpIndex: the index of the predicate/filter op
11724 * @minPos: minimum position in the filtered set (1-based)
11725 * @maxPos: maximum position in the filtered set (1-based)
11727 * Filter a location set, keeping only nodes for which the predicate
11728 * expression matches. Afterwards, keep only nodes between minPos and maxPos
11729 * in the filtered result.
11732 xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt
,
11733 xmlLocationSetPtr locset
,
11735 int minPos
, int maxPos
)
11737 xmlXPathContextPtr xpctxt
;
11738 xmlNodePtr oldnode
;
11740 xmlXPathStepOpPtr filterOp
;
11744 if ((locset
== NULL
) || (locset
->locNr
== 0) || (filterOpIndex
== -1))
11747 xpctxt
= ctxt
->context
;
11748 oldnode
= xpctxt
->node
;
11749 olddoc
= xpctxt
->doc
;
11750 oldcs
= xpctxt
->contextSize
;
11751 oldpp
= xpctxt
->proximityPosition
;
11752 filterOp
= &ctxt
->comp
->steps
[filterOpIndex
];
11754 xpctxt
->contextSize
= locset
->locNr
;
11756 for (i
= 0, j
= 0, pos
= 1; i
< locset
->locNr
; i
++) {
11757 xmlNodePtr contextNode
= locset
->locTab
[i
]->user
;
11760 xpctxt
->node
= contextNode
;
11761 xpctxt
->proximityPosition
= i
+ 1;
11764 * Also set the xpath document in case things like
11765 * key() are evaluated in the predicate.
11767 * TODO: Get real doc for namespace nodes.
11769 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11770 (contextNode
->doc
!= NULL
))
11771 xpctxt
->doc
= contextNode
->doc
;
11773 res
= xmlXPathCompOpEvalToBoolean(ctxt
, filterOp
, 1);
11775 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
11778 /* Shouldn't happen */
11779 xmlXPathErr(ctxt
, XPATH_EXPR_ERROR
);
11783 if ((res
!= 0) && ((pos
>= minPos
) && (pos
<= maxPos
))) {
11785 locset
->locTab
[j
] = locset
->locTab
[i
];
11786 locset
->locTab
[i
] = NULL
;
11791 /* Remove the entry from the initial location set. */
11792 xmlXPathFreeObject(locset
->locTab
[i
]);
11793 locset
->locTab
[i
] = NULL
;
11797 if (pos
== maxPos
) {
11806 /* Free remaining nodes. */
11807 for (; i
< locset
->locNr
; i
++)
11808 xmlXPathFreeObject(locset
->locTab
[i
]);
11812 /* If too many elements were removed, shrink table to preserve memory. */
11813 if ((locset
->locMax
> XML_NODESET_DEFAULT
) &&
11814 (locset
->locNr
< locset
->locMax
/ 2)) {
11815 xmlXPathObjectPtr
*tmp
;
11816 int locMax
= locset
->locNr
;
11818 if (locMax
< XML_NODESET_DEFAULT
)
11819 locMax
= XML_NODESET_DEFAULT
;
11820 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(locset
->locTab
,
11821 locMax
* sizeof(xmlXPathObjectPtr
));
11823 xmlXPathPErrMemory(ctxt
, "shrinking locset\n");
11825 locset
->locTab
= tmp
;
11826 locset
->locMax
= locMax
;
11830 xpctxt
->node
= oldnode
;
11831 xpctxt
->doc
= olddoc
;
11832 xpctxt
->contextSize
= oldcs
;
11833 xpctxt
->proximityPosition
= oldpp
;
11835 #endif /* LIBXML_XPTR_LOCS_ENABLED */
11838 * xmlXPathCompOpEvalPredicate:
11839 * @ctxt: the XPath Parser context
11840 * @op: the predicate op
11841 * @set: the node set to filter
11842 * @minPos: minimum position in the filtered set (1-based)
11843 * @maxPos: maximum position in the filtered set (1-based)
11844 * @hasNsNodes: true if the node set may contain namespace nodes
11846 * Filter a node set, keeping only nodes for which the sequence of predicate
11847 * expressions matches. Afterwards, keep only nodes between minPos and maxPos
11848 * in the filtered result.
11851 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt
,
11852 xmlXPathStepOpPtr op
,
11854 int minPos
, int maxPos
,
11857 if (op
->ch1
!= -1) {
11858 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11860 * Process inner predicates first.
11862 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11863 xmlGenericError(xmlGenericErrorContext
,
11864 "xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11865 XP_ERROR(XPATH_INVALID_OPERAND
);
11867 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
11868 XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED
);
11869 ctxt
->context
->depth
+= 1;
11870 xmlXPathCompOpEvalPredicate(ctxt
, &comp
->steps
[op
->ch1
], set
,
11871 1, set
->nodeNr
, hasNsNodes
);
11872 ctxt
->context
->depth
-= 1;
11877 xmlXPathNodeSetFilter(ctxt
, set
, op
->ch2
, minPos
, maxPos
, hasNsNodes
);
11881 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt
,
11882 xmlXPathStepOpPtr op
,
11886 xmlXPathStepOpPtr exprOp
;
11889 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11893 * If not -1, then ch1 will point to:
11894 * 1) For predicates (XPATH_OP_PREDICATE):
11895 * - an inner predicate operator
11896 * 2) For filters (XPATH_OP_FILTER):
11897 * - an inner filter operator OR
11898 * - an expression selecting the node set.
11899 * E.g. "key('a', 'b')" or "(//foo | //bar)".
11901 if ((op
->op
!= XPATH_OP_PREDICATE
) && (op
->op
!= XPATH_OP_FILTER
))
11904 if (op
->ch2
!= -1) {
11905 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11909 if ((exprOp
!= NULL
) &&
11910 (exprOp
->op
== XPATH_OP_VALUE
) &&
11911 (exprOp
->value4
!= NULL
) &&
11912 (((xmlXPathObjectPtr
) exprOp
->value4
)->type
== XPATH_NUMBER
))
11914 double floatval
= ((xmlXPathObjectPtr
) exprOp
->value4
)->floatval
;
11917 * We have a "[n]" predicate here.
11918 * TODO: Unfortunately this simplistic test here is not
11919 * able to detect a position() predicate in compound
11920 * expressions like "[@attr = 'a" and position() = 1],
11921 * and even not the usage of position() in
11922 * "[position() = 1]"; thus - obviously - a position-range,
11923 * like it "[position() < 5]", is also not detected.
11924 * Maybe we could rewrite the AST to ease the optimization.
11927 if ((floatval
> INT_MIN
) && (floatval
< INT_MAX
)) {
11928 *maxPos
= (int) floatval
;
11929 if (floatval
== (double) *maxPos
)
11937 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt
,
11938 xmlXPathStepOpPtr op
,
11939 xmlNodePtr
* first
, xmlNodePtr
* last
,
11943 #define XP_TEST_HIT \
11944 if (hasAxisRange != 0) { \
11945 if (++pos == maxPos) { \
11946 if (addNode(seq, cur) < 0) \
11947 ctxt->error = XPATH_MEMORY_ERROR; \
11948 goto axis_range_end; } \
11950 if (addNode(seq, cur) < 0) \
11951 ctxt->error = XPATH_MEMORY_ERROR; \
11952 if (breakOnFirstHit) goto first_hit; }
11954 #define XP_TEST_HIT_NS \
11955 if (hasAxisRange != 0) { \
11956 if (++pos == maxPos) { \
11958 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11959 ctxt->error = XPATH_MEMORY_ERROR; \
11960 goto axis_range_end; } \
11963 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11964 ctxt->error = XPATH_MEMORY_ERROR; \
11965 if (breakOnFirstHit) goto first_hit; }
11967 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) op
->value
;
11968 xmlXPathTestVal test
= (xmlXPathTestVal
) op
->value2
;
11969 xmlXPathTypeVal type
= (xmlXPathTypeVal
) op
->value3
;
11970 const xmlChar
*prefix
= op
->value4
;
11971 const xmlChar
*name
= op
->value5
;
11972 const xmlChar
*URI
= NULL
;
11975 int nbMatches
= 0, prevMatches
= 0;
11977 int total
= 0, hasNsNodes
= 0;
11978 /* The popped object holding the context nodes */
11979 xmlXPathObjectPtr obj
;
11980 /* The set of context nodes for the node tests */
11981 xmlNodeSetPtr contextSeq
;
11983 xmlNodePtr contextNode
;
11984 /* The final resulting node set wrt to all context nodes */
11985 xmlNodeSetPtr outSeq
;
11987 * The temporary resulting node set wrt 1 context node.
11988 * Used to feed predicate evaluation.
11992 /* First predicate operator */
11993 xmlXPathStepOpPtr predOp
;
11994 int maxPos
; /* The requested position() (when a "[n]" predicate) */
11995 int hasPredicateRange
, hasAxisRange
, pos
;
11996 int breakOnFirstHit
;
11998 xmlXPathTraversalFunction next
= NULL
;
11999 int (*addNode
) (xmlNodeSetPtr
, xmlNodePtr
);
12000 xmlXPathNodeSetMergeFunction mergeAndClear
;
12001 xmlNodePtr oldContextNode
;
12002 xmlXPathContextPtr xpctxt
= ctxt
->context
;
12005 CHECK_TYPE0(XPATH_NODESET
);
12006 obj
= valuePop(ctxt
);
12008 * Setup namespaces.
12010 if (prefix
!= NULL
) {
12011 URI
= xmlXPathNsLookup(xpctxt
, prefix
);
12013 xmlXPathReleaseObject(xpctxt
, obj
);
12014 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
12020 * MAYBE FUTURE TODO: merging optimizations:
12021 * - If the nodes to be traversed wrt to the initial nodes and
12022 * the current axis cannot overlap, then we could avoid searching
12023 * for duplicates during the merge.
12024 * But the question is how/when to evaluate if they cannot overlap.
12025 * Example: if we know that for two initial nodes, the one is
12026 * not in the ancestor-or-self axis of the other, then we could safely
12027 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12028 * the descendant-or-self axis.
12030 mergeAndClear
= xmlXPathNodeSetMergeAndClear
;
12032 case AXIS_ANCESTOR
:
12034 next
= xmlXPathNextAncestor
;
12036 case AXIS_ANCESTOR_OR_SELF
:
12038 next
= xmlXPathNextAncestorOrSelf
;
12040 case AXIS_ATTRIBUTE
:
12043 next
= xmlXPathNextAttribute
;
12044 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12048 if (((test
== NODE_TEST_NAME
) || (test
== NODE_TEST_ALL
)) &&
12049 (type
== NODE_TYPE_NODE
))
12052 * Optimization if an element node type is 'element'.
12054 next
= xmlXPathNextChildElement
;
12056 next
= xmlXPathNextChild
;
12057 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12059 case AXIS_DESCENDANT
:
12061 next
= xmlXPathNextDescendant
;
12063 case AXIS_DESCENDANT_OR_SELF
:
12065 next
= xmlXPathNextDescendantOrSelf
;
12067 case AXIS_FOLLOWING
:
12069 next
= xmlXPathNextFollowing
;
12071 case AXIS_FOLLOWING_SIBLING
:
12073 next
= xmlXPathNextFollowingSibling
;
12075 case AXIS_NAMESPACE
:
12078 next
= (xmlXPathTraversalFunction
) xmlXPathNextNamespace
;
12079 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12083 next
= xmlXPathNextParent
;
12085 case AXIS_PRECEDING
:
12087 next
= xmlXPathNextPrecedingInternal
;
12089 case AXIS_PRECEDING_SIBLING
:
12091 next
= xmlXPathNextPrecedingSibling
;
12096 next
= xmlXPathNextSelf
;
12097 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12102 xmlXPathDebugDumpStepAxis(op
,
12103 (obj
->nodesetval
!= NULL
) ? obj
->nodesetval
->nodeNr
: 0);
12106 if (next
== NULL
) {
12107 xmlXPathReleaseObject(xpctxt
, obj
);
12110 contextSeq
= obj
->nodesetval
;
12111 if ((contextSeq
== NULL
) || (contextSeq
->nodeNr
<= 0)) {
12112 xmlXPathReleaseObject(xpctxt
, obj
);
12113 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, NULL
));
12117 * Predicate optimization ---------------------------------------------
12118 * If this step has a last predicate, which contains a position(),
12119 * then we'll optimize (although not exactly "position()", but only
12120 * the short-hand form, i.e., "[n]".
12122 * Example - expression "/foo[parent::bar][1]":
12124 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12126 * PREDICATE -- op->ch2 (predOp)
12127 * PREDICATE -- predOp->ch1 = [parent::bar]
12129 * COLLECT 'parent' 'name' 'node' bar
12131 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12136 hasPredicateRange
= 0;
12138 if (op
->ch2
!= -1) {
12140 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12142 predOp
= &ctxt
->comp
->steps
[op
->ch2
];
12143 if (xmlXPathIsPositionalPredicate(ctxt
, predOp
, &maxPos
)) {
12144 if (predOp
->ch1
!= -1) {
12146 * Use the next inner predicate operator.
12148 predOp
= &ctxt
->comp
->steps
[predOp
->ch1
];
12149 hasPredicateRange
= 1;
12152 * There's no other predicate than the [n] predicate.
12159 breakOnFirstHit
= ((toBool
) && (predOp
== NULL
)) ? 1 : 0;
12161 * Axis traversal -----------------------------------------------------
12165 * - For the attribute axis, the principal node type is attribute.
12166 * - For the namespace axis, the principal node type is namespace.
12167 * - For other axes, the principal node type is element.
12169 * A node test * is true for any node of the
12170 * principal node type. For example, child::* will
12171 * select all element children of the context node
12173 oldContextNode
= xpctxt
->node
;
12174 addNode
= xmlXPathNodeSetAddUnique
;
12177 contextNode
= NULL
;
12181 while (((contextIdx
< contextSeq
->nodeNr
) || (contextNode
!= NULL
)) &&
12182 (ctxt
->error
== XPATH_EXPRESSION_OK
)) {
12183 xpctxt
->node
= contextSeq
->nodeTab
[contextIdx
++];
12186 seq
= xmlXPathNodeSetCreate(NULL
);
12188 /* TODO: Propagate memory error. */
12194 * Traverse the axis and test the nodes.
12200 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12203 cur
= next(ctxt
, cur
);
12208 * QUESTION TODO: What does the "first" and "last" stuff do?
12210 if ((first
!= NULL
) && (*first
!= NULL
)) {
12213 if (((total
% 256) == 0) &&
12214 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12215 (xmlXPathCmpNodesExt(*first
, cur
) >= 0))
12217 (xmlXPathCmpNodes(*first
, cur
) >= 0))
12223 if ((last
!= NULL
) && (*last
!= NULL
)) {
12226 if (((total
% 256) == 0) &&
12227 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12228 (xmlXPathCmpNodesExt(cur
, *last
) >= 0))
12230 (xmlXPathCmpNodes(cur
, *last
) >= 0))
12240 xmlGenericError(xmlGenericErrorContext
, " %s", cur
->name
);
12244 case NODE_TEST_NONE
:
12248 case NODE_TEST_TYPE
:
12249 if (type
== NODE_TYPE_NODE
) {
12250 switch (cur
->type
) {
12251 case XML_DOCUMENT_NODE
:
12252 case XML_HTML_DOCUMENT_NODE
:
12253 case XML_ELEMENT_NODE
:
12254 case XML_ATTRIBUTE_NODE
:
12256 case XML_COMMENT_NODE
:
12257 case XML_CDATA_SECTION_NODE
:
12258 case XML_TEXT_NODE
:
12261 case XML_NAMESPACE_DECL
: {
12262 if (axis
== AXIS_NAMESPACE
) {
12273 } else if (cur
->type
== (xmlElementType
) type
) {
12274 if (cur
->type
== XML_NAMESPACE_DECL
)
12278 } else if ((type
== NODE_TYPE_TEXT
) &&
12279 (cur
->type
== XML_CDATA_SECTION_NODE
))
12285 if ((cur
->type
== XML_PI_NODE
) &&
12286 ((name
== NULL
) || xmlStrEqual(name
, cur
->name
)))
12291 case NODE_TEST_ALL
:
12292 if (axis
== AXIS_ATTRIBUTE
) {
12293 if (cur
->type
== XML_ATTRIBUTE_NODE
)
12295 if (prefix
== NULL
)
12298 } else if ((cur
->ns
!= NULL
) &&
12299 (xmlStrEqual(URI
, cur
->ns
->href
)))
12304 } else if (axis
== AXIS_NAMESPACE
) {
12305 if (cur
->type
== XML_NAMESPACE_DECL
)
12310 if (cur
->type
== XML_ELEMENT_NODE
) {
12311 if (prefix
== NULL
)
12315 } else if ((cur
->ns
!= NULL
) &&
12316 (xmlStrEqual(URI
, cur
->ns
->href
)))
12323 case NODE_TEST_NS
:{
12327 case NODE_TEST_NAME
:
12328 if (axis
== AXIS_ATTRIBUTE
) {
12329 if (cur
->type
!= XML_ATTRIBUTE_NODE
)
12331 } else if (axis
== AXIS_NAMESPACE
) {
12332 if (cur
->type
!= XML_NAMESPACE_DECL
)
12335 if (cur
->type
!= XML_ELEMENT_NODE
)
12338 switch (cur
->type
) {
12339 case XML_ELEMENT_NODE
:
12340 if (xmlStrEqual(name
, cur
->name
)) {
12341 if (prefix
== NULL
) {
12342 if (cur
->ns
== NULL
)
12347 if ((cur
->ns
!= NULL
) &&
12348 (xmlStrEqual(URI
, cur
->ns
->href
)))
12355 case XML_ATTRIBUTE_NODE
:{
12356 xmlAttrPtr attr
= (xmlAttrPtr
) cur
;
12358 if (xmlStrEqual(name
, attr
->name
)) {
12359 if (prefix
== NULL
) {
12360 if ((attr
->ns
== NULL
) ||
12361 (attr
->ns
->prefix
== NULL
))
12366 if ((attr
->ns
!= NULL
) &&
12376 case XML_NAMESPACE_DECL
:
12377 if (cur
->type
== XML_NAMESPACE_DECL
) {
12378 xmlNsPtr ns
= (xmlNsPtr
) cur
;
12380 if ((ns
->prefix
!= NULL
) && (name
!= NULL
)
12381 && (xmlStrEqual(ns
->prefix
, name
)))
12391 } /* switch(test) */
12392 } while ((cur
!= NULL
) && (ctxt
->error
== XPATH_EXPRESSION_OK
));
12394 goto apply_predicates
;
12396 axis_range_end
: /* ----------------------------------------------------- */
12398 * We have a "/foo[n]", and position() = n was reached.
12399 * Note that we can have as well "/foo/::parent::foo[1]", so
12400 * a duplicate-aware merge is still needed.
12401 * Merge with the result.
12403 if (outSeq
== NULL
) {
12407 /* TODO: Check memory error. */
12408 outSeq
= mergeAndClear(outSeq
, seq
);
12410 * Break if only a true/false result was requested.
12416 first_hit
: /* ---------------------------------------------------------- */
12418 * Break if only a true/false result was requested and
12419 * no predicates existed and a node test succeeded.
12421 if (outSeq
== NULL
) {
12425 /* TODO: Check memory error. */
12426 outSeq
= mergeAndClear(outSeq
, seq
);
12431 nbMatches
+= seq
->nodeNr
;
12434 apply_predicates
: /* --------------------------------------------------- */
12435 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
12439 * Apply predicates.
12441 if ((predOp
!= NULL
) && (seq
->nodeNr
> 0)) {
12443 * E.g. when we have a "/foo[some expression][n]".
12446 * QUESTION TODO: The old predicate evaluation took into
12447 * account location-sets.
12448 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12449 * Do we expect such a set here?
12450 * All what I learned now from the evaluation semantics
12451 * does not indicate that a location-set will be processed
12452 * here, so this looks OK.
12455 * Iterate over all predicates, starting with the outermost
12457 * TODO: Problem: we cannot execute the inner predicates first
12458 * since we cannot go back *up* the operator tree!
12460 * 1) Use of recursive functions (like is it currently done
12461 * via xmlXPathCompOpEval())
12462 * 2) Add a predicate evaluation information stack to the
12464 * 3) Change the way the operators are linked; we need a
12465 * "parent" field on xmlXPathStepOp
12467 * For the moment, I'll try to solve this with a recursive
12468 * function: xmlXPathCompOpEvalPredicate().
12470 if (hasPredicateRange
!= 0)
12471 xmlXPathCompOpEvalPredicate(ctxt
, predOp
, seq
, maxPos
, maxPos
,
12474 xmlXPathCompOpEvalPredicate(ctxt
, predOp
, seq
, 1, seq
->nodeNr
,
12477 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
12483 if (seq
->nodeNr
> 0) {
12485 * Add to result set.
12487 if (outSeq
== NULL
) {
12491 /* TODO: Check memory error. */
12492 outSeq
= mergeAndClear(outSeq
, seq
);
12501 if ((obj
->boolval
) && (obj
->user
!= NULL
)) {
12503 * QUESTION TODO: What does this do and why?
12504 * TODO: Do we have to do this also for the "error"
12505 * cleanup further down?
12507 ctxt
->value
->boolval
= 1;
12508 ctxt
->value
->user
= obj
->user
;
12512 xmlXPathReleaseObject(xpctxt
, obj
);
12515 * Ensure we return at least an empty set.
12517 if (outSeq
== NULL
) {
12518 if ((seq
!= NULL
) && (seq
->nodeNr
== 0))
12521 /* TODO: Check memory error. */
12522 outSeq
= xmlXPathNodeSetCreate(NULL
);
12524 if ((seq
!= NULL
) && (seq
!= outSeq
)) {
12525 xmlXPathFreeNodeSet(seq
);
12528 * Hand over the result. Better to push the set also in
12531 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, outSeq
));
12533 * Reset the context node.
12535 xpctxt
->node
= oldContextNode
;
12537 * When traversing the namespace axis in "toBool" mode, it's
12538 * possible that tmpNsList wasn't freed.
12540 if (xpctxt
->tmpNsList
!= NULL
) {
12541 xmlFree(xpctxt
->tmpNsList
);
12542 xpctxt
->tmpNsList
= NULL
;
12546 xmlGenericError(xmlGenericErrorContext
,
12547 "\nExamined %d nodes, found %d nodes at that step\n",
12555 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12556 xmlXPathStepOpPtr op
, xmlNodePtr
* first
);
12559 * xmlXPathCompOpEvalFirst:
12560 * @ctxt: the XPath parser context with the compiled expression
12561 * @op: an XPath compiled operation
12562 * @first: the first elem found so far
12564 * Evaluate the Precompiled XPath operation searching only the first
12565 * element in document order
12567 * Returns the number of examined objects.
12570 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
12571 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12573 int total
= 0, cur
;
12574 xmlXPathCompExprPtr comp
;
12575 xmlXPathObjectPtr arg1
, arg2
;
12578 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12580 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
12581 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED
);
12582 ctxt
->context
->depth
+= 1;
12587 case XPATH_OP_UNION
:
12589 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12592 if ((ctxt
->value
!= NULL
)
12593 && (ctxt
->value
->type
== XPATH_NODESET
)
12594 && (ctxt
->value
->nodesetval
!= NULL
)
12595 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12597 * limit tree traversing to first node in the result
12600 * OPTIMIZE TODO: This implicitly sorts
12601 * the result, even if not needed. E.g. if the argument
12602 * of the count() function, no sorting is needed.
12603 * OPTIMIZE TODO: How do we know if the node-list wasn't
12606 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12607 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12608 *first
= ctxt
->value
->nodesetval
->nodeTab
[0];
12611 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch2
],
12615 arg2
= valuePop(ctxt
);
12616 arg1
= valuePop(ctxt
);
12617 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12618 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12619 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12620 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12621 XP_ERROR0(XPATH_INVALID_TYPE
);
12623 if ((ctxt
->context
->opLimit
!= 0) &&
12624 (((arg1
->nodesetval
!= NULL
) &&
12625 (xmlXPathCheckOpLimit(ctxt
,
12626 arg1
->nodesetval
->nodeNr
) < 0)) ||
12627 ((arg2
->nodesetval
!= NULL
) &&
12628 (xmlXPathCheckOpLimit(ctxt
,
12629 arg2
->nodesetval
->nodeNr
) < 0)))) {
12630 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12631 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12635 /* TODO: Check memory error. */
12636 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12638 valuePush(ctxt
, arg1
);
12639 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12642 xmlXPathCompSwap(op
);
12645 case XPATH_OP_ROOT
:
12646 xmlXPathRoot(ctxt
);
12648 case XPATH_OP_NODE
:
12650 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12653 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12655 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12656 ctxt
->context
->node
));
12658 case XPATH_OP_COLLECT
:{
12662 total
= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12665 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, first
, NULL
, 0);
12668 case XPATH_OP_VALUE
:
12670 xmlXPathCacheObjectCopy(ctxt
->context
,
12671 (xmlXPathObjectPtr
) op
->value4
));
12673 case XPATH_OP_SORT
:
12676 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12679 if ((ctxt
->value
!= NULL
)
12680 && (ctxt
->value
->type
== XPATH_NODESET
)
12681 && (ctxt
->value
->nodesetval
!= NULL
)
12682 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12683 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12685 #ifdef XP_OPTIMIZED_FILTER_FIRST
12686 case XPATH_OP_FILTER
:
12687 total
+= xmlXPathCompOpEvalFilterFirst(ctxt
, op
, first
);
12691 total
+= xmlXPathCompOpEval(ctxt
, op
);
12695 ctxt
->context
->depth
-= 1;
12700 * xmlXPathCompOpEvalLast:
12701 * @ctxt: the XPath parser context with the compiled expression
12702 * @op: an XPath compiled operation
12703 * @last: the last elem found so far
12705 * Evaluate the Precompiled XPath operation searching only the last
12706 * element in document order
12708 * Returns the number of nodes traversed
12711 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
,
12714 int total
= 0, cur
;
12715 xmlXPathCompExprPtr comp
;
12716 xmlXPathObjectPtr arg1
, arg2
;
12719 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12721 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
12722 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED
);
12723 ctxt
->context
->depth
+= 1;
12728 case XPATH_OP_UNION
:
12730 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
], last
);
12732 if ((ctxt
->value
!= NULL
)
12733 && (ctxt
->value
->type
== XPATH_NODESET
)
12734 && (ctxt
->value
->nodesetval
!= NULL
)
12735 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12737 * limit tree traversing to first node in the result
12739 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12740 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12742 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->value
->
12743 nodesetval
->nodeNr
-
12747 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch2
], last
);
12749 if ((ctxt
->value
!= NULL
)
12750 && (ctxt
->value
->type
== XPATH_NODESET
)
12751 && (ctxt
->value
->nodesetval
!= NULL
)
12752 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) { /* TODO: NOP ? */
12755 arg2
= valuePop(ctxt
);
12756 arg1
= valuePop(ctxt
);
12757 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
12758 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
12759 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12760 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12761 XP_ERROR0(XPATH_INVALID_TYPE
);
12763 if ((ctxt
->context
->opLimit
!= 0) &&
12764 (((arg1
->nodesetval
!= NULL
) &&
12765 (xmlXPathCheckOpLimit(ctxt
,
12766 arg1
->nodesetval
->nodeNr
) < 0)) ||
12767 ((arg2
->nodesetval
!= NULL
) &&
12768 (xmlXPathCheckOpLimit(ctxt
,
12769 arg2
->nodesetval
->nodeNr
) < 0)))) {
12770 xmlXPathReleaseObject(ctxt
->context
, arg1
);
12771 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12775 /* TODO: Check memory error. */
12776 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12778 valuePush(ctxt
, arg1
);
12779 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12782 xmlXPathCompSwap(op
);
12785 case XPATH_OP_ROOT
:
12786 xmlXPathRoot(ctxt
);
12788 case XPATH_OP_NODE
:
12790 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12793 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12795 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12796 ctxt
->context
->node
));
12798 case XPATH_OP_COLLECT
:{
12802 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12805 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, last
, 0);
12808 case XPATH_OP_VALUE
:
12810 xmlXPathCacheObjectCopy(ctxt
->context
,
12811 (xmlXPathObjectPtr
) op
->value4
));
12813 case XPATH_OP_SORT
:
12816 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
],
12819 if ((ctxt
->value
!= NULL
)
12820 && (ctxt
->value
->type
== XPATH_NODESET
)
12821 && (ctxt
->value
->nodesetval
!= NULL
)
12822 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12823 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12826 total
+= xmlXPathCompOpEval(ctxt
, op
);
12830 ctxt
->context
->depth
-= 1;
12834 #ifdef XP_OPTIMIZED_FILTER_FIRST
12836 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12837 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12840 xmlXPathCompExprPtr comp
;
12841 xmlXPathObjectPtr obj
;
12847 * Optimization for ()[last()] selection i.e. the last elem
12849 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
12850 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
12851 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
12852 int f
= comp
->steps
[op
->ch2
].ch1
;
12855 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
12856 (comp
->steps
[f
].value5
== NULL
) &&
12857 (comp
->steps
[f
].value
== 0) &&
12858 (comp
->steps
[f
].value4
!= NULL
) &&
12860 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
12861 xmlNodePtr last
= NULL
;
12864 xmlXPathCompOpEvalLast(ctxt
,
12865 &comp
->steps
[op
->ch1
],
12869 * The nodeset should be in document order,
12870 * Keep only the last value
12872 if ((ctxt
->value
!= NULL
) &&
12873 (ctxt
->value
->type
== XPATH_NODESET
) &&
12874 (ctxt
->value
->nodesetval
!= NULL
) &&
12875 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
12876 (ctxt
->value
->nodesetval
->nodeNr
> 1)) {
12877 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
12878 *first
= *(ctxt
->value
->nodesetval
->nodeTab
);
12885 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12889 if (ctxt
->value
== NULL
)
12892 #ifdef LIBXML_XPTR_LOCS_ENABLED
12894 * Hum are we filtering the result of an XPointer expression
12896 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
12897 xmlLocationSetPtr locset
= ctxt
->value
->user
;
12899 if (locset
!= NULL
) {
12900 xmlXPathLocationSetFilter(ctxt
, locset
, op
->ch2
, 1, 1);
12901 if (locset
->locNr
> 0)
12902 *first
= (xmlNodePtr
) locset
->locTab
[0]->user
;
12907 #endif /* LIBXML_XPTR_LOCS_ENABLED */
12910 * In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12911 * the stack. We have to temporarily remove the nodeset object from the
12912 * stack to avoid freeing it prematurely.
12914 CHECK_TYPE0(XPATH_NODESET
);
12915 obj
= valuePop(ctxt
);
12916 set
= obj
->nodesetval
;
12918 xmlXPathNodeSetFilter(ctxt
, set
, op
->ch2
, 1, 1, 1);
12919 if (set
->nodeNr
> 0)
12920 *first
= set
->nodeTab
[0];
12922 valuePush(ctxt
, obj
);
12926 #endif /* XP_OPTIMIZED_FILTER_FIRST */
12929 * xmlXPathCompOpEval:
12930 * @ctxt: the XPath parser context with the compiled expression
12931 * @op: an XPath compiled operation
12933 * Evaluate the Precompiled XPath operation
12934 * Returns the number of nodes traversed
12937 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
)
12941 xmlXPathCompExprPtr comp
;
12942 xmlXPathObjectPtr arg1
, arg2
;
12945 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
12947 if (ctxt
->context
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
12948 XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED
);
12949 ctxt
->context
->depth
+= 1;
12955 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12957 xmlXPathBooleanFunction(ctxt
, 1);
12958 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 0))
12960 arg2
= valuePop(ctxt
);
12961 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12963 xmlXPathFreeObject(arg2
);
12966 xmlXPathBooleanFunction(ctxt
, 1);
12967 if (ctxt
->value
!= NULL
)
12968 ctxt
->value
->boolval
&= arg2
->boolval
;
12969 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12972 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12974 xmlXPathBooleanFunction(ctxt
, 1);
12975 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 1))
12977 arg2
= valuePop(ctxt
);
12978 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12980 xmlXPathFreeObject(arg2
);
12983 xmlXPathBooleanFunction(ctxt
, 1);
12984 if (ctxt
->value
!= NULL
)
12985 ctxt
->value
->boolval
|= arg2
->boolval
;
12986 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12988 case XPATH_OP_EQUAL
:
12989 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12991 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12994 equal
= xmlXPathEqualValues(ctxt
);
12996 equal
= xmlXPathNotEqualValues(ctxt
);
12997 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, equal
));
13000 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13002 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13004 ret
= xmlXPathCompareValues(ctxt
, op
->value
, op
->value2
);
13005 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
13007 case XPATH_OP_PLUS
:
13008 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13010 if (op
->ch2
!= -1) {
13011 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13014 if (op
->value
== 0)
13015 xmlXPathSubValues(ctxt
);
13016 else if (op
->value
== 1)
13017 xmlXPathAddValues(ctxt
);
13018 else if (op
->value
== 2)
13019 xmlXPathValueFlipSign(ctxt
);
13020 else if (op
->value
== 3) {
13022 CHECK_TYPE0(XPATH_NUMBER
);
13025 case XPATH_OP_MULT
:
13026 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13028 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13030 if (op
->value
== 0)
13031 xmlXPathMultValues(ctxt
);
13032 else if (op
->value
== 1)
13033 xmlXPathDivValues(ctxt
);
13034 else if (op
->value
== 2)
13035 xmlXPathModValues(ctxt
);
13037 case XPATH_OP_UNION
:
13038 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13040 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13043 arg2
= valuePop(ctxt
);
13044 arg1
= valuePop(ctxt
);
13045 if ((arg1
== NULL
) || (arg1
->type
!= XPATH_NODESET
) ||
13046 (arg2
== NULL
) || (arg2
->type
!= XPATH_NODESET
)) {
13047 xmlXPathReleaseObject(ctxt
->context
, arg1
);
13048 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13049 XP_ERROR0(XPATH_INVALID_TYPE
);
13051 if ((ctxt
->context
->opLimit
!= 0) &&
13052 (((arg1
->nodesetval
!= NULL
) &&
13053 (xmlXPathCheckOpLimit(ctxt
,
13054 arg1
->nodesetval
->nodeNr
) < 0)) ||
13055 ((arg2
->nodesetval
!= NULL
) &&
13056 (xmlXPathCheckOpLimit(ctxt
,
13057 arg2
->nodesetval
->nodeNr
) < 0)))) {
13058 xmlXPathReleaseObject(ctxt
->context
, arg1
);
13059 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13063 if ((arg1
->nodesetval
== NULL
) ||
13064 ((arg2
->nodesetval
!= NULL
) &&
13065 (arg2
->nodesetval
->nodeNr
!= 0)))
13067 /* TODO: Check memory error. */
13068 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
13072 valuePush(ctxt
, arg1
);
13073 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13075 case XPATH_OP_ROOT
:
13076 xmlXPathRoot(ctxt
);
13078 case XPATH_OP_NODE
:
13080 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13083 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13085 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
13086 ctxt
->context
->node
));
13088 case XPATH_OP_COLLECT
:{
13092 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13095 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 0);
13098 case XPATH_OP_VALUE
:
13100 xmlXPathCacheObjectCopy(ctxt
->context
,
13101 (xmlXPathObjectPtr
) op
->value4
));
13103 case XPATH_OP_VARIABLE
:{
13104 xmlXPathObjectPtr val
;
13108 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13109 if (op
->value5
== NULL
) {
13110 val
= xmlXPathVariableLookup(ctxt
->context
, op
->value4
);
13112 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13113 valuePush(ctxt
, val
);
13115 const xmlChar
*URI
;
13117 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13119 xmlGenericError(xmlGenericErrorContext
,
13120 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13121 (char *) op
->value4
, (char *)op
->value5
);
13122 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13125 val
= xmlXPathVariableLookupNS(ctxt
->context
,
13128 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR
);
13129 valuePush(ctxt
, val
);
13133 case XPATH_OP_FUNCTION
:{
13134 xmlXPathFunction func
;
13135 const xmlChar
*oldFunc
, *oldFuncURI
;
13139 frame
= ctxt
->valueNr
;
13140 if (op
->ch1
!= -1) {
13142 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13143 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13146 if (ctxt
->valueNr
< frame
+ op
->value
) {
13147 xmlGenericError(xmlGenericErrorContext
,
13148 "xmlXPathCompOpEval: parameter error\n");
13149 ctxt
->error
= XPATH_INVALID_OPERAND
;
13152 for (i
= 0; i
< op
->value
; i
++) {
13153 if (ctxt
->valueTab
[(ctxt
->valueNr
- 1) - i
] == NULL
) {
13154 xmlGenericError(xmlGenericErrorContext
,
13155 "xmlXPathCompOpEval: parameter error\n");
13156 ctxt
->error
= XPATH_INVALID_OPERAND
;
13160 if (op
->cache
!= NULL
)
13163 const xmlChar
*URI
= NULL
;
13165 if (op
->value5
== NULL
)
13167 xmlXPathFunctionLookup(ctxt
->context
,
13170 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13172 xmlGenericError(xmlGenericErrorContext
,
13173 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13174 (char *)op
->value4
, (char *)op
->value5
);
13175 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13178 func
= xmlXPathFunctionLookupNS(ctxt
->context
,
13181 if (func
== NULL
) {
13182 xmlGenericError(xmlGenericErrorContext
,
13183 "xmlXPathCompOpEval: function %s not found\n",
13184 (char *)op
->value4
);
13185 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR
);
13188 op
->cacheURI
= (void *) URI
;
13190 oldFunc
= ctxt
->context
->function
;
13191 oldFuncURI
= ctxt
->context
->functionURI
;
13192 ctxt
->context
->function
= op
->value4
;
13193 ctxt
->context
->functionURI
= op
->cacheURI
;
13194 func(ctxt
, op
->value
);
13195 ctxt
->context
->function
= oldFunc
;
13196 ctxt
->context
->functionURI
= oldFuncURI
;
13197 if ((ctxt
->error
== XPATH_EXPRESSION_OK
) &&
13198 (ctxt
->valueNr
!= frame
+ 1))
13199 XP_ERROR0(XPATH_STACK_ERROR
);
13203 if (op
->ch1
!= -1) {
13204 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13207 if (op
->ch2
!= -1) {
13208 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13212 case XPATH_OP_PREDICATE
:
13213 case XPATH_OP_FILTER
:{
13214 xmlXPathObjectPtr obj
;
13218 * Optimization for ()[1] selection i.e. the first elem
13220 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13221 #ifdef XP_OPTIMIZED_FILTER_FIRST
13223 * FILTER TODO: Can we assume that the inner processing
13224 * will result in an ordered list if we have an
13226 * What about an additional field or flag on
13227 * xmlXPathObject like @sorted ? This way we wouldn't need
13228 * to assume anything, so it would be more robust and
13229 * easier to optimize.
13231 ((comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) || /* 18 */
13232 (comp
->steps
[op
->ch1
].op
== XPATH_OP_FILTER
)) && /* 17 */
13234 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13236 (comp
->steps
[op
->ch2
].op
== XPATH_OP_VALUE
)) { /* 12 */
13237 xmlXPathObjectPtr val
;
13239 val
= comp
->steps
[op
->ch2
].value4
;
13240 if ((val
!= NULL
) && (val
->type
== XPATH_NUMBER
) &&
13241 (val
->floatval
== 1.0)) {
13242 xmlNodePtr first
= NULL
;
13245 xmlXPathCompOpEvalFirst(ctxt
,
13246 &comp
->steps
[op
->ch1
],
13250 * The nodeset should be in document order,
13251 * Keep only the first value
13253 if ((ctxt
->value
!= NULL
) &&
13254 (ctxt
->value
->type
== XPATH_NODESET
) &&
13255 (ctxt
->value
->nodesetval
!= NULL
) &&
13256 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13257 xmlXPathNodeSetClearFromPos(ctxt
->value
->nodesetval
,
13263 * Optimization for ()[last()] selection i.e. the last elem
13265 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13266 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13267 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
13268 int f
= comp
->steps
[op
->ch2
].ch1
;
13271 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
13272 (comp
->steps
[f
].value5
== NULL
) &&
13273 (comp
->steps
[f
].value
== 0) &&
13274 (comp
->steps
[f
].value4
!= NULL
) &&
13276 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
13277 xmlNodePtr last
= NULL
;
13280 xmlXPathCompOpEvalLast(ctxt
,
13281 &comp
->steps
[op
->ch1
],
13285 * The nodeset should be in document order,
13286 * Keep only the last value
13288 if ((ctxt
->value
!= NULL
) &&
13289 (ctxt
->value
->type
== XPATH_NODESET
) &&
13290 (ctxt
->value
->nodesetval
!= NULL
) &&
13291 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
13292 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13293 xmlXPathNodeSetKeepLast(ctxt
->value
->nodesetval
);
13298 * Process inner predicates first.
13299 * Example "index[parent::book][1]":
13301 * PREDICATE <-- we are here "[1]"
13302 * PREDICATE <-- process "[parent::book]" first
13304 * COLLECT 'parent' 'name' 'node' book
13306 * ELEM Object is a number : 1
13310 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13314 if (ctxt
->value
== NULL
)
13317 #ifdef LIBXML_XPTR_LOCS_ENABLED
13319 * Hum are we filtering the result of an XPointer expression
13321 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13322 xmlLocationSetPtr locset
= ctxt
->value
->user
;
13323 xmlXPathLocationSetFilter(ctxt
, locset
, op
->ch2
,
13327 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13330 * In case of errors, xmlXPathNodeSetFilter can pop additional
13331 * nodes from the stack. We have to temporarily remove the
13332 * nodeset object from the stack to avoid freeing it
13335 CHECK_TYPE0(XPATH_NODESET
);
13336 obj
= valuePop(ctxt
);
13337 set
= obj
->nodesetval
;
13339 xmlXPathNodeSetFilter(ctxt
, set
, op
->ch2
,
13340 1, set
->nodeNr
, 1);
13341 valuePush(ctxt
, obj
);
13344 case XPATH_OP_SORT
:
13346 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13348 if ((ctxt
->value
!= NULL
) &&
13349 (ctxt
->value
->type
== XPATH_NODESET
) &&
13350 (ctxt
->value
->nodesetval
!= NULL
) &&
13351 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13353 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
13356 #ifdef LIBXML_XPTR_LOCS_ENABLED
13357 case XPATH_OP_RANGETO
:{
13358 xmlXPathObjectPtr range
;
13359 xmlXPathObjectPtr res
, obj
;
13360 xmlXPathObjectPtr tmp
;
13361 xmlLocationSetPtr newlocset
= NULL
;
13362 xmlLocationSetPtr oldlocset
;
13363 xmlNodeSetPtr oldset
;
13364 xmlNodePtr oldnode
= ctxt
->context
->node
;
13365 int oldcs
= ctxt
->context
->contextSize
;
13366 int oldpp
= ctxt
->context
->proximityPosition
;
13369 if (op
->ch1
!= -1) {
13371 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13374 if (ctxt
->value
== NULL
) {
13375 XP_ERROR0(XPATH_INVALID_OPERAND
);
13380 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13382 * Extract the old locset, and then evaluate the result of the
13383 * expression for all the element in the locset. use it to grow
13386 CHECK_TYPE0(XPATH_LOCATIONSET
);
13388 if ((ctxt
->value
->user
== NULL
) ||
13389 (((xmlLocationSetPtr
) ctxt
->value
->user
)->locNr
== 0))
13392 obj
= valuePop(ctxt
);
13393 oldlocset
= obj
->user
;
13395 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13397 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13399 * Run the evaluation with a node list made of a
13400 * single item in the nodelocset.
13402 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13403 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13404 ctxt
->context
->proximityPosition
= i
+ 1;
13405 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13406 ctxt
->context
->node
);
13407 valuePush(ctxt
, tmp
);
13411 xmlXPathCompOpEval(ctxt
,
13412 &comp
->steps
[op
->ch2
]);
13413 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13414 xmlXPtrFreeLocationSet(newlocset
);
13415 goto rangeto_error
;
13418 res
= valuePop(ctxt
);
13419 if (res
->type
== XPATH_LOCATIONSET
) {
13420 xmlLocationSetPtr rloc
=
13421 (xmlLocationSetPtr
)res
->user
;
13422 for (j
=0; j
<rloc
->locNr
; j
++) {
13423 range
= xmlXPtrNewRange(
13424 oldlocset
->locTab
[i
]->user
,
13425 oldlocset
->locTab
[i
]->index
,
13426 rloc
->locTab
[j
]->user2
,
13427 rloc
->locTab
[j
]->index2
);
13428 if (range
!= NULL
) {
13429 xmlXPtrLocationSetAdd(newlocset
, range
);
13433 range
= xmlXPtrNewRangeNodeObject(
13434 (xmlNodePtr
)oldlocset
->locTab
[i
]->user
, res
);
13435 if (range
!= NULL
) {
13436 xmlXPtrLocationSetAdd(newlocset
,range
);
13444 xmlXPathReleaseObject(ctxt
->context
, res
);
13446 if (ctxt
->value
== tmp
) {
13447 res
= valuePop(ctxt
);
13448 xmlXPathReleaseObject(ctxt
->context
, res
);
13451 } else { /* Not a location set */
13452 CHECK_TYPE0(XPATH_NODESET
);
13453 obj
= valuePop(ctxt
);
13454 oldset
= obj
->nodesetval
;
13456 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13458 if (oldset
!= NULL
) {
13459 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13461 * Run the evaluation with a node list made of a single item
13464 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13466 * OPTIMIZE TODO: Avoid recreation for every iteration.
13468 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13469 ctxt
->context
->node
);
13470 valuePush(ctxt
, tmp
);
13474 xmlXPathCompOpEval(ctxt
,
13475 &comp
->steps
[op
->ch2
]);
13476 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13477 xmlXPtrFreeLocationSet(newlocset
);
13478 goto rangeto_error
;
13481 res
= valuePop(ctxt
);
13483 xmlXPtrNewRangeNodeObject(oldset
->nodeTab
[i
],
13485 if (range
!= NULL
) {
13486 xmlXPtrLocationSetAdd(newlocset
, range
);
13493 xmlXPathReleaseObject(ctxt
->context
, res
);
13495 if (ctxt
->value
== tmp
) {
13496 res
= valuePop(ctxt
);
13497 xmlXPathReleaseObject(ctxt
->context
, res
);
13504 * The result is used as the new evaluation set.
13506 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13508 xmlXPathReleaseObject(ctxt
->context
, obj
);
13509 ctxt
->context
->node
= oldnode
;
13510 ctxt
->context
->contextSize
= oldcs
;
13511 ctxt
->context
->proximityPosition
= oldpp
;
13514 #endif /* LIBXML_XPTR_LOCS_ENABLED */
13516 xmlGenericError(xmlGenericErrorContext
,
13517 "XPath: unknown precompiled operation %d\n", op
->op
);
13518 ctxt
->error
= XPATH_INVALID_OPERAND
;
13522 ctxt
->context
->depth
-= 1;
13527 * xmlXPathCompOpEvalToBoolean:
13528 * @ctxt: the XPath parser context
13530 * Evaluates if the expression evaluates to true.
13532 * Returns 1 if true, 0 if false and -1 on API or internal errors.
13535 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
13536 xmlXPathStepOpPtr op
,
13539 xmlXPathObjectPtr resObj
= NULL
;
13542 if (OP_LIMIT_EXCEEDED(ctxt
, 1))
13544 /* comp = ctxt->comp; */
13548 case XPATH_OP_VALUE
:
13549 resObj
= (xmlXPathObjectPtr
) op
->value4
;
13551 return(xmlXPathEvaluatePredicateResult(ctxt
, resObj
));
13552 return(xmlXPathCastToBoolean(resObj
));
13553 case XPATH_OP_SORT
:
13555 * We don't need sorting for boolean results. Skip this one.
13557 if (op
->ch1
!= -1) {
13558 op
= &ctxt
->comp
->steps
[op
->ch1
];
13562 case XPATH_OP_COLLECT
:
13566 xmlXPathCompOpEval(ctxt
, &ctxt
->comp
->steps
[op
->ch1
]);
13567 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13570 xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 1);
13571 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13574 resObj
= valuePop(ctxt
);
13575 if (resObj
== NULL
)
13580 * Fallback to call xmlXPathCompOpEval().
13582 xmlXPathCompOpEval(ctxt
, op
);
13583 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
13586 resObj
= valuePop(ctxt
);
13587 if (resObj
== NULL
)
13595 if (resObj
->type
== XPATH_BOOLEAN
) {
13596 res
= resObj
->boolval
;
13597 } else if (isPredicate
) {
13599 * For predicates a result of type "number" is handled
13602 * "If the result is a number, the result will be converted
13603 * to true if the number is equal to the context position
13604 * and will be converted to false otherwise;"
13606 res
= xmlXPathEvaluatePredicateResult(ctxt
, resObj
);
13608 res
= xmlXPathCastToBoolean(resObj
);
13610 xmlXPathReleaseObject(ctxt
->context
, resObj
);
13617 #ifdef XPATH_STREAMING
13619 * xmlXPathRunStreamEval:
13620 * @ctxt: the XPath parser context with the compiled expression
13622 * Evaluate the Precompiled Streamable XPath expression in the given context.
13625 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt
, xmlPatternPtr comp
,
13626 xmlXPathObjectPtr
*resultSeq
, int toBool
)
13628 int max_depth
, min_depth
;
13631 int eval_all_nodes
;
13632 xmlNodePtr cur
= NULL
, limit
= NULL
;
13633 xmlStreamCtxtPtr patstream
= NULL
;
13635 if ((ctxt
== NULL
) || (comp
== NULL
))
13637 max_depth
= xmlPatternMaxDepth(comp
);
13638 if (max_depth
== -1)
13640 if (max_depth
== -2)
13642 min_depth
= xmlPatternMinDepth(comp
);
13643 if (min_depth
== -1)
13645 from_root
= xmlPatternFromRoot(comp
);
13649 printf("stream eval: depth %d from root %d\n", max_depth
, from_root
);
13653 if (resultSeq
== NULL
)
13655 *resultSeq
= xmlXPathCacheNewNodeSet(ctxt
, NULL
);
13656 if (*resultSeq
== NULL
)
13661 * handle the special cases of "/" amd "." being matched
13663 if (min_depth
== 0) {
13668 /* TODO: Check memory error. */
13669 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
,
13670 (xmlNodePtr
) ctxt
->doc
);
13672 /* Select "self::node()" */
13675 /* TODO: Check memory error. */
13676 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, ctxt
->node
);
13679 if (max_depth
== 0) {
13684 cur
= (xmlNodePtr
)ctxt
->doc
;
13685 } else if (ctxt
->node
!= NULL
) {
13686 switch (ctxt
->node
->type
) {
13687 case XML_ELEMENT_NODE
:
13688 case XML_DOCUMENT_NODE
:
13689 case XML_DOCUMENT_FRAG_NODE
:
13690 case XML_HTML_DOCUMENT_NODE
:
13693 case XML_ATTRIBUTE_NODE
:
13694 case XML_TEXT_NODE
:
13695 case XML_CDATA_SECTION_NODE
:
13696 case XML_ENTITY_REF_NODE
:
13697 case XML_ENTITY_NODE
:
13699 case XML_COMMENT_NODE
:
13700 case XML_NOTATION_NODE
:
13702 case XML_DOCUMENT_TYPE_NODE
:
13703 case XML_ELEMENT_DECL
:
13704 case XML_ATTRIBUTE_DECL
:
13705 case XML_ENTITY_DECL
:
13706 case XML_NAMESPACE_DECL
:
13707 case XML_XINCLUDE_START
:
13708 case XML_XINCLUDE_END
:
13717 patstream
= xmlPatternGetStreamCtxt(comp
);
13718 if (patstream
== NULL
) {
13720 * QUESTION TODO: Is this an error?
13725 eval_all_nodes
= xmlStreamWantsAnyNode(patstream
);
13728 ret
= xmlStreamPush(patstream
, NULL
, NULL
);
13730 } else if (ret
== 1) {
13733 /* TODO: Check memory error. */
13734 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
);
13738 goto scan_children
;
13741 if (ctxt
->opLimit
!= 0) {
13742 if (ctxt
->opCount
>= ctxt
->opLimit
) {
13743 xmlGenericError(xmlGenericErrorContext
,
13744 "XPath operation limit exceeded\n");
13745 xmlFreeStreamCtxt(patstream
);
13751 switch (cur
->type
) {
13752 case XML_ELEMENT_NODE
:
13753 case XML_TEXT_NODE
:
13754 case XML_CDATA_SECTION_NODE
:
13755 case XML_COMMENT_NODE
:
13757 if (cur
->type
== XML_ELEMENT_NODE
) {
13758 ret
= xmlStreamPush(patstream
, cur
->name
,
13759 (cur
->ns
? cur
->ns
->href
: NULL
));
13760 } else if (eval_all_nodes
)
13761 ret
= xmlStreamPushNode(patstream
, NULL
, NULL
, cur
->type
);
13767 } else if (ret
== 1) {
13770 if (xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
)
13772 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
13773 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
13776 if ((cur
->children
== NULL
) || (depth
>= max_depth
)) {
13777 ret
= xmlStreamPop(patstream
);
13778 while (cur
->next
!= NULL
) {
13780 if ((cur
->type
!= XML_ENTITY_DECL
) &&
13781 (cur
->type
!= XML_DTD_NODE
))
13790 if (cur
->type
== XML_NAMESPACE_DECL
) break;
13791 if ((cur
->children
!= NULL
) && (depth
< max_depth
)) {
13793 * Do not descend on entities declarations
13795 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
13796 cur
= cur
->children
;
13801 if (cur
->type
!= XML_DTD_NODE
)
13809 while (cur
->next
!= NULL
) {
13811 if ((cur
->type
!= XML_ENTITY_DECL
) &&
13812 (cur
->type
!= XML_DTD_NODE
))
13819 if ((cur
== NULL
) || (cur
== limit
) ||
13820 (cur
->type
== XML_DOCUMENT_NODE
))
13822 if (cur
->type
== XML_ELEMENT_NODE
) {
13823 ret
= xmlStreamPop(patstream
);
13824 } else if ((eval_all_nodes
) &&
13825 ((cur
->type
== XML_TEXT_NODE
) ||
13826 (cur
->type
== XML_CDATA_SECTION_NODE
) ||
13827 (cur
->type
== XML_COMMENT_NODE
) ||
13828 (cur
->type
== XML_PI_NODE
)))
13830 ret
= xmlStreamPop(patstream
);
13832 if (cur
->next
!= NULL
) {
13836 } while (cur
!= NULL
);
13838 } while ((cur
!= NULL
) && (depth
>= 0));
13843 xmlFreeStreamCtxt(patstream
);
13848 xmlFreeStreamCtxt(patstream
);
13851 #endif /* XPATH_STREAMING */
13855 * @ctxt: the XPath parser context with the compiled expression
13856 * @toBool: evaluate to a boolean result
13858 * Evaluate the Precompiled XPath expression in the given context.
13861 xmlXPathRunEval(xmlXPathParserContextPtr ctxt
, int toBool
)
13863 xmlXPathCompExprPtr comp
;
13866 if ((ctxt
== NULL
) || (ctxt
->comp
== NULL
))
13869 if (ctxt
->valueTab
== NULL
) {
13870 /* Allocate the value stack */
13871 ctxt
->valueTab
= (xmlXPathObjectPtr
*)
13872 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
13873 if (ctxt
->valueTab
== NULL
) {
13874 xmlXPathPErrMemory(ctxt
, "creating evaluation context\n");
13878 ctxt
->valueMax
= 10;
13879 ctxt
->value
= NULL
;
13881 #ifdef XPATH_STREAMING
13882 if (ctxt
->comp
->stream
) {
13887 * Evaluation to boolean result.
13889 res
= xmlXPathRunStreamEval(ctxt
->context
,
13890 ctxt
->comp
->stream
, NULL
, 1);
13894 xmlXPathObjectPtr resObj
= NULL
;
13897 * Evaluation to a sequence.
13899 res
= xmlXPathRunStreamEval(ctxt
->context
,
13900 ctxt
->comp
->stream
, &resObj
, 0);
13902 if ((res
!= -1) && (resObj
!= NULL
)) {
13903 valuePush(ctxt
, resObj
);
13906 if (resObj
!= NULL
)
13907 xmlXPathReleaseObject(ctxt
->context
, resObj
);
13910 * QUESTION TODO: This falls back to normal XPath evaluation
13911 * if res == -1. Is this intended?
13916 if (comp
->last
< 0) {
13917 xmlGenericError(xmlGenericErrorContext
,
13918 "xmlXPathRunEval: last is less than zero\n");
13921 oldDepth
= ctxt
->context
->depth
;
13923 return(xmlXPathCompOpEvalToBoolean(ctxt
,
13924 &comp
->steps
[comp
->last
], 0));
13926 xmlXPathCompOpEval(ctxt
, &comp
->steps
[comp
->last
]);
13927 ctxt
->context
->depth
= oldDepth
;
13932 /************************************************************************
13934 * Public interfaces *
13936 ************************************************************************/
13939 * xmlXPathEvalPredicate:
13940 * @ctxt: the XPath context
13941 * @res: the Predicate Expression evaluation result
13943 * Evaluate a predicate result for the current node.
13944 * A PredicateExpr is evaluated by evaluating the Expr and converting
13945 * the result to a boolean. If the result is a number, the result will
13946 * be converted to true if the number is equal to the position of the
13947 * context node in the context node list (as returned by the position
13948 * function) and will be converted to false otherwise; if the result
13949 * is not a number, then the result will be converted as if by a call
13950 * to the boolean function.
13952 * Returns 1 if predicate is true, 0 otherwise
13955 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr res
) {
13956 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
13957 switch (res
->type
) {
13958 case XPATH_BOOLEAN
:
13959 return(res
->boolval
);
13961 return(res
->floatval
== ctxt
->proximityPosition
);
13962 case XPATH_NODESET
:
13963 case XPATH_XSLT_TREE
:
13964 if (res
->nodesetval
== NULL
)
13966 return(res
->nodesetval
->nodeNr
!= 0);
13968 return((res
->stringval
!= NULL
) &&
13969 (xmlStrlen(res
->stringval
) != 0));
13977 * xmlXPathEvaluatePredicateResult:
13978 * @ctxt: the XPath Parser context
13979 * @res: the Predicate Expression evaluation result
13981 * Evaluate a predicate result for the current node.
13982 * A PredicateExpr is evaluated by evaluating the Expr and converting
13983 * the result to a boolean. If the result is a number, the result will
13984 * be converted to true if the number is equal to the position of the
13985 * context node in the context node list (as returned by the position
13986 * function) and will be converted to false otherwise; if the result
13987 * is not a number, then the result will be converted as if by a call
13988 * to the boolean function.
13990 * Returns 1 if predicate is true, 0 otherwise
13993 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt
,
13994 xmlXPathObjectPtr res
) {
13995 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
13996 switch (res
->type
) {
13997 case XPATH_BOOLEAN
:
13998 return(res
->boolval
);
14000 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14001 return((res
->floatval
== ctxt
->context
->proximityPosition
) &&
14002 (!xmlXPathIsNaN(res
->floatval
))); /* MSC pbm Mark Vakoc !*/
14004 return(res
->floatval
== ctxt
->context
->proximityPosition
);
14006 case XPATH_NODESET
:
14007 case XPATH_XSLT_TREE
:
14008 if (res
->nodesetval
== NULL
)
14010 return(res
->nodesetval
->nodeNr
!= 0);
14012 return((res
->stringval
!= NULL
) && (res
->stringval
[0] != 0));
14013 #ifdef LIBXML_XPTR_LOCS_ENABLED
14014 case XPATH_LOCATIONSET
:{
14015 xmlLocationSetPtr ptr
= res
->user
;
14018 return (ptr
->locNr
!= 0);
14027 #ifdef XPATH_STREAMING
14029 * xmlXPathTryStreamCompile:
14030 * @ctxt: an XPath context
14031 * @str: the XPath expression
14033 * Try to compile the XPath expression as a streamable subset.
14035 * Returns the compiled expression or NULL if failed to compile.
14037 static xmlXPathCompExprPtr
14038 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14040 * Optimization: use streaming patterns when the XPath expression can
14041 * be compiled to a stream lookup
14043 xmlPatternPtr stream
;
14044 xmlXPathCompExprPtr comp
;
14045 xmlDictPtr dict
= NULL
;
14046 const xmlChar
**namespaces
= NULL
;
14050 if ((!xmlStrchr(str
, '[')) && (!xmlStrchr(str
, '(')) &&
14051 (!xmlStrchr(str
, '@'))) {
14052 const xmlChar
*tmp
;
14055 * We don't try to handle expressions using the verbose axis
14056 * specifiers ("::"), just the simplified form at this point.
14057 * Additionally, if there is no list of namespaces available and
14058 * there's a ":" in the expression, indicating a prefixed QName,
14059 * then we won't try to compile either. xmlPatterncompile() needs
14060 * to have a list of namespaces at compilation time in order to
14061 * compile prefixed name tests.
14063 tmp
= xmlStrchr(str
, ':');
14064 if ((tmp
!= NULL
) &&
14065 ((ctxt
== NULL
) || (ctxt
->nsNr
== 0) || (tmp
[1] == ':')))
14068 if (ctxt
!= NULL
) {
14070 if (ctxt
->nsNr
> 0) {
14071 namespaces
= xmlMalloc(2 * (ctxt
->nsNr
+ 1) * sizeof(xmlChar
*));
14072 if (namespaces
== NULL
) {
14073 xmlXPathErrMemory(ctxt
, "allocating namespaces array\n");
14076 for (i
= 0, j
= 0; (j
< ctxt
->nsNr
); j
++) {
14077 ns
= ctxt
->namespaces
[j
];
14078 namespaces
[i
++] = ns
->href
;
14079 namespaces
[i
++] = ns
->prefix
;
14081 namespaces
[i
++] = NULL
;
14082 namespaces
[i
] = NULL
;
14086 stream
= xmlPatterncompile(str
, dict
, XML_PATTERN_XPATH
, namespaces
);
14087 if (namespaces
!= NULL
) {
14088 xmlFree((xmlChar
**)namespaces
);
14090 if ((stream
!= NULL
) && (xmlPatternStreamable(stream
) == 1)) {
14091 comp
= xmlXPathNewCompExpr();
14092 if (comp
== NULL
) {
14093 xmlXPathErrMemory(ctxt
, "allocating streamable expression\n");
14094 xmlFreePattern(stream
);
14097 comp
->stream
= stream
;
14100 xmlDictReference(comp
->dict
);
14103 xmlFreePattern(stream
);
14107 #endif /* XPATH_STREAMING */
14110 xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt
,
14111 xmlXPathStepOpPtr op
)
14113 xmlXPathCompExprPtr comp
= pctxt
->comp
;
14114 xmlXPathContextPtr ctxt
;
14117 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14118 * internal representation.
14121 if ((op
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14123 (op
->ch2
== -1 /* no predicate */))
14125 xmlXPathStepOpPtr prevop
= &comp
->steps
[op
->ch1
];
14127 if ((prevop
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14128 ((xmlXPathAxisVal
) prevop
->value
==
14129 AXIS_DESCENDANT_OR_SELF
) &&
14130 (prevop
->ch2
== -1) &&
14131 ((xmlXPathTestVal
) prevop
->value2
== NODE_TEST_TYPE
) &&
14132 ((xmlXPathTypeVal
) prevop
->value3
== NODE_TYPE_NODE
))
14135 * This is a "descendant-or-self::node()" without predicates.
14136 * Try to eliminate it.
14139 switch ((xmlXPathAxisVal
) op
->value
) {
14141 case AXIS_DESCENDANT
:
14143 * Convert "descendant-or-self::node()/child::" or
14144 * "descendant-or-self::node()/descendant::" to
14147 op
->ch1
= prevop
->ch1
;
14148 op
->value
= AXIS_DESCENDANT
;
14151 case AXIS_DESCENDANT_OR_SELF
:
14153 * Convert "descendant-or-self::node()/self::" or
14154 * "descendant-or-self::node()/descendant-or-self::" to
14155 * to "descendant-or-self::"
14157 op
->ch1
= prevop
->ch1
;
14158 op
->value
= AXIS_DESCENDANT_OR_SELF
;
14166 /* OP_VALUE has invalid ch1. */
14167 if (op
->op
== XPATH_OP_VALUE
)
14171 ctxt
= pctxt
->context
;
14172 if (ctxt
!= NULL
) {
14173 if (ctxt
->depth
>= XPATH_MAX_RECURSION_DEPTH
)
14178 xmlXPathOptimizeExpression(pctxt
, &comp
->steps
[op
->ch1
]);
14180 xmlXPathOptimizeExpression(pctxt
, &comp
->steps
[op
->ch2
]);
14186 * xmlXPathCtxtCompile:
14187 * @ctxt: an XPath context
14188 * @str: the XPath expression
14190 * Compile an XPath expression
14192 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14193 * the caller has to free the object.
14195 xmlXPathCompExprPtr
14196 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14197 xmlXPathParserContextPtr pctxt
;
14198 xmlXPathCompExprPtr comp
;
14201 #ifdef XPATH_STREAMING
14202 comp
= xmlXPathTryStreamCompile(ctxt
, str
);
14209 pctxt
= xmlXPathNewParserContext(str
, ctxt
);
14213 oldDepth
= ctxt
->depth
;
14214 xmlXPathCompileExpr(pctxt
, 1);
14216 ctxt
->depth
= oldDepth
;
14218 if( pctxt
->error
!= XPATH_EXPRESSION_OK
)
14220 xmlXPathFreeParserContext(pctxt
);
14224 if (*pctxt
->cur
!= 0) {
14226 * aleksey: in some cases this line prints *second* error message
14227 * (see bug #78858) and probably this should be fixed.
14228 * However, we are not sure that all error messages are printed
14229 * out in other places. It's not critical so we leave it as-is for now
14231 xmlXPatherror(pctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
14234 comp
= pctxt
->comp
;
14235 if ((comp
->nbStep
> 1) && (comp
->last
>= 0)) {
14237 oldDepth
= ctxt
->depth
;
14238 xmlXPathOptimizeExpression(pctxt
, &comp
->steps
[comp
->last
]);
14240 ctxt
->depth
= oldDepth
;
14242 pctxt
->comp
= NULL
;
14244 xmlXPathFreeParserContext(pctxt
);
14246 if (comp
!= NULL
) {
14247 comp
->expr
= xmlStrdup(str
);
14248 #ifdef DEBUG_EVAL_COUNTS
14249 comp
->string
= xmlStrdup(str
);
14258 * @str: the XPath expression
14260 * Compile an XPath expression
14262 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14263 * the caller has to free the object.
14265 xmlXPathCompExprPtr
14266 xmlXPathCompile(const xmlChar
*str
) {
14267 return(xmlXPathCtxtCompile(NULL
, str
));
14271 * xmlXPathCompiledEvalInternal:
14272 * @comp: the compiled XPath expression
14273 * @ctxt: the XPath context
14274 * @resObj: the resulting XPath object or NULL
14275 * @toBool: 1 if only a boolean result is requested
14277 * Evaluate the Precompiled XPath expression in the given context.
14278 * The caller has to free @resObj.
14280 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14281 * the caller has to free the object.
14284 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp
,
14285 xmlXPathContextPtr ctxt
,
14286 xmlXPathObjectPtr
*resObjPtr
,
14289 xmlXPathParserContextPtr pctxt
;
14290 xmlXPathObjectPtr resObj
;
14291 #ifndef LIBXML_THREAD_ENABLED
14292 static int reentance
= 0;
14296 CHECK_CTXT_NEG(ctxt
)
14302 #ifndef LIBXML_THREAD_ENABLED
14305 xmlXPathDisableOptimizer
= 1;
14308 #ifdef DEBUG_EVAL_COUNTS
14310 if ((comp
->string
!= NULL
) && (comp
->nb
> 100)) {
14311 fprintf(stderr
, "100 x %s\n", comp
->string
);
14315 pctxt
= xmlXPathCompParserContext(comp
, ctxt
);
14318 res
= xmlXPathRunEval(pctxt
, toBool
);
14320 if (pctxt
->error
!= XPATH_EXPRESSION_OK
) {
14323 resObj
= valuePop(pctxt
);
14324 if (resObj
== NULL
) {
14326 xmlGenericError(xmlGenericErrorContext
,
14327 "xmlXPathCompiledEval: No result on the stack.\n");
14328 } else if (pctxt
->valueNr
> 0) {
14329 xmlGenericError(xmlGenericErrorContext
,
14330 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14336 *resObjPtr
= resObj
;
14338 xmlXPathReleaseObject(ctxt
, resObj
);
14340 pctxt
->comp
= NULL
;
14341 xmlXPathFreeParserContext(pctxt
);
14342 #ifndef LIBXML_THREAD_ENABLED
14350 * xmlXPathCompiledEval:
14351 * @comp: the compiled XPath expression
14352 * @ctx: the XPath context
14354 * Evaluate the Precompiled XPath expression in the given context.
14356 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14357 * the caller has to free the object.
14360 xmlXPathCompiledEval(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctx
)
14362 xmlXPathObjectPtr res
= NULL
;
14364 xmlXPathCompiledEvalInternal(comp
, ctx
, &res
, 0);
14369 * xmlXPathCompiledEvalToBoolean:
14370 * @comp: the compiled XPath expression
14371 * @ctxt: the XPath context
14373 * Applies the XPath boolean() function on the result of the given
14374 * compiled expression.
14376 * Returns 1 if the expression evaluated to true, 0 if to false and
14377 * -1 in API and internal errors.
14380 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp
,
14381 xmlXPathContextPtr ctxt
)
14383 return(xmlXPathCompiledEvalInternal(comp
, ctxt
, NULL
, 1));
14387 * xmlXPathEvalExpr:
14388 * @ctxt: the XPath Parser context
14390 * Parse and evaluate an XPath expression in the given context,
14391 * then push the result on the context stack
14394 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt
) {
14395 #ifdef XPATH_STREAMING
14396 xmlXPathCompExprPtr comp
;
14400 if (ctxt
== NULL
) return;
14402 #ifdef XPATH_STREAMING
14403 comp
= xmlXPathTryStreamCompile(ctxt
->context
, ctxt
->base
);
14404 if (comp
!= NULL
) {
14405 if (ctxt
->comp
!= NULL
)
14406 xmlXPathFreeCompExpr(ctxt
->comp
);
14411 if (ctxt
->context
!= NULL
)
14412 oldDepth
= ctxt
->context
->depth
;
14413 xmlXPathCompileExpr(ctxt
, 1);
14414 if (ctxt
->context
!= NULL
)
14415 ctxt
->context
->depth
= oldDepth
;
14418 /* Check for trailing characters. */
14419 if (*ctxt
->cur
!= 0)
14420 XP_ERROR(XPATH_EXPR_ERROR
);
14422 if ((ctxt
->comp
->nbStep
> 1) && (ctxt
->comp
->last
>= 0)) {
14423 if (ctxt
->context
!= NULL
)
14424 oldDepth
= ctxt
->context
->depth
;
14425 xmlXPathOptimizeExpression(ctxt
,
14426 &ctxt
->comp
->steps
[ctxt
->comp
->last
]);
14427 if (ctxt
->context
!= NULL
)
14428 ctxt
->context
->depth
= oldDepth
;
14432 xmlXPathRunEval(ctxt
, 0);
14437 * @str: the XPath expression
14438 * @ctx: the XPath context
14440 * Evaluate the XPath Location Path in the given context.
14442 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14443 * the caller has to free the object.
14446 xmlXPathEval(const xmlChar
*str
, xmlXPathContextPtr ctx
) {
14447 xmlXPathParserContextPtr ctxt
;
14448 xmlXPathObjectPtr res
;
14454 ctxt
= xmlXPathNewParserContext(str
, ctx
);
14457 xmlXPathEvalExpr(ctxt
);
14459 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14462 res
= valuePop(ctxt
);
14464 xmlGenericError(xmlGenericErrorContext
,
14465 "xmlXPathCompiledEval: No result on the stack.\n");
14466 } else if (ctxt
->valueNr
> 0) {
14467 xmlGenericError(xmlGenericErrorContext
,
14468 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14473 xmlXPathFreeParserContext(ctxt
);
14478 * xmlXPathSetContextNode:
14479 * @node: the node to to use as the context node
14480 * @ctx: the XPath context
14482 * Sets 'node' as the context node. The node must be in the same
14483 * document as that associated with the context.
14485 * Returns -1 in case of error or 0 if successful
14488 xmlXPathSetContextNode(xmlNodePtr node
, xmlXPathContextPtr ctx
) {
14489 if ((node
== NULL
) || (ctx
== NULL
))
14492 if (node
->doc
== ctx
->doc
) {
14500 * xmlXPathNodeEval:
14501 * @node: the node to to use as the context node
14502 * @str: the XPath expression
14503 * @ctx: the XPath context
14505 * Evaluate the XPath Location Path in the given context. The node 'node'
14506 * is set as the context node. The context node is not restored.
14508 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14509 * the caller has to free the object.
14512 xmlXPathNodeEval(xmlNodePtr node
, const xmlChar
*str
, xmlXPathContextPtr ctx
) {
14515 if (xmlXPathSetContextNode(node
, ctx
) < 0)
14517 return(xmlXPathEval(str
, ctx
));
14521 * xmlXPathEvalExpression:
14522 * @str: the XPath expression
14523 * @ctxt: the XPath context
14525 * Alias for xmlXPathEval().
14527 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14528 * the caller has to free the object.
14531 xmlXPathEvalExpression(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
14532 return(xmlXPathEval(str
, ctxt
));
14535 /************************************************************************
14537 * Extra functions not pertaining to the XPath spec *
14539 ************************************************************************/
14541 * xmlXPathEscapeUriFunction:
14542 * @ctxt: the XPath Parser context
14543 * @nargs: the number of arguments
14545 * Implement the escape-uri() XPath function
14546 * string escape-uri(string $str, bool $escape-reserved)
14548 * This function applies the URI escaping rules defined in section 2 of [RFC
14549 * 2396] to the string supplied as $uri-part, which typically represents all
14550 * or part of a URI. The effect of the function is to replace any special
14551 * character in the string by an escape sequence of the form %xx%yy...,
14552 * where xxyy... is the hexadecimal representation of the octets used to
14553 * represent the character in UTF-8.
14555 * The set of characters that are escaped depends on the setting of the
14556 * boolean argument $escape-reserved.
14558 * If $escape-reserved is true, all characters are escaped other than lower
14559 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
14560 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
14561 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
14562 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
14565 * If $escape-reserved is false, the behavior differs in that characters
14566 * referred to in [RFC 2396] as reserved characters are not escaped. These
14567 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
14569 * [RFC 2396] does not define whether escaped URIs should use lower case or
14570 * upper case for hexadecimal digits. To ensure that escaped URIs can be
14571 * compared using string comparison functions, this function must always use
14572 * the upper-case letters A-F.
14574 * Generally, $escape-reserved should be set to true when escaping a string
14575 * that is to form a single part of a URI, and to false when escaping an
14576 * entire URI or URI reference.
14578 * In the case of non-ascii characters, the string is encoded according to
14579 * utf-8 and then converted according to RFC 2396.
14582 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
14583 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
14584 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
14585 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
14589 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
14590 xmlXPathObjectPtr str
;
14591 int escape_reserved
;
14598 escape_reserved
= xmlXPathPopBoolean(ctxt
);
14601 str
= valuePop(ctxt
);
14603 target
= xmlBufCreate();
14609 for (cptr
= str
->stringval
; *cptr
; cptr
++) {
14610 if ((*cptr
>= 'A' && *cptr
<= 'Z') ||
14611 (*cptr
>= 'a' && *cptr
<= 'z') ||
14612 (*cptr
>= '0' && *cptr
<= '9') ||
14613 *cptr
== '-' || *cptr
== '_' || *cptr
== '.' ||
14614 *cptr
== '!' || *cptr
== '~' || *cptr
== '*' ||
14615 *cptr
== '\''|| *cptr
== '(' || *cptr
== ')' ||
14617 ((cptr
[1] >= 'A' && cptr
[1] <= 'F') ||
14618 (cptr
[1] >= 'a' && cptr
[1] <= 'f') ||
14619 (cptr
[1] >= '0' && cptr
[1] <= '9')) &&
14620 ((cptr
[2] >= 'A' && cptr
[2] <= 'F') ||
14621 (cptr
[2] >= 'a' && cptr
[2] <= 'f') ||
14622 (cptr
[2] >= '0' && cptr
[2] <= '9'))) ||
14623 (!escape_reserved
&&
14624 (*cptr
== ';' || *cptr
== '/' || *cptr
== '?' ||
14625 *cptr
== ':' || *cptr
== '@' || *cptr
== '&' ||
14626 *cptr
== '=' || *cptr
== '+' || *cptr
== '$' ||
14628 xmlBufAdd(target
, cptr
, 1);
14630 if ((*cptr
>> 4) < 10)
14631 escape
[1] = '0' + (*cptr
>> 4);
14633 escape
[1] = 'A' - 10 + (*cptr
>> 4);
14634 if ((*cptr
& 0xF) < 10)
14635 escape
[2] = '0' + (*cptr
& 0xF);
14637 escape
[2] = 'A' - 10 + (*cptr
& 0xF);
14639 xmlBufAdd(target
, &escape
[0], 3);
14643 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
14644 xmlBufContent(target
)));
14645 xmlBufFree(target
);
14646 xmlXPathReleaseObject(ctxt
->context
, str
);
14650 * xmlXPathRegisterAllFunctions:
14651 * @ctxt: the XPath context
14653 * Registers all default XPath functions in this context
14656 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt
)
14658 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"boolean",
14659 xmlXPathBooleanFunction
);
14660 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"ceiling",
14661 xmlXPathCeilingFunction
);
14662 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"count",
14663 xmlXPathCountFunction
);
14664 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"concat",
14665 xmlXPathConcatFunction
);
14666 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"contains",
14667 xmlXPathContainsFunction
);
14668 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"id",
14669 xmlXPathIdFunction
);
14670 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"false",
14671 xmlXPathFalseFunction
);
14672 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"floor",
14673 xmlXPathFloorFunction
);
14674 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"last",
14675 xmlXPathLastFunction
);
14676 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"lang",
14677 xmlXPathLangFunction
);
14678 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"local-name",
14679 xmlXPathLocalNameFunction
);
14680 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"not",
14681 xmlXPathNotFunction
);
14682 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"name",
14683 xmlXPathNameFunction
);
14684 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"namespace-uri",
14685 xmlXPathNamespaceURIFunction
);
14686 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"normalize-space",
14687 xmlXPathNormalizeFunction
);
14688 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"number",
14689 xmlXPathNumberFunction
);
14690 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"position",
14691 xmlXPathPositionFunction
);
14692 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"round",
14693 xmlXPathRoundFunction
);
14694 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string",
14695 xmlXPathStringFunction
);
14696 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string-length",
14697 xmlXPathStringLengthFunction
);
14698 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"starts-with",
14699 xmlXPathStartsWithFunction
);
14700 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring",
14701 xmlXPathSubstringFunction
);
14702 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-before",
14703 xmlXPathSubstringBeforeFunction
);
14704 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-after",
14705 xmlXPathSubstringAfterFunction
);
14706 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"sum",
14707 xmlXPathSumFunction
);
14708 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"true",
14709 xmlXPathTrueFunction
);
14710 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"translate",
14711 xmlXPathTranslateFunction
);
14713 xmlXPathRegisterFuncNS(ctxt
, (const xmlChar
*)"escape-uri",
14714 (const xmlChar
*)"http://www.w3.org/2002/08/xquery-functions",
14715 xmlXPathEscapeUriFunction
);
14718 #endif /* LIBXML_XPATH_ENABLED */