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
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
54 #ifdef LIBXML_PATTERN_ENABLED
55 #include <libxml/pattern.h>
60 #ifdef LIBXML_PATTERN_ENABLED
61 #define XPATH_STREAMING
65 xmlGenericError(xmlGenericErrorContext, \
66 "Unimplemented block at %s:%d\n", \
72 * Use the Timsort algorithm provided in timsort.h to sort
73 * nodeset as this is a great improvement over the old Shell sort
74 * used in xmlXPathNodeSetSort()
79 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
80 * If defined, this will use xmlXPathCmpNodesExt() instead of
81 * xmlXPathCmpNodes(). The new function is optimized comparison of
82 * non-element nodes; actually it will speed up comparison only if
83 * xmlXPathOrderDocElems() was called in order to index the elements of
84 * a tree in document order; Libxslt does such an indexing, thus it will
85 * benefit from this optimization.
87 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
90 * XP_OPTIMIZED_FILTER_FIRST:
91 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
92 * in a way, that it stop evaluation at the first node.
94 #define XP_OPTIMIZED_FILTER_FIRST
98 * Internal flag to enable tracking of how much XPath objects have been
101 /* #define XP_DEBUG_OBJ_USAGE */
105 * when compiling an XPath expression we arbitrary limit the maximum
106 * number of step operation in the compiled expression. 1000000 is
107 * an insanely large value which should never be reached under normal
110 #define XPATH_MAX_STEPS 1000000
113 * XPATH_MAX_STACK_DEPTH:
114 * when evaluating an XPath expression we arbitrary limit the maximum
115 * number of object allowed to be pushed on the stack. 1000000 is
116 * an insanely large value which should never be reached under normal
119 #define XPATH_MAX_STACK_DEPTH 1000000
122 * XPATH_MAX_NODESET_LENGTH:
123 * when evaluating an XPath expression nodesets are created and we
124 * arbitrary limit the maximum length of those node set. 10000000 is
125 * an insanely large value which should never be reached under normal
126 * circumstances, one would first need to construct an in memory tree
127 * with more than 10 millions nodes.
129 #define XPATH_MAX_NODESET_LENGTH 10000000
133 * There are a few spots where some tests are done which depend upon ascii
134 * data. These should be enhanced for full UTF8 support (see particularly
135 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
139 * Wrapper for the Timsort argorithm from timsort.h
142 #define SORT_NAME libxml_domnode
143 #define SORT_TYPE xmlNodePtr
149 * Comparison function for the Timsort implementation
151 * Returns -2 in case of error -1 if first point < second point, 0 if
152 * it's the same node, +1 otherwise
155 int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
);
156 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
157 static int xmlXPathCmpNodesExt(xmlNodePtr
, xmlNodePtr
);
158 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
160 int res
= xmlXPathCmpNodesExt(x
, y
);
161 return res
== -2 ? res
: -res
;
164 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
166 int res
= xmlXPathCmpNodes(x
, y
);
167 return res
== -2 ? res
: -res
;
170 #define SORT_CMP(x, y) (wrap_cmp(x, y))
172 #endif /* WITH_TIM_SORT */
174 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
176 /************************************************************************
178 * Floating point stuff *
180 ************************************************************************/
182 #ifndef TRIO_REPLACE_STDIO
183 #define TRIO_PUBLIC static
188 * The lack of portability of this section of the libc is annoying !
190 double xmlXPathNAN
= 0;
191 double xmlXPathPINF
= 1;
192 double xmlXPathNINF
= -1;
193 static double xmlXPathNZERO
= 0; /* not exported from headers */
194 static int xmlXPathInitialized
= 0;
199 * Initialize the XPath environment
203 if (xmlXPathInitialized
) return;
205 xmlXPathPINF
= trio_pinf();
206 xmlXPathNINF
= trio_ninf();
207 xmlXPathNAN
= trio_nan();
208 xmlXPathNZERO
= trio_nzero();
210 xmlXPathInitialized
= 1;
215 * @val: a double value
217 * Provides a portable isnan() function to detect whether a double
218 * is a NotaNumber. Based on trio code
219 * http://sourceforge.net/projects/ctrio/
221 * Returns 1 if the value is a NaN, 0 otherwise
224 xmlXPathIsNaN(double val
) {
225 return(trio_isnan(val
));
230 * @val: a double value
232 * Provides a portable isinf() function to detect whether a double
233 * is a +Infinite or -Infinite. Based on trio code
234 * http://sourceforge.net/projects/ctrio/
236 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
239 xmlXPathIsInf(double val
) {
240 return(trio_isinf(val
));
243 #endif /* SCHEMAS or XPATH */
244 #ifdef LIBXML_XPATH_ENABLED
247 * @val: a double value
249 * Provides a portable function to detect the sign of a double
250 * Modified from trio code
251 * http://sourceforge.net/projects/ctrio/
253 * Returns 1 if the value is Negative, 0 if positive
256 xmlXPathGetSign(double val
) {
257 return(trio_signbit(val
));
262 * TODO: when compatibility allows remove all "fake node libxslt" strings
263 * the test should just be name[0] = ' '
265 #ifdef DEBUG_XPATH_EXPRESSION
268 #define DEBUG_EVAL_COUNTS
271 static xmlNs xmlXPathXMLNamespaceStruct
= {
279 static xmlNsPtr xmlXPathXMLNamespace
= &xmlXPathXMLNamespaceStruct
;
280 #ifndef LIBXML_THREAD_ENABLED
282 * Optimizer is disabled only when threaded apps are detected while
283 * the library ain't compiled for thread safety.
285 static int xmlXPathDisableOptimizer
= 0;
288 /************************************************************************
290 * Error handling routines *
292 ************************************************************************/
298 * Macro to raise an XPath error and return NULL.
300 #define XP_ERRORNULL(X) \
301 { xmlXPathErr(ctxt, X); return(NULL); }
304 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
306 static const char *xmlXPathErrorMessages
[] = {
309 "Unfinished literal\n",
310 "Start of literal\n",
311 "Expected $ for variable reference\n",
312 "Undefined variable\n",
313 "Invalid predicate\n",
314 "Invalid expression\n",
315 "Missing closing curly brace\n",
316 "Unregistered function\n",
319 "Invalid number of arguments\n",
320 "Invalid context size\n",
321 "Invalid context position\n",
322 "Memory allocation error\n",
325 "Sub resource error\n",
326 "Undefined namespace prefix\n",
328 "Char out of XML range\n",
329 "Invalid or incomplete context\n",
330 "Stack usage errror\n",
331 "Forbidden variable\n",
332 "?? Unknown error ??\n" /* Must be last in the list! */
334 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
335 sizeof(xmlXPathErrorMessages[0])) - 1)
338 * @ctxt: an XPath context
339 * @extra: extra informations
341 * Handle a redefinition of attribute error
344 xmlXPathErrMemory(xmlXPathContextPtr ctxt
, const char *extra
)
350 xmlStrPrintf(buf
, 200,
351 BAD_CAST
"Memory allocation failed : %s\n",
353 ctxt
->lastError
.message
= (char *) xmlStrdup(buf
);
355 ctxt
->lastError
.message
= (char *)
356 xmlStrdup(BAD_CAST
"Memory allocation failed\n");
358 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
359 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
360 if (ctxt
->error
!= NULL
)
361 ctxt
->error(ctxt
->userData
, &ctxt
->lastError
);
364 __xmlRaiseError(NULL
, NULL
, NULL
,
365 NULL
, NULL
, XML_FROM_XPATH
,
366 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
367 extra
, NULL
, NULL
, 0, 0,
368 "Memory allocation failed : %s\n", extra
);
370 __xmlRaiseError(NULL
, NULL
, NULL
,
371 NULL
, NULL
, XML_FROM_XPATH
,
372 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
373 NULL
, NULL
, NULL
, 0, 0,
374 "Memory allocation failed\n");
379 * xmlXPathPErrMemory:
380 * @ctxt: an XPath parser context
381 * @extra: extra informations
383 * Handle a redefinition of attribute error
386 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt
, const char *extra
)
389 xmlXPathErrMemory(NULL
, extra
);
391 ctxt
->error
= XPATH_MEMORY_ERROR
;
392 xmlXPathErrMemory(ctxt
->context
, extra
);
398 * @ctxt: a XPath parser context
399 * @error: the error code
401 * Handle an XPath error
404 xmlXPathErr(xmlXPathParserContextPtr ctxt
, int error
)
406 if ((error
< 0) || (error
> MAXERRNO
))
409 __xmlRaiseError(NULL
, NULL
, NULL
,
410 NULL
, NULL
, XML_FROM_XPATH
,
411 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
412 XML_ERR_ERROR
, NULL
, 0,
413 NULL
, NULL
, NULL
, 0, 0,
414 "%s", xmlXPathErrorMessages
[error
]);
418 if (ctxt
->context
== NULL
) {
419 __xmlRaiseError(NULL
, NULL
, NULL
,
420 NULL
, NULL
, XML_FROM_XPATH
,
421 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
422 XML_ERR_ERROR
, NULL
, 0,
423 (const char *) ctxt
->base
, NULL
, NULL
,
424 ctxt
->cur
- ctxt
->base
, 0,
425 "%s", xmlXPathErrorMessages
[error
]);
429 /* cleanup current last error */
430 xmlResetError(&ctxt
->context
->lastError
);
432 ctxt
->context
->lastError
.domain
= XML_FROM_XPATH
;
433 ctxt
->context
->lastError
.code
= error
+ XML_XPATH_EXPRESSION_OK
-
435 ctxt
->context
->lastError
.level
= XML_ERR_ERROR
;
436 ctxt
->context
->lastError
.str1
= (char *) xmlStrdup(ctxt
->base
);
437 ctxt
->context
->lastError
.int1
= ctxt
->cur
- ctxt
->base
;
438 ctxt
->context
->lastError
.node
= ctxt
->context
->debugNode
;
439 if (ctxt
->context
->error
!= NULL
) {
440 ctxt
->context
->error(ctxt
->context
->userData
,
441 &ctxt
->context
->lastError
);
443 __xmlRaiseError(NULL
, NULL
, NULL
,
444 NULL
, ctxt
->context
->debugNode
, XML_FROM_XPATH
,
445 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
446 XML_ERR_ERROR
, NULL
, 0,
447 (const char *) ctxt
->base
, NULL
, NULL
,
448 ctxt
->cur
- ctxt
->base
, 0,
449 "%s", xmlXPathErrorMessages
[error
]);
456 * @ctxt: the XPath Parser context
457 * @file: the file name
458 * @line: the line number
459 * @no: the error number
461 * Formats an error message.
464 xmlXPatherror(xmlXPathParserContextPtr ctxt
, const char *file ATTRIBUTE_UNUSED
,
465 int line ATTRIBUTE_UNUSED
, int no
) {
466 xmlXPathErr(ctxt
, no
);
469 /************************************************************************
473 ************************************************************************/
478 * Pointer-list for various purposes.
480 typedef struct _xmlPointerList xmlPointerList
;
481 typedef xmlPointerList
*xmlPointerListPtr
;
482 struct _xmlPointerList
{
488 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
489 * and here, we should make the functions public.
492 xmlPointerListAddSize(xmlPointerListPtr list
,
496 if (list
->items
== NULL
) {
497 if (initialSize
<= 0)
499 list
->items
= (void **) xmlMalloc(initialSize
* sizeof(void *));
500 if (list
->items
== NULL
) {
501 xmlXPathErrMemory(NULL
,
502 "xmlPointerListCreate: allocating item\n");
506 list
->size
= initialSize
;
507 } else if (list
->size
<= list
->number
) {
508 if (list
->size
> 50000000) {
509 xmlXPathErrMemory(NULL
,
510 "xmlPointerListAddSize: re-allocating item\n");
514 list
->items
= (void **) xmlRealloc(list
->items
,
515 list
->size
* sizeof(void *));
516 if (list
->items
== NULL
) {
517 xmlXPathErrMemory(NULL
,
518 "xmlPointerListAddSize: re-allocating item\n");
523 list
->items
[list
->number
++] = item
;
528 * xsltPointerListCreate:
530 * Creates an xsltPointerList structure.
532 * Returns a xsltPointerList structure or NULL in case of an error.
534 static xmlPointerListPtr
535 xmlPointerListCreate(int initialSize
)
537 xmlPointerListPtr ret
;
539 ret
= xmlMalloc(sizeof(xmlPointerList
));
541 xmlXPathErrMemory(NULL
,
542 "xmlPointerListCreate: allocating item\n");
545 memset(ret
, 0, sizeof(xmlPointerList
));
546 if (initialSize
> 0) {
547 xmlPointerListAddSize(ret
, NULL
, initialSize
);
554 * xsltPointerListFree:
556 * Frees the xsltPointerList structure. This does not free
557 * the content of the list.
560 xmlPointerListFree(xmlPointerListPtr list
)
564 if (list
->items
!= NULL
)
565 xmlFree(list
->items
);
569 /************************************************************************
573 ************************************************************************/
590 XPATH_OP_RESET
, /* 10 */
592 XPATH_OP_VALUE
, /* 12 */
597 XPATH_OP_FILTER
, /* 17 */
598 XPATH_OP_SORT
/* 18 */
599 #ifdef LIBXML_XPTR_ENABLED
606 AXIS_ANCESTOR_OR_SELF
,
610 AXIS_DESCENDANT_OR_SELF
,
612 AXIS_FOLLOWING_SIBLING
,
616 AXIS_PRECEDING_SIBLING
,
631 NODE_TYPE_COMMENT
= XML_COMMENT_NODE
,
632 NODE_TYPE_TEXT
= XML_TEXT_NODE
,
633 NODE_TYPE_PI
= XML_PI_NODE
636 typedef struct _xmlXPathStepOp xmlXPathStepOp
;
637 typedef xmlXPathStepOp
*xmlXPathStepOpPtr
;
638 struct _xmlXPathStepOp
{
639 xmlXPathOp op
; /* The identifier of the operation */
640 int ch1
; /* First child */
641 int ch2
; /* Second child */
651 struct _xmlXPathCompExpr
{
652 int nbStep
; /* Number of steps in this expression */
653 int maxStep
; /* Maximum number of steps allocated */
654 xmlXPathStepOp
*steps
; /* ops for computation of this expression */
655 int last
; /* index of last step in expression */
656 xmlChar
*expr
; /* the expression being computed */
657 xmlDictPtr dict
; /* the dictionnary to use if any */
658 #ifdef DEBUG_EVAL_COUNTS
662 #ifdef XPATH_STREAMING
663 xmlPatternPtr stream
;
667 /************************************************************************
669 * Forward declarations *
671 ************************************************************************/
673 xmlXPathFreeValueTree(xmlNodeSetPtr obj
);
675 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
);
677 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
678 xmlXPathStepOpPtr op
, xmlNodePtr
*first
);
680 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
681 xmlXPathStepOpPtr op
,
684 /************************************************************************
686 * Parser Type functions *
688 ************************************************************************/
691 * xmlXPathNewCompExpr:
693 * Create a new Xpath component
695 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
697 static xmlXPathCompExprPtr
698 xmlXPathNewCompExpr(void) {
699 xmlXPathCompExprPtr cur
;
701 cur
= (xmlXPathCompExprPtr
) xmlMalloc(sizeof(xmlXPathCompExpr
));
703 xmlXPathErrMemory(NULL
, "allocating component\n");
706 memset(cur
, 0, sizeof(xmlXPathCompExpr
));
709 cur
->steps
= (xmlXPathStepOp
*) xmlMalloc(cur
->maxStep
*
710 sizeof(xmlXPathStepOp
));
711 if (cur
->steps
== NULL
) {
712 xmlXPathErrMemory(NULL
, "allocating steps\n");
716 memset(cur
->steps
, 0, cur
->maxStep
* sizeof(xmlXPathStepOp
));
718 #ifdef DEBUG_EVAL_COUNTS
725 * xmlXPathFreeCompExpr:
726 * @comp: an XPATH comp
728 * Free up the memory allocated by @comp
731 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp
)
733 xmlXPathStepOpPtr op
;
738 if (comp
->dict
== NULL
) {
739 for (i
= 0; i
< comp
->nbStep
; i
++) {
740 op
= &comp
->steps
[i
];
741 if (op
->value4
!= NULL
) {
742 if (op
->op
== XPATH_OP_VALUE
)
743 xmlXPathFreeObject(op
->value4
);
747 if (op
->value5
!= NULL
)
751 for (i
= 0; i
< comp
->nbStep
; i
++) {
752 op
= &comp
->steps
[i
];
753 if (op
->value4
!= NULL
) {
754 if (op
->op
== XPATH_OP_VALUE
)
755 xmlXPathFreeObject(op
->value4
);
758 xmlDictFree(comp
->dict
);
760 if (comp
->steps
!= NULL
) {
761 xmlFree(comp
->steps
);
763 #ifdef DEBUG_EVAL_COUNTS
764 if (comp
->string
!= NULL
) {
765 xmlFree(comp
->string
);
768 #ifdef XPATH_STREAMING
769 if (comp
->stream
!= NULL
) {
770 xmlFreePatternList(comp
->stream
);
773 if (comp
->expr
!= NULL
) {
781 * xmlXPathCompExprAdd:
782 * @comp: the compiled expression
783 * @ch1: first child index
784 * @ch2: second child index
786 * @value: the first int value
787 * @value2: the second int value
788 * @value3: the third int value
789 * @value4: the first string value
790 * @value5: the second string value
792 * Add a step to an XPath Compiled Expression
794 * Returns -1 in case of failure, the index otherwise
797 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp
, int ch1
, int ch2
,
798 xmlXPathOp op
, int value
,
799 int value2
, int value3
, void *value4
, void *value5
) {
800 if (comp
->nbStep
>= comp
->maxStep
) {
801 xmlXPathStepOp
*real
;
803 if (comp
->maxStep
>= XPATH_MAX_STEPS
) {
804 xmlXPathErrMemory(NULL
, "adding step\n");
808 real
= (xmlXPathStepOp
*) xmlRealloc(comp
->steps
,
809 comp
->maxStep
* sizeof(xmlXPathStepOp
));
812 xmlXPathErrMemory(NULL
, "adding step\n");
817 comp
->last
= comp
->nbStep
;
818 comp
->steps
[comp
->nbStep
].ch1
= ch1
;
819 comp
->steps
[comp
->nbStep
].ch2
= ch2
;
820 comp
->steps
[comp
->nbStep
].op
= op
;
821 comp
->steps
[comp
->nbStep
].value
= value
;
822 comp
->steps
[comp
->nbStep
].value2
= value2
;
823 comp
->steps
[comp
->nbStep
].value3
= value3
;
824 if ((comp
->dict
!= NULL
) &&
825 ((op
== XPATH_OP_FUNCTION
) || (op
== XPATH_OP_VARIABLE
) ||
826 (op
== XPATH_OP_COLLECT
))) {
827 if (value4
!= NULL
) {
828 comp
->steps
[comp
->nbStep
].value4
= (xmlChar
*)
829 (void *)xmlDictLookup(comp
->dict
, value4
, -1);
832 comp
->steps
[comp
->nbStep
].value4
= NULL
;
833 if (value5
!= NULL
) {
834 comp
->steps
[comp
->nbStep
].value5
= (xmlChar
*)
835 (void *)xmlDictLookup(comp
->dict
, value5
, -1);
838 comp
->steps
[comp
->nbStep
].value5
= NULL
;
840 comp
->steps
[comp
->nbStep
].value4
= value4
;
841 comp
->steps
[comp
->nbStep
].value5
= value5
;
843 comp
->steps
[comp
->nbStep
].cache
= NULL
;
844 return(comp
->nbStep
++);
849 * @comp: the compiled expression
850 * @op: operation index
852 * Swaps 2 operations in the compiled expression
855 xmlXPathCompSwap(xmlXPathStepOpPtr op
) {
858 #ifndef LIBXML_THREAD_ENABLED
860 * Since this manipulates possibly shared variables, this is
861 * disabled if one detects that the library is used in a multithreaded
864 if (xmlXPathDisableOptimizer
)
873 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
874 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
875 (op), (val), (val2), (val3), (val4), (val5))
876 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
877 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
878 (op), (val), (val2), (val3), (val4), (val5))
880 #define PUSH_LEAVE_EXPR(op, val, val2) \
881 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
883 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
884 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
886 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
887 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
888 (val), (val2), 0 ,NULL ,NULL)
890 /************************************************************************
892 * XPath object cache structures *
894 ************************************************************************/
896 /* #define XP_DEFAULT_CACHE_ON */
898 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
900 typedef struct _xmlXPathContextCache xmlXPathContextCache
;
901 typedef xmlXPathContextCache
*xmlXPathContextCachePtr
;
902 struct _xmlXPathContextCache
{
903 xmlPointerListPtr nodesetObjs
; /* contains xmlXPathObjectPtr */
904 xmlPointerListPtr stringObjs
; /* contains xmlXPathObjectPtr */
905 xmlPointerListPtr booleanObjs
; /* contains xmlXPathObjectPtr */
906 xmlPointerListPtr numberObjs
; /* contains xmlXPathObjectPtr */
907 xmlPointerListPtr miscObjs
; /* contains xmlXPathObjectPtr */
913 #ifdef XP_DEBUG_OBJ_USAGE
915 int dbgCachedNodeset
;
923 int dbgCachedXSLTTree
;
924 int dbgCachedUndefined
;
928 int dbgReusedNodeset
;
936 int dbgReusedXSLTTree
;
937 int dbgReusedUndefined
;
942 /************************************************************************
944 * Debugging related functions *
946 ************************************************************************/
949 xmlGenericError(xmlGenericErrorContext, \
950 "Internal error at %s:%d\n", \
953 #ifdef LIBXML_DEBUG_ENABLED
955 xmlXPathDebugDumpNode(FILE *output
, xmlNodePtr cur
, int depth
) {
959 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
960 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
961 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
963 fprintf(output
, "%s", shift
);
964 fprintf(output
, "Node is NULL !\n");
969 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
970 (cur
->type
== XML_HTML_DOCUMENT_NODE
)) {
971 fprintf(output
, "%s", shift
);
972 fprintf(output
, " /\n");
973 } else if (cur
->type
== XML_ATTRIBUTE_NODE
)
974 xmlDebugDumpAttr(output
, (xmlAttrPtr
)cur
, depth
);
976 xmlDebugDumpOneNode(output
, cur
, depth
);
979 xmlXPathDebugDumpNodeList(FILE *output
, xmlNodePtr cur
, int depth
) {
984 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
985 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
986 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
988 fprintf(output
, "%s", shift
);
989 fprintf(output
, "Node is NULL !\n");
994 while (cur
!= NULL
) {
997 xmlDebugDumpOneNode(output
, tmp
, depth
);
1002 xmlXPathDebugDumpNodeSet(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1006 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1007 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1008 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1011 fprintf(output
, "%s", shift
);
1012 fprintf(output
, "NodeSet is NULL !\n");
1018 fprintf(output
, "Set contains %d nodes:\n", cur
->nodeNr
);
1019 for (i
= 0;i
< cur
->nodeNr
;i
++) {
1020 fprintf(output
, "%s", shift
);
1021 fprintf(output
, "%d", i
+ 1);
1022 xmlXPathDebugDumpNode(output
, cur
->nodeTab
[i
], depth
+ 1);
1028 xmlXPathDebugDumpValueTree(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1032 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1033 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1034 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1036 if ((cur
== NULL
) || (cur
->nodeNr
== 0) || (cur
->nodeTab
[0] == NULL
)) {
1037 fprintf(output
, "%s", shift
);
1038 fprintf(output
, "Value Tree is NULL !\n");
1043 fprintf(output
, "%s", shift
);
1044 fprintf(output
, "%d", i
+ 1);
1045 xmlXPathDebugDumpNodeList(output
, cur
->nodeTab
[0]->children
, depth
+ 1);
1047 #if defined(LIBXML_XPTR_ENABLED)
1049 xmlXPathDebugDumpLocationSet(FILE *output
, xmlLocationSetPtr cur
, int depth
) {
1053 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1054 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1055 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1058 fprintf(output
, "%s", shift
);
1059 fprintf(output
, "LocationSet is NULL !\n");
1064 for (i
= 0;i
< cur
->locNr
;i
++) {
1065 fprintf(output
, "%s", shift
);
1066 fprintf(output
, "%d : ", i
+ 1);
1067 xmlXPathDebugDumpObject(output
, cur
->locTab
[i
], depth
+ 1);
1070 #endif /* LIBXML_XPTR_ENABLED */
1073 * xmlXPathDebugDumpObject:
1074 * @output: the FILE * to dump the output
1075 * @cur: the object to inspect
1076 * @depth: indentation level
1078 * Dump the content of the object for debugging purposes
1081 xmlXPathDebugDumpObject(FILE *output
, xmlXPathObjectPtr cur
, int depth
) {
1085 if (output
== NULL
) return;
1087 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1088 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1089 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1092 fprintf(output
, "%s", shift
);
1095 fprintf(output
, "Object is empty (NULL)\n");
1099 case XPATH_UNDEFINED
:
1100 fprintf(output
, "Object is uninitialized\n");
1103 fprintf(output
, "Object is a Node Set :\n");
1104 xmlXPathDebugDumpNodeSet(output
, cur
->nodesetval
, depth
);
1106 case XPATH_XSLT_TREE
:
1107 fprintf(output
, "Object is an XSLT value tree :\n");
1108 xmlXPathDebugDumpValueTree(output
, cur
->nodesetval
, depth
);
1111 fprintf(output
, "Object is a Boolean : ");
1112 if (cur
->boolval
) fprintf(output
, "true\n");
1113 else fprintf(output
, "false\n");
1116 switch (xmlXPathIsInf(cur
->floatval
)) {
1118 fprintf(output
, "Object is a number : Infinity\n");
1121 fprintf(output
, "Object is a number : -Infinity\n");
1124 if (xmlXPathIsNaN(cur
->floatval
)) {
1125 fprintf(output
, "Object is a number : NaN\n");
1126 } else if (cur
->floatval
== 0 && xmlXPathGetSign(cur
->floatval
) != 0) {
1127 fprintf(output
, "Object is a number : 0\n");
1129 fprintf(output
, "Object is a number : %0g\n", cur
->floatval
);
1134 fprintf(output
, "Object is a string : ");
1135 xmlDebugDumpString(output
, cur
->stringval
);
1136 fprintf(output
, "\n");
1139 fprintf(output
, "Object is a point : index %d in node", cur
->index
);
1140 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
, depth
+ 1);
1141 fprintf(output
, "\n");
1144 if ((cur
->user2
== NULL
) ||
1145 ((cur
->user2
== cur
->user
) && (cur
->index
== cur
->index2
))) {
1146 fprintf(output
, "Object is a collapsed range :\n");
1147 fprintf(output
, "%s", shift
);
1148 if (cur
->index
>= 0)
1149 fprintf(output
, "index %d in ", cur
->index
);
1150 fprintf(output
, "node\n");
1151 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1154 fprintf(output
, "Object is a range :\n");
1155 fprintf(output
, "%s", shift
);
1156 fprintf(output
, "From ");
1157 if (cur
->index
>= 0)
1158 fprintf(output
, "index %d in ", cur
->index
);
1159 fprintf(output
, "node\n");
1160 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1162 fprintf(output
, "%s", shift
);
1163 fprintf(output
, "To ");
1164 if (cur
->index2
>= 0)
1165 fprintf(output
, "index %d in ", cur
->index2
);
1166 fprintf(output
, "node\n");
1167 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user2
,
1169 fprintf(output
, "\n");
1172 case XPATH_LOCATIONSET
:
1173 #if defined(LIBXML_XPTR_ENABLED)
1174 fprintf(output
, "Object is a Location Set:\n");
1175 xmlXPathDebugDumpLocationSet(output
,
1176 (xmlLocationSetPtr
) cur
->user
, depth
);
1180 fprintf(output
, "Object is user defined\n");
1186 xmlXPathDebugDumpStepOp(FILE *output
, xmlXPathCompExprPtr comp
,
1187 xmlXPathStepOpPtr op
, int depth
) {
1191 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1192 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1193 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1195 fprintf(output
, "%s", shift
);
1197 fprintf(output
, "Step is NULL\n");
1202 fprintf(output
, "END"); break;
1204 fprintf(output
, "AND"); break;
1206 fprintf(output
, "OR"); break;
1207 case XPATH_OP_EQUAL
:
1209 fprintf(output
, "EQUAL =");
1211 fprintf(output
, "EQUAL !=");
1215 fprintf(output
, "CMP <");
1217 fprintf(output
, "CMP >");
1219 fprintf(output
, "=");
1223 fprintf(output
, "PLUS -");
1224 else if (op
->value
== 1)
1225 fprintf(output
, "PLUS +");
1226 else if (op
->value
== 2)
1227 fprintf(output
, "PLUS unary -");
1228 else if (op
->value
== 3)
1229 fprintf(output
, "PLUS unary - -");
1233 fprintf(output
, "MULT *");
1234 else if (op
->value
== 1)
1235 fprintf(output
, "MULT div");
1237 fprintf(output
, "MULT mod");
1239 case XPATH_OP_UNION
:
1240 fprintf(output
, "UNION"); break;
1242 fprintf(output
, "ROOT"); break;
1244 fprintf(output
, "NODE"); break;
1245 case XPATH_OP_RESET
:
1246 fprintf(output
, "RESET"); break;
1248 fprintf(output
, "SORT"); break;
1249 case XPATH_OP_COLLECT
: {
1250 xmlXPathAxisVal axis
= (xmlXPathAxisVal
)op
->value
;
1251 xmlXPathTestVal test
= (xmlXPathTestVal
)op
->value2
;
1252 xmlXPathTypeVal type
= (xmlXPathTypeVal
)op
->value3
;
1253 const xmlChar
*prefix
= op
->value4
;
1254 const xmlChar
*name
= op
->value5
;
1256 fprintf(output
, "COLLECT ");
1259 fprintf(output
, " 'ancestors' "); break;
1260 case AXIS_ANCESTOR_OR_SELF
:
1261 fprintf(output
, " 'ancestors-or-self' "); break;
1262 case AXIS_ATTRIBUTE
:
1263 fprintf(output
, " 'attributes' "); break;
1265 fprintf(output
, " 'child' "); break;
1266 case AXIS_DESCENDANT
:
1267 fprintf(output
, " 'descendant' "); break;
1268 case AXIS_DESCENDANT_OR_SELF
:
1269 fprintf(output
, " 'descendant-or-self' "); break;
1270 case AXIS_FOLLOWING
:
1271 fprintf(output
, " 'following' "); break;
1272 case AXIS_FOLLOWING_SIBLING
:
1273 fprintf(output
, " 'following-siblings' "); break;
1274 case AXIS_NAMESPACE
:
1275 fprintf(output
, " 'namespace' "); break;
1277 fprintf(output
, " 'parent' "); break;
1278 case AXIS_PRECEDING
:
1279 fprintf(output
, " 'preceding' "); break;
1280 case AXIS_PRECEDING_SIBLING
:
1281 fprintf(output
, " 'preceding-sibling' "); break;
1283 fprintf(output
, " 'self' "); break;
1286 case NODE_TEST_NONE
:
1287 fprintf(output
, "'none' "); break;
1288 case NODE_TEST_TYPE
:
1289 fprintf(output
, "'type' "); break;
1291 fprintf(output
, "'PI' "); break;
1293 fprintf(output
, "'all' "); break;
1295 fprintf(output
, "'namespace' "); break;
1296 case NODE_TEST_NAME
:
1297 fprintf(output
, "'name' "); break;
1300 case NODE_TYPE_NODE
:
1301 fprintf(output
, "'node' "); break;
1302 case NODE_TYPE_COMMENT
:
1303 fprintf(output
, "'comment' "); break;
1304 case NODE_TYPE_TEXT
:
1305 fprintf(output
, "'text' "); break;
1307 fprintf(output
, "'PI' "); break;
1310 fprintf(output
, "%s:", prefix
);
1312 fprintf(output
, "%s", (const char *) name
);
1316 case XPATH_OP_VALUE
: {
1317 xmlXPathObjectPtr object
= (xmlXPathObjectPtr
) op
->value4
;
1319 fprintf(output
, "ELEM ");
1320 xmlXPathDebugDumpObject(output
, object
, 0);
1323 case XPATH_OP_VARIABLE
: {
1324 const xmlChar
*prefix
= op
->value5
;
1325 const xmlChar
*name
= op
->value4
;
1328 fprintf(output
, "VARIABLE %s:%s", prefix
, name
);
1330 fprintf(output
, "VARIABLE %s", name
);
1333 case XPATH_OP_FUNCTION
: {
1334 int nbargs
= op
->value
;
1335 const xmlChar
*prefix
= op
->value5
;
1336 const xmlChar
*name
= op
->value4
;
1339 fprintf(output
, "FUNCTION %s:%s(%d args)",
1340 prefix
, name
, nbargs
);
1342 fprintf(output
, "FUNCTION %s(%d args)", name
, nbargs
);
1345 case XPATH_OP_ARG
: fprintf(output
, "ARG"); break;
1346 case XPATH_OP_PREDICATE
: fprintf(output
, "PREDICATE"); break;
1347 case XPATH_OP_FILTER
: fprintf(output
, "FILTER"); break;
1348 #ifdef LIBXML_XPTR_ENABLED
1349 case XPATH_OP_RANGETO
: fprintf(output
, "RANGETO"); break;
1352 fprintf(output
, "UNKNOWN %d\n", op
->op
); return;
1354 fprintf(output
, "\n");
1357 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch1
], depth
+ 1);
1359 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch2
], depth
+ 1);
1363 * xmlXPathDebugDumpCompExpr:
1364 * @output: the FILE * for the output
1365 * @comp: the precompiled XPath expression
1366 * @depth: the indentation level.
1368 * Dumps the tree of the compiled XPath expression.
1371 xmlXPathDebugDumpCompExpr(FILE *output
, xmlXPathCompExprPtr comp
,
1376 if ((output
== NULL
) || (comp
== NULL
)) return;
1378 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1379 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1380 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1382 fprintf(output
, "%s", shift
);
1384 fprintf(output
, "Compiled Expression : %d elements\n",
1387 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[i
], depth
+ 1);
1390 #ifdef XP_DEBUG_OBJ_USAGE
1393 * XPath object usage related debugging variables.
1395 static int xmlXPathDebugObjCounterUndefined
= 0;
1396 static int xmlXPathDebugObjCounterNodeset
= 0;
1397 static int xmlXPathDebugObjCounterBool
= 0;
1398 static int xmlXPathDebugObjCounterNumber
= 0;
1399 static int xmlXPathDebugObjCounterString
= 0;
1400 static int xmlXPathDebugObjCounterPoint
= 0;
1401 static int xmlXPathDebugObjCounterRange
= 0;
1402 static int xmlXPathDebugObjCounterLocset
= 0;
1403 static int xmlXPathDebugObjCounterUsers
= 0;
1404 static int xmlXPathDebugObjCounterXSLTTree
= 0;
1405 static int xmlXPathDebugObjCounterAll
= 0;
1407 static int xmlXPathDebugObjTotalUndefined
= 0;
1408 static int xmlXPathDebugObjTotalNodeset
= 0;
1409 static int xmlXPathDebugObjTotalBool
= 0;
1410 static int xmlXPathDebugObjTotalNumber
= 0;
1411 static int xmlXPathDebugObjTotalString
= 0;
1412 static int xmlXPathDebugObjTotalPoint
= 0;
1413 static int xmlXPathDebugObjTotalRange
= 0;
1414 static int xmlXPathDebugObjTotalLocset
= 0;
1415 static int xmlXPathDebugObjTotalUsers
= 0;
1416 static int xmlXPathDebugObjTotalXSLTTree
= 0;
1417 static int xmlXPathDebugObjTotalAll
= 0;
1419 static int xmlXPathDebugObjMaxUndefined
= 0;
1420 static int xmlXPathDebugObjMaxNodeset
= 0;
1421 static int xmlXPathDebugObjMaxBool
= 0;
1422 static int xmlXPathDebugObjMaxNumber
= 0;
1423 static int xmlXPathDebugObjMaxString
= 0;
1424 static int xmlXPathDebugObjMaxPoint
= 0;
1425 static int xmlXPathDebugObjMaxRange
= 0;
1426 static int xmlXPathDebugObjMaxLocset
= 0;
1427 static int xmlXPathDebugObjMaxUsers
= 0;
1428 static int xmlXPathDebugObjMaxXSLTTree
= 0;
1429 static int xmlXPathDebugObjMaxAll
= 0;
1431 /* REVISIT TODO: Make this static when committing */
1433 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt
)
1436 if (ctxt
->cache
!= NULL
) {
1437 xmlXPathContextCachePtr cache
=
1438 (xmlXPathContextCachePtr
) ctxt
->cache
;
1440 cache
->dbgCachedAll
= 0;
1441 cache
->dbgCachedNodeset
= 0;
1442 cache
->dbgCachedString
= 0;
1443 cache
->dbgCachedBool
= 0;
1444 cache
->dbgCachedNumber
= 0;
1445 cache
->dbgCachedPoint
= 0;
1446 cache
->dbgCachedRange
= 0;
1447 cache
->dbgCachedLocset
= 0;
1448 cache
->dbgCachedUsers
= 0;
1449 cache
->dbgCachedXSLTTree
= 0;
1450 cache
->dbgCachedUndefined
= 0;
1452 cache
->dbgReusedAll
= 0;
1453 cache
->dbgReusedNodeset
= 0;
1454 cache
->dbgReusedString
= 0;
1455 cache
->dbgReusedBool
= 0;
1456 cache
->dbgReusedNumber
= 0;
1457 cache
->dbgReusedPoint
= 0;
1458 cache
->dbgReusedRange
= 0;
1459 cache
->dbgReusedLocset
= 0;
1460 cache
->dbgReusedUsers
= 0;
1461 cache
->dbgReusedXSLTTree
= 0;
1462 cache
->dbgReusedUndefined
= 0;
1466 xmlXPathDebugObjCounterUndefined
= 0;
1467 xmlXPathDebugObjCounterNodeset
= 0;
1468 xmlXPathDebugObjCounterBool
= 0;
1469 xmlXPathDebugObjCounterNumber
= 0;
1470 xmlXPathDebugObjCounterString
= 0;
1471 xmlXPathDebugObjCounterPoint
= 0;
1472 xmlXPathDebugObjCounterRange
= 0;
1473 xmlXPathDebugObjCounterLocset
= 0;
1474 xmlXPathDebugObjCounterUsers
= 0;
1475 xmlXPathDebugObjCounterXSLTTree
= 0;
1476 xmlXPathDebugObjCounterAll
= 0;
1478 xmlXPathDebugObjTotalUndefined
= 0;
1479 xmlXPathDebugObjTotalNodeset
= 0;
1480 xmlXPathDebugObjTotalBool
= 0;
1481 xmlXPathDebugObjTotalNumber
= 0;
1482 xmlXPathDebugObjTotalString
= 0;
1483 xmlXPathDebugObjTotalPoint
= 0;
1484 xmlXPathDebugObjTotalRange
= 0;
1485 xmlXPathDebugObjTotalLocset
= 0;
1486 xmlXPathDebugObjTotalUsers
= 0;
1487 xmlXPathDebugObjTotalXSLTTree
= 0;
1488 xmlXPathDebugObjTotalAll
= 0;
1490 xmlXPathDebugObjMaxUndefined
= 0;
1491 xmlXPathDebugObjMaxNodeset
= 0;
1492 xmlXPathDebugObjMaxBool
= 0;
1493 xmlXPathDebugObjMaxNumber
= 0;
1494 xmlXPathDebugObjMaxString
= 0;
1495 xmlXPathDebugObjMaxPoint
= 0;
1496 xmlXPathDebugObjMaxRange
= 0;
1497 xmlXPathDebugObjMaxLocset
= 0;
1498 xmlXPathDebugObjMaxUsers
= 0;
1499 xmlXPathDebugObjMaxXSLTTree
= 0;
1500 xmlXPathDebugObjMaxAll
= 0;
1505 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt
,
1506 xmlXPathObjectType objType
)
1511 if (ctxt
->cache
!= NULL
) {
1512 xmlXPathContextCachePtr cache
=
1513 (xmlXPathContextCachePtr
) ctxt
->cache
;
1517 cache
->dbgReusedAll
++;
1519 case XPATH_UNDEFINED
:
1520 cache
->dbgReusedUndefined
++;
1523 cache
->dbgReusedNodeset
++;
1526 cache
->dbgReusedBool
++;
1529 cache
->dbgReusedNumber
++;
1532 cache
->dbgReusedString
++;
1535 cache
->dbgReusedPoint
++;
1538 cache
->dbgReusedRange
++;
1540 case XPATH_LOCATIONSET
:
1541 cache
->dbgReusedLocset
++;
1544 cache
->dbgReusedUsers
++;
1546 case XPATH_XSLT_TREE
:
1547 cache
->dbgReusedXSLTTree
++;
1556 case XPATH_UNDEFINED
:
1558 xmlXPathDebugObjTotalUndefined
++;
1559 xmlXPathDebugObjCounterUndefined
++;
1560 if (xmlXPathDebugObjCounterUndefined
>
1561 xmlXPathDebugObjMaxUndefined
)
1562 xmlXPathDebugObjMaxUndefined
=
1563 xmlXPathDebugObjCounterUndefined
;
1567 xmlXPathDebugObjTotalNodeset
++;
1568 xmlXPathDebugObjCounterNodeset
++;
1569 if (xmlXPathDebugObjCounterNodeset
>
1570 xmlXPathDebugObjMaxNodeset
)
1571 xmlXPathDebugObjMaxNodeset
=
1572 xmlXPathDebugObjCounterNodeset
;
1576 xmlXPathDebugObjTotalBool
++;
1577 xmlXPathDebugObjCounterBool
++;
1578 if (xmlXPathDebugObjCounterBool
>
1579 xmlXPathDebugObjMaxBool
)
1580 xmlXPathDebugObjMaxBool
=
1581 xmlXPathDebugObjCounterBool
;
1585 xmlXPathDebugObjTotalNumber
++;
1586 xmlXPathDebugObjCounterNumber
++;
1587 if (xmlXPathDebugObjCounterNumber
>
1588 xmlXPathDebugObjMaxNumber
)
1589 xmlXPathDebugObjMaxNumber
=
1590 xmlXPathDebugObjCounterNumber
;
1594 xmlXPathDebugObjTotalString
++;
1595 xmlXPathDebugObjCounterString
++;
1596 if (xmlXPathDebugObjCounterString
>
1597 xmlXPathDebugObjMaxString
)
1598 xmlXPathDebugObjMaxString
=
1599 xmlXPathDebugObjCounterString
;
1603 xmlXPathDebugObjTotalPoint
++;
1604 xmlXPathDebugObjCounterPoint
++;
1605 if (xmlXPathDebugObjCounterPoint
>
1606 xmlXPathDebugObjMaxPoint
)
1607 xmlXPathDebugObjMaxPoint
=
1608 xmlXPathDebugObjCounterPoint
;
1612 xmlXPathDebugObjTotalRange
++;
1613 xmlXPathDebugObjCounterRange
++;
1614 if (xmlXPathDebugObjCounterRange
>
1615 xmlXPathDebugObjMaxRange
)
1616 xmlXPathDebugObjMaxRange
=
1617 xmlXPathDebugObjCounterRange
;
1619 case XPATH_LOCATIONSET
:
1621 xmlXPathDebugObjTotalLocset
++;
1622 xmlXPathDebugObjCounterLocset
++;
1623 if (xmlXPathDebugObjCounterLocset
>
1624 xmlXPathDebugObjMaxLocset
)
1625 xmlXPathDebugObjMaxLocset
=
1626 xmlXPathDebugObjCounterLocset
;
1630 xmlXPathDebugObjTotalUsers
++;
1631 xmlXPathDebugObjCounterUsers
++;
1632 if (xmlXPathDebugObjCounterUsers
>
1633 xmlXPathDebugObjMaxUsers
)
1634 xmlXPathDebugObjMaxUsers
=
1635 xmlXPathDebugObjCounterUsers
;
1637 case XPATH_XSLT_TREE
:
1639 xmlXPathDebugObjTotalXSLTTree
++;
1640 xmlXPathDebugObjCounterXSLTTree
++;
1641 if (xmlXPathDebugObjCounterXSLTTree
>
1642 xmlXPathDebugObjMaxXSLTTree
)
1643 xmlXPathDebugObjMaxXSLTTree
=
1644 xmlXPathDebugObjCounterXSLTTree
;
1650 xmlXPathDebugObjTotalAll
++;
1651 xmlXPathDebugObjCounterAll
++;
1652 if (xmlXPathDebugObjCounterAll
>
1653 xmlXPathDebugObjMaxAll
)
1654 xmlXPathDebugObjMaxAll
=
1655 xmlXPathDebugObjCounterAll
;
1659 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt
,
1660 xmlXPathObjectType objType
)
1665 if (ctxt
->cache
!= NULL
) {
1666 xmlXPathContextCachePtr cache
=
1667 (xmlXPathContextCachePtr
) ctxt
->cache
;
1671 cache
->dbgCachedAll
++;
1673 case XPATH_UNDEFINED
:
1674 cache
->dbgCachedUndefined
++;
1677 cache
->dbgCachedNodeset
++;
1680 cache
->dbgCachedBool
++;
1683 cache
->dbgCachedNumber
++;
1686 cache
->dbgCachedString
++;
1689 cache
->dbgCachedPoint
++;
1692 cache
->dbgCachedRange
++;
1694 case XPATH_LOCATIONSET
:
1695 cache
->dbgCachedLocset
++;
1698 cache
->dbgCachedUsers
++;
1700 case XPATH_XSLT_TREE
:
1701 cache
->dbgCachedXSLTTree
++;
1710 case XPATH_UNDEFINED
:
1711 xmlXPathDebugObjCounterUndefined
--;
1714 xmlXPathDebugObjCounterNodeset
--;
1717 xmlXPathDebugObjCounterBool
--;
1720 xmlXPathDebugObjCounterNumber
--;
1723 xmlXPathDebugObjCounterString
--;
1726 xmlXPathDebugObjCounterPoint
--;
1729 xmlXPathDebugObjCounterRange
--;
1731 case XPATH_LOCATIONSET
:
1732 xmlXPathDebugObjCounterLocset
--;
1735 xmlXPathDebugObjCounterUsers
--;
1737 case XPATH_XSLT_TREE
:
1738 xmlXPathDebugObjCounterXSLTTree
--;
1743 xmlXPathDebugObjCounterAll
--;
1746 /* REVISIT TODO: Make this static when committing */
1748 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt
)
1750 int reqAll
, reqNodeset
, reqString
, reqBool
, reqNumber
,
1751 reqXSLTTree
, reqUndefined
;
1752 int caAll
= 0, caNodeset
= 0, caString
= 0, caBool
= 0,
1753 caNumber
= 0, caXSLTTree
= 0, caUndefined
= 0;
1754 int reAll
= 0, reNodeset
= 0, reString
= 0, reBool
= 0,
1755 reNumber
= 0, reXSLTTree
= 0, reUndefined
= 0;
1756 int leftObjs
= xmlXPathDebugObjCounterAll
;
1758 reqAll
= xmlXPathDebugObjTotalAll
;
1759 reqNodeset
= xmlXPathDebugObjTotalNodeset
;
1760 reqString
= xmlXPathDebugObjTotalString
;
1761 reqBool
= xmlXPathDebugObjTotalBool
;
1762 reqNumber
= xmlXPathDebugObjTotalNumber
;
1763 reqXSLTTree
= xmlXPathDebugObjTotalXSLTTree
;
1764 reqUndefined
= xmlXPathDebugObjTotalUndefined
;
1766 printf("# XPath object usage:\n");
1769 if (ctxt
->cache
!= NULL
) {
1770 xmlXPathContextCachePtr cache
=
1771 (xmlXPathContextCachePtr
) ctxt
->cache
;
1773 reAll
= cache
->dbgReusedAll
;
1775 reNodeset
= cache
->dbgReusedNodeset
;
1776 reqNodeset
+= reNodeset
;
1777 reString
= cache
->dbgReusedString
;
1778 reqString
+= reString
;
1779 reBool
= cache
->dbgReusedBool
;
1781 reNumber
= cache
->dbgReusedNumber
;
1782 reqNumber
+= reNumber
;
1783 reXSLTTree
= cache
->dbgReusedXSLTTree
;
1784 reqXSLTTree
+= reXSLTTree
;
1785 reUndefined
= cache
->dbgReusedUndefined
;
1786 reqUndefined
+= reUndefined
;
1788 caAll
= cache
->dbgCachedAll
;
1789 caBool
= cache
->dbgCachedBool
;
1790 caNodeset
= cache
->dbgCachedNodeset
;
1791 caString
= cache
->dbgCachedString
;
1792 caNumber
= cache
->dbgCachedNumber
;
1793 caXSLTTree
= cache
->dbgCachedXSLTTree
;
1794 caUndefined
= cache
->dbgCachedUndefined
;
1796 if (cache
->nodesetObjs
)
1797 leftObjs
-= cache
->nodesetObjs
->number
;
1798 if (cache
->stringObjs
)
1799 leftObjs
-= cache
->stringObjs
->number
;
1800 if (cache
->booleanObjs
)
1801 leftObjs
-= cache
->booleanObjs
->number
;
1802 if (cache
->numberObjs
)
1803 leftObjs
-= cache
->numberObjs
->number
;
1804 if (cache
->miscObjs
)
1805 leftObjs
-= cache
->miscObjs
->number
;
1810 printf("# total : %d\n", reqAll
);
1811 printf("# left : %d\n", leftObjs
);
1812 printf("# created: %d\n", xmlXPathDebugObjTotalAll
);
1813 printf("# reused : %d\n", reAll
);
1814 printf("# max : %d\n", xmlXPathDebugObjMaxAll
);
1816 printf("# node-sets\n");
1817 printf("# total : %d\n", reqNodeset
);
1818 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset
);
1819 printf("# reused : %d\n", reNodeset
);
1820 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset
);
1822 printf("# strings\n");
1823 printf("# total : %d\n", reqString
);
1824 printf("# created: %d\n", xmlXPathDebugObjTotalString
);
1825 printf("# reused : %d\n", reString
);
1826 printf("# max : %d\n", xmlXPathDebugObjMaxString
);
1828 printf("# booleans\n");
1829 printf("# total : %d\n", reqBool
);
1830 printf("# created: %d\n", xmlXPathDebugObjTotalBool
);
1831 printf("# reused : %d\n", reBool
);
1832 printf("# max : %d\n", xmlXPathDebugObjMaxBool
);
1834 printf("# numbers\n");
1835 printf("# total : %d\n", reqNumber
);
1836 printf("# created: %d\n", xmlXPathDebugObjTotalNumber
);
1837 printf("# reused : %d\n", reNumber
);
1838 printf("# max : %d\n", xmlXPathDebugObjMaxNumber
);
1840 printf("# XSLT result tree fragments\n");
1841 printf("# total : %d\n", reqXSLTTree
);
1842 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree
);
1843 printf("# reused : %d\n", reXSLTTree
);
1844 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree
);
1846 printf("# undefined\n");
1847 printf("# total : %d\n", reqUndefined
);
1848 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined
);
1849 printf("# reused : %d\n", reUndefined
);
1850 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined
);
1854 #endif /* XP_DEBUG_OBJ_USAGE */
1856 #endif /* LIBXML_DEBUG_ENABLED */
1858 /************************************************************************
1860 * XPath object caching *
1862 ************************************************************************/
1867 * Create a new object cache
1869 * Returns the xmlXPathCache just allocated.
1871 static xmlXPathContextCachePtr
1872 xmlXPathNewCache(void)
1874 xmlXPathContextCachePtr ret
;
1876 ret
= (xmlXPathContextCachePtr
) xmlMalloc(sizeof(xmlXPathContextCache
));
1878 xmlXPathErrMemory(NULL
, "creating object cache\n");
1881 memset(ret
, 0 , (size_t) sizeof(xmlXPathContextCache
));
1882 ret
->maxNodeset
= 100;
1883 ret
->maxString
= 100;
1884 ret
->maxBoolean
= 100;
1885 ret
->maxNumber
= 100;
1891 xmlXPathCacheFreeObjectList(xmlPointerListPtr list
)
1894 xmlXPathObjectPtr obj
;
1899 for (i
= 0; i
< list
->number
; i
++) {
1900 obj
= list
->items
[i
];
1902 * Note that it is already assured that we don't need to
1903 * look out for namespace nodes in the node-set.
1905 if (obj
->nodesetval
!= NULL
) {
1906 if (obj
->nodesetval
->nodeTab
!= NULL
)
1907 xmlFree(obj
->nodesetval
->nodeTab
);
1908 xmlFree(obj
->nodesetval
);
1911 #ifdef XP_DEBUG_OBJ_USAGE
1912 xmlXPathDebugObjCounterAll
--;
1915 xmlPointerListFree(list
);
1919 xmlXPathFreeCache(xmlXPathContextCachePtr cache
)
1923 if (cache
->nodesetObjs
)
1924 xmlXPathCacheFreeObjectList(cache
->nodesetObjs
);
1925 if (cache
->stringObjs
)
1926 xmlXPathCacheFreeObjectList(cache
->stringObjs
);
1927 if (cache
->booleanObjs
)
1928 xmlXPathCacheFreeObjectList(cache
->booleanObjs
);
1929 if (cache
->numberObjs
)
1930 xmlXPathCacheFreeObjectList(cache
->numberObjs
);
1931 if (cache
->miscObjs
)
1932 xmlXPathCacheFreeObjectList(cache
->miscObjs
);
1937 * xmlXPathContextSetCache:
1939 * @ctxt: the XPath context
1940 * @active: enables/disables (creates/frees) the cache
1941 * @value: a value with semantics dependant on @options
1942 * @options: options (currently only the value 0 is used)
1944 * Creates/frees an object cache on the XPath context.
1945 * If activates XPath objects (xmlXPathObject) will be cached internally
1948 * 0: This will set the XPath object caching:
1950 * This will set the maximum number of XPath objects
1951 * to be cached per slot
1952 * There are 5 slots for: node-set, string, number, boolean, and
1953 * misc objects. Use <0 for the default number (100).
1954 * Other values for @options have currently no effect.
1956 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
1959 xmlXPathContextSetCache(xmlXPathContextPtr ctxt
,
1967 xmlXPathContextCachePtr cache
;
1969 if (ctxt
->cache
== NULL
) {
1970 ctxt
->cache
= xmlXPathNewCache();
1971 if (ctxt
->cache
== NULL
)
1974 cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
1978 cache
->maxNodeset
= value
;
1979 cache
->maxString
= value
;
1980 cache
->maxNumber
= value
;
1981 cache
->maxBoolean
= value
;
1982 cache
->maxMisc
= value
;
1984 } else if (ctxt
->cache
!= NULL
) {
1985 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
1992 * xmlXPathCacheWrapNodeSet:
1993 * @ctxt: the XPath context
1994 * @val: the NodePtr value
1996 * This is the cached version of xmlXPathWrapNodeSet().
1997 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1999 * Returns the created or reused object.
2001 static xmlXPathObjectPtr
2002 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt
, xmlNodeSetPtr val
)
2004 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2005 xmlXPathContextCachePtr cache
=
2006 (xmlXPathContextCachePtr
) ctxt
->cache
;
2008 if ((cache
->miscObjs
!= NULL
) &&
2009 (cache
->miscObjs
->number
!= 0))
2011 xmlXPathObjectPtr ret
;
2013 ret
= (xmlXPathObjectPtr
)
2014 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2015 ret
->type
= XPATH_NODESET
;
2016 ret
->nodesetval
= val
;
2017 #ifdef XP_DEBUG_OBJ_USAGE
2018 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2024 return(xmlXPathWrapNodeSet(val
));
2029 * xmlXPathCacheWrapString:
2030 * @ctxt: the XPath context
2031 * @val: the xmlChar * value
2033 * This is the cached version of xmlXPathWrapString().
2034 * Wraps the @val string into an XPath object.
2036 * Returns the created or reused object.
2038 static xmlXPathObjectPtr
2039 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt
, xmlChar
*val
)
2041 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2042 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2044 if ((cache
->stringObjs
!= NULL
) &&
2045 (cache
->stringObjs
->number
!= 0))
2048 xmlXPathObjectPtr ret
;
2050 ret
= (xmlXPathObjectPtr
)
2051 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2052 ret
->type
= XPATH_STRING
;
2053 ret
->stringval
= val
;
2054 #ifdef XP_DEBUG_OBJ_USAGE
2055 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2058 } else if ((cache
->miscObjs
!= NULL
) &&
2059 (cache
->miscObjs
->number
!= 0))
2061 xmlXPathObjectPtr ret
;
2063 * Fallback to misc-cache.
2065 ret
= (xmlXPathObjectPtr
)
2066 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2068 ret
->type
= XPATH_STRING
;
2069 ret
->stringval
= val
;
2070 #ifdef XP_DEBUG_OBJ_USAGE
2071 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2076 return(xmlXPathWrapString(val
));
2080 * xmlXPathCacheNewNodeSet:
2081 * @ctxt: the XPath context
2082 * @val: the NodePtr value
2084 * This is the cached version of xmlXPathNewNodeSet().
2085 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2086 * it with the single Node @val
2088 * Returns the created or reused object.
2090 static xmlXPathObjectPtr
2091 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt
, xmlNodePtr val
)
2093 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2094 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2096 if ((cache
->nodesetObjs
!= NULL
) &&
2097 (cache
->nodesetObjs
->number
!= 0))
2099 xmlXPathObjectPtr ret
;
2101 * Use the nodset-cache.
2103 ret
= (xmlXPathObjectPtr
)
2104 cache
->nodesetObjs
->items
[--cache
->nodesetObjs
->number
];
2105 ret
->type
= XPATH_NODESET
;
2108 if ((ret
->nodesetval
->nodeMax
== 0) ||
2109 (val
->type
== XML_NAMESPACE_DECL
))
2111 xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
);
2113 ret
->nodesetval
->nodeTab
[0] = val
;
2114 ret
->nodesetval
->nodeNr
= 1;
2117 #ifdef XP_DEBUG_OBJ_USAGE
2118 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2121 } else if ((cache
->miscObjs
!= NULL
) &&
2122 (cache
->miscObjs
->number
!= 0))
2124 xmlXPathObjectPtr ret
;
2126 * Fallback to misc-cache.
2129 ret
= (xmlXPathObjectPtr
)
2130 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2132 ret
->type
= XPATH_NODESET
;
2134 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
2135 if (ret
->nodesetval
== NULL
) {
2136 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
2137 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
2140 #ifdef XP_DEBUG_OBJ_USAGE
2141 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2146 return(xmlXPathNewNodeSet(val
));
2150 * xmlXPathCacheNewCString:
2151 * @ctxt: the XPath context
2152 * @val: the char * value
2154 * This is the cached version of xmlXPathNewCString().
2155 * Acquire an xmlXPathObjectPtr of type string and of value @val
2157 * Returns the created or reused object.
2159 static xmlXPathObjectPtr
2160 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt
, const char *val
)
2162 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2163 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2165 if ((cache
->stringObjs
!= NULL
) &&
2166 (cache
->stringObjs
->number
!= 0))
2168 xmlXPathObjectPtr ret
;
2170 ret
= (xmlXPathObjectPtr
)
2171 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2173 ret
->type
= XPATH_STRING
;
2174 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2175 #ifdef XP_DEBUG_OBJ_USAGE
2176 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2179 } else if ((cache
->miscObjs
!= NULL
) &&
2180 (cache
->miscObjs
->number
!= 0))
2182 xmlXPathObjectPtr ret
;
2184 ret
= (xmlXPathObjectPtr
)
2185 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2187 ret
->type
= XPATH_STRING
;
2188 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2189 #ifdef XP_DEBUG_OBJ_USAGE
2190 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2195 return(xmlXPathNewCString(val
));
2199 * xmlXPathCacheNewString:
2200 * @ctxt: the XPath context
2201 * @val: the xmlChar * value
2203 * This is the cached version of xmlXPathNewString().
2204 * Acquire an xmlXPathObjectPtr of type string and of value @val
2206 * Returns the created or reused object.
2208 static xmlXPathObjectPtr
2209 xmlXPathCacheNewString(xmlXPathContextPtr ctxt
, const xmlChar
*val
)
2211 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2212 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2214 if ((cache
->stringObjs
!= NULL
) &&
2215 (cache
->stringObjs
->number
!= 0))
2217 xmlXPathObjectPtr ret
;
2219 ret
= (xmlXPathObjectPtr
)
2220 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2221 ret
->type
= XPATH_STRING
;
2223 ret
->stringval
= xmlStrdup(val
);
2225 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2226 #ifdef XP_DEBUG_OBJ_USAGE
2227 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2230 } else if ((cache
->miscObjs
!= NULL
) &&
2231 (cache
->miscObjs
->number
!= 0))
2233 xmlXPathObjectPtr ret
;
2235 ret
= (xmlXPathObjectPtr
)
2236 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2238 ret
->type
= XPATH_STRING
;
2240 ret
->stringval
= xmlStrdup(val
);
2242 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2243 #ifdef XP_DEBUG_OBJ_USAGE
2244 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2249 return(xmlXPathNewString(val
));
2253 * xmlXPathCacheNewBoolean:
2254 * @ctxt: the XPath context
2255 * @val: the boolean value
2257 * This is the cached version of xmlXPathNewBoolean().
2258 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2260 * Returns the created or reused object.
2262 static xmlXPathObjectPtr
2263 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt
, int val
)
2265 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2266 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2268 if ((cache
->booleanObjs
!= NULL
) &&
2269 (cache
->booleanObjs
->number
!= 0))
2271 xmlXPathObjectPtr ret
;
2273 ret
= (xmlXPathObjectPtr
)
2274 cache
->booleanObjs
->items
[--cache
->booleanObjs
->number
];
2275 ret
->type
= XPATH_BOOLEAN
;
2276 ret
->boolval
= (val
!= 0);
2277 #ifdef XP_DEBUG_OBJ_USAGE
2278 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2281 } else if ((cache
->miscObjs
!= NULL
) &&
2282 (cache
->miscObjs
->number
!= 0))
2284 xmlXPathObjectPtr ret
;
2286 ret
= (xmlXPathObjectPtr
)
2287 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2289 ret
->type
= XPATH_BOOLEAN
;
2290 ret
->boolval
= (val
!= 0);
2291 #ifdef XP_DEBUG_OBJ_USAGE
2292 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2297 return(xmlXPathNewBoolean(val
));
2301 * xmlXPathCacheNewFloat:
2302 * @ctxt: the XPath context
2303 * @val: the double value
2305 * This is the cached version of xmlXPathNewFloat().
2306 * Acquires an xmlXPathObjectPtr of type double and of value @val
2308 * Returns the created or reused object.
2310 static xmlXPathObjectPtr
2311 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt
, double val
)
2313 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2314 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2316 if ((cache
->numberObjs
!= NULL
) &&
2317 (cache
->numberObjs
->number
!= 0))
2319 xmlXPathObjectPtr ret
;
2321 ret
= (xmlXPathObjectPtr
)
2322 cache
->numberObjs
->items
[--cache
->numberObjs
->number
];
2323 ret
->type
= XPATH_NUMBER
;
2324 ret
->floatval
= val
;
2325 #ifdef XP_DEBUG_OBJ_USAGE
2326 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2329 } else if ((cache
->miscObjs
!= NULL
) &&
2330 (cache
->miscObjs
->number
!= 0))
2332 xmlXPathObjectPtr ret
;
2334 ret
= (xmlXPathObjectPtr
)
2335 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2337 ret
->type
= XPATH_NUMBER
;
2338 ret
->floatval
= val
;
2339 #ifdef XP_DEBUG_OBJ_USAGE
2340 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2345 return(xmlXPathNewFloat(val
));
2349 * xmlXPathCacheConvertString:
2350 * @ctxt: the XPath context
2351 * @val: an XPath object
2353 * This is the cached version of xmlXPathConvertString().
2354 * Converts an existing object to its string() equivalent
2356 * Returns a created or reused object, the old one is freed (cached)
2357 * (or the operation is done directly on @val)
2360 static xmlXPathObjectPtr
2361 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2362 xmlChar
*res
= NULL
;
2365 return(xmlXPathCacheNewCString(ctxt
, ""));
2367 switch (val
->type
) {
2368 case XPATH_UNDEFINED
:
2370 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
2374 case XPATH_XSLT_TREE
:
2375 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
2380 res
= xmlXPathCastBooleanToString(val
->boolval
);
2383 res
= xmlXPathCastNumberToString(val
->floatval
);
2388 case XPATH_LOCATIONSET
:
2392 xmlXPathReleaseObject(ctxt
, val
);
2394 return(xmlXPathCacheNewCString(ctxt
, ""));
2395 return(xmlXPathCacheWrapString(ctxt
, res
));
2399 * xmlXPathCacheObjectCopy:
2400 * @ctxt: the XPath context
2401 * @val: the original object
2403 * This is the cached version of xmlXPathObjectCopy().
2404 * Acquire a copy of a given object
2406 * Returns a created or reused created object.
2408 static xmlXPathObjectPtr
2409 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
)
2414 if (XP_HAS_CACHE(ctxt
)) {
2415 switch (val
->type
) {
2417 return(xmlXPathCacheWrapNodeSet(ctxt
,
2418 xmlXPathNodeSetMerge(NULL
, val
->nodesetval
)));
2420 return(xmlXPathCacheNewString(ctxt
, val
->stringval
));
2422 return(xmlXPathCacheNewBoolean(ctxt
, val
->boolval
));
2424 return(xmlXPathCacheNewFloat(ctxt
, val
->floatval
));
2429 return(xmlXPathObjectCopy(val
));
2433 * xmlXPathCacheConvertBoolean:
2434 * @ctxt: the XPath context
2435 * @val: an XPath object
2437 * This is the cached version of xmlXPathConvertBoolean().
2438 * Converts an existing object to its boolean() equivalent
2440 * Returns a created or reused object, the old one is freed (or the operation
2441 * is done directly on @val)
2443 static xmlXPathObjectPtr
2444 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2445 xmlXPathObjectPtr ret
;
2448 return(xmlXPathCacheNewBoolean(ctxt
, 0));
2449 if (val
->type
== XPATH_BOOLEAN
)
2451 ret
= xmlXPathCacheNewBoolean(ctxt
, xmlXPathCastToBoolean(val
));
2452 xmlXPathReleaseObject(ctxt
, val
);
2457 * xmlXPathCacheConvertNumber:
2458 * @ctxt: the XPath context
2459 * @val: an XPath object
2461 * This is the cached version of xmlXPathConvertNumber().
2462 * Converts an existing object to its number() equivalent
2464 * Returns a created or reused object, the old one is freed (or the operation
2465 * is done directly on @val)
2467 static xmlXPathObjectPtr
2468 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2469 xmlXPathObjectPtr ret
;
2472 return(xmlXPathCacheNewFloat(ctxt
, 0.0));
2473 if (val
->type
== XPATH_NUMBER
)
2475 ret
= xmlXPathCacheNewFloat(ctxt
, xmlXPathCastToNumber(val
));
2476 xmlXPathReleaseObject(ctxt
, val
);
2480 /************************************************************************
2482 * Parser stacks related functions and macros *
2484 ************************************************************************/
2488 * @ctxt: an XPath parser context
2490 * Set the callee evaluation frame
2492 * Returns the previous frame value to be restored once done
2495 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt
) {
2500 ret
= ctxt
->valueFrame
;
2501 ctxt
->valueFrame
= ctxt
->valueNr
;
2507 * @ctxt: an XPath parser context
2508 * @frame: the previous frame value
2510 * Remove the callee evaluation frame
2513 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt
, int frame
) {
2516 if (ctxt
->valueNr
< ctxt
->valueFrame
) {
2517 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2519 ctxt
->valueFrame
= frame
;
2524 * @ctxt: an XPath evaluation context
2526 * Pops the top XPath object from the value stack
2528 * Returns the XPath object just removed
2531 valuePop(xmlXPathParserContextPtr ctxt
)
2533 xmlXPathObjectPtr ret
;
2535 if ((ctxt
== NULL
) || (ctxt
->valueNr
<= 0))
2538 if (ctxt
->valueNr
<= ctxt
->valueFrame
) {
2539 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2544 if (ctxt
->valueNr
> 0)
2545 ctxt
->value
= ctxt
->valueTab
[ctxt
->valueNr
- 1];
2548 ret
= ctxt
->valueTab
[ctxt
->valueNr
];
2549 ctxt
->valueTab
[ctxt
->valueNr
] = NULL
;
2554 * @ctxt: an XPath evaluation context
2555 * @value: the XPath object
2557 * Pushes a new XPath object on top of the value stack
2559 * returns the number of items on the value stack
2562 valuePush(xmlXPathParserContextPtr ctxt
, xmlXPathObjectPtr value
)
2564 if ((ctxt
== NULL
) || (value
== NULL
)) return(-1);
2565 if (ctxt
->valueNr
>= ctxt
->valueMax
) {
2566 xmlXPathObjectPtr
*tmp
;
2568 if (ctxt
->valueMax
>= XPATH_MAX_STACK_DEPTH
) {
2569 xmlXPathErrMemory(NULL
, "XPath stack depth limit reached\n");
2570 ctxt
->error
= XPATH_MEMORY_ERROR
;
2573 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(ctxt
->valueTab
,
2574 2 * ctxt
->valueMax
*
2575 sizeof(ctxt
->valueTab
[0]));
2577 xmlXPathErrMemory(NULL
, "pushing value\n");
2578 ctxt
->error
= XPATH_MEMORY_ERROR
;
2581 ctxt
->valueMax
*= 2;
2582 ctxt
->valueTab
= tmp
;
2584 ctxt
->valueTab
[ctxt
->valueNr
] = value
;
2585 ctxt
->value
= value
;
2586 return (ctxt
->valueNr
++);
2590 * xmlXPathPopBoolean:
2591 * @ctxt: an XPath parser context
2593 * Pops a boolean from the stack, handling conversion if needed.
2594 * Check error with #xmlXPathCheckError.
2596 * Returns the boolean
2599 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt
) {
2600 xmlXPathObjectPtr obj
;
2603 obj
= valuePop(ctxt
);
2605 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2608 if (obj
->type
!= XPATH_BOOLEAN
)
2609 ret
= xmlXPathCastToBoolean(obj
);
2612 xmlXPathReleaseObject(ctxt
->context
, obj
);
2617 * xmlXPathPopNumber:
2618 * @ctxt: an XPath parser context
2620 * Pops a number from the stack, handling conversion if needed.
2621 * Check error with #xmlXPathCheckError.
2623 * Returns the number
2626 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt
) {
2627 xmlXPathObjectPtr obj
;
2630 obj
= valuePop(ctxt
);
2632 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2635 if (obj
->type
!= XPATH_NUMBER
)
2636 ret
= xmlXPathCastToNumber(obj
);
2638 ret
= obj
->floatval
;
2639 xmlXPathReleaseObject(ctxt
->context
, obj
);
2644 * xmlXPathPopString:
2645 * @ctxt: an XPath parser context
2647 * Pops a string from the stack, handling conversion if needed.
2648 * Check error with #xmlXPathCheckError.
2650 * Returns the string
2653 xmlXPathPopString (xmlXPathParserContextPtr ctxt
) {
2654 xmlXPathObjectPtr obj
;
2657 obj
= valuePop(ctxt
);
2659 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2662 ret
= xmlXPathCastToString(obj
); /* this does required strdup */
2663 /* TODO: needs refactoring somewhere else */
2664 if (obj
->stringval
== ret
)
2665 obj
->stringval
= NULL
;
2666 xmlXPathReleaseObject(ctxt
->context
, obj
);
2671 * xmlXPathPopNodeSet:
2672 * @ctxt: an XPath parser context
2674 * Pops a node-set from the stack, handling conversion if needed.
2675 * Check error with #xmlXPathCheckError.
2677 * Returns the node-set
2680 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt
) {
2681 xmlXPathObjectPtr obj
;
2684 if (ctxt
== NULL
) return(NULL
);
2685 if (ctxt
->value
== NULL
) {
2686 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2689 if (!xmlXPathStackIsNodeSet(ctxt
)) {
2690 xmlXPathSetTypeError(ctxt
);
2693 obj
= valuePop(ctxt
);
2694 ret
= obj
->nodesetval
;
2696 /* to fix memory leak of not clearing obj->user */
2697 if (obj
->boolval
&& obj
->user
!= NULL
)
2698 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
2700 obj
->nodesetval
= NULL
;
2701 xmlXPathReleaseObject(ctxt
->context
, obj
);
2706 * xmlXPathPopExternal:
2707 * @ctxt: an XPath parser context
2709 * Pops an external object from the stack, handling conversion if needed.
2710 * Check error with #xmlXPathCheckError.
2712 * Returns the object
2715 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt
) {
2716 xmlXPathObjectPtr obj
;
2719 if ((ctxt
== NULL
) || (ctxt
->value
== NULL
)) {
2720 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2723 if (ctxt
->value
->type
!= XPATH_USERS
) {
2724 xmlXPathSetTypeError(ctxt
);
2727 obj
= valuePop(ctxt
);
2730 xmlXPathReleaseObject(ctxt
->context
, obj
);
2735 * Macros for accessing the content. Those should be used only by the parser,
2738 * Dirty macros, i.e. one need to make assumption on the context to use them
2740 * CUR_PTR return the current pointer to the xmlChar to be parsed.
2741 * CUR returns the current xmlChar value, i.e. a 8 bit value
2742 * in ISO-Latin or UTF-8.
2743 * This should be used internally by the parser
2744 * only to compare to ASCII values otherwise it would break when
2745 * running with UTF-8 encoding.
2746 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2747 * to compare on ASCII based substring.
2748 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2749 * strings within the parser.
2750 * CURRENT Returns the current char value, with the full decoding of
2751 * UTF-8 if we are using this mode. It returns an int.
2752 * NEXT Skip to the next character, this does the proper decoding
2753 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
2754 * It returns the pointer to the current xmlChar.
2757 #define CUR (*ctxt->cur)
2758 #define SKIP(val) ctxt->cur += (val)
2759 #define NXT(val) ctxt->cur[(val)]
2760 #define CUR_PTR ctxt->cur
2761 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2763 #define COPY_BUF(l,b,i,v) \
2764 if (l == 1) b[i++] = (xmlChar) v; \
2765 else i += xmlCopyChar(l,&b[i],v)
2767 #define NEXTL(l) ctxt->cur += l
2769 #define SKIP_BLANKS \
2770 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2772 #define CURRENT (*ctxt->cur)
2773 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2780 #define DBL_EPSILON 1E-9
2783 #define UPPER_DOUBLE 1E9
2784 #define LOWER_DOUBLE 1E-5
2785 #define LOWER_DOUBLE_EXP 5
2787 #define INTEGER_DIGITS DBL_DIG
2788 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2789 #define EXPONENT_DIGITS (3 + 2)
2792 * xmlXPathFormatNumber:
2793 * @number: number to format
2794 * @buffer: output buffer
2795 * @buffersize: size of output buffer
2797 * Convert the number into a string representation.
2800 xmlXPathFormatNumber(double number
, char buffer
[], int buffersize
)
2802 switch (xmlXPathIsInf(number
)) {
2804 if (buffersize
> (int)sizeof("Infinity"))
2805 snprintf(buffer
, buffersize
, "Infinity");
2808 if (buffersize
> (int)sizeof("-Infinity"))
2809 snprintf(buffer
, buffersize
, "-Infinity");
2812 if (xmlXPathIsNaN(number
)) {
2813 if (buffersize
> (int)sizeof("NaN"))
2814 snprintf(buffer
, buffersize
, "NaN");
2815 } else if (number
== 0 && xmlXPathGetSign(number
) != 0) {
2816 snprintf(buffer
, buffersize
, "0");
2817 } else if (number
== ((int) number
)) {
2820 int value
= (int) number
;
2826 snprintf(work
, 29, "%d", value
);
2828 while ((*cur
) && (ptr
- buffer
< buffersize
)) {
2832 if (ptr
- buffer
< buffersize
) {
2834 } else if (buffersize
> 0) {
2840 For the dimension of work,
2841 DBL_DIG is number of significant digits
2842 EXPONENT is only needed for "scientific notation"
2843 3 is sign, decimal point, and terminating zero
2844 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2845 Note that this dimension is slightly (a few characters)
2846 larger than actually necessary.
2848 char work
[DBL_DIG
+ EXPONENT_DIGITS
+ 3 + LOWER_DOUBLE_EXP
];
2849 int integer_place
, fraction_place
;
2851 char *after_fraction
;
2852 double absolute_value
;
2855 absolute_value
= fabs(number
);
2858 * First choose format - scientific or regular floating point.
2859 * In either case, result is in work, and after_fraction points
2860 * just past the fractional part.
2862 if ( ((absolute_value
> UPPER_DOUBLE
) ||
2863 (absolute_value
< LOWER_DOUBLE
)) &&
2864 (absolute_value
!= 0.0) ) {
2865 /* Use scientific notation */
2866 integer_place
= DBL_DIG
+ EXPONENT_DIGITS
+ 1;
2867 fraction_place
= DBL_DIG
- 1;
2868 size
= snprintf(work
, sizeof(work
),"%*.*e",
2869 integer_place
, fraction_place
, number
);
2870 while ((size
> 0) && (work
[size
] != 'e')) size
--;
2874 /* Use regular notation */
2875 if (absolute_value
> 0.0) {
2876 integer_place
= (int)log10(absolute_value
);
2877 if (integer_place
> 0)
2878 fraction_place
= DBL_DIG
- integer_place
- 1;
2880 fraction_place
= DBL_DIG
- integer_place
;
2884 size
= snprintf(work
, sizeof(work
), "%0.*f",
2885 fraction_place
, number
);
2888 /* Remove fractional trailing zeroes */
2889 after_fraction
= work
+ size
;
2890 ptr
= after_fraction
;
2891 while (*(--ptr
) == '0')
2895 while ((*ptr
++ = *after_fraction
++) != 0);
2897 /* Finally copy result back to caller */
2898 size
= strlen(work
) + 1;
2899 if (size
> buffersize
) {
2900 work
[buffersize
- 1] = 0;
2903 memmove(buffer
, work
, size
);
2910 /************************************************************************
2912 * Routines to handle NodeSets *
2914 ************************************************************************/
2917 * xmlXPathOrderDocElems:
2918 * @doc: an input document
2920 * Call this routine to speed up XPath computation on static documents.
2921 * This stamps all the element nodes with the document order
2922 * Like for line information, the order is kept in the element->content
2923 * field, the value stored is actually - the node number (starting at -1)
2924 * to be able to differentiate from line numbers.
2926 * Returns the number of elements found in the document or -1 in case
2930 xmlXPathOrderDocElems(xmlDocPtr doc
) {
2936 cur
= doc
->children
;
2937 while (cur
!= NULL
) {
2938 if (cur
->type
== XML_ELEMENT_NODE
) {
2939 cur
->content
= (void *) (-(++count
));
2940 if (cur
->children
!= NULL
) {
2941 cur
= cur
->children
;
2945 if (cur
->next
!= NULL
) {
2953 if (cur
== (xmlNodePtr
) doc
) {
2957 if (cur
->next
!= NULL
) {
2961 } while (cur
!= NULL
);
2968 * @node1: the first node
2969 * @node2: the second node
2971 * Compare two nodes w.r.t document order
2973 * Returns -2 in case of error 1 if first point < second point, 0 if
2974 * it's the same node, -1 otherwise
2977 xmlXPathCmpNodes(xmlNodePtr node1
, xmlNodePtr node2
) {
2979 int attr1
= 0, attr2
= 0;
2980 xmlNodePtr attrNode1
= NULL
, attrNode2
= NULL
;
2981 xmlNodePtr cur
, root
;
2983 if ((node1
== NULL
) || (node2
== NULL
))
2986 * a couple of optimizations which will avoid computations in most cases
2988 if (node1
== node2
) /* trivial case */
2990 if (node1
->type
== XML_ATTRIBUTE_NODE
) {
2993 node1
= node1
->parent
;
2995 if (node2
->type
== XML_ATTRIBUTE_NODE
) {
2998 node2
= node2
->parent
;
3000 if (node1
== node2
) {
3001 if (attr1
== attr2
) {
3002 /* not required, but we keep attributes in order */
3004 cur
= attrNode2
->prev
;
3005 while (cur
!= NULL
) {
3006 if (cur
== attrNode1
)
3018 if ((node1
->type
== XML_NAMESPACE_DECL
) ||
3019 (node2
->type
== XML_NAMESPACE_DECL
))
3021 if (node1
== node2
->prev
)
3023 if (node1
== node2
->next
)
3027 * Speedup using document order if availble.
3029 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3030 (node2
->type
== XML_ELEMENT_NODE
) &&
3031 (0 > (long) node1
->content
) &&
3032 (0 > (long) node2
->content
) &&
3033 (node1
->doc
== node2
->doc
)) {
3036 l1
= -((long) node1
->content
);
3037 l2
= -((long) node2
->content
);
3045 * compute depth to root
3047 for (depth2
= 0, cur
= node2
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3053 for (depth1
= 0, cur
= node1
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3059 * Distinct document (or distinct entities :-( ) case.
3065 * get the nearest common ancestor.
3067 while (depth1
> depth2
) {
3069 node1
= node1
->parent
;
3071 while (depth2
> depth1
) {
3073 node2
= node2
->parent
;
3075 while (node1
->parent
!= node2
->parent
) {
3076 node1
= node1
->parent
;
3077 node2
= node2
->parent
;
3078 /* should not happen but just in case ... */
3079 if ((node1
== NULL
) || (node2
== NULL
))
3085 if (node1
== node2
->prev
)
3087 if (node1
== node2
->next
)
3090 * Speedup using document order if availble.
3092 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3093 (node2
->type
== XML_ELEMENT_NODE
) &&
3094 (0 > (long) node1
->content
) &&
3095 (0 > (long) node2
->content
) &&
3096 (node1
->doc
== node2
->doc
)) {
3099 l1
= -((long) node1
->content
);
3100 l2
= -((long) node2
->content
);
3107 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
3110 return(-1); /* assume there is no sibling list corruption */
3113 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3115 * xmlXPathCmpNodesExt:
3116 * @node1: the first node
3117 * @node2: the second node
3119 * Compare two nodes w.r.t document order.
3120 * This one is optimized for handling of non-element nodes.
3122 * Returns -2 in case of error 1 if first point < second point, 0 if
3123 * it's the same node, -1 otherwise
3126 xmlXPathCmpNodesExt(xmlNodePtr node1
, xmlNodePtr node2
) {
3128 int misc
= 0, precedence1
= 0, precedence2
= 0;
3129 xmlNodePtr miscNode1
= NULL
, miscNode2
= NULL
;
3130 xmlNodePtr cur
, root
;
3133 if ((node1
== NULL
) || (node2
== NULL
))
3140 * a couple of optimizations which will avoid computations in most cases
3142 switch (node1
->type
) {
3143 case XML_ELEMENT_NODE
:
3144 if (node2
->type
== XML_ELEMENT_NODE
) {
3145 if ((0 > (long) node1
->content
) && /* TODO: Would a != 0 suffice here? */
3146 (0 > (long) node2
->content
) &&
3147 (node1
->doc
== node2
->doc
))
3149 l1
= -((long) node1
->content
);
3150 l2
= -((long) node2
->content
);
3156 goto turtle_comparison
;
3159 case XML_ATTRIBUTE_NODE
:
3160 precedence1
= 1; /* element is owner */
3162 node1
= node1
->parent
;
3166 case XML_CDATA_SECTION_NODE
:
3167 case XML_COMMENT_NODE
:
3171 * Find nearest element node.
3173 if (node1
->prev
!= NULL
) {
3175 node1
= node1
->prev
;
3176 if (node1
->type
== XML_ELEMENT_NODE
) {
3177 precedence1
= 3; /* element in prev-sibl axis */
3180 if (node1
->prev
== NULL
) {
3181 precedence1
= 2; /* element is parent */
3183 * URGENT TODO: Are there any cases, where the
3184 * parent of such a node is not an element node?
3186 node1
= node1
->parent
;
3191 precedence1
= 2; /* element is parent */
3192 node1
= node1
->parent
;
3194 if ((node1
== NULL
) || (node1
->type
!= XML_ELEMENT_NODE
) ||
3195 (0 <= (long) node1
->content
)) {
3197 * Fallback for whatever case.
3205 case XML_NAMESPACE_DECL
:
3207 * TODO: why do we return 1 for namespace nodes?
3213 switch (node2
->type
) {
3214 case XML_ELEMENT_NODE
:
3216 case XML_ATTRIBUTE_NODE
:
3217 precedence2
= 1; /* element is owner */
3219 node2
= node2
->parent
;
3223 case XML_CDATA_SECTION_NODE
:
3224 case XML_COMMENT_NODE
:
3227 if (node2
->prev
!= NULL
) {
3229 node2
= node2
->prev
;
3230 if (node2
->type
== XML_ELEMENT_NODE
) {
3231 precedence2
= 3; /* element in prev-sibl axis */
3234 if (node2
->prev
== NULL
) {
3235 precedence2
= 2; /* element is parent */
3236 node2
= node2
->parent
;
3241 precedence2
= 2; /* element is parent */
3242 node2
= node2
->parent
;
3244 if ((node2
== NULL
) || (node2
->type
!= XML_ELEMENT_NODE
) ||
3245 (0 <= (long) node1
->content
))
3253 case XML_NAMESPACE_DECL
:
3259 if (node1
== node2
) {
3260 if (precedence1
== precedence2
) {
3262 * The ugly case; but normally there aren't many
3263 * adjacent non-element nodes around.
3265 cur
= miscNode2
->prev
;
3266 while (cur
!= NULL
) {
3267 if (cur
== miscNode1
)
3269 if (cur
->type
== XML_ELEMENT_NODE
)
3276 * Evaluate based on higher precedence wrt to the element.
3277 * TODO: This assumes attributes are sorted before content.
3278 * Is this 100% correct?
3280 if (precedence1
< precedence2
)
3287 * Special case: One of the helper-elements is contained by the other.
3290 * <node1>Text-1(precedence1 == 2)</node1>
3292 * Text-6(precedence2 == 3)
3295 if ((precedence2
== 3) && (precedence1
> 1)) {
3296 cur
= node1
->parent
;
3303 if ((precedence1
== 3) && (precedence2
> 1)) {
3304 cur
= node2
->parent
;
3314 * Speedup using document order if availble.
3316 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3317 (node2
->type
== XML_ELEMENT_NODE
) &&
3318 (0 > (long) node1
->content
) &&
3319 (0 > (long) node2
->content
) &&
3320 (node1
->doc
== node2
->doc
)) {
3322 l1
= -((long) node1
->content
);
3323 l2
= -((long) node2
->content
);
3332 if (node1
== node2
->prev
)
3334 if (node1
== node2
->next
)
3337 * compute depth to root
3339 for (depth2
= 0, cur
= node2
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3345 for (depth1
= 0, cur
= node1
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3351 * Distinct document (or distinct entities :-( ) case.
3357 * get the nearest common ancestor.
3359 while (depth1
> depth2
) {
3361 node1
= node1
->parent
;
3363 while (depth2
> depth1
) {
3365 node2
= node2
->parent
;
3367 while (node1
->parent
!= node2
->parent
) {
3368 node1
= node1
->parent
;
3369 node2
= node2
->parent
;
3370 /* should not happen but just in case ... */
3371 if ((node1
== NULL
) || (node2
== NULL
))
3377 if (node1
== node2
->prev
)
3379 if (node1
== node2
->next
)
3382 * Speedup using document order if availble.
3384 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3385 (node2
->type
== XML_ELEMENT_NODE
) &&
3386 (0 > (long) node1
->content
) &&
3387 (0 > (long) node2
->content
) &&
3388 (node1
->doc
== node2
->doc
)) {
3390 l1
= -((long) node1
->content
);
3391 l2
= -((long) node2
->content
);
3398 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
3401 return(-1); /* assume there is no sibling list corruption */
3403 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
3406 * xmlXPathNodeSetSort:
3407 * @set: the node set
3409 * Sort the node set in document order
3412 xmlXPathNodeSetSort(xmlNodeSetPtr set
) {
3413 #ifndef WITH_TIM_SORT
3414 int i
, j
, incr
, len
;
3421 #ifndef WITH_TIM_SORT
3423 * Use the old Shell's sort implementation to sort the node-set
3424 * Timsort ought to be quite faster
3427 for (incr
= len
/ 2; incr
> 0; incr
/= 2) {
3428 for (i
= incr
; i
< len
; i
++) {
3431 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3432 if (xmlXPathCmpNodesExt(set
->nodeTab
[j
],
3433 set
->nodeTab
[j
+ incr
]) == -1)
3435 if (xmlXPathCmpNodes(set
->nodeTab
[j
],
3436 set
->nodeTab
[j
+ incr
]) == -1)
3439 tmp
= set
->nodeTab
[j
];
3440 set
->nodeTab
[j
] = set
->nodeTab
[j
+ incr
];
3441 set
->nodeTab
[j
+ incr
] = tmp
;
3448 #else /* WITH_TIM_SORT */
3449 libxml_domnode_tim_sort(set
->nodeTab
, set
->nodeNr
);
3450 #endif /* WITH_TIM_SORT */
3453 #define XML_NODESET_DEFAULT 10
3455 * xmlXPathNodeSetDupNs:
3456 * @node: the parent node of the namespace XPath node
3457 * @ns: the libxml namespace declaration node.
3459 * Namespace node in libxml don't match the XPath semantic. In a node set
3460 * the namespace nodes are duplicated and the next pointer is set to the
3461 * parent node in the XPath semantic.
3463 * Returns the newly created object.
3466 xmlXPathNodeSetDupNs(xmlNodePtr node
, xmlNsPtr ns
) {
3469 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3471 if ((node
== NULL
) || (node
->type
== XML_NAMESPACE_DECL
))
3472 return((xmlNodePtr
) ns
);
3475 * Allocate a new Namespace and fill the fields.
3477 cur
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
3479 xmlXPathErrMemory(NULL
, "duplicating namespace\n");
3482 memset(cur
, 0, sizeof(xmlNs
));
3483 cur
->type
= XML_NAMESPACE_DECL
;
3484 if (ns
->href
!= NULL
)
3485 cur
->href
= xmlStrdup(ns
->href
);
3486 if (ns
->prefix
!= NULL
)
3487 cur
->prefix
= xmlStrdup(ns
->prefix
);
3488 cur
->next
= (xmlNsPtr
) node
;
3489 return((xmlNodePtr
) cur
);
3493 * xmlXPathNodeSetFreeNs:
3494 * @ns: the XPath namespace node found in a nodeset.
3496 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3497 * the namespace nodes are duplicated and the next pointer is set to the
3498 * parent node in the XPath semantic. Check if such a node needs to be freed
3501 xmlXPathNodeSetFreeNs(xmlNsPtr ns
) {
3502 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3505 if ((ns
->next
!= NULL
) && (ns
->next
->type
!= XML_NAMESPACE_DECL
)) {
3506 if (ns
->href
!= NULL
)
3507 xmlFree((xmlChar
*)ns
->href
);
3508 if (ns
->prefix
!= NULL
)
3509 xmlFree((xmlChar
*)ns
->prefix
);
3515 * xmlXPathNodeSetCreate:
3516 * @val: an initial xmlNodePtr, or NULL
3518 * Create a new xmlNodeSetPtr of type double and of value @val
3520 * Returns the newly created object.
3523 xmlXPathNodeSetCreate(xmlNodePtr val
) {
3526 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3528 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3531 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3533 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3534 sizeof(xmlNodePtr
));
3535 if (ret
->nodeTab
== NULL
) {
3536 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3540 memset(ret
->nodeTab
, 0 ,
3541 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3542 ret
->nodeMax
= XML_NODESET_DEFAULT
;
3543 if (val
->type
== XML_NAMESPACE_DECL
) {
3544 xmlNsPtr ns
= (xmlNsPtr
) val
;
3546 ret
->nodeTab
[ret
->nodeNr
++] =
3547 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3549 ret
->nodeTab
[ret
->nodeNr
++] = val
;
3555 * xmlXPathNodeSetCreateSize:
3556 * @size: the initial size of the set
3558 * Create a new xmlNodeSetPtr of type double and of value @val
3560 * Returns the newly created object.
3562 static xmlNodeSetPtr
3563 xmlXPathNodeSetCreateSize(int size
) {
3566 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3568 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3571 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3572 if (size
< XML_NODESET_DEFAULT
)
3573 size
= XML_NODESET_DEFAULT
;
3574 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(size
* sizeof(xmlNodePtr
));
3575 if (ret
->nodeTab
== NULL
) {
3576 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3580 memset(ret
->nodeTab
, 0 , size
* (size_t) sizeof(xmlNodePtr
));
3581 ret
->nodeMax
= size
;
3586 * xmlXPathNodeSetContains:
3587 * @cur: the node-set
3590 * checks whether @cur contains @val
3592 * Returns true (1) if @cur contains @val, false (0) otherwise
3595 xmlXPathNodeSetContains (xmlNodeSetPtr cur
, xmlNodePtr val
) {
3598 if ((cur
== NULL
) || (val
== NULL
)) return(0);
3599 if (val
->type
== XML_NAMESPACE_DECL
) {
3600 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3601 if (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
3604 ns1
= (xmlNsPtr
) val
;
3605 ns2
= (xmlNsPtr
) cur
->nodeTab
[i
];
3608 if ((ns1
->next
!= NULL
) && (ns2
->next
== ns1
->next
) &&
3609 (xmlStrEqual(ns1
->prefix
, ns2
->prefix
)))
3614 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3615 if (cur
->nodeTab
[i
] == val
)
3623 * xmlXPathNodeSetAddNs:
3624 * @cur: the initial node set
3625 * @node: the hosting node
3626 * @ns: a the namespace node
3628 * add a new namespace node to an existing NodeSet
3630 * Returns 0 in case of success and -1 in case of error
3633 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur
, xmlNodePtr node
, xmlNsPtr ns
) {
3637 if ((cur
== NULL
) || (ns
== NULL
) || (node
== NULL
) ||
3638 (ns
->type
!= XML_NAMESPACE_DECL
) ||
3639 (node
->type
!= XML_ELEMENT_NODE
))
3642 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3644 * prevent duplicates
3646 for (i
= 0;i
< cur
->nodeNr
;i
++) {
3647 if ((cur
->nodeTab
[i
] != NULL
) &&
3648 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) &&
3649 (((xmlNsPtr
)cur
->nodeTab
[i
])->next
== (xmlNsPtr
) node
) &&
3650 (xmlStrEqual(ns
->prefix
, ((xmlNsPtr
)cur
->nodeTab
[i
])->prefix
)))
3655 * grow the nodeTab if needed
3657 if (cur
->nodeMax
== 0) {
3658 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3659 sizeof(xmlNodePtr
));
3660 if (cur
->nodeTab
== NULL
) {
3661 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3664 memset(cur
->nodeTab
, 0 ,
3665 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3666 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3667 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3670 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3671 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3674 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3675 sizeof(xmlNodePtr
));
3677 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3681 cur
->nodeTab
= temp
;
3683 cur
->nodeTab
[cur
->nodeNr
++] = xmlXPathNodeSetDupNs(node
, ns
);
3688 * xmlXPathNodeSetAdd:
3689 * @cur: the initial node set
3690 * @val: a new xmlNodePtr
3692 * add a new xmlNodePtr to an existing NodeSet
3694 * Returns 0 in case of success, and -1 in case of error
3697 xmlXPathNodeSetAdd(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3700 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3702 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3706 for (i
= 0;i
< cur
->nodeNr
;i
++)
3707 if (cur
->nodeTab
[i
] == val
) return(0);
3710 * grow the nodeTab if needed
3712 if (cur
->nodeMax
== 0) {
3713 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3714 sizeof(xmlNodePtr
));
3715 if (cur
->nodeTab
== NULL
) {
3716 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3719 memset(cur
->nodeTab
, 0 ,
3720 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3721 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3722 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3725 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3726 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3729 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3730 sizeof(xmlNodePtr
));
3732 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3736 cur
->nodeTab
= temp
;
3738 if (val
->type
== XML_NAMESPACE_DECL
) {
3739 xmlNsPtr ns
= (xmlNsPtr
) val
;
3741 cur
->nodeTab
[cur
->nodeNr
++] =
3742 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3744 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3749 * xmlXPathNodeSetAddUnique:
3750 * @cur: the initial node set
3751 * @val: a new xmlNodePtr
3753 * add a new xmlNodePtr to an existing NodeSet, optimized version
3754 * when we are sure the node is not already in the set.
3756 * Returns 0 in case of success and -1 in case of failure
3759 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3760 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3762 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3764 * grow the nodeTab if needed
3766 if (cur
->nodeMax
== 0) {
3767 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3768 sizeof(xmlNodePtr
));
3769 if (cur
->nodeTab
== NULL
) {
3770 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3773 memset(cur
->nodeTab
, 0 ,
3774 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3775 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3776 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3779 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3780 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3783 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3784 sizeof(xmlNodePtr
));
3786 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3789 cur
->nodeTab
= temp
;
3792 if (val
->type
== XML_NAMESPACE_DECL
) {
3793 xmlNsPtr ns
= (xmlNsPtr
) val
;
3795 cur
->nodeTab
[cur
->nodeNr
++] =
3796 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3798 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3803 * xmlXPathNodeSetMerge:
3804 * @val1: the first NodeSet or NULL
3805 * @val2: the second NodeSet
3807 * Merges two nodesets, all nodes from @val2 are added to @val1
3808 * if @val1 is NULL, a new set is created and copied from @val2
3810 * Returns @val1 once extended or NULL in case of error.
3813 xmlXPathNodeSetMerge(xmlNodeSetPtr val1
, xmlNodeSetPtr val2
) {
3814 int i
, j
, initNr
, skip
;
3817 if (val2
== NULL
) return(val1
);
3819 val1
= xmlXPathNodeSetCreate(NULL
);
3824 * TODO: The optimization won't work in every case, since
3825 * those nasty namespace nodes need to be added with
3826 * xmlXPathNodeSetDupNs() to the set; thus a pure
3827 * memcpy is not possible.
3828 * If there was a flag on the nodesetval, indicating that
3829 * some temporary nodes are in, that would be helpfull.
3832 * Optimization: Create an equally sized node-set
3833 * and memcpy the content.
3835 val1
= xmlXPathNodeSetCreateSize(val2
->nodeNr
);
3838 if (val2
->nodeNr
!= 0) {
3839 if (val2
->nodeNr
== 1)
3840 *(val1
->nodeTab
) = *(val2
->nodeTab
);
3842 memcpy(val1
->nodeTab
, val2
->nodeTab
,
3843 val2
->nodeNr
* sizeof(xmlNodePtr
));
3845 val1
->nodeNr
= val2
->nodeNr
;
3851 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3852 initNr
= val1
->nodeNr
;
3854 for (i
= 0;i
< val2
->nodeNr
;i
++) {
3855 n2
= val2
->nodeTab
[i
];
3857 * check against duplicates
3860 for (j
= 0; j
< initNr
; j
++) {
3861 n1
= val1
->nodeTab
[j
];
3865 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3866 (n2
->type
== XML_NAMESPACE_DECL
)) {
3867 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3868 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3869 ((xmlNsPtr
) n2
)->prefix
)))
3880 * grow the nodeTab if needed
3882 if (val1
->nodeMax
== 0) {
3883 val1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3884 sizeof(xmlNodePtr
));
3885 if (val1
->nodeTab
== NULL
) {
3886 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3889 memset(val1
->nodeTab
, 0 ,
3890 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3891 val1
->nodeMax
= XML_NODESET_DEFAULT
;
3892 } else if (val1
->nodeNr
== val1
->nodeMax
) {
3895 if (val1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3896 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
3899 temp
= (xmlNodePtr
*) xmlRealloc(val1
->nodeTab
, val1
->nodeMax
* 2 *
3900 sizeof(xmlNodePtr
));
3902 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3905 val1
->nodeTab
= temp
;
3908 if (n2
->type
== XML_NAMESPACE_DECL
) {
3909 xmlNsPtr ns
= (xmlNsPtr
) n2
;
3911 val1
->nodeTab
[val1
->nodeNr
++] =
3912 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3914 val1
->nodeTab
[val1
->nodeNr
++] = n2
;
3922 * xmlXPathNodeSetMergeAndClear:
3923 * @set1: the first NodeSet or NULL
3924 * @set2: the second NodeSet
3925 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3927 * Merges two nodesets, all nodes from @set2 are added to @set1
3928 * if @set1 is NULL, a new set is created and copied from @set2.
3929 * Checks for duplicate nodes. Clears set2.
3931 * Returns @set1 once extended or NULL in case of error.
3933 static xmlNodeSetPtr
3934 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
,
3937 if ((set1
== NULL
) && (hasNullEntries
== 0)) {
3939 * Note that doing a memcpy of the list, namespace nodes are
3940 * just assigned to set1, since set2 is cleared anyway.
3942 set1
= xmlXPathNodeSetCreateSize(set2
->nodeNr
);
3945 if (set2
->nodeNr
!= 0) {
3946 memcpy(set1
->nodeTab
, set2
->nodeTab
,
3947 set2
->nodeNr
* sizeof(xmlNodePtr
));
3948 set1
->nodeNr
= set2
->nodeNr
;
3951 int i
, j
, initNbSet1
;
3955 set1
= xmlXPathNodeSetCreate(NULL
);
3959 initNbSet1
= set1
->nodeNr
;
3960 for (i
= 0;i
< set2
->nodeNr
;i
++) {
3961 n2
= set2
->nodeTab
[i
];
3963 * Skip NULLed entries.
3970 for (j
= 0; j
< initNbSet1
; j
++) {
3971 n1
= set1
->nodeTab
[j
];
3974 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3975 (n2
->type
== XML_NAMESPACE_DECL
))
3977 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3978 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3979 ((xmlNsPtr
) n2
)->prefix
)))
3982 * Free the namespace node.
3984 set2
->nodeTab
[i
] = NULL
;
3985 xmlXPathNodeSetFreeNs((xmlNsPtr
) n2
);
3991 * grow the nodeTab if needed
3993 if (set1
->nodeMax
== 0) {
3994 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
3995 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
3996 if (set1
->nodeTab
== NULL
) {
3997 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4000 memset(set1
->nodeTab
, 0,
4001 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4002 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4003 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4006 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4007 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4010 temp
= (xmlNodePtr
*) xmlRealloc(
4011 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4013 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4016 set1
->nodeTab
= temp
;
4019 if (n2
->type
== XML_NAMESPACE_DECL
) {
4020 xmlNsPtr ns
= (xmlNsPtr
) n2
;
4022 set1
->nodeTab
[set1
->nodeNr
++] =
4023 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
4025 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4035 * xmlXPathNodeSetMergeAndClearNoDupls:
4036 * @set1: the first NodeSet or NULL
4037 * @set2: the second NodeSet
4038 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4040 * Merges two nodesets, all nodes from @set2 are added to @set1
4041 * if @set1 is NULL, a new set is created and copied from @set2.
4042 * Doesn't chack for duplicate nodes. Clears set2.
4044 * Returns @set1 once extended or NULL in case of error.
4046 static xmlNodeSetPtr
4047 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
,
4052 if ((set1
== NULL
) && (hasNullEntries
== 0)) {
4054 * Note that doing a memcpy of the list, namespace nodes are
4055 * just assigned to set1, since set2 is cleared anyway.
4057 set1
= xmlXPathNodeSetCreateSize(set2
->nodeNr
);
4060 if (set2
->nodeNr
!= 0) {
4061 memcpy(set1
->nodeTab
, set2
->nodeTab
,
4062 set2
->nodeNr
* sizeof(xmlNodePtr
));
4063 set1
->nodeNr
= set2
->nodeNr
;
4070 set1
= xmlXPathNodeSetCreate(NULL
);
4074 for (i
= 0;i
< set2
->nodeNr
;i
++) {
4075 n2
= set2
->nodeTab
[i
];
4077 * Skip NULLed entries.
4081 if (set1
->nodeMax
== 0) {
4082 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
4083 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4084 if (set1
->nodeTab
== NULL
) {
4085 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4088 memset(set1
->nodeTab
, 0,
4089 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4090 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4091 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4094 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4095 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4098 temp
= (xmlNodePtr
*) xmlRealloc(
4099 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4101 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4104 set1
->nodeTab
= temp
;
4107 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4115 * xmlXPathNodeSetDel:
4116 * @cur: the initial node set
4117 * @val: an xmlNodePtr
4119 * Removes an xmlNodePtr from an existing NodeSet
4122 xmlXPathNodeSetDel(xmlNodeSetPtr cur
, xmlNodePtr val
) {
4125 if (cur
== NULL
) return;
4126 if (val
== NULL
) return;
4129 * find node in nodeTab
4131 for (i
= 0;i
< cur
->nodeNr
;i
++)
4132 if (cur
->nodeTab
[i
] == val
) break;
4134 if (i
>= cur
->nodeNr
) { /* not found */
4136 xmlGenericError(xmlGenericErrorContext
,
4137 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4142 if ((cur
->nodeTab
[i
] != NULL
) &&
4143 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4144 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[i
]);
4146 for (;i
< cur
->nodeNr
;i
++)
4147 cur
->nodeTab
[i
] = cur
->nodeTab
[i
+ 1];
4148 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4152 * xmlXPathNodeSetRemove:
4153 * @cur: the initial node set
4154 * @val: the index to remove
4156 * Removes an entry from an existing NodeSet list.
4159 xmlXPathNodeSetRemove(xmlNodeSetPtr cur
, int val
) {
4160 if (cur
== NULL
) return;
4161 if (val
>= cur
->nodeNr
) return;
4162 if ((cur
->nodeTab
[val
] != NULL
) &&
4163 (cur
->nodeTab
[val
]->type
== XML_NAMESPACE_DECL
))
4164 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[val
]);
4166 for (;val
< cur
->nodeNr
;val
++)
4167 cur
->nodeTab
[val
] = cur
->nodeTab
[val
+ 1];
4168 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4172 * xmlXPathFreeNodeSet:
4173 * @obj: the xmlNodeSetPtr to free
4175 * Free the NodeSet compound (not the actual nodes !).
4178 xmlXPathFreeNodeSet(xmlNodeSetPtr obj
) {
4179 if (obj
== NULL
) return;
4180 if (obj
->nodeTab
!= NULL
) {
4183 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4184 for (i
= 0;i
< obj
->nodeNr
;i
++)
4185 if ((obj
->nodeTab
[i
] != NULL
) &&
4186 (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4187 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4188 xmlFree(obj
->nodeTab
);
4194 * xmlXPathNodeSetClear:
4195 * @set: the node set to clear
4197 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4198 * are feed), but does *not* free the list itself. Sets the length of the
4202 xmlXPathNodeSetClear(xmlNodeSetPtr set
, int hasNsNodes
)
4204 if ((set
== NULL
) || (set
->nodeNr
<= 0))
4206 else if (hasNsNodes
) {
4210 for (i
= 0; i
< set
->nodeNr
; i
++) {
4211 node
= set
->nodeTab
[i
];
4212 if ((node
!= NULL
) &&
4213 (node
->type
== XML_NAMESPACE_DECL
))
4214 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4221 * xmlXPathNodeSetClearFromPos:
4222 * @set: the node set to be cleared
4223 * @pos: the start position to clear from
4225 * Clears the list from temporary XPath objects (e.g. namespace nodes
4226 * are feed) starting with the entry at @pos, but does *not* free the list
4227 * itself. Sets the length of the list to @pos.
4230 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set
, int pos
, int hasNsNodes
)
4232 if ((set
== NULL
) || (set
->nodeNr
<= 0) || (pos
>= set
->nodeNr
))
4234 else if ((hasNsNodes
)) {
4238 for (i
= pos
; i
< set
->nodeNr
; i
++) {
4239 node
= set
->nodeTab
[i
];
4240 if ((node
!= NULL
) &&
4241 (node
->type
== XML_NAMESPACE_DECL
))
4242 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4249 * xmlXPathFreeValueTree:
4250 * @obj: the xmlNodeSetPtr to free
4252 * Free the NodeSet compound and the actual tree, this is different
4253 * from xmlXPathFreeNodeSet()
4256 xmlXPathFreeValueTree(xmlNodeSetPtr obj
) {
4259 if (obj
== NULL
) return;
4261 if (obj
->nodeTab
!= NULL
) {
4262 for (i
= 0;i
< obj
->nodeNr
;i
++) {
4263 if (obj
->nodeTab
[i
] != NULL
) {
4264 if (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
4265 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4267 xmlFreeNodeList(obj
->nodeTab
[i
]);
4271 xmlFree(obj
->nodeTab
);
4276 #if defined(DEBUG) || defined(DEBUG_STEP)
4278 * xmlGenericErrorContextNodeSet:
4279 * @output: a FILE * for the output
4280 * @obj: the xmlNodeSetPtr to display
4282 * Quick display of a NodeSet
4285 xmlGenericErrorContextNodeSet(FILE *output
, xmlNodeSetPtr obj
) {
4288 if (output
== NULL
) output
= xmlGenericErrorContext
;
4290 fprintf(output
, "NodeSet == NULL !\n");
4293 if (obj
->nodeNr
== 0) {
4294 fprintf(output
, "NodeSet is empty\n");
4297 if (obj
->nodeTab
== NULL
) {
4298 fprintf(output
, " nodeTab == NULL !\n");
4301 for (i
= 0; i
< obj
->nodeNr
; i
++) {
4302 if (obj
->nodeTab
[i
] == NULL
) {
4303 fprintf(output
, " NULL !\n");
4306 if ((obj
->nodeTab
[i
]->type
== XML_DOCUMENT_NODE
) ||
4307 (obj
->nodeTab
[i
]->type
== XML_HTML_DOCUMENT_NODE
))
4308 fprintf(output
, " /");
4309 else if (obj
->nodeTab
[i
]->name
== NULL
)
4310 fprintf(output
, " noname!");
4311 else fprintf(output
, " %s", obj
->nodeTab
[i
]->name
);
4313 fprintf(output
, "\n");
4318 * xmlXPathNewNodeSet:
4319 * @val: the NodePtr value
4321 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4322 * it with the single Node @val
4324 * Returns the newly created object.
4327 xmlXPathNewNodeSet(xmlNodePtr val
) {
4328 xmlXPathObjectPtr ret
;
4330 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4332 xmlXPathErrMemory(NULL
, "creating nodeset\n");
4335 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4336 ret
->type
= XPATH_NODESET
;
4338 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4339 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4340 #ifdef XP_DEBUG_OBJ_USAGE
4341 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4347 * xmlXPathNewValueTree:
4348 * @val: the NodePtr value
4350 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4351 * it with the tree root @val
4353 * Returns the newly created object.
4356 xmlXPathNewValueTree(xmlNodePtr val
) {
4357 xmlXPathObjectPtr ret
;
4359 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4361 xmlXPathErrMemory(NULL
, "creating result value tree\n");
4364 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4365 ret
->type
= XPATH_XSLT_TREE
;
4367 ret
->user
= (void *) val
;
4368 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4369 #ifdef XP_DEBUG_OBJ_USAGE
4370 xmlXPathDebugObjUsageRequested(NULL
, XPATH_XSLT_TREE
);
4376 * xmlXPathNewNodeSetList:
4377 * @val: an existing NodeSet
4379 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4380 * it with the Nodeset @val
4382 * Returns the newly created object.
4385 xmlXPathNewNodeSetList(xmlNodeSetPtr val
)
4387 xmlXPathObjectPtr ret
;
4392 else if (val
->nodeTab
== NULL
)
4393 ret
= xmlXPathNewNodeSet(NULL
);
4395 ret
= xmlXPathNewNodeSet(val
->nodeTab
[0]);
4397 for (i
= 1; i
< val
->nodeNr
; ++i
) {
4398 if (xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
->nodeTab
[i
])
4408 * xmlXPathWrapNodeSet:
4409 * @val: the NodePtr value
4411 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4413 * Returns the newly created object.
4416 xmlXPathWrapNodeSet(xmlNodeSetPtr val
) {
4417 xmlXPathObjectPtr ret
;
4419 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4421 xmlXPathErrMemory(NULL
, "creating node set object\n");
4424 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4425 ret
->type
= XPATH_NODESET
;
4426 ret
->nodesetval
= val
;
4427 #ifdef XP_DEBUG_OBJ_USAGE
4428 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4434 * xmlXPathFreeNodeSetList:
4435 * @obj: an existing NodeSetList object
4437 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4438 * the list contrary to xmlXPathFreeObject().
4441 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj
) {
4442 if (obj
== NULL
) return;
4443 #ifdef XP_DEBUG_OBJ_USAGE
4444 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
4450 * xmlXPathDifference:
4451 * @nodes1: a node-set
4452 * @nodes2: a node-set
4454 * Implements the EXSLT - Sets difference() function:
4455 * node-set set:difference (node-set, node-set)
4457 * Returns the difference between the two node sets, or nodes1 if
4461 xmlXPathDifference (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4466 if (xmlXPathNodeSetIsEmpty(nodes2
))
4469 ret
= xmlXPathNodeSetCreate(NULL
);
4470 if (xmlXPathNodeSetIsEmpty(nodes1
))
4473 l1
= xmlXPathNodeSetGetLength(nodes1
);
4475 for (i
= 0; i
< l1
; i
++) {
4476 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4477 if (!xmlXPathNodeSetContains(nodes2
, cur
)) {
4478 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4486 * xmlXPathIntersection:
4487 * @nodes1: a node-set
4488 * @nodes2: a node-set
4490 * Implements the EXSLT - Sets intersection() function:
4491 * node-set set:intersection (node-set, node-set)
4493 * Returns a node set comprising the nodes that are within both the
4494 * node sets passed as arguments
4497 xmlXPathIntersection (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4498 xmlNodeSetPtr ret
= xmlXPathNodeSetCreate(NULL
);
4504 if (xmlXPathNodeSetIsEmpty(nodes1
))
4506 if (xmlXPathNodeSetIsEmpty(nodes2
))
4509 l1
= xmlXPathNodeSetGetLength(nodes1
);
4511 for (i
= 0; i
< l1
; i
++) {
4512 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4513 if (xmlXPathNodeSetContains(nodes2
, cur
)) {
4514 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4522 * xmlXPathDistinctSorted:
4523 * @nodes: a node-set, sorted by document order
4525 * Implements the EXSLT - Sets distinct() function:
4526 * node-set set:distinct (node-set)
4528 * Returns a subset of the nodes contained in @nodes, or @nodes if
4532 xmlXPathDistinctSorted (xmlNodeSetPtr nodes
) {
4534 xmlHashTablePtr hash
;
4539 if (xmlXPathNodeSetIsEmpty(nodes
))
4542 ret
= xmlXPathNodeSetCreate(NULL
);
4545 l
= xmlXPathNodeSetGetLength(nodes
);
4546 hash
= xmlHashCreate (l
);
4547 for (i
= 0; i
< l
; i
++) {
4548 cur
= xmlXPathNodeSetItem(nodes
, i
);
4549 strval
= xmlXPathCastNodeToString(cur
);
4550 if (xmlHashLookup(hash
, strval
) == NULL
) {
4551 xmlHashAddEntry(hash
, strval
, strval
);
4552 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4558 xmlHashFree(hash
, (xmlHashDeallocator
) xmlFree
);
4564 * @nodes: a node-set
4566 * Implements the EXSLT - Sets distinct() function:
4567 * node-set set:distinct (node-set)
4568 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4569 * is called with the sorted node-set
4571 * Returns a subset of the nodes contained in @nodes, or @nodes if
4575 xmlXPathDistinct (xmlNodeSetPtr nodes
) {
4576 if (xmlXPathNodeSetIsEmpty(nodes
))
4579 xmlXPathNodeSetSort(nodes
);
4580 return(xmlXPathDistinctSorted(nodes
));
4584 * xmlXPathHasSameNodes:
4585 * @nodes1: a node-set
4586 * @nodes2: a node-set
4588 * Implements the EXSLT - Sets has-same-nodes function:
4589 * boolean set:has-same-node(node-set, node-set)
4591 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4595 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4599 if (xmlXPathNodeSetIsEmpty(nodes1
) ||
4600 xmlXPathNodeSetIsEmpty(nodes2
))
4603 l
= xmlXPathNodeSetGetLength(nodes1
);
4604 for (i
= 0; i
< l
; i
++) {
4605 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4606 if (xmlXPathNodeSetContains(nodes2
, cur
))
4613 * xmlXPathNodeLeadingSorted:
4614 * @nodes: a node-set, sorted by document order
4617 * Implements the EXSLT - Sets leading() function:
4618 * node-set set:leading (node-set, node-set)
4620 * Returns the nodes in @nodes that precede @node in document order,
4621 * @nodes if @node is NULL or an empty node-set if @nodes
4622 * doesn't contain @node
4625 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4633 ret
= xmlXPathNodeSetCreate(NULL
);
4636 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4637 (!xmlXPathNodeSetContains(nodes
, node
)))
4640 l
= xmlXPathNodeSetGetLength(nodes
);
4641 for (i
= 0; i
< l
; i
++) {
4642 cur
= xmlXPathNodeSetItem(nodes
, i
);
4645 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4652 * xmlXPathNodeLeading:
4653 * @nodes: a node-set
4656 * Implements the EXSLT - Sets leading() function:
4657 * node-set set:leading (node-set, node-set)
4658 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4661 * Returns the nodes in @nodes that precede @node in document order,
4662 * @nodes if @node is NULL or an empty node-set if @nodes
4663 * doesn't contain @node
4666 xmlXPathNodeLeading (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4667 xmlXPathNodeSetSort(nodes
);
4668 return(xmlXPathNodeLeadingSorted(nodes
, node
));
4672 * xmlXPathLeadingSorted:
4673 * @nodes1: a node-set, sorted by document order
4674 * @nodes2: a node-set, sorted by document order
4676 * Implements the EXSLT - Sets leading() function:
4677 * node-set set:leading (node-set, node-set)
4679 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4680 * in document order, @nodes1 if @nodes2 is NULL or empty or
4681 * an empty node-set if @nodes1 doesn't contain @nodes2
4684 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4685 if (xmlXPathNodeSetIsEmpty(nodes2
))
4687 return(xmlXPathNodeLeadingSorted(nodes1
,
4688 xmlXPathNodeSetItem(nodes2
, 1)));
4693 * @nodes1: a node-set
4694 * @nodes2: a node-set
4696 * Implements the EXSLT - Sets leading() function:
4697 * node-set set:leading (node-set, node-set)
4698 * @nodes1 and @nodes2 are sorted by document order, then
4699 * #exslSetsLeadingSorted is called.
4701 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4702 * in document order, @nodes1 if @nodes2 is NULL or empty or
4703 * an empty node-set if @nodes1 doesn't contain @nodes2
4706 xmlXPathLeading (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4707 if (xmlXPathNodeSetIsEmpty(nodes2
))
4709 if (xmlXPathNodeSetIsEmpty(nodes1
))
4710 return(xmlXPathNodeSetCreate(NULL
));
4711 xmlXPathNodeSetSort(nodes1
);
4712 xmlXPathNodeSetSort(nodes2
);
4713 return(xmlXPathNodeLeadingSorted(nodes1
,
4714 xmlXPathNodeSetItem(nodes2
, 1)));
4718 * xmlXPathNodeTrailingSorted:
4719 * @nodes: a node-set, sorted by document order
4722 * Implements the EXSLT - Sets trailing() function:
4723 * node-set set:trailing (node-set, node-set)
4725 * Returns the nodes in @nodes that follow @node in document order,
4726 * @nodes if @node is NULL or an empty node-set if @nodes
4727 * doesn't contain @node
4730 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4738 ret
= xmlXPathNodeSetCreate(NULL
);
4741 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4742 (!xmlXPathNodeSetContains(nodes
, node
)))
4745 l
= xmlXPathNodeSetGetLength(nodes
);
4746 for (i
= l
- 1; i
>= 0; i
--) {
4747 cur
= xmlXPathNodeSetItem(nodes
, i
);
4750 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4753 xmlXPathNodeSetSort(ret
); /* bug 413451 */
4758 * xmlXPathNodeTrailing:
4759 * @nodes: a node-set
4762 * Implements the EXSLT - Sets trailing() function:
4763 * node-set set:trailing (node-set, node-set)
4764 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4767 * Returns the nodes in @nodes that follow @node in document order,
4768 * @nodes if @node is NULL or an empty node-set if @nodes
4769 * doesn't contain @node
4772 xmlXPathNodeTrailing (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4773 xmlXPathNodeSetSort(nodes
);
4774 return(xmlXPathNodeTrailingSorted(nodes
, node
));
4778 * xmlXPathTrailingSorted:
4779 * @nodes1: a node-set, sorted by document order
4780 * @nodes2: a node-set, sorted by document order
4782 * Implements the EXSLT - Sets trailing() function:
4783 * node-set set:trailing (node-set, node-set)
4785 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4786 * in document order, @nodes1 if @nodes2 is NULL or empty or
4787 * an empty node-set if @nodes1 doesn't contain @nodes2
4790 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4791 if (xmlXPathNodeSetIsEmpty(nodes2
))
4793 return(xmlXPathNodeTrailingSorted(nodes1
,
4794 xmlXPathNodeSetItem(nodes2
, 0)));
4799 * @nodes1: a node-set
4800 * @nodes2: a node-set
4802 * Implements the EXSLT - Sets trailing() function:
4803 * node-set set:trailing (node-set, node-set)
4804 * @nodes1 and @nodes2 are sorted by document order, then
4805 * #xmlXPathTrailingSorted is called.
4807 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4808 * in document order, @nodes1 if @nodes2 is NULL or empty or
4809 * an empty node-set if @nodes1 doesn't contain @nodes2
4812 xmlXPathTrailing (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4813 if (xmlXPathNodeSetIsEmpty(nodes2
))
4815 if (xmlXPathNodeSetIsEmpty(nodes1
))
4816 return(xmlXPathNodeSetCreate(NULL
));
4817 xmlXPathNodeSetSort(nodes1
);
4818 xmlXPathNodeSetSort(nodes2
);
4819 return(xmlXPathNodeTrailingSorted(nodes1
,
4820 xmlXPathNodeSetItem(nodes2
, 0)));
4823 /************************************************************************
4825 * Routines to handle extra functions *
4827 ************************************************************************/
4830 * xmlXPathRegisterFunc:
4831 * @ctxt: the XPath context
4832 * @name: the function name
4833 * @f: the function implementation or NULL
4835 * Register a new function. If @f is NULL it unregisters the function
4837 * Returns 0 in case of success, -1 in case of error
4840 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4841 xmlXPathFunction f
) {
4842 return(xmlXPathRegisterFuncNS(ctxt
, name
, NULL
, f
));
4846 * xmlXPathRegisterFuncNS:
4847 * @ctxt: the XPath context
4848 * @name: the function name
4849 * @ns_uri: the function namespace URI
4850 * @f: the function implementation or NULL
4852 * Register a new function. If @f is NULL it unregisters the function
4854 * Returns 0 in case of success, -1 in case of error
4857 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4858 const xmlChar
*ns_uri
, xmlXPathFunction f
) {
4864 if (ctxt
->funcHash
== NULL
)
4865 ctxt
->funcHash
= xmlHashCreate(0);
4866 if (ctxt
->funcHash
== NULL
)
4869 return(xmlHashRemoveEntry2(ctxt
->funcHash
, name
, ns_uri
, NULL
));
4870 return(xmlHashAddEntry2(ctxt
->funcHash
, name
, ns_uri
, XML_CAST_FPTR(f
)));
4874 * xmlXPathRegisterFuncLookup:
4875 * @ctxt: the XPath context
4876 * @f: the lookup function
4877 * @funcCtxt: the lookup data
4879 * Registers an external mechanism to do function lookup.
4882 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt
,
4883 xmlXPathFuncLookupFunc f
,
4887 ctxt
->funcLookupFunc
= f
;
4888 ctxt
->funcLookupData
= funcCtxt
;
4892 * xmlXPathFunctionLookup:
4893 * @ctxt: the XPath context
4894 * @name: the function name
4896 * Search in the Function array of the context for the given
4899 * Returns the xmlXPathFunction or NULL if not found
4902 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
4906 if (ctxt
->funcLookupFunc
!= NULL
) {
4907 xmlXPathFunction ret
;
4908 xmlXPathFuncLookupFunc f
;
4910 f
= ctxt
->funcLookupFunc
;
4911 ret
= f(ctxt
->funcLookupData
, name
, NULL
);
4915 return(xmlXPathFunctionLookupNS(ctxt
, name
, NULL
));
4919 * xmlXPathFunctionLookupNS:
4920 * @ctxt: the XPath context
4921 * @name: the function name
4922 * @ns_uri: the function namespace URI
4924 * Search in the Function array of the context for the given
4927 * Returns the xmlXPathFunction or NULL if not found
4930 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4931 const xmlChar
*ns_uri
) {
4932 xmlXPathFunction ret
;
4939 if (ctxt
->funcLookupFunc
!= NULL
) {
4940 xmlXPathFuncLookupFunc f
;
4942 f
= ctxt
->funcLookupFunc
;
4943 ret
= f(ctxt
->funcLookupData
, name
, ns_uri
);
4948 if (ctxt
->funcHash
== NULL
)
4951 XML_CAST_FPTR(ret
) = xmlHashLookup2(ctxt
->funcHash
, name
, ns_uri
);
4956 * xmlXPathRegisteredFuncsCleanup:
4957 * @ctxt: the XPath context
4959 * Cleanup the XPath context data associated to registered functions
4962 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt
) {
4966 xmlHashFree(ctxt
->funcHash
, NULL
);
4967 ctxt
->funcHash
= NULL
;
4970 /************************************************************************
4972 * Routines to handle Variables *
4974 ************************************************************************/
4977 * xmlXPathRegisterVariable:
4978 * @ctxt: the XPath context
4979 * @name: the variable name
4980 * @value: the variable value or NULL
4982 * Register a new variable value. If @value is NULL it unregisters
4985 * Returns 0 in case of success, -1 in case of error
4988 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4989 xmlXPathObjectPtr value
) {
4990 return(xmlXPathRegisterVariableNS(ctxt
, name
, NULL
, value
));
4994 * xmlXPathRegisterVariableNS:
4995 * @ctxt: the XPath context
4996 * @name: the variable name
4997 * @ns_uri: the variable namespace URI
4998 * @value: the variable value or NULL
5000 * Register a new variable value. If @value is NULL it unregisters
5003 * Returns 0 in case of success, -1 in case of error
5006 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5007 const xmlChar
*ns_uri
,
5008 xmlXPathObjectPtr value
) {
5014 if (ctxt
->varHash
== NULL
)
5015 ctxt
->varHash
= xmlHashCreate(0);
5016 if (ctxt
->varHash
== NULL
)
5019 return(xmlHashRemoveEntry2(ctxt
->varHash
, name
, ns_uri
,
5020 (xmlHashDeallocator
)xmlXPathFreeObject
));
5021 return(xmlHashUpdateEntry2(ctxt
->varHash
, name
, ns_uri
,
5023 (xmlHashDeallocator
)xmlXPathFreeObject
));
5027 * xmlXPathRegisterVariableLookup:
5028 * @ctxt: the XPath context
5029 * @f: the lookup function
5030 * @data: the lookup data
5032 * register an external mechanism to do variable lookup
5035 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt
,
5036 xmlXPathVariableLookupFunc f
, void *data
) {
5039 ctxt
->varLookupFunc
= f
;
5040 ctxt
->varLookupData
= data
;
5044 * xmlXPathVariableLookup:
5045 * @ctxt: the XPath context
5046 * @name: the variable name
5048 * Search in the Variable array of the context for the given
5051 * Returns a copy of the value or NULL if not found
5054 xmlXPathVariableLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
5058 if (ctxt
->varLookupFunc
!= NULL
) {
5059 xmlXPathObjectPtr ret
;
5061 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5062 (ctxt
->varLookupData
, name
, NULL
);
5065 return(xmlXPathVariableLookupNS(ctxt
, name
, NULL
));
5069 * xmlXPathVariableLookupNS:
5070 * @ctxt: the XPath context
5071 * @name: the variable name
5072 * @ns_uri: the variable namespace URI
5074 * Search in the Variable array of the context for the given
5077 * Returns the a copy of the value or NULL if not found
5080 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5081 const xmlChar
*ns_uri
) {
5085 if (ctxt
->varLookupFunc
!= NULL
) {
5086 xmlXPathObjectPtr ret
;
5088 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5089 (ctxt
->varLookupData
, name
, ns_uri
);
5090 if (ret
!= NULL
) return(ret
);
5093 if (ctxt
->varHash
== NULL
)
5098 return(xmlXPathCacheObjectCopy(ctxt
, (xmlXPathObjectPtr
)
5099 xmlHashLookup2(ctxt
->varHash
, name
, ns_uri
)));
5103 * xmlXPathRegisteredVariablesCleanup:
5104 * @ctxt: the XPath context
5106 * Cleanup the XPath context data associated to registered variables
5109 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt
) {
5113 xmlHashFree(ctxt
->varHash
, (xmlHashDeallocator
)xmlXPathFreeObject
);
5114 ctxt
->varHash
= NULL
;
5118 * xmlXPathRegisterNs:
5119 * @ctxt: the XPath context
5120 * @prefix: the namespace prefix cannot be NULL or empty string
5121 * @ns_uri: the namespace name
5123 * Register a new namespace. If @ns_uri is NULL it unregisters
5126 * Returns 0 in case of success, -1 in case of error
5129 xmlXPathRegisterNs(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
,
5130 const xmlChar
*ns_uri
) {
5138 if (ctxt
->nsHash
== NULL
)
5139 ctxt
->nsHash
= xmlHashCreate(10);
5140 if (ctxt
->nsHash
== NULL
)
5143 return(xmlHashRemoveEntry(ctxt
->nsHash
, prefix
,
5144 (xmlHashDeallocator
)xmlFree
));
5145 return(xmlHashUpdateEntry(ctxt
->nsHash
, prefix
, (void *) xmlStrdup(ns_uri
),
5146 (xmlHashDeallocator
)xmlFree
));
5151 * @ctxt: the XPath context
5152 * @prefix: the namespace prefix value
5154 * Search in the namespace declaration array of the context for the given
5155 * namespace name associated to the given prefix
5157 * Returns the value or NULL if not found
5160 xmlXPathNsLookup(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
) {
5166 #ifdef XML_XML_NAMESPACE
5167 if (xmlStrEqual(prefix
, (const xmlChar
*) "xml"))
5168 return(XML_XML_NAMESPACE
);
5171 if (ctxt
->namespaces
!= NULL
) {
5174 for (i
= 0;i
< ctxt
->nsNr
;i
++) {
5175 if ((ctxt
->namespaces
[i
] != NULL
) &&
5176 (xmlStrEqual(ctxt
->namespaces
[i
]->prefix
, prefix
)))
5177 return(ctxt
->namespaces
[i
]->href
);
5181 return((const xmlChar
*) xmlHashLookup(ctxt
->nsHash
, prefix
));
5185 * xmlXPathRegisteredNsCleanup:
5186 * @ctxt: the XPath context
5188 * Cleanup the XPath context data associated to registered variables
5191 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt
) {
5195 xmlHashFree(ctxt
->nsHash
, (xmlHashDeallocator
)xmlFree
);
5196 ctxt
->nsHash
= NULL
;
5199 /************************************************************************
5201 * Routines to handle Values *
5203 ************************************************************************/
5205 /* Allocations are terrible, one needs to optimize all this !!! */
5209 * @val: the double value
5211 * Create a new xmlXPathObjectPtr of type double and of value @val
5213 * Returns the newly created object.
5216 xmlXPathNewFloat(double val
) {
5217 xmlXPathObjectPtr ret
;
5219 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5221 xmlXPathErrMemory(NULL
, "creating float object\n");
5224 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5225 ret
->type
= XPATH_NUMBER
;
5226 ret
->floatval
= val
;
5227 #ifdef XP_DEBUG_OBJ_USAGE
5228 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NUMBER
);
5234 * xmlXPathNewBoolean:
5235 * @val: the boolean value
5237 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5239 * Returns the newly created object.
5242 xmlXPathNewBoolean(int val
) {
5243 xmlXPathObjectPtr ret
;
5245 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5247 xmlXPathErrMemory(NULL
, "creating boolean object\n");
5250 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5251 ret
->type
= XPATH_BOOLEAN
;
5252 ret
->boolval
= (val
!= 0);
5253 #ifdef XP_DEBUG_OBJ_USAGE
5254 xmlXPathDebugObjUsageRequested(NULL
, XPATH_BOOLEAN
);
5260 * xmlXPathNewString:
5261 * @val: the xmlChar * value
5263 * Create a new xmlXPathObjectPtr of type string and of value @val
5265 * Returns the newly created object.
5268 xmlXPathNewString(const xmlChar
*val
) {
5269 xmlXPathObjectPtr ret
;
5271 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5273 xmlXPathErrMemory(NULL
, "creating string object\n");
5276 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5277 ret
->type
= XPATH_STRING
;
5279 ret
->stringval
= xmlStrdup(val
);
5281 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
5282 #ifdef XP_DEBUG_OBJ_USAGE
5283 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5289 * xmlXPathWrapString:
5290 * @val: the xmlChar * value
5292 * Wraps the @val string into an XPath object.
5294 * Returns the newly created object.
5297 xmlXPathWrapString (xmlChar
*val
) {
5298 xmlXPathObjectPtr ret
;
5300 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5302 xmlXPathErrMemory(NULL
, "creating string object\n");
5305 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5306 ret
->type
= XPATH_STRING
;
5307 ret
->stringval
= val
;
5308 #ifdef XP_DEBUG_OBJ_USAGE
5309 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5315 * xmlXPathNewCString:
5316 * @val: the char * value
5318 * Create a new xmlXPathObjectPtr of type string and of value @val
5320 * Returns the newly created object.
5323 xmlXPathNewCString(const char *val
) {
5324 xmlXPathObjectPtr ret
;
5326 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5328 xmlXPathErrMemory(NULL
, "creating string object\n");
5331 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5332 ret
->type
= XPATH_STRING
;
5333 ret
->stringval
= xmlStrdup(BAD_CAST val
);
5334 #ifdef XP_DEBUG_OBJ_USAGE
5335 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5341 * xmlXPathWrapCString:
5342 * @val: the char * value
5344 * Wraps a string into an XPath object.
5346 * Returns the newly created object.
5349 xmlXPathWrapCString (char * val
) {
5350 return(xmlXPathWrapString((xmlChar
*)(val
)));
5354 * xmlXPathWrapExternal:
5355 * @val: the user data
5357 * Wraps the @val data into an XPath object.
5359 * Returns the newly created object.
5362 xmlXPathWrapExternal (void *val
) {
5363 xmlXPathObjectPtr ret
;
5365 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5367 xmlXPathErrMemory(NULL
, "creating user object\n");
5370 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5371 ret
->type
= XPATH_USERS
;
5373 #ifdef XP_DEBUG_OBJ_USAGE
5374 xmlXPathDebugObjUsageRequested(NULL
, XPATH_USERS
);
5380 * xmlXPathObjectCopy:
5381 * @val: the original object
5383 * allocate a new copy of a given object
5385 * Returns the newly created object.
5388 xmlXPathObjectCopy(xmlXPathObjectPtr val
) {
5389 xmlXPathObjectPtr ret
;
5394 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5396 xmlXPathErrMemory(NULL
, "copying object\n");
5399 memcpy(ret
, val
, (size_t) sizeof(xmlXPathObject
));
5400 #ifdef XP_DEBUG_OBJ_USAGE
5401 xmlXPathDebugObjUsageRequested(NULL
, val
->type
);
5403 switch (val
->type
) {
5410 ret
->stringval
= xmlStrdup(val
->stringval
);
5412 case XPATH_XSLT_TREE
:
5415 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5416 this previous handling is no longer correct, and can cause some serious
5417 problems (ref. bug 145547)
5419 if ((val
->nodesetval
!= NULL
) &&
5420 (val
->nodesetval
->nodeTab
!= NULL
)) {
5421 xmlNodePtr cur
, tmp
;
5425 top
= xmlNewDoc(NULL
);
5426 top
->name
= (char *)
5427 xmlStrdup(val
->nodesetval
->nodeTab
[0]->name
);
5431 cur
= val
->nodesetval
->nodeTab
[0]->children
;
5432 while (cur
!= NULL
) {
5433 tmp
= xmlDocCopyNode(cur
, top
, 1);
5434 xmlAddChild((xmlNodePtr
) top
, tmp
);
5439 ret
->nodesetval
= xmlXPathNodeSetCreate((xmlNodePtr
) top
);
5441 ret
->nodesetval
= xmlXPathNodeSetCreate(NULL
);
5442 /* Deallocate the copied tree value */
5446 ret
->nodesetval
= xmlXPathNodeSetMerge(NULL
, val
->nodesetval
);
5447 /* Do not deallocate the copied tree value */
5450 case XPATH_LOCATIONSET
:
5451 #ifdef LIBXML_XPTR_ENABLED
5453 xmlLocationSetPtr loc
= val
->user
;
5454 ret
->user
= (void *) xmlXPtrLocationSetMerge(NULL
, loc
);
5459 ret
->user
= val
->user
;
5461 case XPATH_UNDEFINED
:
5462 xmlGenericError(xmlGenericErrorContext
,
5463 "xmlXPathObjectCopy: unsupported type %d\n",
5471 * xmlXPathFreeObject:
5472 * @obj: the object to free
5474 * Free up an xmlXPathObjectPtr object.
5477 xmlXPathFreeObject(xmlXPathObjectPtr obj
) {
5478 if (obj
== NULL
) return;
5479 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
5482 if (obj
->user
!= NULL
) {
5483 xmlXPathFreeNodeSet(obj
->nodesetval
);
5484 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
5487 obj
->type
= XPATH_XSLT_TREE
; /* TODO: Just for debugging. */
5488 if (obj
->nodesetval
!= NULL
)
5489 xmlXPathFreeValueTree(obj
->nodesetval
);
5491 if (obj
->nodesetval
!= NULL
)
5492 xmlXPathFreeNodeSet(obj
->nodesetval
);
5494 #ifdef LIBXML_XPTR_ENABLED
5495 } else if (obj
->type
== XPATH_LOCATIONSET
) {
5496 if (obj
->user
!= NULL
)
5497 xmlXPtrFreeLocationSet(obj
->user
);
5499 } else if (obj
->type
== XPATH_STRING
) {
5500 if (obj
->stringval
!= NULL
)
5501 xmlFree(obj
->stringval
);
5503 #ifdef XP_DEBUG_OBJ_USAGE
5504 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5510 * xmlXPathReleaseObject:
5511 * @obj: the xmlXPathObjectPtr to free or to cache
5513 * Depending on the state of the cache this frees the given
5514 * XPath object or stores it in the cache.
5517 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
)
5519 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5520 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5521 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5523 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5527 if ((ctxt
== NULL
) || (ctxt
->cache
== NULL
)) {
5528 xmlXPathFreeObject(obj
);
5530 xmlXPathContextCachePtr cache
=
5531 (xmlXPathContextCachePtr
) ctxt
->cache
;
5533 switch (obj
->type
) {
5535 case XPATH_XSLT_TREE
:
5536 if (obj
->nodesetval
!= NULL
) {
5539 * It looks like the @boolval is used for
5540 * evaluation if this an XSLT Result Tree Fragment.
5541 * TODO: Check if this assumption is correct.
5543 obj
->type
= XPATH_XSLT_TREE
; /* just for debugging */
5544 xmlXPathFreeValueTree(obj
->nodesetval
);
5545 obj
->nodesetval
= NULL
;
5546 } else if ((obj
->nodesetval
->nodeMax
<= 40) &&
5547 (XP_CACHE_WANTS(cache
->nodesetObjs
,
5548 cache
->maxNodeset
)))
5550 XP_CACHE_ADD(cache
->nodesetObjs
, obj
);
5553 xmlXPathFreeNodeSet(obj
->nodesetval
);
5554 obj
->nodesetval
= NULL
;
5559 if (obj
->stringval
!= NULL
)
5560 xmlFree(obj
->stringval
);
5562 if (XP_CACHE_WANTS(cache
->stringObjs
, cache
->maxString
)) {
5563 XP_CACHE_ADD(cache
->stringObjs
, obj
);
5568 if (XP_CACHE_WANTS(cache
->booleanObjs
, cache
->maxBoolean
)) {
5569 XP_CACHE_ADD(cache
->booleanObjs
, obj
);
5574 if (XP_CACHE_WANTS(cache
->numberObjs
, cache
->maxNumber
)) {
5575 XP_CACHE_ADD(cache
->numberObjs
, obj
);
5579 #ifdef LIBXML_XPTR_ENABLED
5580 case XPATH_LOCATIONSET
:
5581 if (obj
->user
!= NULL
) {
5582 xmlXPtrFreeLocationSet(obj
->user
);
5591 * Fallback to adding to the misc-objects slot.
5593 if (XP_CACHE_WANTS(cache
->miscObjs
, cache
->maxMisc
)) {
5594 XP_CACHE_ADD(cache
->miscObjs
, obj
);
5600 #ifdef XP_DEBUG_OBJ_USAGE
5601 xmlXPathDebugObjUsageReleased(ctxt
, obj
->type
);
5604 if (obj
->nodesetval
!= NULL
) {
5605 xmlNodeSetPtr tmpset
= obj
->nodesetval
;
5608 * TODO: Due to those nasty ns-nodes, we need to traverse
5609 * the list and free the ns-nodes.
5610 * URGENT TODO: Check if it's actually slowing things down.
5611 * Maybe we shouldn't try to preserve the list.
5613 if (tmpset
->nodeNr
> 1) {
5617 for (i
= 0; i
< tmpset
->nodeNr
; i
++) {
5618 node
= tmpset
->nodeTab
[i
];
5619 if ((node
!= NULL
) &&
5620 (node
->type
== XML_NAMESPACE_DECL
))
5622 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
5625 } else if (tmpset
->nodeNr
== 1) {
5626 if ((tmpset
->nodeTab
[0] != NULL
) &&
5627 (tmpset
->nodeTab
[0]->type
== XML_NAMESPACE_DECL
))
5628 xmlXPathNodeSetFreeNs((xmlNsPtr
) tmpset
->nodeTab
[0]);
5631 memset(obj
, 0, sizeof(xmlXPathObject
));
5632 obj
->nodesetval
= tmpset
;
5634 memset(obj
, 0, sizeof(xmlXPathObject
));
5640 * Cache is full; free the object.
5642 if (obj
->nodesetval
!= NULL
)
5643 xmlXPathFreeNodeSet(obj
->nodesetval
);
5644 #ifdef XP_DEBUG_OBJ_USAGE
5645 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5653 /************************************************************************
5655 * Type Casting Routines *
5657 ************************************************************************/
5660 * xmlXPathCastBooleanToString:
5663 * Converts a boolean to its string value.
5665 * Returns a newly allocated string.
5668 xmlXPathCastBooleanToString (int val
) {
5671 ret
= xmlStrdup((const xmlChar
*) "true");
5673 ret
= xmlStrdup((const xmlChar
*) "false");
5678 * xmlXPathCastNumberToString:
5681 * Converts a number to its string value.
5683 * Returns a newly allocated string.
5686 xmlXPathCastNumberToString (double val
) {
5688 switch (xmlXPathIsInf(val
)) {
5690 ret
= xmlStrdup((const xmlChar
*) "Infinity");
5693 ret
= xmlStrdup((const xmlChar
*) "-Infinity");
5696 if (xmlXPathIsNaN(val
)) {
5697 ret
= xmlStrdup((const xmlChar
*) "NaN");
5698 } else if (val
== 0 && xmlXPathGetSign(val
) != 0) {
5699 ret
= xmlStrdup((const xmlChar
*) "0");
5701 /* could be improved */
5703 xmlXPathFormatNumber(val
, buf
, 99);
5705 ret
= xmlStrdup((const xmlChar
*) buf
);
5712 * xmlXPathCastNodeToString:
5715 * Converts a node to its string value.
5717 * Returns a newly allocated string.
5720 xmlXPathCastNodeToString (xmlNodePtr node
) {
5722 if ((ret
= xmlNodeGetContent(node
)) == NULL
)
5723 ret
= xmlStrdup((const xmlChar
*) "");
5728 * xmlXPathCastNodeSetToString:
5731 * Converts a node-set to its string value.
5733 * Returns a newly allocated string.
5736 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns
) {
5737 if ((ns
== NULL
) || (ns
->nodeNr
== 0) || (ns
->nodeTab
== NULL
))
5738 return(xmlStrdup((const xmlChar
*) ""));
5741 xmlXPathNodeSetSort(ns
);
5742 return(xmlXPathCastNodeToString(ns
->nodeTab
[0]));
5746 * xmlXPathCastToString:
5747 * @val: an XPath object
5749 * Converts an existing object to its string() equivalent
5751 * Returns the allocated string value of the object, NULL in case of error.
5752 * It's up to the caller to free the string memory with xmlFree().
5755 xmlXPathCastToString(xmlXPathObjectPtr val
) {
5756 xmlChar
*ret
= NULL
;
5759 return(xmlStrdup((const xmlChar
*) ""));
5760 switch (val
->type
) {
5761 case XPATH_UNDEFINED
:
5763 xmlGenericError(xmlGenericErrorContext
, "String: undefined\n");
5765 ret
= xmlStrdup((const xmlChar
*) "");
5768 case XPATH_XSLT_TREE
:
5769 ret
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5772 return(xmlStrdup(val
->stringval
));
5774 ret
= xmlXPathCastBooleanToString(val
->boolval
);
5776 case XPATH_NUMBER
: {
5777 ret
= xmlXPathCastNumberToString(val
->floatval
);
5783 case XPATH_LOCATIONSET
:
5785 ret
= xmlStrdup((const xmlChar
*) "");
5792 * xmlXPathConvertString:
5793 * @val: an XPath object
5795 * Converts an existing object to its string() equivalent
5797 * Returns the new object, the old one is freed (or the operation
5798 * is done directly on @val)
5801 xmlXPathConvertString(xmlXPathObjectPtr val
) {
5802 xmlChar
*res
= NULL
;
5805 return(xmlXPathNewCString(""));
5807 switch (val
->type
) {
5808 case XPATH_UNDEFINED
:
5810 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
5814 case XPATH_XSLT_TREE
:
5815 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5820 res
= xmlXPathCastBooleanToString(val
->boolval
);
5823 res
= xmlXPathCastNumberToString(val
->floatval
);
5828 case XPATH_LOCATIONSET
:
5832 xmlXPathFreeObject(val
);
5834 return(xmlXPathNewCString(""));
5835 return(xmlXPathWrapString(res
));
5839 * xmlXPathCastBooleanToNumber:
5842 * Converts a boolean to its number value
5844 * Returns the number value
5847 xmlXPathCastBooleanToNumber(int val
) {
5854 * xmlXPathCastStringToNumber:
5857 * Converts a string to its number value
5859 * Returns the number value
5862 xmlXPathCastStringToNumber(const xmlChar
* val
) {
5863 return(xmlXPathStringEvalNumber(val
));
5867 * xmlXPathCastNodeToNumber:
5870 * Converts a node to its number value
5872 * Returns the number value
5875 xmlXPathCastNodeToNumber (xmlNodePtr node
) {
5880 return(xmlXPathNAN
);
5881 strval
= xmlXPathCastNodeToString(node
);
5883 return(xmlXPathNAN
);
5884 ret
= xmlXPathCastStringToNumber(strval
);
5891 * xmlXPathCastNodeSetToNumber:
5894 * Converts a node-set to its number value
5896 * Returns the number value
5899 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns
) {
5904 return(xmlXPathNAN
);
5905 str
= xmlXPathCastNodeSetToString(ns
);
5906 ret
= xmlXPathCastStringToNumber(str
);
5912 * xmlXPathCastToNumber:
5913 * @val: an XPath object
5915 * Converts an XPath object to its number value
5917 * Returns the number value
5920 xmlXPathCastToNumber(xmlXPathObjectPtr val
) {
5924 return(xmlXPathNAN
);
5925 switch (val
->type
) {
5926 case XPATH_UNDEFINED
:
5928 xmlGenericError(xmlGenericErrorContext
, "NUMBER: undefined\n");
5933 case XPATH_XSLT_TREE
:
5934 ret
= xmlXPathCastNodeSetToNumber(val
->nodesetval
);
5937 ret
= xmlXPathCastStringToNumber(val
->stringval
);
5940 ret
= val
->floatval
;
5943 ret
= xmlXPathCastBooleanToNumber(val
->boolval
);
5948 case XPATH_LOCATIONSET
:
5957 * xmlXPathConvertNumber:
5958 * @val: an XPath object
5960 * Converts an existing object to its number() equivalent
5962 * Returns the new object, the old one is freed (or the operation
5963 * is done directly on @val)
5966 xmlXPathConvertNumber(xmlXPathObjectPtr val
) {
5967 xmlXPathObjectPtr ret
;
5970 return(xmlXPathNewFloat(0.0));
5971 if (val
->type
== XPATH_NUMBER
)
5973 ret
= xmlXPathNewFloat(xmlXPathCastToNumber(val
));
5974 xmlXPathFreeObject(val
);
5979 * xmlXPathCastNumberToBoolean:
5982 * Converts a number to its boolean value
5984 * Returns the boolean value
5987 xmlXPathCastNumberToBoolean (double val
) {
5988 if (xmlXPathIsNaN(val
) || (val
== 0.0))
5994 * xmlXPathCastStringToBoolean:
5997 * Converts a string to its boolean value
5999 * Returns the boolean value
6002 xmlXPathCastStringToBoolean (const xmlChar
*val
) {
6003 if ((val
== NULL
) || (xmlStrlen(val
) == 0))
6009 * xmlXPathCastNodeSetToBoolean:
6012 * Converts a node-set to its boolean value
6014 * Returns the boolean value
6017 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns
) {
6018 if ((ns
== NULL
) || (ns
->nodeNr
== 0))
6024 * xmlXPathCastToBoolean:
6025 * @val: an XPath object
6027 * Converts an XPath object to its boolean value
6029 * Returns the boolean value
6032 xmlXPathCastToBoolean (xmlXPathObjectPtr val
) {
6037 switch (val
->type
) {
6038 case XPATH_UNDEFINED
:
6040 xmlGenericError(xmlGenericErrorContext
, "BOOLEAN: undefined\n");
6045 case XPATH_XSLT_TREE
:
6046 ret
= xmlXPathCastNodeSetToBoolean(val
->nodesetval
);
6049 ret
= xmlXPathCastStringToBoolean(val
->stringval
);
6052 ret
= xmlXPathCastNumberToBoolean(val
->floatval
);
6060 case XPATH_LOCATIONSET
:
6070 * xmlXPathConvertBoolean:
6071 * @val: an XPath object
6073 * Converts an existing object to its boolean() equivalent
6075 * Returns the new object, the old one is freed (or the operation
6076 * is done directly on @val)
6079 xmlXPathConvertBoolean(xmlXPathObjectPtr val
) {
6080 xmlXPathObjectPtr ret
;
6083 return(xmlXPathNewBoolean(0));
6084 if (val
->type
== XPATH_BOOLEAN
)
6086 ret
= xmlXPathNewBoolean(xmlXPathCastToBoolean(val
));
6087 xmlXPathFreeObject(val
);
6091 /************************************************************************
6093 * Routines to handle XPath contexts *
6095 ************************************************************************/
6098 * xmlXPathNewContext:
6099 * @doc: the XML document
6101 * Create a new xmlXPathContext
6103 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6106 xmlXPathNewContext(xmlDocPtr doc
) {
6107 xmlXPathContextPtr ret
;
6109 ret
= (xmlXPathContextPtr
) xmlMalloc(sizeof(xmlXPathContext
));
6111 xmlXPathErrMemory(NULL
, "creating context\n");
6114 memset(ret
, 0 , (size_t) sizeof(xmlXPathContext
));
6118 ret
->varHash
= NULL
;
6124 ret
->funcHash
= xmlHashCreate(0);
6133 ret
->contextSize
= -1;
6134 ret
->proximityPosition
= -1;
6136 #ifdef XP_DEFAULT_CACHE_ON
6137 if (xmlXPathContextSetCache(ret
, 1, -1, 0) == -1) {
6138 xmlXPathFreeContext(ret
);
6143 xmlXPathRegisterAllFunctions(ret
);
6149 * xmlXPathFreeContext:
6150 * @ctxt: the context to free
6152 * Free up an xmlXPathContext
6155 xmlXPathFreeContext(xmlXPathContextPtr ctxt
) {
6156 if (ctxt
== NULL
) return;
6158 if (ctxt
->cache
!= NULL
)
6159 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
6160 xmlXPathRegisteredNsCleanup(ctxt
);
6161 xmlXPathRegisteredFuncsCleanup(ctxt
);
6162 xmlXPathRegisteredVariablesCleanup(ctxt
);
6163 xmlResetError(&ctxt
->lastError
);
6167 /************************************************************************
6169 * Routines to handle XPath parser contexts *
6171 ************************************************************************/
6173 #define CHECK_CTXT(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"); \
6184 #define CHECK_CTXT_NEG(ctxt) \
6185 if (ctxt == NULL) { \
6186 __xmlRaiseError(NULL, NULL, NULL, \
6187 NULL, NULL, XML_FROM_XPATH, \
6188 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6189 __FILE__, __LINE__, \
6190 NULL, NULL, NULL, 0, 0, \
6191 "NULL context pointer\n"); \
6196 #define CHECK_CONTEXT(ctxt) \
6197 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6198 (ctxt->doc->children == NULL)) { \
6199 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6205 * xmlXPathNewParserContext:
6206 * @str: the XPath expression
6207 * @ctxt: the XPath context
6209 * Create a new xmlXPathParserContext
6211 * Returns the xmlXPathParserContext just allocated.
6213 xmlXPathParserContextPtr
6214 xmlXPathNewParserContext(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
6215 xmlXPathParserContextPtr ret
;
6217 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6219 xmlXPathErrMemory(ctxt
, "creating parser context\n");
6222 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6223 ret
->cur
= ret
->base
= str
;
6224 ret
->context
= ctxt
;
6226 ret
->comp
= xmlXPathNewCompExpr();
6227 if (ret
->comp
== NULL
) {
6228 xmlFree(ret
->valueTab
);
6232 if ((ctxt
!= NULL
) && (ctxt
->dict
!= NULL
)) {
6233 ret
->comp
->dict
= ctxt
->dict
;
6234 xmlDictReference(ret
->comp
->dict
);
6241 * xmlXPathCompParserContext:
6242 * @comp: the XPath compiled expression
6243 * @ctxt: the XPath context
6245 * Create a new xmlXPathParserContext when processing a compiled expression
6247 * Returns the xmlXPathParserContext just allocated.
6249 static xmlXPathParserContextPtr
6250 xmlXPathCompParserContext(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctxt
) {
6251 xmlXPathParserContextPtr ret
;
6253 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6255 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6258 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6260 /* Allocate the value stack */
6261 ret
->valueTab
= (xmlXPathObjectPtr
*)
6262 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
6263 if (ret
->valueTab
== NULL
) {
6265 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6271 ret
->valueFrame
= 0;
6273 ret
->context
= ctxt
;
6280 * xmlXPathFreeParserContext:
6281 * @ctxt: the context to free
6283 * Free up an xmlXPathParserContext
6286 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt
) {
6287 if (ctxt
->valueTab
!= NULL
) {
6288 xmlFree(ctxt
->valueTab
);
6290 if (ctxt
->comp
!= NULL
) {
6291 #ifdef XPATH_STREAMING
6292 if (ctxt
->comp
->stream
!= NULL
) {
6293 xmlFreePatternList(ctxt
->comp
->stream
);
6294 ctxt
->comp
->stream
= NULL
;
6297 xmlXPathFreeCompExpr(ctxt
->comp
);
6302 /************************************************************************
6304 * The implicit core function library *
6306 ************************************************************************/
6309 * xmlXPathNodeValHash:
6310 * @node: a node pointer
6312 * Function computing the beginning of the string value of the node,
6313 * used to speed up comparisons
6315 * Returns an int usable as a hash
6318 xmlXPathNodeValHash(xmlNodePtr node
) {
6320 const xmlChar
* string
= NULL
;
6321 xmlNodePtr tmp
= NULL
;
6322 unsigned int ret
= 0;
6327 if (node
->type
== XML_DOCUMENT_NODE
) {
6328 tmp
= xmlDocGetRootElement((xmlDocPtr
) node
);
6330 node
= node
->children
;
6338 switch (node
->type
) {
6339 case XML_COMMENT_NODE
:
6341 case XML_CDATA_SECTION_NODE
:
6343 string
= node
->content
;
6348 return(((unsigned int) string
[0]) +
6349 (((unsigned int) string
[1]) << 8));
6350 case XML_NAMESPACE_DECL
:
6351 string
= ((xmlNsPtr
)node
)->href
;
6356 return(((unsigned int) string
[0]) +
6357 (((unsigned int) string
[1]) << 8));
6358 case XML_ATTRIBUTE_NODE
:
6359 tmp
= ((xmlAttrPtr
) node
)->children
;
6361 case XML_ELEMENT_NODE
:
6362 tmp
= node
->children
;
6367 while (tmp
!= NULL
) {
6368 switch (tmp
->type
) {
6369 case XML_COMMENT_NODE
:
6371 case XML_CDATA_SECTION_NODE
:
6373 string
= tmp
->content
;
6375 case XML_NAMESPACE_DECL
:
6376 string
= ((xmlNsPtr
)tmp
)->href
;
6381 if ((string
!= NULL
) && (string
[0] != 0)) {
6383 return(ret
+ (((unsigned int) string
[0]) << 8));
6385 if (string
[1] == 0) {
6387 ret
= (unsigned int) string
[0];
6389 return(((unsigned int) string
[0]) +
6390 (((unsigned int) string
[1]) << 8));
6396 if ((tmp
->children
!= NULL
) && (tmp
->type
!= XML_DTD_NODE
)) {
6397 if (tmp
->children
->type
!= XML_ENTITY_DECL
) {
6398 tmp
= tmp
->children
;
6405 if (tmp
->next
!= NULL
) {
6418 if (tmp
->next
!= NULL
) {
6422 } while (tmp
!= NULL
);
6428 * xmlXPathStringHash:
6431 * Function computing the beginning of the string value of the node,
6432 * used to speed up comparisons
6434 * Returns an int usable as a hash
6437 xmlXPathStringHash(const xmlChar
* string
) {
6439 return((unsigned int) 0);
6442 return(((unsigned int) string
[0]) +
6443 (((unsigned int) string
[1]) << 8));
6447 * xmlXPathCompareNodeSetFloat:
6448 * @ctxt: the XPath Parser context
6449 * @inf: less than (1) or greater than (0)
6450 * @strict: is the comparison strict
6451 * @arg: the node set
6454 * Implement the compare operation between a nodeset and a number
6455 * @ns < @val (1, 1, ...
6456 * @ns <= @val (1, 0, ...
6457 * @ns > @val (0, 1, ...
6458 * @ns >= @val (0, 0, ...
6460 * If one object to be compared is a node-set and the other is a number,
6461 * then the comparison will be true if and only if there is a node in the
6462 * node-set such that the result of performing the comparison on the number
6463 * to be compared and on the result of converting the string-value of that
6464 * node to a number using the number function is true.
6466 * Returns 0 or 1 depending on the results of the test.
6469 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6470 xmlXPathObjectPtr arg
, xmlXPathObjectPtr f
) {
6475 if ((f
== NULL
) || (arg
== NULL
) ||
6476 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6477 xmlXPathReleaseObject(ctxt
->context
, arg
);
6478 xmlXPathReleaseObject(ctxt
->context
, f
);
6481 ns
= arg
->nodesetval
;
6483 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6484 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6487 xmlXPathCacheNewString(ctxt
->context
, str2
));
6489 xmlXPathNumberFunction(ctxt
, 1);
6490 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, f
));
6491 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6497 xmlXPathReleaseObject(ctxt
->context
, arg
);
6498 xmlXPathReleaseObject(ctxt
->context
, f
);
6503 * xmlXPathCompareNodeSetString:
6504 * @ctxt: the XPath Parser context
6505 * @inf: less than (1) or greater than (0)
6506 * @strict: is the comparison strict
6507 * @arg: the node set
6510 * Implement the compare operation between a nodeset and a string
6511 * @ns < @val (1, 1, ...
6512 * @ns <= @val (1, 0, ...
6513 * @ns > @val (0, 1, ...
6514 * @ns >= @val (0, 0, ...
6516 * If one object to be compared is a node-set and the other is a string,
6517 * then the comparison will be true if and only if there is a node in
6518 * the node-set such that the result of performing the comparison on the
6519 * string-value of the node and the other string is true.
6521 * Returns 0 or 1 depending on the results of the test.
6524 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6525 xmlXPathObjectPtr arg
, xmlXPathObjectPtr s
) {
6530 if ((s
== NULL
) || (arg
== NULL
) ||
6531 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6532 xmlXPathReleaseObject(ctxt
->context
, arg
);
6533 xmlXPathReleaseObject(ctxt
->context
, s
);
6536 ns
= arg
->nodesetval
;
6538 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6539 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6542 xmlXPathCacheNewString(ctxt
->context
, str2
));
6544 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, s
));
6545 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6551 xmlXPathReleaseObject(ctxt
->context
, arg
);
6552 xmlXPathReleaseObject(ctxt
->context
, s
);
6557 * xmlXPathCompareNodeSets:
6558 * @inf: less than (1) or greater than (0)
6559 * @strict: is the comparison strict
6560 * @arg1: the first node set object
6561 * @arg2: the second node set object
6563 * Implement the compare operation on nodesets:
6565 * If both objects to be compared are node-sets, then the comparison
6566 * will be true if and only if there is a node in the first node-set
6567 * and a node in the second node-set such that the result of performing
6568 * the comparison on the string-values of the two nodes is true.
6570 * When neither object to be compared is a node-set and the operator
6571 * is <=, <, >= or >, then the objects are compared by converting both
6572 * objects to numbers and comparing the numbers according to IEEE 754.
6574 * The number function converts its argument to a number as follows:
6575 * - a string that consists of optional whitespace followed by an
6576 * optional minus sign followed by a Number followed by whitespace
6577 * is converted to the IEEE 754 number that is nearest (according
6578 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6579 * represented by the string; any other string is converted to NaN
6581 * Conclusion all nodes need to be converted first to their string value
6582 * and then the comparison must be done when possible
6585 xmlXPathCompareNodeSets(int inf
, int strict
,
6586 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6594 if ((arg1
== NULL
) ||
6595 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
))) {
6596 xmlXPathFreeObject(arg2
);
6599 if ((arg2
== NULL
) ||
6600 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
))) {
6601 xmlXPathFreeObject(arg1
);
6602 xmlXPathFreeObject(arg2
);
6606 ns1
= arg1
->nodesetval
;
6607 ns2
= arg2
->nodesetval
;
6609 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0)) {
6610 xmlXPathFreeObject(arg1
);
6611 xmlXPathFreeObject(arg2
);
6614 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0)) {
6615 xmlXPathFreeObject(arg1
);
6616 xmlXPathFreeObject(arg2
);
6620 values2
= (double *) xmlMalloc(ns2
->nodeNr
* sizeof(double));
6621 if (values2
== NULL
) {
6622 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6623 xmlXPathFreeObject(arg1
);
6624 xmlXPathFreeObject(arg2
);
6627 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6628 val1
= xmlXPathCastNodeToNumber(ns1
->nodeTab
[i
]);
6629 if (xmlXPathIsNaN(val1
))
6631 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6633 values2
[j
] = xmlXPathCastNodeToNumber(ns2
->nodeTab
[j
]);
6635 if (xmlXPathIsNaN(values2
[j
]))
6638 ret
= (val1
< values2
[j
]);
6639 else if (inf
&& !strict
)
6640 ret
= (val1
<= values2
[j
]);
6641 else if (!inf
&& strict
)
6642 ret
= (val1
> values2
[j
]);
6643 else if (!inf
&& !strict
)
6644 ret
= (val1
>= values2
[j
]);
6653 xmlXPathFreeObject(arg1
);
6654 xmlXPathFreeObject(arg2
);
6659 * xmlXPathCompareNodeSetValue:
6660 * @ctxt: the XPath Parser context
6661 * @inf: less than (1) or greater than (0)
6662 * @strict: is the comparison strict
6663 * @arg: the node set
6666 * Implement the compare operation between a nodeset and a value
6667 * @ns < @val (1, 1, ...
6668 * @ns <= @val (1, 0, ...
6669 * @ns > @val (0, 1, ...
6670 * @ns >= @val (0, 0, ...
6672 * If one object to be compared is a node-set and the other is a boolean,
6673 * then the comparison will be true if and only if the result of performing
6674 * the comparison on the boolean and on the result of converting
6675 * the node-set to a boolean using the boolean function is true.
6677 * Returns 0 or 1 depending on the results of the test.
6680 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6681 xmlXPathObjectPtr arg
, xmlXPathObjectPtr val
) {
6682 if ((val
== NULL
) || (arg
== NULL
) ||
6683 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6688 return(xmlXPathCompareNodeSetFloat(ctxt
, inf
, strict
, arg
, val
));
6690 case XPATH_XSLT_TREE
:
6691 return(xmlXPathCompareNodeSets(inf
, strict
, arg
, val
));
6693 return(xmlXPathCompareNodeSetString(ctxt
, inf
, strict
, arg
, val
));
6695 valuePush(ctxt
, arg
);
6696 xmlXPathBooleanFunction(ctxt
, 1);
6697 valuePush(ctxt
, val
);
6698 return(xmlXPathCompareValues(ctxt
, inf
, strict
));
6706 * xmlXPathEqualNodeSetString:
6707 * @arg: the nodeset object argument
6708 * @str: the string to compare to.
6709 * @neq: flag to show whether for '=' (0) or '!=' (1)
6711 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6712 * If one object to be compared is a node-set and the other is a string,
6713 * then the comparison will be true if and only if there is a node in
6714 * the node-set such that the result of performing the comparison on the
6715 * string-value of the node and the other string is true.
6717 * Returns 0 or 1 depending on the results of the test.
6720 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg
, const xmlChar
* str
, int neq
)
6727 if ((str
== NULL
) || (arg
== NULL
) ||
6728 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6730 ns
= arg
->nodesetval
;
6732 * A NULL nodeset compared with a string is always false
6733 * (since there is no node equal, and no node not equal)
6735 if ((ns
== NULL
) || (ns
->nodeNr
<= 0) )
6737 hash
= xmlXPathStringHash(str
);
6738 for (i
= 0; i
< ns
->nodeNr
; i
++) {
6739 if (xmlXPathNodeValHash(ns
->nodeTab
[i
]) == hash
) {
6740 str2
= xmlNodeGetContent(ns
->nodeTab
[i
]);
6741 if ((str2
!= NULL
) && (xmlStrEqual(str
, str2
))) {
6746 } else if ((str2
== NULL
) && (xmlStrEqual(str
, BAD_CAST
""))) {
6764 * xmlXPathEqualNodeSetFloat:
6765 * @arg: the nodeset object argument
6766 * @f: the float to compare to
6767 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6769 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6770 * If one object to be compared is a node-set and the other is a number,
6771 * then the comparison will be true if and only if there is a node in
6772 * the node-set such that the result of performing the comparison on the
6773 * number to be compared and on the result of converting the string-value
6774 * of that node to a number using the number function is true.
6776 * Returns 0 or 1 depending on the results of the test.
6779 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt
,
6780 xmlXPathObjectPtr arg
, double f
, int neq
) {
6784 xmlXPathObjectPtr val
;
6787 if ((arg
== NULL
) ||
6788 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6791 ns
= arg
->nodesetval
;
6793 for (i
=0;i
<ns
->nodeNr
;i
++) {
6794 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6796 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, str2
));
6798 xmlXPathNumberFunction(ctxt
, 1);
6799 val
= valuePop(ctxt
);
6801 xmlXPathReleaseObject(ctxt
->context
, val
);
6802 if (!xmlXPathIsNaN(v
)) {
6803 if ((!neq
) && (v
==f
)) {
6806 } else if ((neq
) && (v
!=f
)) {
6810 } else { /* NaN is unequal to any value */
6823 * xmlXPathEqualNodeSets:
6824 * @arg1: first nodeset object argument
6825 * @arg2: second nodeset object argument
6826 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6828 * Implement the equal / not equal operation on XPath nodesets:
6829 * @arg1 == @arg2 or @arg1 != @arg2
6830 * If both objects to be compared are node-sets, then the comparison
6831 * will be true if and only if there is a node in the first node-set and
6832 * a node in the second node-set such that the result of performing the
6833 * comparison on the string-values of the two nodes is true.
6835 * (needless to say, this is a costly operation)
6837 * Returns 0 or 1 depending on the results of the test.
6840 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
, int neq
) {
6842 unsigned int *hashs1
;
6843 unsigned int *hashs2
;
6850 if ((arg1
== NULL
) ||
6851 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)))
6853 if ((arg2
== NULL
) ||
6854 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
)))
6857 ns1
= arg1
->nodesetval
;
6858 ns2
= arg2
->nodesetval
;
6860 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0))
6862 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0))
6866 * for equal, check if there is a node pertaining to both sets
6869 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6870 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6871 if (ns1
->nodeTab
[i
] == ns2
->nodeTab
[j
])
6874 values1
= (xmlChar
**) xmlMalloc(ns1
->nodeNr
* sizeof(xmlChar
*));
6875 if (values1
== NULL
) {
6876 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6879 hashs1
= (unsigned int *) xmlMalloc(ns1
->nodeNr
* sizeof(unsigned int));
6880 if (hashs1
== NULL
) {
6881 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6885 memset(values1
, 0, ns1
->nodeNr
* sizeof(xmlChar
*));
6886 values2
= (xmlChar
**) xmlMalloc(ns2
->nodeNr
* sizeof(xmlChar
*));
6887 if (values2
== NULL
) {
6888 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6893 hashs2
= (unsigned int *) xmlMalloc(ns2
->nodeNr
* sizeof(unsigned int));
6894 if (hashs2
== NULL
) {
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
);
6984 case XPATH_LOCATIONSET
:
6988 case XPATH_XSLT_TREE
:
6993 switch (arg2
->type
) {
6994 case XPATH_UNDEFINED
:
6996 xmlGenericError(xmlGenericErrorContext
,
6997 "Equal: undefined\n");
7001 ret
= (arg2
->boolval
==
7002 xmlXPathCastNumberToBoolean(arg1
->floatval
));
7005 valuePush(ctxt
, arg2
);
7006 xmlXPathNumberFunction(ctxt
, 1);
7007 arg2
= valuePop(ctxt
);
7008 /* no break on purpose */
7010 /* Hand check NaN and Infinity equalities */
7011 if (xmlXPathIsNaN(arg1
->floatval
) ||
7012 xmlXPathIsNaN(arg2
->floatval
)) {
7014 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7015 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7019 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7020 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7024 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7025 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7029 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7030 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7035 ret
= (arg1
->floatval
== arg2
->floatval
);
7041 case XPATH_LOCATIONSET
:
7045 case XPATH_XSLT_TREE
:
7050 switch (arg2
->type
) {
7051 case XPATH_UNDEFINED
:
7053 xmlGenericError(xmlGenericErrorContext
,
7054 "Equal: undefined\n");
7058 if ((arg1
->stringval
== NULL
) ||
7059 (arg1
->stringval
[0] == 0)) ret
= 0;
7062 ret
= (arg2
->boolval
== ret
);
7065 ret
= xmlStrEqual(arg1
->stringval
, arg2
->stringval
);
7068 valuePush(ctxt
, arg1
);
7069 xmlXPathNumberFunction(ctxt
, 1);
7070 arg1
= valuePop(ctxt
);
7071 /* Hand check NaN and Infinity equalities */
7072 if (xmlXPathIsNaN(arg1
->floatval
) ||
7073 xmlXPathIsNaN(arg2
->floatval
)) {
7075 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7076 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7080 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7081 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7085 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7086 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7090 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7091 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7096 ret
= (arg1
->floatval
== arg2
->floatval
);
7102 case XPATH_LOCATIONSET
:
7106 case XPATH_XSLT_TREE
:
7113 case XPATH_LOCATIONSET
:
7117 case XPATH_XSLT_TREE
:
7120 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7121 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7126 * xmlXPathEqualValues:
7127 * @ctxt: the XPath Parser context
7129 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7131 * Returns 0 or 1 depending on the results of the test.
7134 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt
) {
7135 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7138 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7139 arg2
= valuePop(ctxt
);
7140 arg1
= valuePop(ctxt
);
7141 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7143 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7145 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7146 XP_ERROR0(XPATH_INVALID_OPERAND
);
7151 xmlGenericError(xmlGenericErrorContext
,
7152 "Equal: by pointer\n");
7154 xmlXPathFreeObject(arg1
);
7159 *If either argument is a nodeset, it's a 'special case'
7161 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7162 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7164 *Hack it to assure arg1 is the nodeset
7166 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7171 switch (arg2
->type
) {
7172 case XPATH_UNDEFINED
:
7174 xmlGenericError(xmlGenericErrorContext
,
7175 "Equal: undefined\n");
7179 case XPATH_XSLT_TREE
:
7180 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 0);
7183 if ((arg1
->nodesetval
== NULL
) ||
7184 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7187 ret
= (ret
== arg2
->boolval
);
7190 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 0);
7193 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
, 0);
7198 case XPATH_LOCATIONSET
:
7202 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7203 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7207 return (xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7211 * xmlXPathNotEqualValues:
7212 * @ctxt: the XPath Parser context
7214 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7216 * Returns 0 or 1 depending on the results of the test.
7219 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt
) {
7220 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7223 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7224 arg2
= valuePop(ctxt
);
7225 arg1
= valuePop(ctxt
);
7226 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7228 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7230 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7231 XP_ERROR0(XPATH_INVALID_OPERAND
);
7236 xmlGenericError(xmlGenericErrorContext
,
7237 "NotEqual: by pointer\n");
7239 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7244 *If either argument is a nodeset, it's a 'special case'
7246 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7247 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7249 *Hack it to assure arg1 is the nodeset
7251 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7256 switch (arg2
->type
) {
7257 case XPATH_UNDEFINED
:
7259 xmlGenericError(xmlGenericErrorContext
,
7260 "NotEqual: undefined\n");
7264 case XPATH_XSLT_TREE
:
7265 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 1);
7268 if ((arg1
->nodesetval
== NULL
) ||
7269 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7272 ret
= (ret
!= arg2
->boolval
);
7275 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 1);
7278 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
,1);
7283 case XPATH_LOCATIONSET
:
7287 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7288 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7292 return (!xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7296 * xmlXPathCompareValues:
7297 * @ctxt: the XPath Parser context
7298 * @inf: less than (1) or greater than (0)
7299 * @strict: is the comparison strict
7301 * Implement the compare operation on XPath objects:
7302 * @arg1 < @arg2 (1, 1, ...
7303 * @arg1 <= @arg2 (1, 0, ...
7304 * @arg1 > @arg2 (0, 1, ...
7305 * @arg1 >= @arg2 (0, 0, ...
7307 * When neither object to be compared is a node-set and the operator is
7308 * <=, <, >=, >, then the objects are compared by converted both objects
7309 * to numbers and comparing the numbers according to IEEE 754. The <
7310 * comparison will be true if and only if the first number is less than the
7311 * second number. The <= comparison will be true if and only if the first
7312 * number is less than or equal to the second number. The > comparison
7313 * will be true if and only if the first number is greater than the second
7314 * number. The >= comparison will be true if and only if the first number
7315 * is greater than or equal to the second number.
7317 * Returns 1 if the comparison succeeded, 0 if it failed
7320 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt
, int inf
, int strict
) {
7321 int ret
= 0, arg1i
= 0, arg2i
= 0;
7322 xmlXPathObjectPtr arg1
, arg2
;
7324 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7325 arg2
= valuePop(ctxt
);
7326 arg1
= valuePop(ctxt
);
7327 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7329 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7331 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7332 XP_ERROR0(XPATH_INVALID_OPERAND
);
7335 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7336 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7338 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7339 * are not freed from within this routine; they will be freed from the
7340 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7342 if (((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
)) &&
7343 ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
))){
7344 ret
= xmlXPathCompareNodeSets(inf
, strict
, arg1
, arg2
);
7346 if ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7347 ret
= xmlXPathCompareNodeSetValue(ctxt
, inf
, strict
,
7350 ret
= xmlXPathCompareNodeSetValue(ctxt
, !inf
, strict
,
7357 if (arg1
->type
!= XPATH_NUMBER
) {
7358 valuePush(ctxt
, arg1
);
7359 xmlXPathNumberFunction(ctxt
, 1);
7360 arg1
= valuePop(ctxt
);
7362 if (arg1
->type
!= XPATH_NUMBER
) {
7363 xmlXPathFreeObject(arg1
);
7364 xmlXPathFreeObject(arg2
);
7365 XP_ERROR0(XPATH_INVALID_OPERAND
);
7367 if (arg2
->type
!= XPATH_NUMBER
) {
7368 valuePush(ctxt
, arg2
);
7369 xmlXPathNumberFunction(ctxt
, 1);
7370 arg2
= valuePop(ctxt
);
7372 if (arg2
->type
!= XPATH_NUMBER
) {
7373 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7374 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7375 XP_ERROR0(XPATH_INVALID_OPERAND
);
7378 * Add tests for infinity and nan
7379 * => feedback on 3.4 for Inf and NaN
7381 /* Hand check NaN and Infinity comparisons */
7382 if (xmlXPathIsNaN(arg1
->floatval
) || xmlXPathIsNaN(arg2
->floatval
)) {
7385 arg1i
=xmlXPathIsInf(arg1
->floatval
);
7386 arg2i
=xmlXPathIsInf(arg2
->floatval
);
7387 if (inf
&& strict
) {
7388 if ((arg1i
== -1 && arg2i
!= -1) ||
7389 (arg2i
== 1 && arg1i
!= 1)) {
7391 } else if (arg1i
== 0 && arg2i
== 0) {
7392 ret
= (arg1
->floatval
< arg2
->floatval
);
7397 else if (inf
&& !strict
) {
7398 if (arg1i
== -1 || arg2i
== 1) {
7400 } else if (arg1i
== 0 && arg2i
== 0) {
7401 ret
= (arg1
->floatval
<= arg2
->floatval
);
7406 else if (!inf
&& strict
) {
7407 if ((arg1i
== 1 && arg2i
!= 1) ||
7408 (arg2i
== -1 && arg1i
!= -1)) {
7410 } else if (arg1i
== 0 && arg2i
== 0) {
7411 ret
= (arg1
->floatval
> arg2
->floatval
);
7416 else if (!inf
&& !strict
) {
7417 if (arg1i
== 1 || arg2i
== -1) {
7419 } else if (arg1i
== 0 && arg2i
== 0) {
7420 ret
= (arg1
->floatval
>= arg2
->floatval
);
7426 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7427 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7432 * xmlXPathValueFlipSign:
7433 * @ctxt: the XPath Parser context
7435 * Implement the unary - operation on an XPath object
7436 * The numeric operators convert their operands to numbers as if
7437 * by calling the number function.
7440 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt
) {
7441 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return;
7443 CHECK_TYPE(XPATH_NUMBER
);
7444 if (xmlXPathIsNaN(ctxt
->value
->floatval
))
7445 ctxt
->value
->floatval
=xmlXPathNAN
;
7446 else if (xmlXPathIsInf(ctxt
->value
->floatval
) == 1)
7447 ctxt
->value
->floatval
=xmlXPathNINF
;
7448 else if (xmlXPathIsInf(ctxt
->value
->floatval
) == -1)
7449 ctxt
->value
->floatval
=xmlXPathPINF
;
7450 else if (ctxt
->value
->floatval
== 0) {
7451 if (xmlXPathGetSign(ctxt
->value
->floatval
) == 0)
7452 ctxt
->value
->floatval
= xmlXPathNZERO
;
7454 ctxt
->value
->floatval
= 0;
7457 ctxt
->value
->floatval
= - ctxt
->value
->floatval
;
7461 * xmlXPathAddValues:
7462 * @ctxt: the XPath Parser context
7464 * Implement the add operation on XPath objects:
7465 * The numeric operators convert their operands to numbers as if
7466 * by calling the number function.
7469 xmlXPathAddValues(xmlXPathParserContextPtr ctxt
) {
7470 xmlXPathObjectPtr arg
;
7473 arg
= valuePop(ctxt
);
7475 XP_ERROR(XPATH_INVALID_OPERAND
);
7476 val
= xmlXPathCastToNumber(arg
);
7477 xmlXPathReleaseObject(ctxt
->context
, arg
);
7479 CHECK_TYPE(XPATH_NUMBER
);
7480 ctxt
->value
->floatval
+= val
;
7484 * xmlXPathSubValues:
7485 * @ctxt: the XPath Parser context
7487 * Implement the subtraction operation on XPath objects:
7488 * The numeric operators convert their operands to numbers as if
7489 * by calling the number function.
7492 xmlXPathSubValues(xmlXPathParserContextPtr ctxt
) {
7493 xmlXPathObjectPtr arg
;
7496 arg
= valuePop(ctxt
);
7498 XP_ERROR(XPATH_INVALID_OPERAND
);
7499 val
= xmlXPathCastToNumber(arg
);
7500 xmlXPathReleaseObject(ctxt
->context
, arg
);
7502 CHECK_TYPE(XPATH_NUMBER
);
7503 ctxt
->value
->floatval
-= val
;
7507 * xmlXPathMultValues:
7508 * @ctxt: the XPath Parser context
7510 * Implement the multiply operation on XPath objects:
7511 * The numeric operators convert their operands to numbers as if
7512 * by calling the number function.
7515 xmlXPathMultValues(xmlXPathParserContextPtr ctxt
) {
7516 xmlXPathObjectPtr arg
;
7519 arg
= valuePop(ctxt
);
7521 XP_ERROR(XPATH_INVALID_OPERAND
);
7522 val
= xmlXPathCastToNumber(arg
);
7523 xmlXPathReleaseObject(ctxt
->context
, arg
);
7525 CHECK_TYPE(XPATH_NUMBER
);
7526 ctxt
->value
->floatval
*= val
;
7530 * xmlXPathDivValues:
7531 * @ctxt: the XPath Parser context
7533 * Implement the div operation on XPath objects @arg1 / @arg2:
7534 * The numeric operators convert their operands to numbers as if
7535 * by calling the number function.
7538 xmlXPathDivValues(xmlXPathParserContextPtr ctxt
) {
7539 xmlXPathObjectPtr arg
;
7542 arg
= valuePop(ctxt
);
7544 XP_ERROR(XPATH_INVALID_OPERAND
);
7545 val
= xmlXPathCastToNumber(arg
);
7546 xmlXPathReleaseObject(ctxt
->context
, arg
);
7548 CHECK_TYPE(XPATH_NUMBER
);
7549 if (xmlXPathIsNaN(val
) || xmlXPathIsNaN(ctxt
->value
->floatval
))
7550 ctxt
->value
->floatval
= xmlXPathNAN
;
7551 else if (val
== 0 && xmlXPathGetSign(val
) != 0) {
7552 if (ctxt
->value
->floatval
== 0)
7553 ctxt
->value
->floatval
= xmlXPathNAN
;
7554 else if (ctxt
->value
->floatval
> 0)
7555 ctxt
->value
->floatval
= xmlXPathNINF
;
7556 else if (ctxt
->value
->floatval
< 0)
7557 ctxt
->value
->floatval
= xmlXPathPINF
;
7559 else if (val
== 0) {
7560 if (ctxt
->value
->floatval
== 0)
7561 ctxt
->value
->floatval
= xmlXPathNAN
;
7562 else if (ctxt
->value
->floatval
> 0)
7563 ctxt
->value
->floatval
= xmlXPathPINF
;
7564 else if (ctxt
->value
->floatval
< 0)
7565 ctxt
->value
->floatval
= xmlXPathNINF
;
7567 ctxt
->value
->floatval
/= val
;
7571 * xmlXPathModValues:
7572 * @ctxt: the XPath Parser context
7574 * Implement the mod operation on XPath objects: @arg1 / @arg2
7575 * The numeric operators convert their operands to numbers as if
7576 * by calling the number function.
7579 xmlXPathModValues(xmlXPathParserContextPtr ctxt
) {
7580 xmlXPathObjectPtr arg
;
7583 arg
= valuePop(ctxt
);
7585 XP_ERROR(XPATH_INVALID_OPERAND
);
7586 arg2
= xmlXPathCastToNumber(arg
);
7587 xmlXPathReleaseObject(ctxt
->context
, arg
);
7589 CHECK_TYPE(XPATH_NUMBER
);
7590 arg1
= ctxt
->value
->floatval
;
7592 ctxt
->value
->floatval
= xmlXPathNAN
;
7594 ctxt
->value
->floatval
= fmod(arg1
, arg2
);
7598 /************************************************************************
7600 * The traversal functions *
7602 ************************************************************************/
7605 * A traversal function enumerates nodes along an axis.
7606 * Initially it must be called with NULL, and it indicates
7607 * termination on the axis by returning NULL.
7609 typedef xmlNodePtr (*xmlXPathTraversalFunction
)
7610 (xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
);
7613 * xmlXPathTraversalFunctionExt:
7614 * A traversal function enumerates nodes along an axis.
7615 * Initially it must be called with NULL, and it indicates
7616 * termination on the axis by returning NULL.
7617 * The context node of the traversal is specified via @contextNode.
7619 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt
)
7620 (xmlNodePtr cur
, xmlNodePtr contextNode
);
7623 * xmlXPathNodeSetMergeFunction:
7624 * Used for merging node sets in xmlXPathCollectAndTest().
7626 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction
)
7627 (xmlNodeSetPtr
, xmlNodeSetPtr
, int);
7632 * @ctxt: the XPath Parser context
7633 * @cur: the current node in the traversal
7635 * Traversal function for the "self" direction
7636 * The self axis contains just the context node itself
7638 * Returns the next element following that axis
7641 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7642 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7644 return(ctxt
->context
->node
);
7649 * xmlXPathNextChild:
7650 * @ctxt: the XPath Parser context
7651 * @cur: the current node in the traversal
7653 * Traversal function for the "child" direction
7654 * The child axis contains the children of the context node in document order.
7656 * Returns the next element following that axis
7659 xmlXPathNextChild(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7660 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7662 if (ctxt
->context
->node
== NULL
) return(NULL
);
7663 switch (ctxt
->context
->node
->type
) {
7664 case XML_ELEMENT_NODE
:
7666 case XML_CDATA_SECTION_NODE
:
7667 case XML_ENTITY_REF_NODE
:
7668 case XML_ENTITY_NODE
:
7670 case XML_COMMENT_NODE
:
7671 case XML_NOTATION_NODE
:
7673 return(ctxt
->context
->node
->children
);
7674 case XML_DOCUMENT_NODE
:
7675 case XML_DOCUMENT_TYPE_NODE
:
7676 case XML_DOCUMENT_FRAG_NODE
:
7677 case XML_HTML_DOCUMENT_NODE
:
7678 #ifdef LIBXML_DOCB_ENABLED
7679 case XML_DOCB_DOCUMENT_NODE
:
7681 return(((xmlDocPtr
) ctxt
->context
->node
)->children
);
7682 case XML_ELEMENT_DECL
:
7683 case XML_ATTRIBUTE_DECL
:
7684 case XML_ENTITY_DECL
:
7685 case XML_ATTRIBUTE_NODE
:
7686 case XML_NAMESPACE_DECL
:
7687 case XML_XINCLUDE_START
:
7688 case XML_XINCLUDE_END
:
7693 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
7694 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
7700 * xmlXPathNextChildElement:
7701 * @ctxt: the XPath Parser context
7702 * @cur: the current node in the traversal
7704 * Traversal function for the "child" direction and nodes of type element.
7705 * The child axis contains the children of the context node in document order.
7707 * Returns the next element following that axis
7710 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7711 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7713 cur
= ctxt
->context
->node
;
7714 if (cur
== NULL
) return(NULL
);
7716 * Get the first element child.
7718 switch (cur
->type
) {
7719 case XML_ELEMENT_NODE
:
7720 case XML_DOCUMENT_FRAG_NODE
:
7721 case XML_ENTITY_REF_NODE
: /* URGENT TODO: entify-refs as well? */
7722 case XML_ENTITY_NODE
:
7723 cur
= cur
->children
;
7725 if (cur
->type
== XML_ELEMENT_NODE
)
7729 } while ((cur
!= NULL
) &&
7730 (cur
->type
!= XML_ELEMENT_NODE
));
7734 case XML_DOCUMENT_NODE
:
7735 case XML_HTML_DOCUMENT_NODE
:
7736 #ifdef LIBXML_DOCB_ENABLED
7737 case XML_DOCB_DOCUMENT_NODE
:
7739 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7746 * Get the next sibling element node.
7748 switch (cur
->type
) {
7749 case XML_ELEMENT_NODE
:
7751 case XML_ENTITY_REF_NODE
:
7752 case XML_ENTITY_NODE
:
7753 case XML_CDATA_SECTION_NODE
:
7755 case XML_COMMENT_NODE
:
7756 case XML_XINCLUDE_END
:
7758 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7762 if (cur
->next
!= NULL
) {
7763 if (cur
->next
->type
== XML_ELEMENT_NODE
)
7768 } while ((cur
!= NULL
) && (cur
->type
!= XML_ELEMENT_NODE
));
7776 * xmlXPathNextDescendantOrSelfElemParent:
7777 * @ctxt: the XPath Parser context
7778 * @cur: the current node in the traversal
7780 * Traversal function for the "descendant-or-self" axis.
7781 * Additionally it returns only nodes which can be parents of
7785 * Returns the next element following that axis
7788 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur
,
7789 xmlNodePtr contextNode
)
7792 if (contextNode
== NULL
)
7794 switch (contextNode
->type
) {
7795 case XML_ELEMENT_NODE
:
7796 case XML_XINCLUDE_START
:
7797 case XML_DOCUMENT_FRAG_NODE
:
7798 case XML_DOCUMENT_NODE
:
7799 #ifdef LIBXML_DOCB_ENABLED
7800 case XML_DOCB_DOCUMENT_NODE
:
7802 case XML_HTML_DOCUMENT_NODE
:
7803 return(contextNode
);
7809 xmlNodePtr start
= cur
;
7811 while (cur
!= NULL
) {
7812 switch (cur
->type
) {
7813 case XML_ELEMENT_NODE
:
7814 /* TODO: OK to have XInclude here? */
7815 case XML_XINCLUDE_START
:
7816 case XML_DOCUMENT_FRAG_NODE
:
7819 if (cur
->children
!= NULL
) {
7820 cur
= cur
->children
;
7824 /* Not sure if we need those here. */
7825 case XML_DOCUMENT_NODE
:
7826 #ifdef LIBXML_DOCB_ENABLED
7827 case XML_DOCB_DOCUMENT_NODE
:
7829 case XML_HTML_DOCUMENT_NODE
:
7832 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7838 if ((cur
== NULL
) || (cur
== contextNode
))
7840 if (cur
->next
!= NULL
) {
7853 * xmlXPathNextDescendant:
7854 * @ctxt: the XPath Parser context
7855 * @cur: the current node in the traversal
7857 * Traversal function for the "descendant" direction
7858 * the descendant axis contains the descendants of the context node in document
7859 * order; a descendant is a child or a child of a child and so on.
7861 * Returns the next element following that axis
7864 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7865 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7867 if (ctxt
->context
->node
== NULL
)
7869 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7870 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7873 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
7874 return(ctxt
->context
->doc
->children
);
7875 return(ctxt
->context
->node
->children
);
7878 if (cur
->type
== XML_NAMESPACE_DECL
)
7880 if (cur
->children
!= NULL
) {
7882 * Do not descend on entities declarations
7884 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
7885 cur
= cur
->children
;
7889 if (cur
->type
!= XML_DTD_NODE
)
7894 if (cur
== ctxt
->context
->node
) return(NULL
);
7896 while (cur
->next
!= NULL
) {
7898 if ((cur
->type
!= XML_ENTITY_DECL
) &&
7899 (cur
->type
!= XML_DTD_NODE
))
7905 if (cur
== NULL
) break;
7906 if (cur
== ctxt
->context
->node
) return(NULL
);
7907 if (cur
->next
!= NULL
) {
7911 } while (cur
!= NULL
);
7916 * xmlXPathNextDescendantOrSelf:
7917 * @ctxt: the XPath Parser context
7918 * @cur: the current node in the traversal
7920 * Traversal function for the "descendant-or-self" direction
7921 * the descendant-or-self axis contains the context node and the descendants
7922 * of the context node in document order; thus the context node is the first
7923 * node on the axis, and the first child of the context node is the second node
7926 * Returns the next element following that axis
7929 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7930 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7932 if (ctxt
->context
->node
== NULL
)
7934 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7935 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7937 return(ctxt
->context
->node
);
7940 return(xmlXPathNextDescendant(ctxt
, cur
));
7944 * xmlXPathNextParent:
7945 * @ctxt: the XPath Parser context
7946 * @cur: the current node in the traversal
7948 * Traversal function for the "parent" direction
7949 * The parent axis contains the parent of the context node, if there is one.
7951 * Returns the next element following that axis
7954 xmlXPathNextParent(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7955 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7957 * the parent of an attribute or namespace node is the element
7958 * to which the attribute or namespace node is attached
7959 * Namespace handling !!!
7962 if (ctxt
->context
->node
== NULL
) return(NULL
);
7963 switch (ctxt
->context
->node
->type
) {
7964 case XML_ELEMENT_NODE
:
7966 case XML_CDATA_SECTION_NODE
:
7967 case XML_ENTITY_REF_NODE
:
7968 case XML_ENTITY_NODE
:
7970 case XML_COMMENT_NODE
:
7971 case XML_NOTATION_NODE
:
7973 case XML_ELEMENT_DECL
:
7974 case XML_ATTRIBUTE_DECL
:
7975 case XML_XINCLUDE_START
:
7976 case XML_XINCLUDE_END
:
7977 case XML_ENTITY_DECL
:
7978 if (ctxt
->context
->node
->parent
== NULL
)
7979 return((xmlNodePtr
) ctxt
->context
->doc
);
7980 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
7981 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
7982 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
7983 BAD_CAST
"fake node libxslt"))))
7985 return(ctxt
->context
->node
->parent
);
7986 case XML_ATTRIBUTE_NODE
: {
7987 xmlAttrPtr att
= (xmlAttrPtr
) ctxt
->context
->node
;
7989 return(att
->parent
);
7991 case XML_DOCUMENT_NODE
:
7992 case XML_DOCUMENT_TYPE_NODE
:
7993 case XML_DOCUMENT_FRAG_NODE
:
7994 case XML_HTML_DOCUMENT_NODE
:
7995 #ifdef LIBXML_DOCB_ENABLED
7996 case XML_DOCB_DOCUMENT_NODE
:
7999 case XML_NAMESPACE_DECL
: {
8000 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8002 if ((ns
->next
!= NULL
) &&
8003 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8004 return((xmlNodePtr
) ns
->next
);
8013 * xmlXPathNextAncestor:
8014 * @ctxt: the XPath Parser context
8015 * @cur: the current node in the traversal
8017 * Traversal function for the "ancestor" direction
8018 * the ancestor axis contains the ancestors of the context node; the ancestors
8019 * of the context node consist of the parent of context node and the parent's
8020 * parent and so on; the nodes are ordered in reverse document order; thus the
8021 * parent is the first node on the axis, and the parent's parent is the second
8024 * Returns the next element following that axis
8027 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8028 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8030 * the parent of an attribute or namespace node is the element
8031 * to which the attribute or namespace node is attached
8035 if (ctxt
->context
->node
== NULL
) return(NULL
);
8036 switch (ctxt
->context
->node
->type
) {
8037 case XML_ELEMENT_NODE
:
8039 case XML_CDATA_SECTION_NODE
:
8040 case XML_ENTITY_REF_NODE
:
8041 case XML_ENTITY_NODE
:
8043 case XML_COMMENT_NODE
:
8045 case XML_ELEMENT_DECL
:
8046 case XML_ATTRIBUTE_DECL
:
8047 case XML_ENTITY_DECL
:
8048 case XML_NOTATION_NODE
:
8049 case XML_XINCLUDE_START
:
8050 case XML_XINCLUDE_END
:
8051 if (ctxt
->context
->node
->parent
== NULL
)
8052 return((xmlNodePtr
) ctxt
->context
->doc
);
8053 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
8054 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
8055 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
8056 BAD_CAST
"fake node libxslt"))))
8058 return(ctxt
->context
->node
->parent
);
8059 case XML_ATTRIBUTE_NODE
: {
8060 xmlAttrPtr tmp
= (xmlAttrPtr
) ctxt
->context
->node
;
8062 return(tmp
->parent
);
8064 case XML_DOCUMENT_NODE
:
8065 case XML_DOCUMENT_TYPE_NODE
:
8066 case XML_DOCUMENT_FRAG_NODE
:
8067 case XML_HTML_DOCUMENT_NODE
:
8068 #ifdef LIBXML_DOCB_ENABLED
8069 case XML_DOCB_DOCUMENT_NODE
:
8072 case XML_NAMESPACE_DECL
: {
8073 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8075 if ((ns
->next
!= NULL
) &&
8076 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8077 return((xmlNodePtr
) ns
->next
);
8078 /* Bad, how did that namespace end up here ? */
8084 if (cur
== ctxt
->context
->doc
->children
)
8085 return((xmlNodePtr
) ctxt
->context
->doc
);
8086 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8088 switch (cur
->type
) {
8089 case XML_ELEMENT_NODE
:
8091 case XML_CDATA_SECTION_NODE
:
8092 case XML_ENTITY_REF_NODE
:
8093 case XML_ENTITY_NODE
:
8095 case XML_COMMENT_NODE
:
8096 case XML_NOTATION_NODE
:
8098 case XML_ELEMENT_DECL
:
8099 case XML_ATTRIBUTE_DECL
:
8100 case XML_ENTITY_DECL
:
8101 case XML_XINCLUDE_START
:
8102 case XML_XINCLUDE_END
:
8103 if (cur
->parent
== NULL
)
8105 if ((cur
->parent
->type
== XML_ELEMENT_NODE
) &&
8106 ((cur
->parent
->name
[0] == ' ') ||
8107 (xmlStrEqual(cur
->parent
->name
,
8108 BAD_CAST
"fake node libxslt"))))
8110 return(cur
->parent
);
8111 case XML_ATTRIBUTE_NODE
: {
8112 xmlAttrPtr att
= (xmlAttrPtr
) ctxt
->context
->node
;
8114 return(att
->parent
);
8116 case XML_NAMESPACE_DECL
: {
8117 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8119 if ((ns
->next
!= NULL
) &&
8120 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8121 return((xmlNodePtr
) ns
->next
);
8122 /* Bad, how did that namespace end up here ? */
8125 case XML_DOCUMENT_NODE
:
8126 case XML_DOCUMENT_TYPE_NODE
:
8127 case XML_DOCUMENT_FRAG_NODE
:
8128 case XML_HTML_DOCUMENT_NODE
:
8129 #ifdef LIBXML_DOCB_ENABLED
8130 case XML_DOCB_DOCUMENT_NODE
:
8138 * xmlXPathNextAncestorOrSelf:
8139 * @ctxt: the XPath Parser context
8140 * @cur: the current node in the traversal
8142 * Traversal function for the "ancestor-or-self" direction
8143 * he ancestor-or-self axis contains the context node and ancestors of
8144 * the context node in reverse document order; thus the context node is
8145 * the first node on the axis, and the context node's parent the second;
8146 * parent here is defined the same as with the parent axis.
8148 * Returns the next element following that axis
8151 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8152 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8154 return(ctxt
->context
->node
);
8155 return(xmlXPathNextAncestor(ctxt
, cur
));
8159 * xmlXPathNextFollowingSibling:
8160 * @ctxt: the XPath Parser context
8161 * @cur: the current node in the traversal
8163 * Traversal function for the "following-sibling" direction
8164 * The following-sibling axis contains the following siblings of the context
8165 * node in document order.
8167 * Returns the next element following that axis
8170 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8171 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8172 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8173 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8175 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8178 return(ctxt
->context
->node
->next
);
8183 * xmlXPathNextPrecedingSibling:
8184 * @ctxt: the XPath Parser context
8185 * @cur: the current node in the traversal
8187 * Traversal function for the "preceding-sibling" direction
8188 * The preceding-sibling axis contains the preceding siblings of the context
8189 * node in reverse document order; the first preceding sibling is first on the
8190 * axis; the sibling preceding that node is the second on the axis and so on.
8192 * Returns the next element following that axis
8195 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8196 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8197 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8198 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8200 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8203 return(ctxt
->context
->node
->prev
);
8204 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
)) {
8207 return(ctxt
->context
->node
->prev
);
8213 * xmlXPathNextFollowing:
8214 * @ctxt: the XPath Parser context
8215 * @cur: the current node in the traversal
8217 * Traversal function for the "following" direction
8218 * The following axis contains all nodes in the same document as the context
8219 * node that are after the context node in document order, excluding any
8220 * descendants and excluding attribute nodes and namespace nodes; the nodes
8221 * are ordered in document order
8223 * Returns the next element following that axis
8226 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8227 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8228 if ((cur
!= NULL
) && (cur
->type
!= XML_ATTRIBUTE_NODE
) &&
8229 (cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->children
!= NULL
))
8230 return(cur
->children
);
8233 cur
= ctxt
->context
->node
;
8234 if (cur
->type
== XML_NAMESPACE_DECL
)
8236 if (cur
->type
== XML_ATTRIBUTE_NODE
)
8239 if (cur
== NULL
) return(NULL
) ; /* ERROR */
8240 if (cur
->next
!= NULL
) return(cur
->next
) ;
8243 if (cur
== NULL
) break;
8244 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
) return(NULL
);
8245 if (cur
->next
!= NULL
) return(cur
->next
);
8246 } while (cur
!= NULL
);
8251 * xmlXPathIsAncestor:
8252 * @ancestor: the ancestor node
8253 * @node: the current node
8255 * Check that @ancestor is a @node's ancestor
8257 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8260 xmlXPathIsAncestor(xmlNodePtr ancestor
, xmlNodePtr node
) {
8261 if ((ancestor
== NULL
) || (node
== NULL
)) return(0);
8262 if (node
->type
== XML_NAMESPACE_DECL
)
8264 if (ancestor
->type
== XML_NAMESPACE_DECL
)
8266 /* nodes need to be in the same document */
8267 if (ancestor
->doc
!= node
->doc
) return(0);
8268 /* avoid searching if ancestor or node is the root node */
8269 if (ancestor
== (xmlNodePtr
) node
->doc
) return(1);
8270 if (node
== (xmlNodePtr
) ancestor
->doc
) return(0);
8271 while (node
->parent
!= NULL
) {
8272 if (node
->parent
== ancestor
)
8274 node
= node
->parent
;
8280 * xmlXPathNextPreceding:
8281 * @ctxt: the XPath Parser context
8282 * @cur: the current node in the traversal
8284 * Traversal function for the "preceding" direction
8285 * the preceding axis contains all nodes in the same document as the context
8286 * node that are before the context node in document order, excluding any
8287 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8288 * ordered in reverse document order
8290 * Returns the next element following that axis
8293 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
)
8295 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8297 cur
= ctxt
->context
->node
;
8298 if (cur
->type
== XML_NAMESPACE_DECL
)
8300 if (cur
->type
== XML_ATTRIBUTE_NODE
)
8301 return(cur
->parent
);
8303 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
8305 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8308 if (cur
->prev
!= NULL
) {
8309 for (cur
= cur
->prev
; cur
->last
!= NULL
; cur
= cur
->last
) ;
8316 if (cur
== ctxt
->context
->doc
->children
)
8318 } while (xmlXPathIsAncestor(cur
, ctxt
->context
->node
));
8323 * xmlXPathNextPrecedingInternal:
8324 * @ctxt: the XPath Parser context
8325 * @cur: the current node in the traversal
8327 * Traversal function for the "preceding" direction
8328 * the preceding axis contains all nodes in the same document as the context
8329 * node that are before the context node in document order, excluding any
8330 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8331 * ordered in reverse document order
8332 * This is a faster implementation but internal only since it requires a
8333 * state kept in the parser context: ctxt->ancestor.
8335 * Returns the next element following that axis
8338 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt
,
8341 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8343 cur
= ctxt
->context
->node
;
8346 if (cur
->type
== XML_NAMESPACE_DECL
)
8348 ctxt
->ancestor
= cur
->parent
;
8350 if (cur
->type
== XML_NAMESPACE_DECL
)
8352 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8354 while (cur
->prev
== NULL
) {
8358 if (cur
== ctxt
->context
->doc
->children
)
8360 if (cur
!= ctxt
->ancestor
)
8362 ctxt
->ancestor
= cur
->parent
;
8365 while (cur
->last
!= NULL
)
8371 * xmlXPathNextNamespace:
8372 * @ctxt: the XPath Parser context
8373 * @cur: the current attribute in the traversal
8375 * Traversal function for the "namespace" direction
8376 * the namespace axis contains the namespace nodes of the context node;
8377 * the order of nodes on this axis is implementation-defined; the axis will
8378 * be empty unless the context node is an element
8380 * We keep the XML namespace node at the end of the list.
8382 * Returns the next element following that axis
8385 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8386 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8387 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
) return(NULL
);
8388 if (ctxt
->context
->tmpNsList
== NULL
&& cur
!= (xmlNodePtr
) xmlXPathXMLNamespace
) {
8389 if (ctxt
->context
->tmpNsList
!= NULL
)
8390 xmlFree(ctxt
->context
->tmpNsList
);
8391 ctxt
->context
->tmpNsList
=
8392 xmlGetNsList(ctxt
->context
->doc
, ctxt
->context
->node
);
8393 ctxt
->context
->tmpNsNr
= 0;
8394 if (ctxt
->context
->tmpNsList
!= NULL
) {
8395 while (ctxt
->context
->tmpNsList
[ctxt
->context
->tmpNsNr
] != NULL
) {
8396 ctxt
->context
->tmpNsNr
++;
8399 return((xmlNodePtr
) xmlXPathXMLNamespace
);
8401 if (ctxt
->context
->tmpNsNr
> 0) {
8402 return (xmlNodePtr
)ctxt
->context
->tmpNsList
[--ctxt
->context
->tmpNsNr
];
8404 if (ctxt
->context
->tmpNsList
!= NULL
)
8405 xmlFree(ctxt
->context
->tmpNsList
);
8406 ctxt
->context
->tmpNsList
= NULL
;
8412 * xmlXPathNextAttribute:
8413 * @ctxt: the XPath Parser context
8414 * @cur: the current attribute in the traversal
8416 * Traversal function for the "attribute" direction
8417 * TODO: support DTD inherited default attributes
8419 * Returns the next element following that axis
8422 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8423 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8424 if (ctxt
->context
->node
== NULL
)
8426 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
)
8429 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
8431 return((xmlNodePtr
)ctxt
->context
->node
->properties
);
8433 return((xmlNodePtr
)cur
->next
);
8436 /************************************************************************
8438 * NodeTest Functions *
8440 ************************************************************************/
8442 #define IS_FUNCTION 200
8445 /************************************************************************
8447 * Implicit tree core function library *
8449 ************************************************************************/
8453 * @ctxt: the XPath Parser context
8455 * Initialize the context to the root of the document
8458 xmlXPathRoot(xmlXPathParserContextPtr ctxt
) {
8459 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8461 ctxt
->context
->node
= (xmlNodePtr
) ctxt
->context
->doc
;
8462 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8463 ctxt
->context
->node
));
8466 /************************************************************************
8468 * The explicit core function library *
8469 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8471 ************************************************************************/
8475 * xmlXPathLastFunction:
8476 * @ctxt: the XPath Parser context
8477 * @nargs: the number of arguments
8479 * Implement the last() XPath function
8481 * The last function returns the number of nodes in the context node list.
8484 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8486 if (ctxt
->context
->contextSize
>= 0) {
8488 xmlXPathCacheNewFloat(ctxt
->context
,
8489 (double) ctxt
->context
->contextSize
));
8491 xmlGenericError(xmlGenericErrorContext
,
8492 "last() : %d\n", ctxt
->context
->contextSize
);
8495 XP_ERROR(XPATH_INVALID_CTXT_SIZE
);
8500 * xmlXPathPositionFunction:
8501 * @ctxt: the XPath Parser context
8502 * @nargs: the number of arguments
8504 * Implement the position() XPath function
8506 * The position function returns the position of the context node in the
8507 * context node list. The first position is 1, and so the last position
8508 * will be equal to last().
8511 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8513 if (ctxt
->context
->proximityPosition
>= 0) {
8515 xmlXPathCacheNewFloat(ctxt
->context
,
8516 (double) ctxt
->context
->proximityPosition
));
8518 xmlGenericError(xmlGenericErrorContext
, "position() : %d\n",
8519 ctxt
->context
->proximityPosition
);
8522 XP_ERROR(XPATH_INVALID_CTXT_POSITION
);
8527 * xmlXPathCountFunction:
8528 * @ctxt: the XPath Parser context
8529 * @nargs: the number of arguments
8531 * Implement the count() XPath function
8532 * number count(node-set)
8535 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8536 xmlXPathObjectPtr cur
;
8539 if ((ctxt
->value
== NULL
) ||
8540 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8541 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8542 XP_ERROR(XPATH_INVALID_TYPE
);
8543 cur
= valuePop(ctxt
);
8545 if ((cur
== NULL
) || (cur
->nodesetval
== NULL
))
8546 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8547 else if ((cur
->type
== XPATH_NODESET
) || (cur
->type
== XPATH_XSLT_TREE
)) {
8548 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8549 (double) cur
->nodesetval
->nodeNr
));
8551 if ((cur
->nodesetval
->nodeNr
!= 1) ||
8552 (cur
->nodesetval
->nodeTab
== NULL
)) {
8553 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8558 tmp
= cur
->nodesetval
->nodeTab
[0];
8559 if ((tmp
!= NULL
) && (tmp
->type
!= XML_NAMESPACE_DECL
)) {
8560 tmp
= tmp
->children
;
8561 while (tmp
!= NULL
) {
8566 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) i
));
8569 xmlXPathReleaseObject(ctxt
->context
, cur
);
8573 * xmlXPathGetElementsByIds:
8574 * @doc: the document
8575 * @ids: a whitespace separated list of IDs
8577 * Selects elements by their unique ID.
8579 * Returns a node-set of selected elements.
8581 static xmlNodeSetPtr
8582 xmlXPathGetElementsByIds (xmlDocPtr doc
, const xmlChar
*ids
) {
8584 const xmlChar
*cur
= ids
;
8587 xmlNodePtr elem
= NULL
;
8589 if (ids
== NULL
) return(NULL
);
8591 ret
= xmlXPathNodeSetCreate(NULL
);
8595 while (IS_BLANK_CH(*cur
)) cur
++;
8597 while ((!IS_BLANK_CH(*cur
)) && (*cur
!= 0))
8600 ID
= xmlStrndup(ids
, cur
- ids
);
8603 * We used to check the fact that the value passed
8604 * was an NCName, but this generated much troubles for
8605 * me and Aleksey Sanin, people blatantly violated that
8606 * constaint, like Visa3D spec.
8607 * if (xmlValidateNCName(ID, 1) == 0)
8609 attr
= xmlGetID(doc
, ID
);
8611 if (attr
->type
== XML_ATTRIBUTE_NODE
)
8612 elem
= attr
->parent
;
8613 else if (attr
->type
== XML_ELEMENT_NODE
)
8614 elem
= (xmlNodePtr
) attr
;
8618 xmlXPathNodeSetAdd(ret
, elem
);
8623 while (IS_BLANK_CH(*cur
)) cur
++;
8630 * xmlXPathIdFunction:
8631 * @ctxt: the XPath Parser context
8632 * @nargs: the number of arguments
8634 * Implement the id() XPath function
8635 * node-set id(object)
8636 * The id function selects elements by their unique ID
8637 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8638 * then the result is the union of the result of applying id to the
8639 * string value of each of the nodes in the argument node-set. When the
8640 * argument to id is of any other type, the argument is converted to a
8641 * string as if by a call to the string function; the string is split
8642 * into a whitespace-separated list of tokens (whitespace is any sequence
8643 * of characters matching the production S); the result is a node-set
8644 * containing the elements in the same document as the context node that
8645 * have a unique ID equal to any of the tokens in the list.
8648 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8651 xmlXPathObjectPtr obj
;
8654 obj
= valuePop(ctxt
);
8655 if (obj
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8656 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
8660 ret
= xmlXPathNodeSetCreate(NULL
);
8662 * FIXME -- in an out-of-memory condition this will behave badly.
8663 * The solution is not clear -- we already popped an item from
8664 * ctxt, so the object is in a corrupt state.
8667 if (obj
->nodesetval
!= NULL
) {
8668 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
8670 xmlXPathCastNodeToString(obj
->nodesetval
->nodeTab
[i
]);
8671 ns
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, tokens
);
8672 ret
= xmlXPathNodeSetMerge(ret
, ns
);
8673 xmlXPathFreeNodeSet(ns
);
8678 xmlXPathReleaseObject(ctxt
->context
, obj
);
8679 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8682 obj
= xmlXPathCacheConvertString(ctxt
->context
, obj
);
8683 ret
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, obj
->stringval
);
8684 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8685 xmlXPathReleaseObject(ctxt
->context
, obj
);
8690 * xmlXPathLocalNameFunction:
8691 * @ctxt: the XPath Parser context
8692 * @nargs: the number of arguments
8694 * Implement the local-name() XPath function
8695 * string local-name(node-set?)
8696 * The local-name function returns a string containing the local part
8697 * of the name of the node in the argument node-set that is first in
8698 * document order. If the node-set is empty or the first node has no
8699 * name, an empty string is returned. If the argument is omitted it
8700 * defaults to the context node.
8703 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8704 xmlXPathObjectPtr cur
;
8706 if (ctxt
== NULL
) return;
8709 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8710 ctxt
->context
->node
));
8715 if ((ctxt
->value
== NULL
) ||
8716 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8717 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8718 XP_ERROR(XPATH_INVALID_TYPE
);
8719 cur
= valuePop(ctxt
);
8721 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8722 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8724 int i
= 0; /* Should be first in document order !!!!! */
8725 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8726 case XML_ELEMENT_NODE
:
8727 case XML_ATTRIBUTE_NODE
:
8729 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8730 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8733 xmlXPathCacheNewString(ctxt
->context
,
8734 cur
->nodesetval
->nodeTab
[i
]->name
));
8736 case XML_NAMESPACE_DECL
:
8737 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8738 ((xmlNsPtr
)cur
->nodesetval
->nodeTab
[i
])->prefix
));
8741 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8744 xmlXPathReleaseObject(ctxt
->context
, cur
);
8748 * xmlXPathNamespaceURIFunction:
8749 * @ctxt: the XPath Parser context
8750 * @nargs: the number of arguments
8752 * Implement the namespace-uri() XPath function
8753 * string namespace-uri(node-set?)
8754 * The namespace-uri function returns a string containing the
8755 * namespace URI of the expanded name of the node in the argument
8756 * node-set that is first in document order. If the node-set is empty,
8757 * the first node has no name, or the expanded name has no namespace
8758 * URI, an empty string is returned. If the argument is omitted it
8759 * defaults to the context node.
8762 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8763 xmlXPathObjectPtr cur
;
8765 if (ctxt
== NULL
) return;
8768 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8769 ctxt
->context
->node
));
8773 if ((ctxt
->value
== NULL
) ||
8774 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8775 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8776 XP_ERROR(XPATH_INVALID_TYPE
);
8777 cur
= valuePop(ctxt
);
8779 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8780 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8782 int i
= 0; /* Should be first in document order !!!!! */
8783 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8784 case XML_ELEMENT_NODE
:
8785 case XML_ATTRIBUTE_NODE
:
8786 if (cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
)
8787 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8789 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8790 cur
->nodesetval
->nodeTab
[i
]->ns
->href
));
8793 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8796 xmlXPathReleaseObject(ctxt
->context
, cur
);
8800 * xmlXPathNameFunction:
8801 * @ctxt: the XPath Parser context
8802 * @nargs: the number of arguments
8804 * Implement the name() XPath function
8805 * string name(node-set?)
8806 * The name function returns a string containing a QName representing
8807 * the name of the node in the argument node-set that is first in document
8808 * order. The QName must represent the name with respect to the namespace
8809 * declarations in effect on the node whose name is being represented.
8810 * Typically, this will be the form in which the name occurred in the XML
8811 * source. This need not be the case if there are namespace declarations
8812 * in effect on the node that associate multiple prefixes with the same
8813 * namespace. However, an implementation may include information about
8814 * the original prefix in its representation of nodes; in this case, an
8815 * implementation can ensure that the returned string is always the same
8816 * as the QName used in the XML source. If the argument it omitted it
8817 * defaults to the context node.
8818 * Libxml keep the original prefix so the "real qualified name" used is
8822 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
8824 xmlXPathObjectPtr cur
;
8827 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8828 ctxt
->context
->node
));
8833 if ((ctxt
->value
== NULL
) ||
8834 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8835 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8836 XP_ERROR(XPATH_INVALID_TYPE
);
8837 cur
= valuePop(ctxt
);
8839 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8840 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8842 int i
= 0; /* Should be first in document order !!!!! */
8844 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8845 case XML_ELEMENT_NODE
:
8846 case XML_ATTRIBUTE_NODE
:
8847 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8849 xmlXPathCacheNewCString(ctxt
->context
, ""));
8850 else if ((cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
) ||
8851 (cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
== NULL
)) {
8853 xmlXPathCacheNewString(ctxt
->context
,
8854 cur
->nodesetval
->nodeTab
[i
]->name
));
8858 fullname
= xmlBuildQName(cur
->nodesetval
->nodeTab
[i
]->name
,
8859 cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
,
8861 if (fullname
== cur
->nodesetval
->nodeTab
[i
]->name
)
8862 fullname
= xmlStrdup(cur
->nodesetval
->nodeTab
[i
]->name
);
8863 if (fullname
== NULL
) {
8864 XP_ERROR(XPATH_MEMORY_ERROR
);
8866 valuePush(ctxt
, xmlXPathCacheWrapString(
8867 ctxt
->context
, fullname
));
8871 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8872 cur
->nodesetval
->nodeTab
[i
]));
8873 xmlXPathLocalNameFunction(ctxt
, 1);
8876 xmlXPathReleaseObject(ctxt
->context
, cur
);
8881 * xmlXPathStringFunction:
8882 * @ctxt: the XPath Parser context
8883 * @nargs: the number of arguments
8885 * Implement the string() XPath function
8886 * string string(object?)
8887 * The string function converts an object to a string as follows:
8888 * - A node-set is converted to a string by returning the value of
8889 * the node in the node-set that is first in document order.
8890 * If the node-set is empty, an empty string is returned.
8891 * - A number is converted to a string as follows
8892 * + NaN is converted to the string NaN
8893 * + positive zero is converted to the string 0
8894 * + negative zero is converted to the string 0
8895 * + positive infinity is converted to the string Infinity
8896 * + negative infinity is converted to the string -Infinity
8897 * + if the number is an integer, the number is represented in
8898 * decimal form as a Number with no decimal point and no leading
8899 * zeros, preceded by a minus sign (-) if the number is negative
8900 * + otherwise, the number is represented in decimal form as a
8901 * Number including a decimal point with at least one digit
8902 * before the decimal point and at least one digit after the
8903 * decimal point, preceded by a minus sign (-) if the number
8904 * is negative; there must be no leading zeros before the decimal
8905 * point apart possibly from the one required digit immediately
8906 * before the decimal point; beyond the one required digit
8907 * after the decimal point there must be as many, but only as
8908 * many, more digits as are needed to uniquely distinguish the
8909 * number from all other IEEE 754 numeric values.
8910 * - The boolean false value is converted to the string false.
8911 * The boolean true value is converted to the string true.
8913 * If the argument is omitted, it defaults to a node-set with the
8914 * context node as its only member.
8917 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8918 xmlXPathObjectPtr cur
;
8920 if (ctxt
== NULL
) return;
8923 xmlXPathCacheWrapString(ctxt
->context
,
8924 xmlXPathCastNodeToString(ctxt
->context
->node
)));
8929 cur
= valuePop(ctxt
);
8930 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8931 valuePush(ctxt
, xmlXPathCacheConvertString(ctxt
->context
, cur
));
8935 * xmlXPathStringLengthFunction:
8936 * @ctxt: the XPath Parser context
8937 * @nargs: the number of arguments
8939 * Implement the string-length() XPath function
8940 * number string-length(string?)
8941 * The string-length returns the number of characters in the string
8942 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8943 * the context node converted to a string, in other words the value
8944 * of the context node.
8947 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8948 xmlXPathObjectPtr cur
;
8951 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8953 if (ctxt
->context
->node
== NULL
) {
8954 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0));
8958 content
= xmlXPathCastNodeToString(ctxt
->context
->node
);
8959 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8960 xmlUTF8Strlen(content
)));
8967 CHECK_TYPE(XPATH_STRING
);
8968 cur
= valuePop(ctxt
);
8969 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8970 xmlUTF8Strlen(cur
->stringval
)));
8971 xmlXPathReleaseObject(ctxt
->context
, cur
);
8975 * xmlXPathConcatFunction:
8976 * @ctxt: the XPath Parser context
8977 * @nargs: the number of arguments
8979 * Implement the concat() XPath function
8980 * string concat(string, string, string*)
8981 * The concat function returns the concatenation of its arguments.
8984 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8985 xmlXPathObjectPtr cur
, newobj
;
8988 if (ctxt
== NULL
) return;
8994 cur
= valuePop(ctxt
);
8995 if ((cur
== NULL
) || (cur
->type
!= XPATH_STRING
)) {
8996 xmlXPathReleaseObject(ctxt
->context
, cur
);
9003 newobj
= valuePop(ctxt
);
9004 if ((newobj
== NULL
) || (newobj
->type
!= XPATH_STRING
)) {
9005 xmlXPathReleaseObject(ctxt
->context
, newobj
);
9006 xmlXPathReleaseObject(ctxt
->context
, cur
);
9007 XP_ERROR(XPATH_INVALID_TYPE
);
9009 tmp
= xmlStrcat(newobj
->stringval
, cur
->stringval
);
9010 newobj
->stringval
= cur
->stringval
;
9011 cur
->stringval
= tmp
;
9012 xmlXPathReleaseObject(ctxt
->context
, newobj
);
9015 valuePush(ctxt
, cur
);
9019 * xmlXPathContainsFunction:
9020 * @ctxt: the XPath Parser context
9021 * @nargs: the number of arguments
9023 * Implement the contains() XPath function
9024 * boolean contains(string, string)
9025 * The contains function returns true if the first argument string
9026 * contains the second argument string, and otherwise returns false.
9029 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9030 xmlXPathObjectPtr hay
, needle
;
9034 CHECK_TYPE(XPATH_STRING
);
9035 needle
= valuePop(ctxt
);
9037 hay
= valuePop(ctxt
);
9039 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9040 xmlXPathReleaseObject(ctxt
->context
, hay
);
9041 xmlXPathReleaseObject(ctxt
->context
, needle
);
9042 XP_ERROR(XPATH_INVALID_TYPE
);
9044 if (xmlStrstr(hay
->stringval
, needle
->stringval
))
9045 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9047 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9048 xmlXPathReleaseObject(ctxt
->context
, hay
);
9049 xmlXPathReleaseObject(ctxt
->context
, needle
);
9053 * xmlXPathStartsWithFunction:
9054 * @ctxt: the XPath Parser context
9055 * @nargs: the number of arguments
9057 * Implement the starts-with() XPath function
9058 * boolean starts-with(string, string)
9059 * The starts-with function returns true if the first argument string
9060 * starts with the second argument string, and otherwise returns false.
9063 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9064 xmlXPathObjectPtr hay
, needle
;
9069 CHECK_TYPE(XPATH_STRING
);
9070 needle
= valuePop(ctxt
);
9072 hay
= valuePop(ctxt
);
9074 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9075 xmlXPathReleaseObject(ctxt
->context
, hay
);
9076 xmlXPathReleaseObject(ctxt
->context
, needle
);
9077 XP_ERROR(XPATH_INVALID_TYPE
);
9079 n
= xmlStrlen(needle
->stringval
);
9080 if (xmlStrncmp(hay
->stringval
, needle
->stringval
, n
))
9081 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9083 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9084 xmlXPathReleaseObject(ctxt
->context
, hay
);
9085 xmlXPathReleaseObject(ctxt
->context
, needle
);
9089 * xmlXPathSubstringFunction:
9090 * @ctxt: the XPath Parser context
9091 * @nargs: the number of arguments
9093 * Implement the substring() XPath function
9094 * string substring(string, number, number?)
9095 * The substring function returns the substring of the first argument
9096 * starting at the position specified in the second argument with
9097 * length specified in the third argument. For example,
9098 * substring("12345",2,3) returns "234". If the third argument is not
9099 * specified, it returns the substring starting at the position specified
9100 * in the second argument and continuing to the end of the string. For
9101 * example, substring("12345",2) returns "2345". More precisely, each
9102 * character in the string (see [3.6 Strings]) is considered to have a
9103 * numeric position: the position of the first character is 1, the position
9104 * of the second character is 2 and so on. The returned substring contains
9105 * those characters for which the position of the character is greater than
9106 * or equal to the second argument and, if the third argument is specified,
9107 * less than the sum of the second and third arguments; the comparisons
9108 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9109 * - substring("12345", 1.5, 2.6) returns "234"
9110 * - substring("12345", 0, 3) returns "12"
9111 * - substring("12345", 0 div 0, 3) returns ""
9112 * - substring("12345", 1, 0 div 0) returns ""
9113 * - substring("12345", -42, 1 div 0) returns "12345"
9114 * - substring("12345", -1 div 0, 1 div 0) returns ""
9117 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9118 xmlXPathObjectPtr str
, start
, len
;
9130 * take care of possible last (position) argument
9134 CHECK_TYPE(XPATH_NUMBER
);
9135 len
= valuePop(ctxt
);
9137 xmlXPathReleaseObject(ctxt
->context
, len
);
9141 CHECK_TYPE(XPATH_NUMBER
);
9142 start
= valuePop(ctxt
);
9143 in
= start
->floatval
;
9144 xmlXPathReleaseObject(ctxt
->context
, start
);
9146 CHECK_TYPE(XPATH_STRING
);
9147 str
= valuePop(ctxt
);
9148 m
= xmlUTF8Strlen((const unsigned char *)str
->stringval
);
9151 * If last pos not present, calculate last position
9159 /* Need to check for the special cases where either
9160 * the index is NaN, the length is NaN, or both
9161 * arguments are infinity (relying on Inf + -Inf = NaN)
9163 if (!xmlXPathIsInf(in
) && !xmlXPathIsNaN(in
+ le
)) {
9165 * To meet the requirements of the spec, the arguments
9166 * must be converted to integer format before
9167 * initial index calculations are done
9169 * First we go to integer form, rounding up
9170 * and checking for special cases
9173 if (((double)i
)+0.5 <= in
) i
++;
9175 if (xmlXPathIsInf(le
) == 1) {
9180 else if (xmlXPathIsInf(le
) == -1 || le
< 0.0)
9184 if (((double)l
)+0.5 <= le
) l
++;
9187 /* Now we normalize inidices */
9195 /* number of chars to copy */
9198 ret
= xmlUTF8Strsub(str
->stringval
, i
, l
);
9204 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
9206 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, ret
));
9209 xmlXPathReleaseObject(ctxt
->context
, str
);
9213 * xmlXPathSubstringBeforeFunction:
9214 * @ctxt: the XPath Parser context
9215 * @nargs: the number of arguments
9217 * Implement the substring-before() XPath function
9218 * string substring-before(string, string)
9219 * The substring-before function returns the substring of the first
9220 * argument string that precedes the first occurrence of the second
9221 * argument string in the first argument string, or the empty string
9222 * if the first argument string does not contain the second argument
9223 * string. For example, substring-before("1999/04/01","/") returns 1999.
9226 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9227 xmlXPathObjectPtr str
;
9228 xmlXPathObjectPtr find
;
9230 const xmlChar
*point
;
9235 find
= valuePop(ctxt
);
9237 str
= valuePop(ctxt
);
9239 target
= xmlBufCreate();
9241 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9243 offset
= (int)(point
- str
->stringval
);
9244 xmlBufAdd(target
, str
->stringval
, offset
);
9246 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9247 xmlBufContent(target
)));
9250 xmlXPathReleaseObject(ctxt
->context
, str
);
9251 xmlXPathReleaseObject(ctxt
->context
, find
);
9255 * xmlXPathSubstringAfterFunction:
9256 * @ctxt: the XPath Parser context
9257 * @nargs: the number of arguments
9259 * Implement the substring-after() XPath function
9260 * string substring-after(string, string)
9261 * The substring-after function returns the substring of the first
9262 * argument string that follows the first occurrence of the second
9263 * argument string in the first argument string, or the empty stringi
9264 * if the first argument string does not contain the second argument
9265 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9266 * and substring-after("1999/04/01","19") returns 99/04/01.
9269 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9270 xmlXPathObjectPtr str
;
9271 xmlXPathObjectPtr find
;
9273 const xmlChar
*point
;
9278 find
= valuePop(ctxt
);
9280 str
= valuePop(ctxt
);
9282 target
= xmlBufCreate();
9284 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9286 offset
= (int)(point
- str
->stringval
) + xmlStrlen(find
->stringval
);
9287 xmlBufAdd(target
, &str
->stringval
[offset
],
9288 xmlStrlen(str
->stringval
) - offset
);
9290 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9291 xmlBufContent(target
)));
9294 xmlXPathReleaseObject(ctxt
->context
, str
);
9295 xmlXPathReleaseObject(ctxt
->context
, find
);
9299 * xmlXPathNormalizeFunction:
9300 * @ctxt: the XPath Parser context
9301 * @nargs: the number of arguments
9303 * Implement the normalize-space() XPath function
9304 * string normalize-space(string?)
9305 * The normalize-space function returns the argument string with white
9306 * space normalized by stripping leading and trailing whitespace
9307 * and replacing sequences of whitespace characters by a single
9308 * space. Whitespace characters are the same allowed by the S production
9309 * in XML. If the argument is omitted, it defaults to the context
9310 * node converted to a string, in other words the value of the context node.
9313 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9314 xmlXPathObjectPtr obj
= NULL
;
9315 xmlChar
*source
= NULL
;
9319 if (ctxt
== NULL
) return;
9321 /* Use current context node */
9323 xmlXPathCacheWrapString(ctxt
->context
,
9324 xmlXPathCastNodeToString(ctxt
->context
->node
)));
9330 CHECK_TYPE(XPATH_STRING
);
9331 obj
= valuePop(ctxt
);
9332 source
= obj
->stringval
;
9334 target
= xmlBufCreate();
9335 if (target
&& source
) {
9337 /* Skip leading whitespaces */
9338 while (IS_BLANK_CH(*source
))
9341 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9344 if (IS_BLANK_CH(*source
)) {
9348 xmlBufAdd(target
, &blank
, 1);
9351 xmlBufAdd(target
, source
, 1);
9355 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9356 xmlBufContent(target
)));
9359 xmlXPathReleaseObject(ctxt
->context
, obj
);
9363 * xmlXPathTranslateFunction:
9364 * @ctxt: the XPath Parser context
9365 * @nargs: the number of arguments
9367 * Implement the translate() XPath function
9368 * string translate(string, string, string)
9369 * The translate function returns the first argument string with
9370 * occurrences of characters in the second argument string replaced
9371 * by the character at the corresponding position in the third argument
9372 * string. For example, translate("bar","abc","ABC") returns the string
9373 * BAr. If there is a character in the second argument string with no
9374 * character at a corresponding position in the third argument string
9375 * (because the second argument string is longer than the third argument
9376 * string), then occurrences of that character in the first argument
9377 * string are removed. For example, translate("--aaa--","abc-","ABC")
9378 * returns "AAA". If a character occurs more than once in second
9379 * argument string, then the first occurrence determines the replacement
9380 * character. If the third argument string is longer than the second
9381 * argument string, then excess characters are ignored.
9384 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9385 xmlXPathObjectPtr str
;
9386 xmlXPathObjectPtr from
;
9387 xmlXPathObjectPtr to
;
9391 const xmlChar
*point
;
9397 to
= valuePop(ctxt
);
9399 from
= valuePop(ctxt
);
9401 str
= valuePop(ctxt
);
9403 target
= xmlBufCreate();
9405 max
= xmlUTF8Strlen(to
->stringval
);
9406 for (cptr
= str
->stringval
; (ch
=*cptr
); ) {
9407 offset
= xmlUTF8Strloc(from
->stringval
, cptr
);
9410 point
= xmlUTF8Strpos(to
->stringval
, offset
);
9412 xmlBufAdd(target
, point
, xmlUTF8Strsize(point
, 1));
9415 xmlBufAdd(target
, cptr
, xmlUTF8Strsize(cptr
, 1));
9417 /* Step to next character in input */
9420 /* if not simple ascii, verify proper format */
9421 if ( (ch
& 0xc0) != 0xc0 ) {
9422 xmlGenericError(xmlGenericErrorContext
,
9423 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9424 /* not asserting an XPath error is probably better */
9427 /* then skip over remaining bytes for this char */
9428 while ( (ch
<<= 1) & 0x80 )
9429 if ( (*cptr
++ & 0xc0) != 0x80 ) {
9430 xmlGenericError(xmlGenericErrorContext
,
9431 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9432 /* not asserting an XPath error is probably better */
9435 if (ch
& 0x80) /* must have had error encountered */
9440 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9441 xmlBufContent(target
)));
9443 xmlXPathReleaseObject(ctxt
->context
, str
);
9444 xmlXPathReleaseObject(ctxt
->context
, from
);
9445 xmlXPathReleaseObject(ctxt
->context
, to
);
9449 * xmlXPathBooleanFunction:
9450 * @ctxt: the XPath Parser context
9451 * @nargs: the number of arguments
9453 * Implement the boolean() XPath function
9454 * boolean boolean(object)
9455 * The boolean function converts its argument to a boolean as follows:
9456 * - a number is true if and only if it is neither positive or
9457 * negative zero nor NaN
9458 * - a node-set is true if and only if it is non-empty
9459 * - a string is true if and only if its length is non-zero
9462 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9463 xmlXPathObjectPtr cur
;
9466 cur
= valuePop(ctxt
);
9467 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
9468 cur
= xmlXPathCacheConvertBoolean(ctxt
->context
, cur
);
9469 valuePush(ctxt
, cur
);
9473 * xmlXPathNotFunction:
9474 * @ctxt: the XPath Parser context
9475 * @nargs: the number of arguments
9477 * Implement the not() XPath function
9478 * boolean not(boolean)
9479 * The not function returns true if its argument is false,
9480 * and false otherwise.
9483 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9486 CHECK_TYPE(XPATH_BOOLEAN
);
9487 ctxt
->value
->boolval
= ! ctxt
->value
->boolval
;
9491 * xmlXPathTrueFunction:
9492 * @ctxt: the XPath Parser context
9493 * @nargs: the number of arguments
9495 * Implement the true() XPath function
9499 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9501 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9505 * xmlXPathFalseFunction:
9506 * @ctxt: the XPath Parser context
9507 * @nargs: the number of arguments
9509 * Implement the false() XPath function
9513 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9515 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9519 * xmlXPathLangFunction:
9520 * @ctxt: the XPath Parser context
9521 * @nargs: the number of arguments
9523 * Implement the lang() XPath function
9524 * boolean lang(string)
9525 * The lang function returns true or false depending on whether the
9526 * language of the context node as specified by xml:lang attributes
9527 * is the same as or is a sublanguage of the language specified by
9528 * the argument string. The language of the context node is determined
9529 * by the value of the xml:lang attribute on the context node, or, if
9530 * the context node has no xml:lang attribute, by the value of the
9531 * xml:lang attribute on the nearest ancestor of the context node that
9532 * has an xml:lang attribute. If there is no such attribute, then lang
9533 * returns false. If there is such an attribute, then lang returns
9534 * true if the attribute value is equal to the argument ignoring case,
9535 * or if there is some suffix starting with - such that the attribute
9536 * value is equal to the argument ignoring that suffix of the attribute
9537 * value and ignoring case.
9540 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9541 xmlXPathObjectPtr val
= NULL
;
9542 const xmlChar
*theLang
= NULL
;
9543 const xmlChar
*lang
;
9549 CHECK_TYPE(XPATH_STRING
);
9550 val
= valuePop(ctxt
);
9551 lang
= val
->stringval
;
9552 theLang
= xmlNodeGetLang(ctxt
->context
->node
);
9553 if ((theLang
!= NULL
) && (lang
!= NULL
)) {
9554 for (i
= 0;lang
[i
] != 0;i
++)
9555 if (toupper(lang
[i
]) != toupper(theLang
[i
]))
9557 if ((theLang
[i
] == 0) || (theLang
[i
] == '-'))
9561 if (theLang
!= NULL
)
9562 xmlFree((void *)theLang
);
9564 xmlXPathReleaseObject(ctxt
->context
, val
);
9565 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
9569 * xmlXPathNumberFunction:
9570 * @ctxt: the XPath Parser context
9571 * @nargs: the number of arguments
9573 * Implement the number() XPath function
9574 * number number(object?)
9577 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9578 xmlXPathObjectPtr cur
;
9581 if (ctxt
== NULL
) return;
9583 if (ctxt
->context
->node
== NULL
) {
9584 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0.0));
9586 xmlChar
* content
= xmlNodeGetContent(ctxt
->context
->node
);
9588 res
= xmlXPathStringEvalNumber(content
);
9589 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9596 cur
= valuePop(ctxt
);
9597 valuePush(ctxt
, xmlXPathCacheConvertNumber(ctxt
->context
, cur
));
9601 * xmlXPathSumFunction:
9602 * @ctxt: the XPath Parser context
9603 * @nargs: the number of arguments
9605 * Implement the sum() XPath function
9606 * number sum(node-set)
9607 * The sum function returns the sum of the values of the nodes in
9608 * the argument node-set.
9611 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9612 xmlXPathObjectPtr cur
;
9617 if ((ctxt
->value
== NULL
) ||
9618 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
9619 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
9620 XP_ERROR(XPATH_INVALID_TYPE
);
9621 cur
= valuePop(ctxt
);
9623 if ((cur
->nodesetval
!= NULL
) && (cur
->nodesetval
->nodeNr
!= 0)) {
9624 for (i
= 0; i
< cur
->nodesetval
->nodeNr
; i
++) {
9625 res
+= xmlXPathCastNodeToNumber(cur
->nodesetval
->nodeTab
[i
]);
9628 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9629 xmlXPathReleaseObject(ctxt
->context
, cur
);
9633 * To assure working code on multiple platforms, we want to only depend
9634 * upon the characteristic truncation of converting a floating point value
9635 * to an integer. Unfortunately, because of the different storage sizes
9636 * of our internal floating point value (double) and integer (int), we
9637 * can't directly convert (see bug 301162). This macro is a messy
9640 #define XTRUNC(f, v) \
9641 f = fmod((v), INT_MAX); \
9642 f = (v) - (f) + (double)((int)(f));
9645 * xmlXPathFloorFunction:
9646 * @ctxt: the XPath Parser context
9647 * @nargs: the number of arguments
9649 * Implement the floor() XPath function
9650 * number floor(number)
9651 * The floor function returns the largest (closest to positive infinity)
9652 * number that is not greater than the argument and that is an integer.
9655 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9660 CHECK_TYPE(XPATH_NUMBER
);
9662 XTRUNC(f
, ctxt
->value
->floatval
);
9663 if (f
!= ctxt
->value
->floatval
) {
9664 if (ctxt
->value
->floatval
> 0)
9665 ctxt
->value
->floatval
= f
;
9667 ctxt
->value
->floatval
= f
- 1;
9672 * xmlXPathCeilingFunction:
9673 * @ctxt: the XPath Parser context
9674 * @nargs: the number of arguments
9676 * Implement the ceiling() XPath function
9677 * number ceiling(number)
9678 * The ceiling function returns the smallest (closest to negative infinity)
9679 * number that is not less than the argument and that is an integer.
9682 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9687 CHECK_TYPE(XPATH_NUMBER
);
9690 ctxt
->value
->floatval
= ceil(ctxt
->value
->floatval
);
9692 XTRUNC(f
, ctxt
->value
->floatval
);
9693 if (f
!= ctxt
->value
->floatval
) {
9694 if (ctxt
->value
->floatval
> 0)
9695 ctxt
->value
->floatval
= f
+ 1;
9697 if (ctxt
->value
->floatval
< 0 && f
== 0)
9698 ctxt
->value
->floatval
= xmlXPathNZERO
;
9700 ctxt
->value
->floatval
= f
;
9708 * xmlXPathRoundFunction:
9709 * @ctxt: the XPath Parser context
9710 * @nargs: the number of arguments
9712 * Implement the round() XPath function
9713 * number round(number)
9714 * The round function returns the number that is closest to the
9715 * argument and that is an integer. If there are two such numbers,
9716 * then the one that is even is returned.
9719 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9724 CHECK_TYPE(XPATH_NUMBER
);
9726 if ((xmlXPathIsNaN(ctxt
->value
->floatval
)) ||
9727 (xmlXPathIsInf(ctxt
->value
->floatval
) == 1) ||
9728 (xmlXPathIsInf(ctxt
->value
->floatval
) == -1) ||
9729 (ctxt
->value
->floatval
== 0.0))
9732 XTRUNC(f
, ctxt
->value
->floatval
);
9733 if (ctxt
->value
->floatval
< 0) {
9734 if (ctxt
->value
->floatval
< f
- 0.5)
9735 ctxt
->value
->floatval
= f
- 1;
9737 ctxt
->value
->floatval
= f
;
9738 if (ctxt
->value
->floatval
== 0)
9739 ctxt
->value
->floatval
= xmlXPathNZERO
;
9741 if (ctxt
->value
->floatval
< f
+ 0.5)
9742 ctxt
->value
->floatval
= f
;
9744 ctxt
->value
->floatval
= f
+ 1;
9748 /************************************************************************
9752 ************************************************************************/
9755 * a few forward declarations since we use a recursive call based
9758 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
);
9759 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
);
9760 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
);
9761 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt
);
9762 static xmlChar
* xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
,
9766 * xmlXPathCurrentChar:
9767 * @ctxt: the XPath parser context
9768 * @cur: pointer to the beginning of the char
9769 * @len: pointer to the length of the char read
9771 * The current char value, if using UTF-8 this may actually span multiple
9772 * bytes in the input buffer.
9774 * Returns the current char value and its length
9778 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt
, int *len
) {
9788 * We are supposed to handle UTF8, check it's valid
9789 * From rfc2044: encoding of the Unicode values on UTF-8:
9791 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9792 * 0000 0000-0000 007F 0xxxxxxx
9793 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9794 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9796 * Check for the 0x110000 limit too
9800 if ((cur
[1] & 0xc0) != 0x80)
9801 goto encoding_error
;
9802 if ((c
& 0xe0) == 0xe0) {
9804 if ((cur
[2] & 0xc0) != 0x80)
9805 goto encoding_error
;
9806 if ((c
& 0xf0) == 0xf0) {
9807 if (((c
& 0xf8) != 0xf0) ||
9808 ((cur
[3] & 0xc0) != 0x80))
9809 goto encoding_error
;
9812 val
= (cur
[0] & 0x7) << 18;
9813 val
|= (cur
[1] & 0x3f) << 12;
9814 val
|= (cur
[2] & 0x3f) << 6;
9815 val
|= cur
[3] & 0x3f;
9819 val
= (cur
[0] & 0xf) << 12;
9820 val
|= (cur
[1] & 0x3f) << 6;
9821 val
|= cur
[2] & 0x3f;
9826 val
= (cur
[0] & 0x1f) << 6;
9827 val
|= cur
[1] & 0x3f;
9829 if (!IS_CHAR(val
)) {
9830 XP_ERROR0(XPATH_INVALID_CHAR_ERROR
);
9840 * If we detect an UTF8 error that probably means that the
9841 * input encoding didn't get properly advertised in the
9842 * declaration header. Report the error and switch the encoding
9843 * to ISO-Latin-1 (if you don't like this policy, just declare the
9847 XP_ERROR0(XPATH_ENCODING_ERROR
);
9851 * xmlXPathParseNCName:
9852 * @ctxt: the XPath Parser context
9854 * parse an XML namespace non qualified name.
9856 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9858 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9859 * CombiningChar | Extender
9861 * Returns the namespace name or NULL
9865 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt
) {
9870 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9872 * Accelerator for simple ASCII names
9875 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9876 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9879 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9880 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9881 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9882 (*in
== '_') || (*in
== '.') ||
9885 if ((*in
== ' ') || (*in
== '>') || (*in
== '/') ||
9886 (*in
== '[') || (*in
== ']') || (*in
== ':') ||
9887 (*in
== '@') || (*in
== '*')) {
9888 count
= in
- ctxt
->cur
;
9891 ret
= xmlStrndup(ctxt
->cur
, count
);
9896 return(xmlXPathParseNameComplex(ctxt
, 0));
9901 * xmlXPathParseQName:
9902 * @ctxt: the XPath Parser context
9903 * @prefix: a xmlChar **
9905 * parse an XML qualified name
9907 * [NS 5] QName ::= (Prefix ':')? LocalPart
9909 * [NS 6] Prefix ::= NCName
9911 * [NS 7] LocalPart ::= NCName
9913 * Returns the function returns the local part, and prefix is updated
9914 * to get the Prefix if any.
9918 xmlXPathParseQName(xmlXPathParserContextPtr ctxt
, xmlChar
**prefix
) {
9919 xmlChar
*ret
= NULL
;
9922 ret
= xmlXPathParseNCName(ctxt
);
9923 if (ret
&& CUR
== ':') {
9926 ret
= xmlXPathParseNCName(ctxt
);
9932 * xmlXPathParseName:
9933 * @ctxt: the XPath Parser context
9937 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9938 * CombiningChar | Extender
9940 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9942 * Returns the namespace name or NULL
9946 xmlXPathParseName(xmlXPathParserContextPtr ctxt
) {
9951 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9953 * Accelerator for simple ASCII names
9956 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9957 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9958 (*in
== '_') || (*in
== ':')) {
9960 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9961 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9962 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9963 (*in
== '_') || (*in
== '-') ||
9964 (*in
== ':') || (*in
== '.'))
9966 if ((*in
> 0) && (*in
< 0x80)) {
9967 count
= in
- ctxt
->cur
;
9968 if (count
> XML_MAX_NAME_LENGTH
) {
9970 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9972 ret
= xmlStrndup(ctxt
->cur
, count
);
9977 return(xmlXPathParseNameComplex(ctxt
, 1));
9981 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
, int qualified
) {
9982 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
9987 * Handler for more complex cases
9990 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
9991 (c
== '[') || (c
== ']') || (c
== '@') || /* accelerators */
9992 (c
== '*') || /* accelerators */
9993 (!IS_LETTER(c
) && (c
!= '_') &&
9994 ((qualified
) && (c
!= ':')))) {
9998 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
9999 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
10000 (c
== '.') || (c
== '-') ||
10001 (c
== '_') || ((qualified
) && (c
== ':')) ||
10002 (IS_COMBINING(c
)) ||
10003 (IS_EXTENDER(c
)))) {
10004 COPY_BUF(l
,buf
,len
,c
);
10007 if (len
>= XML_MAX_NAMELEN
) {
10009 * Okay someone managed to make a huge name, so he's ready to pay
10010 * for the processing speed.
10015 if (len
> XML_MAX_NAME_LENGTH
) {
10016 XP_ERRORNULL(XPATH_EXPR_ERROR
);
10018 buffer
= (xmlChar
*) xmlMallocAtomic(max
* sizeof(xmlChar
));
10019 if (buffer
== NULL
) {
10020 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
10022 memcpy(buffer
, buf
, len
);
10023 while ((IS_LETTER(c
)) || (IS_DIGIT(c
)) || /* test bigname.xml */
10024 (c
== '.') || (c
== '-') ||
10025 (c
== '_') || ((qualified
) && (c
== ':')) ||
10026 (IS_COMBINING(c
)) ||
10027 (IS_EXTENDER(c
))) {
10028 if (len
+ 10 > max
) {
10029 if (max
> XML_MAX_NAME_LENGTH
) {
10030 XP_ERRORNULL(XPATH_EXPR_ERROR
);
10033 buffer
= (xmlChar
*) xmlRealloc(buffer
,
10034 max
* sizeof(xmlChar
));
10035 if (buffer
== NULL
) {
10036 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
10039 COPY_BUF(l
,buffer
,len
,c
);
10049 return(xmlStrndup(buf
, len
));
10052 #define MAX_FRAC 20
10055 * These are used as divisors for the fractional part of a number.
10056 * Since the table includes 1.0 (representing '0' fractional digits),
10057 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10059 static double my_pow10
[MAX_FRAC
+1] = {
10060 1.0, 10.0, 100.0, 1000.0, 10000.0,
10061 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10062 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10064 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10065 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10069 * xmlXPathStringEvalNumber:
10070 * @str: A string to scan
10072 * [30a] Float ::= Number ('e' Digits?)?
10074 * [30] Number ::= Digits ('.' Digits?)?
10076 * [31] Digits ::= [0-9]+
10078 * Compile a Number in the string
10079 * In complement of the Number expression, this function also handles
10080 * negative values : '-' Number.
10082 * Returns the double value.
10085 xmlXPathStringEvalNumber(const xmlChar
*str
) {
10086 const xmlChar
*cur
= str
;
10091 int is_exponent_negative
= 0;
10093 unsigned long tmp
= 0;
10096 if (cur
== NULL
) return(0);
10097 while (IS_BLANK_CH(*cur
)) cur
++;
10098 if ((*cur
!= '.') && ((*cur
< '0') || (*cur
> '9')) && (*cur
!= '-')) {
10099 return(xmlXPathNAN
);
10108 * tmp/temp is a workaround against a gcc compiler bug
10109 * http://veillard.com/gcc.bug
10112 while ((*cur
>= '0') && (*cur
<= '9')) {
10114 tmp
= (*cur
- '0');
10117 temp
= (double) tmp
;
10122 while ((*cur
>= '0') && (*cur
<= '9')) {
10123 ret
= ret
* 10 + (*cur
- '0');
10131 double fraction
= 0;
10134 if (((*cur
< '0') || (*cur
> '9')) && (!ok
)) {
10135 return(xmlXPathNAN
);
10137 while (((*cur
>= '0') && (*cur
<= '9')) && (frac
< MAX_FRAC
)) {
10139 fraction
= fraction
* 10 + v
;
10143 fraction
/= my_pow10
[frac
];
10144 ret
= ret
+ fraction
;
10145 while ((*cur
>= '0') && (*cur
<= '9'))
10148 if ((*cur
== 'e') || (*cur
== 'E')) {
10151 is_exponent_negative
= 1;
10153 } else if (*cur
== '+') {
10156 while ((*cur
>= '0') && (*cur
<= '9')) {
10157 exponent
= exponent
* 10 + (*cur
- '0');
10161 while (IS_BLANK_CH(*cur
)) cur
++;
10162 if (*cur
!= 0) return(xmlXPathNAN
);
10163 if (isneg
) ret
= -ret
;
10164 if (is_exponent_negative
) exponent
= -exponent
;
10165 ret
*= pow(10.0, (double)exponent
);
10170 * xmlXPathCompNumber:
10171 * @ctxt: the XPath Parser context
10173 * [30] Number ::= Digits ('.' Digits?)?
10175 * [31] Digits ::= [0-9]+
10177 * Compile a Number, then push it on the stack
10181 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt
)
10186 int is_exponent_negative
= 0;
10188 unsigned long tmp
= 0;
10193 if ((CUR
!= '.') && ((CUR
< '0') || (CUR
> '9'))) {
10194 XP_ERROR(XPATH_NUMBER_ERROR
);
10198 * tmp/temp is a workaround against a gcc compiler bug
10199 * http://veillard.com/gcc.bug
10202 while ((CUR
>= '0') && (CUR
<= '9')) {
10207 temp
= (double) tmp
;
10212 while ((CUR
>= '0') && (CUR
<= '9')) {
10213 ret
= ret
* 10 + (CUR
- '0');
10220 double fraction
= 0;
10223 if (((CUR
< '0') || (CUR
> '9')) && (!ok
)) {
10224 XP_ERROR(XPATH_NUMBER_ERROR
);
10226 while ((CUR
>= '0') && (CUR
<= '9') && (frac
< MAX_FRAC
)) {
10228 fraction
= fraction
* 10 + v
;
10232 fraction
/= my_pow10
[frac
];
10233 ret
= ret
+ fraction
;
10234 while ((CUR
>= '0') && (CUR
<= '9'))
10237 if ((CUR
== 'e') || (CUR
== 'E')) {
10240 is_exponent_negative
= 1;
10242 } else if (CUR
== '+') {
10245 while ((CUR
>= '0') && (CUR
<= '9')) {
10246 exponent
= exponent
* 10 + (CUR
- '0');
10249 if (is_exponent_negative
)
10250 exponent
= -exponent
;
10251 ret
*= pow(10.0, (double) exponent
);
10253 PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_NUMBER
, 0, 0,
10254 xmlXPathCacheNewFloat(ctxt
->context
, ret
), NULL
);
10258 * xmlXPathParseLiteral:
10259 * @ctxt: the XPath Parser context
10263 * [29] Literal ::= '"' [^"]* '"'
10266 * Returns the value found or NULL in case of error
10269 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt
) {
10271 xmlChar
*ret
= NULL
;
10276 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10278 if (!IS_CHAR_CH(CUR
)) {
10279 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10281 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10284 } else if (CUR
== '\'') {
10287 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10289 if (!IS_CHAR_CH(CUR
)) {
10290 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10292 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10296 XP_ERRORNULL(XPATH_START_LITERAL_ERROR
);
10302 * xmlXPathCompLiteral:
10303 * @ctxt: the XPath Parser context
10305 * Parse a Literal and push it on the stack.
10307 * [29] Literal ::= '"' [^"]* '"'
10310 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10313 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt
) {
10315 xmlChar
*ret
= NULL
;
10320 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10322 if (!IS_CHAR_CH(CUR
)) {
10323 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10325 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10328 } else if (CUR
== '\'') {
10331 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10333 if (!IS_CHAR_CH(CUR
)) {
10334 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10336 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10340 XP_ERROR(XPATH_START_LITERAL_ERROR
);
10342 if (ret
== NULL
) return;
10343 PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_STRING
, 0, 0,
10344 xmlXPathCacheNewString(ctxt
->context
, ret
), NULL
);
10349 * xmlXPathCompVariableReference:
10350 * @ctxt: the XPath Parser context
10352 * Parse a VariableReference, evaluate it and push it on the stack.
10354 * The variable bindings consist of a mapping from variable names
10355 * to variable values. The value of a variable is an object, which can be
10356 * of any of the types that are possible for the value of an expression,
10357 * and may also be of additional types not specified here.
10359 * Early evaluation is possible since:
10360 * The variable bindings [...] used to evaluate a subexpression are
10361 * always the same as those used to evaluate the containing expression.
10363 * [36] VariableReference ::= '$' QName
10366 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt
) {
10372 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10375 name
= xmlXPathParseQName(ctxt
, &prefix
);
10376 if (name
== NULL
) {
10377 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10379 ctxt
->comp
->last
= -1;
10380 PUSH_LONG_EXPR(XPATH_OP_VARIABLE
, 0, 0, 0,
10383 if ((ctxt
->context
!= NULL
) && (ctxt
->context
->flags
& XML_XPATH_NOVAR
)) {
10384 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR
);
10389 * xmlXPathIsNodeType:
10390 * @name: a name string
10392 * Is the name given a NodeType one.
10394 * [38] NodeType ::= 'comment'
10396 * | 'processing-instruction'
10399 * Returns 1 if true 0 otherwise
10402 xmlXPathIsNodeType(const xmlChar
*name
) {
10406 if (xmlStrEqual(name
, BAD_CAST
"node"))
10408 if (xmlStrEqual(name
, BAD_CAST
"text"))
10410 if (xmlStrEqual(name
, BAD_CAST
"comment"))
10412 if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
10418 * xmlXPathCompFunctionCall:
10419 * @ctxt: the XPath Parser context
10421 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10422 * [17] Argument ::= Expr
10424 * Compile a function call, the evaluation of all arguments are
10425 * pushed on the stack
10428 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt
) {
10434 name
= xmlXPathParseQName(ctxt
, &prefix
);
10435 if (name
== NULL
) {
10437 XP_ERROR(XPATH_EXPR_ERROR
);
10441 if (prefix
== NULL
)
10442 xmlGenericError(xmlGenericErrorContext
, "Calling function %s\n",
10445 xmlGenericError(xmlGenericErrorContext
, "Calling function %s:%s\n",
10450 XP_ERROR(XPATH_EXPR_ERROR
);
10456 * Optimization for count(): we don't need the node-set to be sorted.
10458 if ((prefix
== NULL
) && (name
[0] == 'c') &&
10459 xmlStrEqual(name
, BAD_CAST
"count"))
10463 ctxt
->comp
->last
= -1;
10466 int op1
= ctxt
->comp
->last
;
10467 ctxt
->comp
->last
= -1;
10468 xmlXPathCompileExpr(ctxt
, sort
);
10469 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
10474 PUSH_BINARY_EXPR(XPATH_OP_ARG
, op1
, ctxt
->comp
->last
, 0, 0);
10476 if (CUR
== ')') break;
10478 XP_ERROR(XPATH_EXPR_ERROR
);
10484 PUSH_LONG_EXPR(XPATH_OP_FUNCTION
, nbargs
, 0, 0,
10491 * xmlXPathCompPrimaryExpr:
10492 * @ctxt: the XPath Parser context
10494 * [15] PrimaryExpr ::= VariableReference
10500 * Compile a primary expression.
10503 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt
) {
10505 if (CUR
== '$') xmlXPathCompVariableReference(ctxt
);
10506 else if (CUR
== '(') {
10509 xmlXPathCompileExpr(ctxt
, 1);
10512 XP_ERROR(XPATH_EXPR_ERROR
);
10516 } else if (IS_ASCII_DIGIT(CUR
) || (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10517 xmlXPathCompNumber(ctxt
);
10518 } else if ((CUR
== '\'') || (CUR
== '"')) {
10519 xmlXPathCompLiteral(ctxt
);
10521 xmlXPathCompFunctionCall(ctxt
);
10527 * xmlXPathCompFilterExpr:
10528 * @ctxt: the XPath Parser context
10530 * [20] FilterExpr ::= PrimaryExpr
10531 * | FilterExpr Predicate
10533 * Compile a filter expression.
10534 * Square brackets are used to filter expressions in the same way that
10535 * they are used in location paths. It is an error if the expression to
10536 * be filtered does not evaluate to a node-set. The context node list
10537 * used for evaluating the expression in square brackets is the node-set
10538 * to be filtered listed in document order.
10542 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt
) {
10543 xmlXPathCompPrimaryExpr(ctxt
);
10547 while (CUR
== '[') {
10548 xmlXPathCompPredicate(ctxt
, 1);
10556 * xmlXPathScanName:
10557 * @ctxt: the XPath Parser context
10559 * Trickery: parse an XML name but without consuming the input flow
10560 * Needed to avoid insanity in the parser state.
10562 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10563 * CombiningChar | Extender
10565 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10567 * [6] Names ::= Name (S Name)*
10569 * Returns the Name parsed or NULL
10573 xmlXPathScanName(xmlXPathParserContextPtr ctxt
) {
10576 const xmlChar
*cur
;
10582 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
10583 (!IS_LETTER(c
) && (c
!= '_') &&
10588 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
10589 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
10590 (c
== '.') || (c
== '-') ||
10591 (c
== '_') || (c
== ':') ||
10592 (IS_COMBINING(c
)) ||
10593 (IS_EXTENDER(c
)))) {
10598 ret
= xmlStrndup(cur
, ctxt
->cur
- cur
);
10604 * xmlXPathCompPathExpr:
10605 * @ctxt: the XPath Parser context
10607 * [19] PathExpr ::= LocationPath
10609 * | FilterExpr '/' RelativeLocationPath
10610 * | FilterExpr '//' RelativeLocationPath
10612 * Compile a path expression.
10613 * The / operator and // operators combine an arbitrary expression
10614 * and a relative location path. It is an error if the expression
10615 * does not evaluate to a node-set.
10616 * The / operator does composition in the same way as when / is
10617 * used in a location path. As in location paths, // is short for
10618 * /descendant-or-self::node()/.
10622 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt
) {
10623 int lc
= 1; /* Should we branch to LocationPath ? */
10624 xmlChar
*name
= NULL
; /* we may have to preparse a name to find out */
10627 if ((CUR
== '$') || (CUR
== '(') ||
10628 (IS_ASCII_DIGIT(CUR
)) ||
10629 (CUR
== '\'') || (CUR
== '"') ||
10630 (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10632 } else if (CUR
== '*') {
10633 /* relative or absolute location path */
10635 } else if (CUR
== '/') {
10636 /* relative or absolute location path */
10638 } else if (CUR
== '@') {
10639 /* relative abbreviated attribute location path */
10641 } else if (CUR
== '.') {
10642 /* relative abbreviated attribute location path */
10646 * Problem is finding if we have a name here whether it's:
10648 * - a function call in which case it's followed by '('
10649 * - an axis in which case it's followed by ':'
10651 * We do an a priori analysis here rather than having to
10652 * maintain parsed token content through the recursive function
10653 * calls. This looks uglier but makes the code easier to
10654 * read/write/debug.
10657 name
= xmlXPathScanName(ctxt
);
10658 if ((name
!= NULL
) && (xmlStrstr(name
, (xmlChar
*) "::") != NULL
)) {
10660 xmlGenericError(xmlGenericErrorContext
,
10661 "PathExpr: Axis\n");
10665 } else if (name
!= NULL
) {
10666 int len
=xmlStrlen(name
);
10669 while (NXT(len
) != 0) {
10670 if (NXT(len
) == '/') {
10673 xmlGenericError(xmlGenericErrorContext
,
10674 "PathExpr: AbbrRelLocation\n");
10678 } else if (IS_BLANK_CH(NXT(len
))) {
10679 /* ignore blanks */
10681 } else if (NXT(len
) == ':') {
10683 xmlGenericError(xmlGenericErrorContext
,
10684 "PathExpr: AbbrRelLocation\n");
10688 } else if ((NXT(len
) == '(')) {
10689 /* Note Type or Function */
10690 if (xmlXPathIsNodeType(name
)) {
10692 xmlGenericError(xmlGenericErrorContext
,
10693 "PathExpr: Type search\n");
10698 xmlGenericError(xmlGenericErrorContext
,
10699 "PathExpr: function call\n");
10704 } else if ((NXT(len
) == '[')) {
10707 xmlGenericError(xmlGenericErrorContext
,
10708 "PathExpr: AbbrRelLocation\n");
10712 } else if ((NXT(len
) == '<') || (NXT(len
) == '>') ||
10713 (NXT(len
) == '=')) {
10722 if (NXT(len
) == 0) {
10724 xmlGenericError(xmlGenericErrorContext
,
10725 "PathExpr: AbbrRelLocation\n");
10732 /* make sure all cases are covered explicitly */
10733 XP_ERROR(XPATH_EXPR_ERROR
);
10739 PUSH_LEAVE_EXPR(XPATH_OP_ROOT
, 0, 0);
10741 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10743 xmlXPathCompLocationPath(ctxt
);
10745 xmlXPathCompFilterExpr(ctxt
);
10747 if ((CUR
== '/') && (NXT(1) == '/')) {
10751 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
10752 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
10753 PUSH_UNARY_EXPR(XPATH_OP_RESET
, ctxt
->comp
->last
, 1, 0);
10755 xmlXPathCompRelativeLocationPath(ctxt
);
10756 } else if (CUR
== '/') {
10757 xmlXPathCompRelativeLocationPath(ctxt
);
10764 * xmlXPathCompUnionExpr:
10765 * @ctxt: the XPath Parser context
10767 * [18] UnionExpr ::= PathExpr
10768 * | UnionExpr '|' PathExpr
10770 * Compile an union expression.
10774 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt
) {
10775 xmlXPathCompPathExpr(ctxt
);
10778 while (CUR
== '|') {
10779 int op1
= ctxt
->comp
->last
;
10780 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10784 xmlXPathCompPathExpr(ctxt
);
10786 PUSH_BINARY_EXPR(XPATH_OP_UNION
, op1
, ctxt
->comp
->last
, 0, 0);
10793 * xmlXPathCompUnaryExpr:
10794 * @ctxt: the XPath Parser context
10796 * [27] UnaryExpr ::= UnionExpr
10799 * Compile an unary expression.
10803 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt
) {
10808 while (CUR
== '-') {
10815 xmlXPathCompUnionExpr(ctxt
);
10819 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 2, 0);
10821 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 3, 0);
10826 * xmlXPathCompMultiplicativeExpr:
10827 * @ctxt: the XPath Parser context
10829 * [26] MultiplicativeExpr ::= UnaryExpr
10830 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10831 * | MultiplicativeExpr 'div' UnaryExpr
10832 * | MultiplicativeExpr 'mod' UnaryExpr
10833 * [34] MultiplyOperator ::= '*'
10835 * Compile an Additive expression.
10839 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt
) {
10840 xmlXPathCompUnaryExpr(ctxt
);
10843 while ((CUR
== '*') ||
10844 ((CUR
== 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10845 ((CUR
== 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10847 int op1
= ctxt
->comp
->last
;
10852 } else if (CUR
== 'd') {
10855 } else if (CUR
== 'm') {
10860 xmlXPathCompUnaryExpr(ctxt
);
10862 PUSH_BINARY_EXPR(XPATH_OP_MULT
, op1
, ctxt
->comp
->last
, op
, 0);
10868 * xmlXPathCompAdditiveExpr:
10869 * @ctxt: the XPath Parser context
10871 * [25] AdditiveExpr ::= MultiplicativeExpr
10872 * | AdditiveExpr '+' MultiplicativeExpr
10873 * | AdditiveExpr '-' MultiplicativeExpr
10875 * Compile an Additive expression.
10879 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt
) {
10881 xmlXPathCompMultiplicativeExpr(ctxt
);
10884 while ((CUR
== '+') || (CUR
== '-')) {
10886 int op1
= ctxt
->comp
->last
;
10888 if (CUR
== '+') plus
= 1;
10892 xmlXPathCompMultiplicativeExpr(ctxt
);
10894 PUSH_BINARY_EXPR(XPATH_OP_PLUS
, op1
, ctxt
->comp
->last
, plus
, 0);
10900 * xmlXPathCompRelationalExpr:
10901 * @ctxt: the XPath Parser context
10903 * [24] RelationalExpr ::= AdditiveExpr
10904 * | RelationalExpr '<' AdditiveExpr
10905 * | RelationalExpr '>' AdditiveExpr
10906 * | RelationalExpr '<=' AdditiveExpr
10907 * | RelationalExpr '>=' AdditiveExpr
10909 * A <= B > C is allowed ? Answer from James, yes with
10910 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10911 * which is basically what got implemented.
10913 * Compile a Relational expression, then push the result
10918 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt
) {
10919 xmlXPathCompAdditiveExpr(ctxt
);
10922 while ((CUR
== '<') ||
10924 ((CUR
== '<') && (NXT(1) == '=')) ||
10925 ((CUR
== '>') && (NXT(1) == '='))) {
10927 int op1
= ctxt
->comp
->last
;
10929 if (CUR
== '<') inf
= 1;
10931 if (NXT(1) == '=') strict
= 0;
10936 xmlXPathCompAdditiveExpr(ctxt
);
10938 PUSH_BINARY_EXPR(XPATH_OP_CMP
, op1
, ctxt
->comp
->last
, inf
, strict
);
10944 * xmlXPathCompEqualityExpr:
10945 * @ctxt: the XPath Parser context
10947 * [23] EqualityExpr ::= RelationalExpr
10948 * | EqualityExpr '=' RelationalExpr
10949 * | EqualityExpr '!=' RelationalExpr
10951 * A != B != C is allowed ? Answer from James, yes with
10952 * (RelationalExpr = RelationalExpr) = RelationalExpr
10953 * (RelationalExpr != RelationalExpr) != RelationalExpr
10954 * which is basically what got implemented.
10956 * Compile an Equality expression.
10960 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt
) {
10961 xmlXPathCompRelationalExpr(ctxt
);
10964 while ((CUR
== '=') || ((CUR
== '!') && (NXT(1) == '='))) {
10966 int op1
= ctxt
->comp
->last
;
10968 if (CUR
== '=') eq
= 1;
10973 xmlXPathCompRelationalExpr(ctxt
);
10975 PUSH_BINARY_EXPR(XPATH_OP_EQUAL
, op1
, ctxt
->comp
->last
, eq
, 0);
10981 * xmlXPathCompAndExpr:
10982 * @ctxt: the XPath Parser context
10984 * [22] AndExpr ::= EqualityExpr
10985 * | AndExpr 'and' EqualityExpr
10987 * Compile an AND expression.
10991 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt
) {
10992 xmlXPathCompEqualityExpr(ctxt
);
10995 while ((CUR
== 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10996 int op1
= ctxt
->comp
->last
;
10999 xmlXPathCompEqualityExpr(ctxt
);
11001 PUSH_BINARY_EXPR(XPATH_OP_AND
, op1
, ctxt
->comp
->last
, 0, 0);
11007 * xmlXPathCompileExpr:
11008 * @ctxt: the XPath Parser context
11010 * [14] Expr ::= OrExpr
11011 * [21] OrExpr ::= AndExpr
11012 * | OrExpr 'or' AndExpr
11014 * Parse and compile an expression
11017 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
) {
11018 xmlXPathCompAndExpr(ctxt
);
11021 while ((CUR
== 'o') && (NXT(1) == 'r')) {
11022 int op1
= ctxt
->comp
->last
;
11025 xmlXPathCompAndExpr(ctxt
);
11027 PUSH_BINARY_EXPR(XPATH_OP_OR
, op1
, ctxt
->comp
->last
, 0, 0);
11030 if ((sort
) && (ctxt
->comp
->steps
[ctxt
->comp
->last
].op
!= XPATH_OP_VALUE
)) {
11031 /* more ops could be optimized too */
11033 * This is the main place to eliminate sorting for
11034 * operations which don't require a sorted node-set.
11037 PUSH_UNARY_EXPR(XPATH_OP_SORT
, ctxt
->comp
->last
, 0, 0);
11042 * xmlXPathCompPredicate:
11043 * @ctxt: the XPath Parser context
11044 * @filter: act as a filter
11046 * [8] Predicate ::= '[' PredicateExpr ']'
11047 * [9] PredicateExpr ::= Expr
11049 * Compile a predicate expression
11052 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
) {
11053 int op1
= ctxt
->comp
->last
;
11057 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11062 ctxt
->comp
->last
= -1;
11064 * This call to xmlXPathCompileExpr() will deactivate sorting
11065 * of the predicate result.
11066 * TODO: Sorting is still activated for filters, since I'm not
11067 * sure if needed. Normally sorting should not be needed, since
11068 * a filter can only diminish the number of items in a sequence,
11069 * but won't change its order; so if the initial sequence is sorted,
11070 * subsequent sorting is not needed.
11073 xmlXPathCompileExpr(ctxt
, 0);
11075 xmlXPathCompileExpr(ctxt
, 1);
11079 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11083 PUSH_BINARY_EXPR(XPATH_OP_FILTER
, op1
, ctxt
->comp
->last
, 0, 0);
11085 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE
, op1
, ctxt
->comp
->last
, 0, 0);
11092 * xmlXPathCompNodeTest:
11093 * @ctxt: the XPath Parser context
11094 * @test: pointer to a xmlXPathTestVal
11095 * @type: pointer to a xmlXPathTypeVal
11096 * @prefix: placeholder for a possible name prefix
11098 * [7] NodeTest ::= NameTest
11099 * | NodeType '(' ')'
11100 * | 'processing-instruction' '(' Literal ')'
11102 * [37] NameTest ::= '*'
11105 * [38] NodeType ::= 'comment'
11107 * | 'processing-instruction'
11110 * Returns the name found and updates @test, @type and @prefix appropriately
11113 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt
, xmlXPathTestVal
*test
,
11114 xmlXPathTypeVal
*type
, const xmlChar
**prefix
,
11118 if ((test
== NULL
) || (type
== NULL
) || (prefix
== NULL
)) {
11122 *type
= (xmlXPathTypeVal
) 0;
11123 *test
= (xmlXPathTestVal
) 0;
11127 if ((name
== NULL
) && (CUR
== '*')) {
11132 *test
= NODE_TEST_ALL
;
11137 name
= xmlXPathParseNCName(ctxt
);
11138 if (name
== NULL
) {
11139 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11142 blanks
= IS_BLANK_CH(CUR
);
11147 * NodeType or PI search
11149 if (xmlStrEqual(name
, BAD_CAST
"comment"))
11150 *type
= NODE_TYPE_COMMENT
;
11151 else if (xmlStrEqual(name
, BAD_CAST
"node"))
11152 *type
= NODE_TYPE_NODE
;
11153 else if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
11154 *type
= NODE_TYPE_PI
;
11155 else if (xmlStrEqual(name
, BAD_CAST
"text"))
11156 *type
= NODE_TYPE_TEXT
;
11160 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11163 *test
= NODE_TEST_TYPE
;
11166 if (*type
== NODE_TYPE_PI
) {
11168 * Specific case: search a PI by name.
11174 name
= xmlXPathParseLiteral(ctxt
);
11176 *test
= NODE_TEST_PI
;
11183 XP_ERRORNULL(XPATH_UNCLOSED_ERROR
);
11188 *test
= NODE_TEST_NAME
;
11189 if ((!blanks
) && (CUR
== ':')) {
11193 * Since currently the parser context don't have a
11194 * namespace list associated:
11195 * The namespace name for this prefix can be computed
11196 * only at evaluation time. The compilation is done
11197 * outside of any context.
11200 *prefix
= xmlXPathNsLookup(ctxt
->context
, name
);
11203 if (*prefix
== NULL
) {
11204 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
11215 *test
= NODE_TEST_ALL
;
11219 name
= xmlXPathParseNCName(ctxt
);
11220 if (name
== NULL
) {
11221 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11228 * xmlXPathIsAxisName:
11229 * @name: a preparsed name token
11231 * [6] AxisName ::= 'ancestor'
11232 * | 'ancestor-or-self'
11236 * | 'descendant-or-self'
11238 * | 'following-sibling'
11242 * | 'preceding-sibling'
11245 * Returns the axis or 0
11247 static xmlXPathAxisVal
11248 xmlXPathIsAxisName(const xmlChar
*name
) {
11249 xmlXPathAxisVal ret
= (xmlXPathAxisVal
) 0;
11252 if (xmlStrEqual(name
, BAD_CAST
"ancestor"))
11253 ret
= AXIS_ANCESTOR
;
11254 if (xmlStrEqual(name
, BAD_CAST
"ancestor-or-self"))
11255 ret
= AXIS_ANCESTOR_OR_SELF
;
11256 if (xmlStrEqual(name
, BAD_CAST
"attribute"))
11257 ret
= AXIS_ATTRIBUTE
;
11260 if (xmlStrEqual(name
, BAD_CAST
"child"))
11264 if (xmlStrEqual(name
, BAD_CAST
"descendant"))
11265 ret
= AXIS_DESCENDANT
;
11266 if (xmlStrEqual(name
, BAD_CAST
"descendant-or-self"))
11267 ret
= AXIS_DESCENDANT_OR_SELF
;
11270 if (xmlStrEqual(name
, BAD_CAST
"following"))
11271 ret
= AXIS_FOLLOWING
;
11272 if (xmlStrEqual(name
, BAD_CAST
"following-sibling"))
11273 ret
= AXIS_FOLLOWING_SIBLING
;
11276 if (xmlStrEqual(name
, BAD_CAST
"namespace"))
11277 ret
= AXIS_NAMESPACE
;
11280 if (xmlStrEqual(name
, BAD_CAST
"parent"))
11282 if (xmlStrEqual(name
, BAD_CAST
"preceding"))
11283 ret
= AXIS_PRECEDING
;
11284 if (xmlStrEqual(name
, BAD_CAST
"preceding-sibling"))
11285 ret
= AXIS_PRECEDING_SIBLING
;
11288 if (xmlStrEqual(name
, BAD_CAST
"self"))
11296 * xmlXPathCompStep:
11297 * @ctxt: the XPath Parser context
11299 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11300 * | AbbreviatedStep
11302 * [12] AbbreviatedStep ::= '.' | '..'
11304 * [5] AxisSpecifier ::= AxisName '::'
11305 * | AbbreviatedAxisSpecifier
11307 * [13] AbbreviatedAxisSpecifier ::= '@'?
11309 * Modified for XPtr range support as:
11311 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11312 * | AbbreviatedStep
11313 * | 'range-to' '(' Expr ')' Predicate*
11315 * Compile one step in a Location Path
11316 * A location step of . is short for self::node(). This is
11317 * particularly useful in conjunction with //. For example, the
11318 * location path .//para is short for
11319 * self::node()/descendant-or-self::node()/child::para
11320 * and so will select all para descendant elements of the context
11322 * Similarly, a location step of .. is short for parent::node().
11323 * For example, ../title is short for parent::node()/child::title
11324 * and so will select the title children of the parent of the context
11328 xmlXPathCompStep(xmlXPathParserContextPtr ctxt
) {
11329 #ifdef LIBXML_XPTR_ENABLED
11335 if ((CUR
== '.') && (NXT(1) == '.')) {
11338 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_PARENT
,
11339 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11340 } else if (CUR
== '.') {
11344 xmlChar
*name
= NULL
;
11345 const xmlChar
*prefix
= NULL
;
11346 xmlXPathTestVal test
= (xmlXPathTestVal
) 0;
11347 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) 0;
11348 xmlXPathTypeVal type
= (xmlXPathTypeVal
) 0;
11352 * The modification needed for XPointer change to the production
11354 #ifdef LIBXML_XPTR_ENABLED
11356 name
= xmlXPathParseNCName(ctxt
);
11357 if ((name
!= NULL
) && (xmlStrEqual(name
, BAD_CAST
"range-to"))) {
11358 op2
= ctxt
->comp
->last
;
11362 XP_ERROR(XPATH_EXPR_ERROR
);
11367 xmlXPathCompileExpr(ctxt
, 1);
11368 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11373 XP_ERROR(XPATH_EXPR_ERROR
);
11377 goto eval_predicates
;
11385 name
= xmlXPathParseNCName(ctxt
);
11386 if (name
!= NULL
) {
11387 axis
= xmlXPathIsAxisName(name
);
11390 if ((CUR
== ':') && (NXT(1) == ':')) {
11395 /* an element name can conflict with an axis one :-\ */
11401 } else if (CUR
== '@') {
11403 axis
= AXIS_ATTRIBUTE
;
11409 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
11414 name
= xmlXPathCompNodeTest(ctxt
, &test
, &type
, &prefix
, name
);
11418 if ((prefix
!= NULL
) && (ctxt
->context
!= NULL
) &&
11419 (ctxt
->context
->flags
& XML_XPATH_CHECKNS
)) {
11420 if (xmlXPathNsLookup(ctxt
->context
, prefix
) == NULL
) {
11421 xmlXPathErr(ctxt
, XPATH_UNDEF_PREFIX_ERROR
);
11425 xmlGenericError(xmlGenericErrorContext
,
11426 "Basis : computing new set\n");
11430 xmlGenericError(xmlGenericErrorContext
, "Basis : ");
11431 if (ctxt
->value
== NULL
)
11432 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11433 else if (ctxt
->value
->nodesetval
== NULL
)
11434 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11436 xmlGenericErrorContextNodeSet(stdout
, ctxt
->value
->nodesetval
);
11439 #ifdef LIBXML_XPTR_ENABLED
11442 op1
= ctxt
->comp
->last
;
11443 ctxt
->comp
->last
= -1;
11446 while (CUR
== '[') {
11447 xmlXPathCompPredicate(ctxt
, 0);
11450 #ifdef LIBXML_XPTR_ENABLED
11452 PUSH_BINARY_EXPR(XPATH_OP_RANGETO
, op2
, op1
, 0, 0);
11455 PUSH_FULL_EXPR(XPATH_OP_COLLECT
, op1
, ctxt
->comp
->last
, axis
,
11456 test
, type
, (void *)prefix
, (void *)name
);
11460 xmlGenericError(xmlGenericErrorContext
, "Step : ");
11461 if (ctxt
->value
== NULL
)
11462 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11463 else if (ctxt
->value
->nodesetval
== NULL
)
11464 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11466 xmlGenericErrorContextNodeSet(xmlGenericErrorContext
,
11467 ctxt
->value
->nodesetval
);
11472 * xmlXPathCompRelativeLocationPath:
11473 * @ctxt: the XPath Parser context
11475 * [3] RelativeLocationPath ::= Step
11476 * | RelativeLocationPath '/' Step
11477 * | AbbreviatedRelativeLocationPath
11478 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11480 * Compile a relative location path.
11483 xmlXPathCompRelativeLocationPath
11484 (xmlXPathParserContextPtr ctxt
) {
11486 if ((CUR
== '/') && (NXT(1) == '/')) {
11489 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11490 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11491 } else if (CUR
== '/') {
11495 xmlXPathCompStep(ctxt
);
11498 while (CUR
== '/') {
11499 if ((CUR
== '/') && (NXT(1) == '/')) {
11502 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11503 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11504 xmlXPathCompStep(ctxt
);
11505 } else if (CUR
== '/') {
11508 xmlXPathCompStep(ctxt
);
11515 * xmlXPathCompLocationPath:
11516 * @ctxt: the XPath Parser context
11518 * [1] LocationPath ::= RelativeLocationPath
11519 * | AbsoluteLocationPath
11520 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11521 * | AbbreviatedAbsoluteLocationPath
11522 * [10] AbbreviatedAbsoluteLocationPath ::=
11523 * '//' RelativeLocationPath
11525 * Compile a location path
11527 * // is short for /descendant-or-self::node()/. For example,
11528 * //para is short for /descendant-or-self::node()/child::para and
11529 * so will select any para element in the document (even a para element
11530 * that is a document element will be selected by //para since the
11531 * document element node is a child of the root node); div//para is
11532 * short for div/descendant-or-self::node()/child::para and so will
11533 * select all para descendants of div children.
11536 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
) {
11539 xmlXPathCompRelativeLocationPath(ctxt
);
11541 while (CUR
== '/') {
11542 if ((CUR
== '/') && (NXT(1) == '/')) {
11545 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11546 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11547 xmlXPathCompRelativeLocationPath(ctxt
);
11548 } else if (CUR
== '/') {
11552 ((IS_ASCII_LETTER(CUR
)) || (CUR
== '_') || (CUR
== '.') ||
11553 (CUR
== '@') || (CUR
== '*')))
11554 xmlXPathCompRelativeLocationPath(ctxt
);
11561 /************************************************************************
11563 * XPath precompiled expression evaluation *
11565 ************************************************************************/
11568 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
);
11572 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op
,
11575 xmlGenericError(xmlGenericErrorContext
, "new step : ");
11576 switch (op
->value
) {
11577 case AXIS_ANCESTOR
:
11578 xmlGenericError(xmlGenericErrorContext
, "axis 'ancestors' ");
11580 case AXIS_ANCESTOR_OR_SELF
:
11581 xmlGenericError(xmlGenericErrorContext
,
11582 "axis 'ancestors-or-self' ");
11584 case AXIS_ATTRIBUTE
:
11585 xmlGenericError(xmlGenericErrorContext
, "axis 'attributes' ");
11588 xmlGenericError(xmlGenericErrorContext
, "axis 'child' ");
11590 case AXIS_DESCENDANT
:
11591 xmlGenericError(xmlGenericErrorContext
, "axis 'descendant' ");
11593 case AXIS_DESCENDANT_OR_SELF
:
11594 xmlGenericError(xmlGenericErrorContext
,
11595 "axis 'descendant-or-self' ");
11597 case AXIS_FOLLOWING
:
11598 xmlGenericError(xmlGenericErrorContext
, "axis 'following' ");
11600 case AXIS_FOLLOWING_SIBLING
:
11601 xmlGenericError(xmlGenericErrorContext
,
11602 "axis 'following-siblings' ");
11604 case AXIS_NAMESPACE
:
11605 xmlGenericError(xmlGenericErrorContext
, "axis 'namespace' ");
11608 xmlGenericError(xmlGenericErrorContext
, "axis 'parent' ");
11610 case AXIS_PRECEDING
:
11611 xmlGenericError(xmlGenericErrorContext
, "axis 'preceding' ");
11613 case AXIS_PRECEDING_SIBLING
:
11614 xmlGenericError(xmlGenericErrorContext
,
11615 "axis 'preceding-sibling' ");
11618 xmlGenericError(xmlGenericErrorContext
, "axis 'self' ");
11621 xmlGenericError(xmlGenericErrorContext
,
11622 " context contains %d nodes\n", nbNodes
);
11623 switch (op
->value2
) {
11624 case NODE_TEST_NONE
:
11625 xmlGenericError(xmlGenericErrorContext
,
11626 " searching for none !!!\n");
11628 case NODE_TEST_TYPE
:
11629 xmlGenericError(xmlGenericErrorContext
,
11630 " searching for type %d\n", op
->value3
);
11633 xmlGenericError(xmlGenericErrorContext
,
11634 " searching for PI !!!\n");
11636 case NODE_TEST_ALL
:
11637 xmlGenericError(xmlGenericErrorContext
,
11638 " searching for *\n");
11641 xmlGenericError(xmlGenericErrorContext
,
11642 " searching for namespace %s\n",
11645 case NODE_TEST_NAME
:
11646 xmlGenericError(xmlGenericErrorContext
,
11647 " searching for name %s\n", op
->value5
);
11649 xmlGenericError(xmlGenericErrorContext
,
11650 " with namespace %s\n", op
->value4
);
11653 xmlGenericError(xmlGenericErrorContext
, "Testing : ");
11655 #endif /* DEBUG_STEP */
11658 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt
,
11659 xmlXPathStepOpPtr op
,
11664 if (op
->ch1
!= -1) {
11665 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11667 * Process inner predicates first.
11669 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11671 * TODO: raise an internal error.
11674 contextSize
= xmlXPathCompOpEvalPredicate(ctxt
,
11675 &comp
->steps
[op
->ch1
], set
, contextSize
, hasNsNodes
);
11677 if (contextSize
<= 0)
11680 if (op
->ch2
!= -1) {
11681 xmlXPathContextPtr xpctxt
= ctxt
->context
;
11682 xmlNodePtr contextNode
, oldContextNode
;
11683 xmlDocPtr oldContextDoc
;
11684 int i
, res
, contextPos
= 0, newContextSize
;
11685 xmlXPathStepOpPtr exprOp
;
11686 xmlXPathObjectPtr contextObj
= NULL
, exprRes
= NULL
;
11688 #ifdef LIBXML_XPTR_ENABLED
11690 * URGENT TODO: Check the following:
11691 * We don't expect location sets if evaluating prediates, right?
11692 * Only filters should expect location sets, right?
11697 * "For each node in the node-set to be filtered, the
11698 * PredicateExpr is evaluated with that node as the
11699 * context node, with the number of nodes in the
11700 * node-set as the context size, and with the proximity
11701 * position of the node in the node-set with respect to
11702 * the axis as the context position;"
11703 * @oldset is the node-set" to be filtered.
11706 * "only predicates change the context position and
11707 * context size (see [2.4 Predicates])."
11709 * node-set context pos
11713 * After applying predicate [position() > 1] :
11714 * node-set context pos
11718 oldContextNode
= xpctxt
->node
;
11719 oldContextDoc
= xpctxt
->doc
;
11721 * Get the expression of this predicate.
11723 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11724 newContextSize
= 0;
11725 for (i
= 0; i
< set
->nodeNr
; i
++) {
11726 if (set
->nodeTab
[i
] == NULL
)
11729 contextNode
= set
->nodeTab
[i
];
11730 xpctxt
->node
= contextNode
;
11731 xpctxt
->contextSize
= contextSize
;
11732 xpctxt
->proximityPosition
= ++contextPos
;
11735 * Also set the xpath document in case things like
11736 * key() are evaluated in the predicate.
11738 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11739 (contextNode
->doc
!= NULL
))
11740 xpctxt
->doc
= contextNode
->doc
;
11742 * Evaluate the predicate expression with 1 context node
11743 * at a time; this node is packaged into a node set; this
11744 * node set is handed over to the evaluation mechanism.
11746 if (contextObj
== NULL
)
11747 contextObj
= xmlXPathCacheNewNodeSet(xpctxt
, contextNode
);
11749 if (xmlXPathNodeSetAddUnique(contextObj
->nodesetval
,
11750 contextNode
) < 0) {
11751 ctxt
->error
= XPATH_MEMORY_ERROR
;
11752 goto evaluation_exit
;
11756 valuePush(ctxt
, contextObj
);
11758 res
= xmlXPathCompOpEvalToBoolean(ctxt
, exprOp
, 1);
11760 if ((ctxt
->error
!= XPATH_EXPRESSION_OK
) || (res
== -1)) {
11761 xmlXPathNodeSetClear(set
, hasNsNodes
);
11762 newContextSize
= 0;
11763 goto evaluation_exit
;
11770 * Remove the entry from the initial node set.
11772 set
->nodeTab
[i
] = NULL
;
11773 if (contextNode
->type
== XML_NAMESPACE_DECL
)
11774 xmlXPathNodeSetFreeNs((xmlNsPtr
) contextNode
);
11776 if (ctxt
->value
== contextObj
) {
11778 * Don't free the temporary XPath object holding the
11779 * context node, in order to avoid massive recreation
11780 * inside this loop.
11783 xmlXPathNodeSetClear(contextObj
->nodesetval
, hasNsNodes
);
11786 * TODO: The object was lost in the evaluation machinery.
11787 * Can this happen? Maybe in internal-error cases.
11793 if (contextObj
!= NULL
) {
11794 if (ctxt
->value
== contextObj
)
11796 xmlXPathReleaseObject(xpctxt
, contextObj
);
11799 if (exprRes
!= NULL
)
11800 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11802 * Reset/invalidate the context.
11804 xpctxt
->node
= oldContextNode
;
11805 xpctxt
->doc
= oldContextDoc
;
11806 xpctxt
->contextSize
= -1;
11807 xpctxt
->proximityPosition
= -1;
11808 return(newContextSize
);
11810 return(contextSize
);
11814 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt
,
11815 xmlXPathStepOpPtr op
,
11822 if (op
->ch1
!= -1) {
11823 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11824 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11826 * TODO: raise an internal error.
11829 contextSize
= xmlXPathCompOpEvalPredicate(ctxt
,
11830 &comp
->steps
[op
->ch1
], set
, contextSize
, hasNsNodes
);
11832 if (contextSize
<= 0)
11836 * Check if the node set contains a sufficient number of nodes for
11837 * the requested range.
11839 if (contextSize
< minPos
) {
11840 xmlXPathNodeSetClear(set
, hasNsNodes
);
11843 if (op
->ch2
== -1) {
11845 * TODO: Can this ever happen?
11847 return (contextSize
);
11849 xmlDocPtr oldContextDoc
;
11850 int i
, pos
= 0, newContextSize
= 0, contextPos
= 0, res
;
11851 xmlXPathStepOpPtr exprOp
;
11852 xmlXPathObjectPtr contextObj
= NULL
, exprRes
= NULL
;
11853 xmlNodePtr oldContextNode
, contextNode
= NULL
;
11854 xmlXPathContextPtr xpctxt
= ctxt
->context
;
11857 #ifdef LIBXML_XPTR_ENABLED
11859 * URGENT TODO: Check the following:
11860 * We don't expect location sets if evaluating prediates, right?
11861 * Only filters should expect location sets, right?
11863 #endif /* LIBXML_XPTR_ENABLED */
11866 * Save old context.
11868 oldContextNode
= xpctxt
->node
;
11869 oldContextDoc
= xpctxt
->doc
;
11871 * Get the expression of this predicate.
11873 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11874 for (i
= 0; i
< set
->nodeNr
; i
++) {
11875 xmlXPathObjectPtr tmp
;
11877 if (set
->nodeTab
[i
] == NULL
)
11880 contextNode
= set
->nodeTab
[i
];
11881 xpctxt
->node
= contextNode
;
11882 xpctxt
->contextSize
= contextSize
;
11883 xpctxt
->proximityPosition
= ++contextPos
;
11886 * Initialize the new set.
11887 * Also set the xpath document in case things like
11888 * key() evaluation are attempted on the predicate
11890 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11891 (contextNode
->doc
!= NULL
))
11892 xpctxt
->doc
= contextNode
->doc
;
11894 * Evaluate the predicate expression with 1 context node
11895 * at a time; this node is packaged into a node set; this
11896 * node set is handed over to the evaluation mechanism.
11898 if (contextObj
== NULL
)
11899 contextObj
= xmlXPathCacheNewNodeSet(xpctxt
, contextNode
);
11901 if (xmlXPathNodeSetAddUnique(contextObj
->nodesetval
,
11902 contextNode
) < 0) {
11903 ctxt
->error
= XPATH_MEMORY_ERROR
;
11904 goto evaluation_exit
;
11908 frame
= xmlXPathSetFrame(ctxt
);
11909 valuePush(ctxt
, contextObj
);
11910 res
= xmlXPathCompOpEvalToBoolean(ctxt
, exprOp
, 1);
11911 tmp
= valuePop(ctxt
);
11912 xmlXPathPopFrame(ctxt
, frame
);
11914 if ((ctxt
->error
!= XPATH_EXPRESSION_OK
) || (res
== -1)) {
11915 while (tmp
!= contextObj
) {
11917 * Free up the result
11918 * then pop off contextObj, which will be freed later
11920 xmlXPathReleaseObject(xpctxt
, tmp
);
11921 tmp
= valuePop(ctxt
);
11923 goto evaluation_error
;
11925 /* push the result back onto the stack */
11926 valuePush(ctxt
, tmp
);
11931 if (res
&& (pos
>= minPos
) && (pos
<= maxPos
)) {
11933 * Fits in the requested range.
11936 if (minPos
== maxPos
) {
11938 * Only 1 node was requested.
11940 if (contextNode
->type
== XML_NAMESPACE_DECL
) {
11942 * As always: take care of those nasty
11945 set
->nodeTab
[i
] = NULL
;
11947 xmlXPathNodeSetClear(set
, hasNsNodes
);
11949 set
->nodeTab
[0] = contextNode
;
11950 goto evaluation_exit
;
11952 if (pos
== maxPos
) {
11956 xmlXPathNodeSetClearFromPos(set
, i
+1, hasNsNodes
);
11957 goto evaluation_exit
;
11961 * Remove the entry from the initial node set.
11963 set
->nodeTab
[i
] = NULL
;
11964 if (contextNode
->type
== XML_NAMESPACE_DECL
)
11965 xmlXPathNodeSetFreeNs((xmlNsPtr
) contextNode
);
11967 if (exprRes
!= NULL
) {
11968 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11971 if (ctxt
->value
== contextObj
) {
11973 * Don't free the temporary XPath object holding the
11974 * context node, in order to avoid massive recreation
11975 * inside this loop.
11978 xmlXPathNodeSetClear(contextObj
->nodesetval
, hasNsNodes
);
11981 * The object was lost in the evaluation machinery.
11982 * Can this happen? Maybe in case of internal-errors.
11987 goto evaluation_exit
;
11990 xmlXPathNodeSetClear(set
, hasNsNodes
);
11991 newContextSize
= 0;
11994 if (contextObj
!= NULL
) {
11995 if (ctxt
->value
== contextObj
)
11997 xmlXPathReleaseObject(xpctxt
, contextObj
);
11999 if (exprRes
!= NULL
)
12000 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
12002 * Reset/invalidate the context.
12004 xpctxt
->node
= oldContextNode
;
12005 xpctxt
->doc
= oldContextDoc
;
12006 xpctxt
->contextSize
= -1;
12007 xpctxt
->proximityPosition
= -1;
12008 return(newContextSize
);
12010 return(contextSize
);
12014 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt
,
12015 xmlXPathStepOpPtr op
,
12019 xmlXPathStepOpPtr exprOp
;
12022 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12026 * If not -1, then ch1 will point to:
12027 * 1) For predicates (XPATH_OP_PREDICATE):
12028 * - an inner predicate operator
12029 * 2) For filters (XPATH_OP_FILTER):
12030 * - an inner filter operater OR
12031 * - an expression selecting the node set.
12032 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12034 if ((op
->op
!= XPATH_OP_PREDICATE
) && (op
->op
!= XPATH_OP_FILTER
))
12037 if (op
->ch2
!= -1) {
12038 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
12042 if ((exprOp
!= NULL
) &&
12043 (exprOp
->op
== XPATH_OP_VALUE
) &&
12044 (exprOp
->value4
!= NULL
) &&
12045 (((xmlXPathObjectPtr
) exprOp
->value4
)->type
== XPATH_NUMBER
))
12048 * We have a "[n]" predicate here.
12049 * TODO: Unfortunately this simplistic test here is not
12050 * able to detect a position() predicate in compound
12051 * expressions like "[@attr = 'a" and position() = 1],
12052 * and even not the usage of position() in
12053 * "[position() = 1]"; thus - obviously - a position-range,
12054 * like it "[position() < 5]", is also not detected.
12055 * Maybe we could rewrite the AST to ease the optimization.
12057 *maxPos
= (int) ((xmlXPathObjectPtr
) exprOp
->value4
)->floatval
;
12059 if (((xmlXPathObjectPtr
) exprOp
->value4
)->floatval
==
12069 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt
,
12070 xmlXPathStepOpPtr op
,
12071 xmlNodePtr
* first
, xmlNodePtr
* last
,
12075 #define XP_TEST_HIT \
12076 if (hasAxisRange != 0) { \
12077 if (++pos == maxPos) { \
12078 if (addNode(seq, cur) < 0) \
12079 ctxt->error = XPATH_MEMORY_ERROR; \
12080 goto axis_range_end; } \
12082 if (addNode(seq, cur) < 0) \
12083 ctxt->error = XPATH_MEMORY_ERROR; \
12084 if (breakOnFirstHit) goto first_hit; }
12086 #define XP_TEST_HIT_NS \
12087 if (hasAxisRange != 0) { \
12088 if (++pos == maxPos) { \
12090 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12091 ctxt->error = XPATH_MEMORY_ERROR; \
12092 goto axis_range_end; } \
12095 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12096 ctxt->error = XPATH_MEMORY_ERROR; \
12097 if (breakOnFirstHit) goto first_hit; }
12099 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) op
->value
;
12100 xmlXPathTestVal test
= (xmlXPathTestVal
) op
->value2
;
12101 xmlXPathTypeVal type
= (xmlXPathTypeVal
) op
->value3
;
12102 const xmlChar
*prefix
= op
->value4
;
12103 const xmlChar
*name
= op
->value5
;
12104 const xmlChar
*URI
= NULL
;
12107 int nbMatches
= 0, prevMatches
= 0;
12109 int total
= 0, hasNsNodes
= 0;
12110 /* The popped object holding the context nodes */
12111 xmlXPathObjectPtr obj
;
12112 /* The set of context nodes for the node tests */
12113 xmlNodeSetPtr contextSeq
;
12115 xmlNodePtr contextNode
;
12116 /* The final resulting node set wrt to all context nodes */
12117 xmlNodeSetPtr outSeq
;
12119 * The temporary resulting node set wrt 1 context node.
12120 * Used to feed predicate evaluation.
12124 /* First predicate operator */
12125 xmlXPathStepOpPtr predOp
;
12126 int maxPos
; /* The requested position() (when a "[n]" predicate) */
12127 int hasPredicateRange
, hasAxisRange
, pos
, size
, newSize
;
12128 int breakOnFirstHit
;
12130 xmlXPathTraversalFunction next
= NULL
;
12131 int (*addNode
) (xmlNodeSetPtr
, xmlNodePtr
);
12132 xmlXPathNodeSetMergeFunction mergeAndClear
;
12133 xmlNodePtr oldContextNode
;
12134 xmlXPathContextPtr xpctxt
= ctxt
->context
;
12137 CHECK_TYPE0(XPATH_NODESET
);
12138 obj
= valuePop(ctxt
);
12140 * Setup namespaces.
12142 if (prefix
!= NULL
) {
12143 URI
= xmlXPathNsLookup(xpctxt
, prefix
);
12145 xmlXPathReleaseObject(xpctxt
, obj
);
12146 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
12152 * MAYBE FUTURE TODO: merging optimizations:
12153 * - If the nodes to be traversed wrt to the initial nodes and
12154 * the current axis cannot overlap, then we could avoid searching
12155 * for duplicates during the merge.
12156 * But the question is how/when to evaluate if they cannot overlap.
12157 * Example: if we know that for two initial nodes, the one is
12158 * not in the ancestor-or-self axis of the other, then we could safely
12159 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12160 * the descendant-or-self axis.
12162 mergeAndClear
= xmlXPathNodeSetMergeAndClear
;
12164 case AXIS_ANCESTOR
:
12166 next
= xmlXPathNextAncestor
;
12168 case AXIS_ANCESTOR_OR_SELF
:
12170 next
= xmlXPathNextAncestorOrSelf
;
12172 case AXIS_ATTRIBUTE
:
12175 next
= xmlXPathNextAttribute
;
12176 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12180 if (((test
== NODE_TEST_NAME
) || (test
== NODE_TEST_ALL
)) &&
12181 (type
== NODE_TYPE_NODE
))
12184 * Optimization if an element node type is 'element'.
12186 next
= xmlXPathNextChildElement
;
12188 next
= xmlXPathNextChild
;
12189 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12191 case AXIS_DESCENDANT
:
12193 next
= xmlXPathNextDescendant
;
12195 case AXIS_DESCENDANT_OR_SELF
:
12197 next
= xmlXPathNextDescendantOrSelf
;
12199 case AXIS_FOLLOWING
:
12201 next
= xmlXPathNextFollowing
;
12203 case AXIS_FOLLOWING_SIBLING
:
12205 next
= xmlXPathNextFollowingSibling
;
12207 case AXIS_NAMESPACE
:
12210 next
= (xmlXPathTraversalFunction
) xmlXPathNextNamespace
;
12211 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12215 next
= xmlXPathNextParent
;
12217 case AXIS_PRECEDING
:
12219 next
= xmlXPathNextPrecedingInternal
;
12221 case AXIS_PRECEDING_SIBLING
:
12223 next
= xmlXPathNextPrecedingSibling
;
12228 next
= xmlXPathNextSelf
;
12229 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12234 xmlXPathDebugDumpStepAxis(op
,
12235 (obj
->nodesetval
!= NULL
) ? obj
->nodesetval
->nodeNr
: 0);
12238 if (next
== NULL
) {
12239 xmlXPathReleaseObject(xpctxt
, obj
);
12242 contextSeq
= obj
->nodesetval
;
12243 if ((contextSeq
== NULL
) || (contextSeq
->nodeNr
<= 0)) {
12244 xmlXPathReleaseObject(xpctxt
, obj
);
12245 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, NULL
));
12249 * Predicate optimization ---------------------------------------------
12250 * If this step has a last predicate, which contains a position(),
12251 * then we'll optimize (although not exactly "position()", but only
12252 * the short-hand form, i.e., "[n]".
12254 * Example - expression "/foo[parent::bar][1]":
12256 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12258 * PREDICATE -- op->ch2 (predOp)
12259 * PREDICATE -- predOp->ch1 = [parent::bar]
12261 * COLLECT 'parent' 'name' 'node' bar
12263 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12268 hasPredicateRange
= 0;
12270 if (op
->ch2
!= -1) {
12272 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12274 predOp
= &ctxt
->comp
->steps
[op
->ch2
];
12275 if (xmlXPathIsPositionalPredicate(ctxt
, predOp
, &maxPos
)) {
12276 if (predOp
->ch1
!= -1) {
12278 * Use the next inner predicate operator.
12280 predOp
= &ctxt
->comp
->steps
[predOp
->ch1
];
12281 hasPredicateRange
= 1;
12284 * There's no other predicate than the [n] predicate.
12291 breakOnFirstHit
= ((toBool
) && (predOp
== NULL
)) ? 1 : 0;
12293 * Axis traversal -----------------------------------------------------
12297 * - For the attribute axis, the principal node type is attribute.
12298 * - For the namespace axis, the principal node type is namespace.
12299 * - For other axes, the principal node type is element.
12301 * A node test * is true for any node of the
12302 * principal node type. For example, child::* will
12303 * select all element children of the context node
12305 oldContextNode
= xpctxt
->node
;
12306 addNode
= xmlXPathNodeSetAddUnique
;
12309 contextNode
= NULL
;
12313 while (((contextIdx
< contextSeq
->nodeNr
) || (contextNode
!= NULL
)) &&
12314 (ctxt
->error
== XPATH_EXPRESSION_OK
)) {
12315 xpctxt
->node
= contextSeq
->nodeTab
[contextIdx
++];
12318 seq
= xmlXPathNodeSetCreate(NULL
);
12325 * Traverse the axis and test the nodes.
12331 cur
= next(ctxt
, cur
);
12336 * QUESTION TODO: What does the "first" and "last" stuff do?
12338 if ((first
!= NULL
) && (*first
!= NULL
)) {
12341 if (((total
% 256) == 0) &&
12342 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12343 (xmlXPathCmpNodesExt(*first
, cur
) >= 0))
12345 (xmlXPathCmpNodes(*first
, cur
) >= 0))
12351 if ((last
!= NULL
) && (*last
!= NULL
)) {
12354 if (((total
% 256) == 0) &&
12355 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12356 (xmlXPathCmpNodesExt(cur
, *last
) >= 0))
12358 (xmlXPathCmpNodes(cur
, *last
) >= 0))
12368 xmlGenericError(xmlGenericErrorContext
, " %s", cur
->name
);
12372 case NODE_TEST_NONE
:
12376 case NODE_TEST_TYPE
:
12378 * TODO: Don't we need to use
12379 * xmlXPathNodeSetAddNs() for namespace nodes here?
12380 * Surprisingly, some c14n tests fail, if we do this.
12382 if (type
== NODE_TYPE_NODE
) {
12383 switch (cur
->type
) {
12384 case XML_DOCUMENT_NODE
:
12385 case XML_HTML_DOCUMENT_NODE
:
12386 #ifdef LIBXML_DOCB_ENABLED
12387 case XML_DOCB_DOCUMENT_NODE
:
12389 case XML_ELEMENT_NODE
:
12390 case XML_ATTRIBUTE_NODE
:
12392 case XML_COMMENT_NODE
:
12393 case XML_CDATA_SECTION_NODE
:
12394 case XML_TEXT_NODE
:
12395 case XML_NAMESPACE_DECL
:
12401 } else if (cur
->type
== type
) {
12402 if (cur
->type
== XML_NAMESPACE_DECL
)
12406 } else if ((type
== NODE_TYPE_TEXT
) &&
12407 (cur
->type
== XML_CDATA_SECTION_NODE
))
12413 if ((cur
->type
== XML_PI_NODE
) &&
12414 ((name
== NULL
) || xmlStrEqual(name
, cur
->name
)))
12419 case NODE_TEST_ALL
:
12420 if (axis
== AXIS_ATTRIBUTE
) {
12421 if (cur
->type
== XML_ATTRIBUTE_NODE
)
12425 } else if (axis
== AXIS_NAMESPACE
) {
12426 if (cur
->type
== XML_NAMESPACE_DECL
)
12431 if (cur
->type
== XML_ELEMENT_NODE
) {
12432 if (prefix
== NULL
)
12436 } else if ((cur
->ns
!= NULL
) &&
12437 (xmlStrEqual(URI
, cur
->ns
->href
)))
12444 case NODE_TEST_NS
:{
12448 case NODE_TEST_NAME
:
12449 if (axis
== AXIS_ATTRIBUTE
) {
12450 if (cur
->type
!= XML_ATTRIBUTE_NODE
)
12452 } else if (axis
== AXIS_NAMESPACE
) {
12453 if (cur
->type
!= XML_NAMESPACE_DECL
)
12456 if (cur
->type
!= XML_ELEMENT_NODE
)
12459 switch (cur
->type
) {
12460 case XML_ELEMENT_NODE
:
12461 if (xmlStrEqual(name
, cur
->name
)) {
12462 if (prefix
== NULL
) {
12463 if (cur
->ns
== NULL
)
12468 if ((cur
->ns
!= NULL
) &&
12469 (xmlStrEqual(URI
, cur
->ns
->href
)))
12476 case XML_ATTRIBUTE_NODE
:{
12477 xmlAttrPtr attr
= (xmlAttrPtr
) cur
;
12479 if (xmlStrEqual(name
, attr
->name
)) {
12480 if (prefix
== NULL
) {
12481 if ((attr
->ns
== NULL
) ||
12482 (attr
->ns
->prefix
== NULL
))
12487 if ((attr
->ns
!= NULL
) &&
12497 case XML_NAMESPACE_DECL
:
12498 if (cur
->type
== XML_NAMESPACE_DECL
) {
12499 xmlNsPtr ns
= (xmlNsPtr
) cur
;
12501 if ((ns
->prefix
!= NULL
) && (name
!= NULL
)
12502 && (xmlStrEqual(ns
->prefix
, name
)))
12512 } /* switch(test) */
12513 } while ((cur
!= NULL
) && (ctxt
->error
== XPATH_EXPRESSION_OK
));
12515 goto apply_predicates
;
12517 axis_range_end
: /* ----------------------------------------------------- */
12519 * We have a "/foo[n]", and position() = n was reached.
12520 * Note that we can have as well "/foo/::parent::foo[1]", so
12521 * a duplicate-aware merge is still needed.
12522 * Merge with the result.
12524 if (outSeq
== NULL
) {
12528 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12530 * Break if only a true/false result was requested.
12536 first_hit
: /* ---------------------------------------------------------- */
12538 * Break if only a true/false result was requested and
12539 * no predicates existed and a node test succeeded.
12541 if (outSeq
== NULL
) {
12545 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12550 nbMatches
+= seq
->nodeNr
;
12553 apply_predicates
: /* --------------------------------------------------- */
12554 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
12558 * Apply predicates.
12560 if ((predOp
!= NULL
) && (seq
->nodeNr
> 0)) {
12562 * E.g. when we have a "/foo[some expression][n]".
12565 * QUESTION TODO: The old predicate evaluation took into
12566 * account location-sets.
12567 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12568 * Do we expect such a set here?
12569 * All what I learned now from the evaluation semantics
12570 * does not indicate that a location-set will be processed
12571 * here, so this looks OK.
12574 * Iterate over all predicates, starting with the outermost
12576 * TODO: Problem: we cannot execute the inner predicates first
12577 * since we cannot go back *up* the operator tree!
12579 * 1) Use of recursive functions (like is it currently done
12580 * via xmlXPathCompOpEval())
12581 * 2) Add a predicate evaluation information stack to the
12583 * 3) Change the way the operators are linked; we need a
12584 * "parent" field on xmlXPathStepOp
12586 * For the moment, I'll try to solve this with a recursive
12587 * function: xmlXPathCompOpEvalPredicate().
12589 size
= seq
->nodeNr
;
12590 if (hasPredicateRange
!= 0)
12591 newSize
= xmlXPathCompOpEvalPositionalPredicate(ctxt
,
12592 predOp
, seq
, size
, maxPos
, maxPos
, hasNsNodes
);
12594 newSize
= xmlXPathCompOpEvalPredicate(ctxt
,
12595 predOp
, seq
, size
, hasNsNodes
);
12597 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
12602 * Add the filtered set of nodes to the result node set.
12604 if (newSize
== 0) {
12606 * The predicates filtered all nodes out.
12608 xmlXPathNodeSetClear(seq
, hasNsNodes
);
12609 } else if (seq
->nodeNr
> 0) {
12611 * Add to result set.
12613 if (outSeq
== NULL
) {
12614 if (size
!= newSize
) {
12616 * We need to merge and clear here, since
12617 * the sequence will contained NULLed entries.
12619 outSeq
= mergeAndClear(NULL
, seq
, 1);
12625 outSeq
= mergeAndClear(outSeq
, seq
,
12626 (size
!= newSize
) ? 1: 0);
12628 * Break if only a true/false result was requested.
12633 } else if (seq
->nodeNr
> 0) {
12635 * Add to result set.
12637 if (outSeq
== NULL
) {
12641 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12647 if ((obj
->boolval
) && (obj
->user
!= NULL
)) {
12649 * QUESTION TODO: What does this do and why?
12650 * TODO: Do we have to do this also for the "error"
12651 * cleanup further down?
12653 ctxt
->value
->boolval
= 1;
12654 ctxt
->value
->user
= obj
->user
;
12658 xmlXPathReleaseObject(xpctxt
, obj
);
12661 * Ensure we return at least an emtpy set.
12663 if (outSeq
== NULL
) {
12664 if ((seq
!= NULL
) && (seq
->nodeNr
== 0))
12667 outSeq
= xmlXPathNodeSetCreate(NULL
);
12668 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12670 if ((seq
!= NULL
) && (seq
!= outSeq
)) {
12671 xmlXPathFreeNodeSet(seq
);
12674 * Hand over the result. Better to push the set also in
12677 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, outSeq
));
12679 * Reset the context node.
12681 xpctxt
->node
= oldContextNode
;
12684 xmlGenericError(xmlGenericErrorContext
,
12685 "\nExamined %d nodes, found %d nodes at that step\n",
12693 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12694 xmlXPathStepOpPtr op
, xmlNodePtr
* first
);
12697 * xmlXPathCompOpEvalFirst:
12698 * @ctxt: the XPath parser context with the compiled expression
12699 * @op: an XPath compiled operation
12700 * @first: the first elem found so far
12702 * Evaluate the Precompiled XPath operation searching only the first
12703 * element in document order
12705 * Returns the number of examined objects.
12708 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
12709 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12711 int total
= 0, cur
;
12712 xmlXPathCompExprPtr comp
;
12713 xmlXPathObjectPtr arg1
, arg2
;
12720 case XPATH_OP_UNION
:
12722 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12725 if ((ctxt
->value
!= NULL
)
12726 && (ctxt
->value
->type
== XPATH_NODESET
)
12727 && (ctxt
->value
->nodesetval
!= NULL
)
12728 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12730 * limit tree traversing to first node in the result
12733 * OPTIMIZE TODO: This implicitely sorts
12734 * the result, even if not needed. E.g. if the argument
12735 * of the count() function, no sorting is needed.
12736 * OPTIMIZE TODO: How do we know if the node-list wasn't
12739 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12740 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12741 *first
= ctxt
->value
->nodesetval
->nodeTab
[0];
12744 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch2
],
12747 CHECK_TYPE0(XPATH_NODESET
);
12748 arg2
= valuePop(ctxt
);
12750 CHECK_TYPE0(XPATH_NODESET
);
12751 arg1
= valuePop(ctxt
);
12753 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12755 valuePush(ctxt
, arg1
);
12756 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12759 xmlXPathCompSwap(op
);
12760 return (total
+ cur
);
12761 case XPATH_OP_ROOT
:
12762 xmlXPathRoot(ctxt
);
12764 case XPATH_OP_NODE
:
12766 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12769 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12771 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12772 ctxt
->context
->node
));
12774 case XPATH_OP_RESET
:
12776 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12779 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12781 ctxt
->context
->node
= NULL
;
12783 case XPATH_OP_COLLECT
:{
12787 total
= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12790 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, first
, NULL
, 0);
12793 case XPATH_OP_VALUE
:
12795 xmlXPathCacheObjectCopy(ctxt
->context
,
12796 (xmlXPathObjectPtr
) op
->value4
));
12798 case XPATH_OP_SORT
:
12801 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12804 if ((ctxt
->value
!= NULL
)
12805 && (ctxt
->value
->type
== XPATH_NODESET
)
12806 && (ctxt
->value
->nodesetval
!= NULL
)
12807 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12808 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12810 #ifdef XP_OPTIMIZED_FILTER_FIRST
12811 case XPATH_OP_FILTER
:
12812 total
+= xmlXPathCompOpEvalFilterFirst(ctxt
, op
, first
);
12816 return (xmlXPathCompOpEval(ctxt
, op
));
12821 * xmlXPathCompOpEvalLast:
12822 * @ctxt: the XPath parser context with the compiled expression
12823 * @op: an XPath compiled operation
12824 * @last: the last elem found so far
12826 * Evaluate the Precompiled XPath operation searching only the last
12827 * element in document order
12829 * Returns the number of nodes traversed
12832 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
,
12835 int total
= 0, cur
;
12836 xmlXPathCompExprPtr comp
;
12837 xmlXPathObjectPtr arg1
, arg2
;
12848 case XPATH_OP_UNION
:
12849 bakd
= ctxt
->context
->doc
;
12850 bak
= ctxt
->context
->node
;
12851 pp
= ctxt
->context
->proximityPosition
;
12852 cs
= ctxt
->context
->contextSize
;
12854 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
], last
);
12856 if ((ctxt
->value
!= NULL
)
12857 && (ctxt
->value
->type
== XPATH_NODESET
)
12858 && (ctxt
->value
->nodesetval
!= NULL
)
12859 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12861 * limit tree traversing to first node in the result
12863 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12864 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12866 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->value
->
12867 nodesetval
->nodeNr
-
12870 ctxt
->context
->doc
= bakd
;
12871 ctxt
->context
->node
= bak
;
12872 ctxt
->context
->proximityPosition
= pp
;
12873 ctxt
->context
->contextSize
= cs
;
12875 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch2
], last
);
12877 if ((ctxt
->value
!= NULL
)
12878 && (ctxt
->value
->type
== XPATH_NODESET
)
12879 && (ctxt
->value
->nodesetval
!= NULL
)
12880 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) { /* TODO: NOP ? */
12882 CHECK_TYPE0(XPATH_NODESET
);
12883 arg2
= valuePop(ctxt
);
12885 CHECK_TYPE0(XPATH_NODESET
);
12886 arg1
= valuePop(ctxt
);
12888 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12890 valuePush(ctxt
, arg1
);
12891 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12894 xmlXPathCompSwap(op
);
12895 return (total
+ cur
);
12896 case XPATH_OP_ROOT
:
12897 xmlXPathRoot(ctxt
);
12899 case XPATH_OP_NODE
:
12901 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12904 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12906 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12907 ctxt
->context
->node
));
12909 case XPATH_OP_RESET
:
12911 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12914 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12916 ctxt
->context
->node
= NULL
;
12918 case XPATH_OP_COLLECT
:{
12922 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12925 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, last
, 0);
12928 case XPATH_OP_VALUE
:
12930 xmlXPathCacheObjectCopy(ctxt
->context
,
12931 (xmlXPathObjectPtr
) op
->value4
));
12933 case XPATH_OP_SORT
:
12936 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
],
12939 if ((ctxt
->value
!= NULL
)
12940 && (ctxt
->value
->type
== XPATH_NODESET
)
12941 && (ctxt
->value
->nodesetval
!= NULL
)
12942 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12943 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12946 return (xmlXPathCompOpEval(ctxt
, op
));
12950 #ifdef XP_OPTIMIZED_FILTER_FIRST
12952 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12953 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12956 xmlXPathCompExprPtr comp
;
12957 xmlXPathObjectPtr res
;
12958 xmlXPathObjectPtr obj
;
12959 xmlNodeSetPtr oldset
;
12960 xmlNodePtr oldnode
;
12967 * Optimization for ()[last()] selection i.e. the last elem
12969 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
12970 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
12971 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
12972 int f
= comp
->steps
[op
->ch2
].ch1
;
12975 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
12976 (comp
->steps
[f
].value5
== NULL
) &&
12977 (comp
->steps
[f
].value
== 0) &&
12978 (comp
->steps
[f
].value4
!= NULL
) &&
12980 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
12981 xmlNodePtr last
= NULL
;
12984 xmlXPathCompOpEvalLast(ctxt
,
12985 &comp
->steps
[op
->ch1
],
12989 * The nodeset should be in document order,
12990 * Keep only the last value
12992 if ((ctxt
->value
!= NULL
) &&
12993 (ctxt
->value
->type
== XPATH_NODESET
) &&
12994 (ctxt
->value
->nodesetval
!= NULL
) &&
12995 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
12996 (ctxt
->value
->nodesetval
->nodeNr
> 1)) {
12997 ctxt
->value
->nodesetval
->nodeTab
[0] =
12998 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->
13003 ctxt
->value
->nodesetval
->nodeNr
= 1;
13004 *first
= *(ctxt
->value
->nodesetval
->nodeTab
);
13011 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13015 if (ctxt
->value
== NULL
)
13018 #ifdef LIBXML_XPTR_ENABLED
13019 oldnode
= ctxt
->context
->node
;
13021 * Hum are we filtering the result of an XPointer expression
13023 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13024 xmlXPathObjectPtr tmp
= NULL
;
13025 xmlLocationSetPtr newlocset
= NULL
;
13026 xmlLocationSetPtr oldlocset
;
13029 * Extract the old locset, and then evaluate the result of the
13030 * expression for all the element in the locset. use it to grow
13033 CHECK_TYPE0(XPATH_LOCATIONSET
);
13034 obj
= valuePop(ctxt
);
13035 oldlocset
= obj
->user
;
13036 ctxt
->context
->node
= NULL
;
13038 if ((oldlocset
== NULL
) || (oldlocset
->locNr
== 0)) {
13039 ctxt
->context
->contextSize
= 0;
13040 ctxt
->context
->proximityPosition
= 0;
13042 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13043 res
= valuePop(ctxt
);
13045 xmlXPathReleaseObject(ctxt
->context
, res
);
13047 valuePush(ctxt
, obj
);
13051 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13053 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13055 * Run the evaluation with a node list made of a
13056 * single item in the nodelocset.
13058 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13059 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13060 ctxt
->context
->proximityPosition
= i
+ 1;
13062 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13063 ctxt
->context
->node
);
13065 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13066 ctxt
->context
->node
) < 0) {
13067 ctxt
->error
= XPATH_MEMORY_ERROR
;
13070 valuePush(ctxt
, tmp
);
13072 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13073 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13074 xmlXPathFreeObject(obj
);
13078 * The result of the evaluation need to be tested to
13079 * decided whether the filter succeeded or not
13081 res
= valuePop(ctxt
);
13082 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13083 xmlXPtrLocationSetAdd(newlocset
,
13084 xmlXPathCacheObjectCopy(ctxt
->context
,
13085 oldlocset
->locTab
[i
]));
13091 xmlXPathReleaseObject(ctxt
->context
, res
);
13093 if (ctxt
->value
== tmp
) {
13095 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13097 * REVISIT TODO: Don't create a temporary nodeset
13098 * for everly iteration.
13100 /* OLD: xmlXPathFreeObject(res); */
13103 ctxt
->context
->node
= NULL
;
13105 * Only put the first node in the result, then leave.
13107 if (newlocset
->locNr
> 0) {
13108 *first
= (xmlNodePtr
) oldlocset
->locTab
[i
]->user
;
13113 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13116 * The result is used as the new evaluation locset.
13118 xmlXPathReleaseObject(ctxt
->context
, obj
);
13119 ctxt
->context
->node
= NULL
;
13120 ctxt
->context
->contextSize
= -1;
13121 ctxt
->context
->proximityPosition
= -1;
13122 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13123 ctxt
->context
->node
= oldnode
;
13126 #endif /* LIBXML_XPTR_ENABLED */
13129 * Extract the old set, and then evaluate the result of the
13130 * expression for all the element in the set. use it to grow
13133 CHECK_TYPE0(XPATH_NODESET
);
13134 obj
= valuePop(ctxt
);
13135 oldset
= obj
->nodesetval
;
13137 oldnode
= ctxt
->context
->node
;
13138 oldDoc
= ctxt
->context
->doc
;
13139 ctxt
->context
->node
= NULL
;
13141 if ((oldset
== NULL
) || (oldset
->nodeNr
== 0)) {
13142 ctxt
->context
->contextSize
= 0;
13143 ctxt
->context
->proximityPosition
= 0;
13144 /* QUESTION TODO: Why was this code commented out?
13147 xmlXPathCompOpEval(ctxt,
13148 &comp->steps[op->ch2]);
13150 res = valuePop(ctxt);
13152 xmlXPathFreeObject(res);
13154 valuePush(ctxt
, obj
);
13155 ctxt
->context
->node
= oldnode
;
13158 xmlNodeSetPtr newset
;
13159 xmlXPathObjectPtr tmp
= NULL
;
13161 * Initialize the new set.
13162 * Also set the xpath document in case things like
13163 * key() evaluation are attempted on the predicate
13165 newset
= xmlXPathNodeSetCreate(NULL
);
13166 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13168 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13170 * Run the evaluation with a node list made of
13171 * a single item in the nodeset.
13173 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13174 if ((oldset
->nodeTab
[i
]->type
!= XML_NAMESPACE_DECL
) &&
13175 (oldset
->nodeTab
[i
]->doc
!= NULL
))
13176 ctxt
->context
->doc
= oldset
->nodeTab
[i
]->doc
;
13178 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13179 ctxt
->context
->node
);
13181 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13182 ctxt
->context
->node
) < 0) {
13183 ctxt
->error
= XPATH_MEMORY_ERROR
;
13186 valuePush(ctxt
, tmp
);
13187 ctxt
->context
->contextSize
= oldset
->nodeNr
;
13188 ctxt
->context
->proximityPosition
= i
+ 1;
13190 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13191 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13192 xmlXPathFreeNodeSet(newset
);
13193 xmlXPathFreeObject(obj
);
13197 * The result of the evaluation needs to be tested to
13198 * decide whether the filter succeeded or not
13200 res
= valuePop(ctxt
);
13201 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13202 if (xmlXPathNodeSetAdd(newset
, oldset
->nodeTab
[i
]) < 0)
13203 ctxt
->error
= XPATH_MEMORY_ERROR
;
13209 xmlXPathReleaseObject(ctxt
->context
, res
);
13211 if (ctxt
->value
== tmp
) {
13214 * Don't free the temporary nodeset
13215 * in order to avoid massive recreation inside this
13218 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13221 ctxt
->context
->node
= NULL
;
13223 * Only put the first node in the result, then leave.
13225 if (newset
->nodeNr
> 0) {
13226 *first
= *(newset
->nodeTab
);
13231 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13234 * The result is used as the new evaluation set.
13236 xmlXPathReleaseObject(ctxt
->context
, obj
);
13237 ctxt
->context
->node
= NULL
;
13238 ctxt
->context
->contextSize
= -1;
13239 ctxt
->context
->proximityPosition
= -1;
13240 /* may want to move this past the '}' later */
13241 ctxt
->context
->doc
= oldDoc
;
13242 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, newset
));
13244 ctxt
->context
->node
= oldnode
;
13247 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13250 * xmlXPathCompOpEval:
13251 * @ctxt: the XPath parser context with the compiled expression
13252 * @op: an XPath compiled operation
13254 * Evaluate the Precompiled XPath operation
13255 * Returns the number of nodes traversed
13258 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
)
13262 xmlXPathCompExprPtr comp
;
13263 xmlXPathObjectPtr arg1
, arg2
;
13275 bakd
= ctxt
->context
->doc
;
13276 bak
= ctxt
->context
->node
;
13277 pp
= ctxt
->context
->proximityPosition
;
13278 cs
= ctxt
->context
->contextSize
;
13279 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13281 xmlXPathBooleanFunction(ctxt
, 1);
13282 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 0))
13284 arg2
= valuePop(ctxt
);
13285 ctxt
->context
->doc
= bakd
;
13286 ctxt
->context
->node
= bak
;
13287 ctxt
->context
->proximityPosition
= pp
;
13288 ctxt
->context
->contextSize
= cs
;
13289 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13291 xmlXPathFreeObject(arg2
);
13294 xmlXPathBooleanFunction(ctxt
, 1);
13295 arg1
= valuePop(ctxt
);
13296 arg1
->boolval
&= arg2
->boolval
;
13297 valuePush(ctxt
, arg1
);
13298 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13301 bakd
= ctxt
->context
->doc
;
13302 bak
= ctxt
->context
->node
;
13303 pp
= ctxt
->context
->proximityPosition
;
13304 cs
= ctxt
->context
->contextSize
;
13305 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13307 xmlXPathBooleanFunction(ctxt
, 1);
13308 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 1))
13310 arg2
= valuePop(ctxt
);
13311 ctxt
->context
->doc
= bakd
;
13312 ctxt
->context
->node
= bak
;
13313 ctxt
->context
->proximityPosition
= pp
;
13314 ctxt
->context
->contextSize
= cs
;
13315 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13317 xmlXPathFreeObject(arg2
);
13320 xmlXPathBooleanFunction(ctxt
, 1);
13321 arg1
= valuePop(ctxt
);
13322 arg1
->boolval
|= arg2
->boolval
;
13323 valuePush(ctxt
, arg1
);
13324 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13326 case XPATH_OP_EQUAL
:
13327 bakd
= ctxt
->context
->doc
;
13328 bak
= ctxt
->context
->node
;
13329 pp
= ctxt
->context
->proximityPosition
;
13330 cs
= ctxt
->context
->contextSize
;
13331 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13333 ctxt
->context
->doc
= bakd
;
13334 ctxt
->context
->node
= bak
;
13335 ctxt
->context
->proximityPosition
= pp
;
13336 ctxt
->context
->contextSize
= cs
;
13337 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13340 equal
= xmlXPathEqualValues(ctxt
);
13342 equal
= xmlXPathNotEqualValues(ctxt
);
13343 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, equal
));
13346 bakd
= ctxt
->context
->doc
;
13347 bak
= ctxt
->context
->node
;
13348 pp
= ctxt
->context
->proximityPosition
;
13349 cs
= ctxt
->context
->contextSize
;
13350 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13352 ctxt
->context
->doc
= bakd
;
13353 ctxt
->context
->node
= bak
;
13354 ctxt
->context
->proximityPosition
= pp
;
13355 ctxt
->context
->contextSize
= cs
;
13356 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13358 ret
= xmlXPathCompareValues(ctxt
, op
->value
, op
->value2
);
13359 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
13361 case XPATH_OP_PLUS
:
13362 bakd
= ctxt
->context
->doc
;
13363 bak
= ctxt
->context
->node
;
13364 pp
= ctxt
->context
->proximityPosition
;
13365 cs
= ctxt
->context
->contextSize
;
13366 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13368 if (op
->ch2
!= -1) {
13369 ctxt
->context
->doc
= bakd
;
13370 ctxt
->context
->node
= bak
;
13371 ctxt
->context
->proximityPosition
= pp
;
13372 ctxt
->context
->contextSize
= cs
;
13373 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13376 if (op
->value
== 0)
13377 xmlXPathSubValues(ctxt
);
13378 else if (op
->value
== 1)
13379 xmlXPathAddValues(ctxt
);
13380 else if (op
->value
== 2)
13381 xmlXPathValueFlipSign(ctxt
);
13382 else if (op
->value
== 3) {
13384 CHECK_TYPE0(XPATH_NUMBER
);
13387 case XPATH_OP_MULT
:
13388 bakd
= ctxt
->context
->doc
;
13389 bak
= ctxt
->context
->node
;
13390 pp
= ctxt
->context
->proximityPosition
;
13391 cs
= ctxt
->context
->contextSize
;
13392 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13394 ctxt
->context
->doc
= bakd
;
13395 ctxt
->context
->node
= bak
;
13396 ctxt
->context
->proximityPosition
= pp
;
13397 ctxt
->context
->contextSize
= cs
;
13398 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13400 if (op
->value
== 0)
13401 xmlXPathMultValues(ctxt
);
13402 else if (op
->value
== 1)
13403 xmlXPathDivValues(ctxt
);
13404 else if (op
->value
== 2)
13405 xmlXPathModValues(ctxt
);
13407 case XPATH_OP_UNION
:
13408 bakd
= ctxt
->context
->doc
;
13409 bak
= ctxt
->context
->node
;
13410 pp
= ctxt
->context
->proximityPosition
;
13411 cs
= ctxt
->context
->contextSize
;
13412 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13414 ctxt
->context
->doc
= bakd
;
13415 ctxt
->context
->node
= bak
;
13416 ctxt
->context
->proximityPosition
= pp
;
13417 ctxt
->context
->contextSize
= cs
;
13418 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13420 CHECK_TYPE0(XPATH_NODESET
);
13421 arg2
= valuePop(ctxt
);
13423 CHECK_TYPE0(XPATH_NODESET
);
13424 arg1
= valuePop(ctxt
);
13426 if ((arg1
->nodesetval
== NULL
) ||
13427 ((arg2
->nodesetval
!= NULL
) &&
13428 (arg2
->nodesetval
->nodeNr
!= 0)))
13430 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
13434 valuePush(ctxt
, arg1
);
13435 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13437 case XPATH_OP_ROOT
:
13438 xmlXPathRoot(ctxt
);
13440 case XPATH_OP_NODE
:
13442 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13445 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13447 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
13448 ctxt
->context
->node
));
13450 case XPATH_OP_RESET
:
13452 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13455 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13457 ctxt
->context
->node
= NULL
;
13459 case XPATH_OP_COLLECT
:{
13463 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13466 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 0);
13469 case XPATH_OP_VALUE
:
13471 xmlXPathCacheObjectCopy(ctxt
->context
,
13472 (xmlXPathObjectPtr
) op
->value4
));
13474 case XPATH_OP_VARIABLE
:{
13475 xmlXPathObjectPtr val
;
13479 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13480 if (op
->value5
== NULL
) {
13481 val
= xmlXPathVariableLookup(ctxt
->context
, op
->value4
);
13483 ctxt
->error
= XPATH_UNDEF_VARIABLE_ERROR
;
13486 valuePush(ctxt
, val
);
13488 const xmlChar
*URI
;
13490 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13492 xmlGenericError(xmlGenericErrorContext
,
13493 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13494 (char *) op
->value4
, (char *)op
->value5
);
13495 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13498 val
= xmlXPathVariableLookupNS(ctxt
->context
,
13501 ctxt
->error
= XPATH_UNDEF_VARIABLE_ERROR
;
13504 valuePush(ctxt
, val
);
13508 case XPATH_OP_FUNCTION
:{
13509 xmlXPathFunction func
;
13510 const xmlChar
*oldFunc
, *oldFuncURI
;
13514 frame
= xmlXPathSetFrame(ctxt
);
13517 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13518 if (ctxt
->valueNr
< op
->value
) {
13519 xmlGenericError(xmlGenericErrorContext
,
13520 "xmlXPathCompOpEval: parameter error\n");
13521 ctxt
->error
= XPATH_INVALID_OPERAND
;
13522 xmlXPathPopFrame(ctxt
, frame
);
13525 for (i
= 0; i
< op
->value
; i
++) {
13526 if (ctxt
->valueTab
[(ctxt
->valueNr
- 1) - i
] == NULL
) {
13527 xmlGenericError(xmlGenericErrorContext
,
13528 "xmlXPathCompOpEval: parameter error\n");
13529 ctxt
->error
= XPATH_INVALID_OPERAND
;
13530 xmlXPathPopFrame(ctxt
, frame
);
13534 if (op
->cache
!= NULL
)
13535 XML_CAST_FPTR(func
) = op
->cache
;
13537 const xmlChar
*URI
= NULL
;
13539 if (op
->value5
== NULL
)
13541 xmlXPathFunctionLookup(ctxt
->context
,
13544 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13546 xmlGenericError(xmlGenericErrorContext
,
13547 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13548 (char *)op
->value4
, (char *)op
->value5
);
13549 xmlXPathPopFrame(ctxt
, frame
);
13550 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13553 func
= xmlXPathFunctionLookupNS(ctxt
->context
,
13556 if (func
== NULL
) {
13557 xmlGenericError(xmlGenericErrorContext
,
13558 "xmlXPathCompOpEval: function %s not found\n",
13559 (char *)op
->value4
);
13560 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR
);
13562 op
->cache
= XML_CAST_FPTR(func
);
13563 op
->cacheURI
= (void *) URI
;
13565 oldFunc
= ctxt
->context
->function
;
13566 oldFuncURI
= ctxt
->context
->functionURI
;
13567 ctxt
->context
->function
= op
->value4
;
13568 ctxt
->context
->functionURI
= op
->cacheURI
;
13569 func(ctxt
, op
->value
);
13570 ctxt
->context
->function
= oldFunc
;
13571 ctxt
->context
->functionURI
= oldFuncURI
;
13572 xmlXPathPopFrame(ctxt
, frame
);
13576 bakd
= ctxt
->context
->doc
;
13577 bak
= ctxt
->context
->node
;
13578 pp
= ctxt
->context
->proximityPosition
;
13579 cs
= ctxt
->context
->contextSize
;
13581 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13582 ctxt
->context
->contextSize
= cs
;
13583 ctxt
->context
->proximityPosition
= pp
;
13584 ctxt
->context
->node
= bak
;
13585 ctxt
->context
->doc
= bakd
;
13587 if (op
->ch2
!= -1) {
13588 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13589 ctxt
->context
->doc
= bakd
;
13590 ctxt
->context
->node
= bak
;
13594 case XPATH_OP_PREDICATE
:
13595 case XPATH_OP_FILTER
:{
13596 xmlXPathObjectPtr res
;
13597 xmlXPathObjectPtr obj
, tmp
;
13598 xmlNodeSetPtr newset
= NULL
;
13599 xmlNodeSetPtr oldset
;
13600 xmlNodePtr oldnode
;
13605 * Optimization for ()[1] selection i.e. the first elem
13607 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13608 #ifdef XP_OPTIMIZED_FILTER_FIRST
13610 * FILTER TODO: Can we assume that the inner processing
13611 * will result in an ordered list if we have an
13613 * What about an additional field or flag on
13614 * xmlXPathObject like @sorted ? This way we wouln'd need
13615 * to assume anything, so it would be more robust and
13616 * easier to optimize.
13618 ((comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) || /* 18 */
13619 (comp
->steps
[op
->ch1
].op
== XPATH_OP_FILTER
)) && /* 17 */
13621 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13623 (comp
->steps
[op
->ch2
].op
== XPATH_OP_VALUE
)) { /* 12 */
13624 xmlXPathObjectPtr val
;
13626 val
= comp
->steps
[op
->ch2
].value4
;
13627 if ((val
!= NULL
) && (val
->type
== XPATH_NUMBER
) &&
13628 (val
->floatval
== 1.0)) {
13629 xmlNodePtr first
= NULL
;
13632 xmlXPathCompOpEvalFirst(ctxt
,
13633 &comp
->steps
[op
->ch1
],
13637 * The nodeset should be in document order,
13638 * Keep only the first value
13640 if ((ctxt
->value
!= NULL
) &&
13641 (ctxt
->value
->type
== XPATH_NODESET
) &&
13642 (ctxt
->value
->nodesetval
!= NULL
) &&
13643 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13644 ctxt
->value
->nodesetval
->nodeNr
= 1;
13649 * Optimization for ()[last()] selection i.e. the last elem
13651 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13652 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13653 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
13654 int f
= comp
->steps
[op
->ch2
].ch1
;
13657 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
13658 (comp
->steps
[f
].value5
== NULL
) &&
13659 (comp
->steps
[f
].value
== 0) &&
13660 (comp
->steps
[f
].value4
!= NULL
) &&
13662 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
13663 xmlNodePtr last
= NULL
;
13666 xmlXPathCompOpEvalLast(ctxt
,
13667 &comp
->steps
[op
->ch1
],
13671 * The nodeset should be in document order,
13672 * Keep only the last value
13674 if ((ctxt
->value
!= NULL
) &&
13675 (ctxt
->value
->type
== XPATH_NODESET
) &&
13676 (ctxt
->value
->nodesetval
!= NULL
) &&
13677 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
13678 (ctxt
->value
->nodesetval
->nodeNr
> 1)) {
13679 ctxt
->value
->nodesetval
->nodeTab
[0] =
13680 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->
13685 ctxt
->value
->nodesetval
->nodeNr
= 1;
13691 * Process inner predicates first.
13692 * Example "index[parent::book][1]":
13694 * PREDICATE <-- we are here "[1]"
13695 * PREDICATE <-- process "[parent::book]" first
13697 * COLLECT 'parent' 'name' 'node' book
13699 * ELEM Object is a number : 1
13703 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13707 if (ctxt
->value
== NULL
)
13710 oldnode
= ctxt
->context
->node
;
13712 #ifdef LIBXML_XPTR_ENABLED
13714 * Hum are we filtering the result of an XPointer expression
13716 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13717 xmlLocationSetPtr newlocset
= NULL
;
13718 xmlLocationSetPtr oldlocset
;
13721 * Extract the old locset, and then evaluate the result of the
13722 * expression for all the element in the locset. use it to grow
13725 CHECK_TYPE0(XPATH_LOCATIONSET
);
13726 obj
= valuePop(ctxt
);
13727 oldlocset
= obj
->user
;
13728 ctxt
->context
->node
= NULL
;
13730 if ((oldlocset
== NULL
) || (oldlocset
->locNr
== 0)) {
13731 ctxt
->context
->contextSize
= 0;
13732 ctxt
->context
->proximityPosition
= 0;
13735 xmlXPathCompOpEval(ctxt
,
13736 &comp
->steps
[op
->ch2
]);
13737 res
= valuePop(ctxt
);
13739 xmlXPathReleaseObject(ctxt
->context
, res
);
13741 valuePush(ctxt
, obj
);
13745 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13747 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13749 * Run the evaluation with a node list made of a
13750 * single item in the nodelocset.
13752 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13753 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13754 ctxt
->context
->proximityPosition
= i
+ 1;
13755 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13756 ctxt
->context
->node
);
13757 valuePush(ctxt
, tmp
);
13761 xmlXPathCompOpEval(ctxt
,
13762 &comp
->steps
[op
->ch2
]);
13763 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13764 xmlXPathFreeObject(obj
);
13769 * The result of the evaluation need to be tested to
13770 * decided whether the filter succeeded or not
13772 res
= valuePop(ctxt
);
13773 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13774 xmlXPtrLocationSetAdd(newlocset
,
13776 (oldlocset
->locTab
[i
]));
13783 xmlXPathReleaseObject(ctxt
->context
, res
);
13785 if (ctxt
->value
== tmp
) {
13786 res
= valuePop(ctxt
);
13787 xmlXPathReleaseObject(ctxt
->context
, res
);
13790 ctxt
->context
->node
= NULL
;
13794 * The result is used as the new evaluation locset.
13796 xmlXPathReleaseObject(ctxt
->context
, obj
);
13797 ctxt
->context
->node
= NULL
;
13798 ctxt
->context
->contextSize
= -1;
13799 ctxt
->context
->proximityPosition
= -1;
13800 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13801 ctxt
->context
->node
= oldnode
;
13804 #endif /* LIBXML_XPTR_ENABLED */
13807 * Extract the old set, and then evaluate the result of the
13808 * expression for all the element in the set. use it to grow
13811 CHECK_TYPE0(XPATH_NODESET
);
13812 obj
= valuePop(ctxt
);
13813 oldset
= obj
->nodesetval
;
13815 oldnode
= ctxt
->context
->node
;
13816 oldDoc
= ctxt
->context
->doc
;
13817 ctxt
->context
->node
= NULL
;
13819 if ((oldset
== NULL
) || (oldset
->nodeNr
== 0)) {
13820 ctxt
->context
->contextSize
= 0;
13821 ctxt
->context
->proximityPosition
= 0;
13825 xmlXPathCompOpEval(ctxt,
13826 &comp->steps[op->ch2]);
13828 res = valuePop(ctxt);
13830 xmlXPathFreeObject(res);
13832 valuePush(ctxt
, obj
);
13833 ctxt
->context
->node
= oldnode
;
13838 * Initialize the new set.
13839 * Also set the xpath document in case things like
13840 * key() evaluation are attempted on the predicate
13842 newset
= xmlXPathNodeSetCreate(NULL
);
13845 * "For each node in the node-set to be filtered, the
13846 * PredicateExpr is evaluated with that node as the
13847 * context node, with the number of nodes in the
13848 * node-set as the context size, and with the proximity
13849 * position of the node in the node-set with respect to
13850 * the axis as the context position;"
13851 * @oldset is the node-set" to be filtered.
13854 * "only predicates change the context position and
13855 * context size (see [2.4 Predicates])."
13857 * node-set context pos
13861 * After applying predicate [position() > 1] :
13862 * node-set context pos
13866 * removed the first node in the node-set, then
13867 * the context position of the
13869 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13871 * Run the evaluation with a node list made of
13872 * a single item in the nodeset.
13874 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13875 if ((oldset
->nodeTab
[i
]->type
!= XML_NAMESPACE_DECL
) &&
13876 (oldset
->nodeTab
[i
]->doc
!= NULL
))
13877 ctxt
->context
->doc
= oldset
->nodeTab
[i
]->doc
;
13879 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13880 ctxt
->context
->node
);
13882 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13883 ctxt
->context
->node
) < 0) {
13884 ctxt
->error
= XPATH_MEMORY_ERROR
;
13887 valuePush(ctxt
, tmp
);
13888 ctxt
->context
->contextSize
= oldset
->nodeNr
;
13889 ctxt
->context
->proximityPosition
= i
+ 1;
13891 * Evaluate the predicate against the context node.
13892 * Can/should we optimize position() predicates
13893 * here (e.g. "[1]")?
13897 xmlXPathCompOpEval(ctxt
,
13898 &comp
->steps
[op
->ch2
]);
13899 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13900 xmlXPathFreeNodeSet(newset
);
13901 xmlXPathFreeObject(obj
);
13906 * The result of the evaluation needs to be tested to
13907 * decide whether the filter succeeded or not
13910 * OPTIMIZE TODO: Can we use
13911 * xmlXPathNodeSetAdd*Unique()* instead?
13913 res
= valuePop(ctxt
);
13914 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13915 if (xmlXPathNodeSetAdd(newset
, oldset
->nodeTab
[i
])
13917 ctxt
->error
= XPATH_MEMORY_ERROR
;
13924 xmlXPathReleaseObject(ctxt
->context
, res
);
13926 if (ctxt
->value
== tmp
) {
13928 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13930 * Don't free the temporary nodeset
13931 * in order to avoid massive recreation inside this
13936 ctxt
->context
->node
= NULL
;
13939 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13941 * The result is used as the new evaluation set.
13943 xmlXPathReleaseObject(ctxt
->context
, obj
);
13944 ctxt
->context
->node
= NULL
;
13945 ctxt
->context
->contextSize
= -1;
13946 ctxt
->context
->proximityPosition
= -1;
13947 /* may want to move this past the '}' later */
13948 ctxt
->context
->doc
= oldDoc
;
13950 xmlXPathCacheWrapNodeSet(ctxt
->context
, newset
));
13952 ctxt
->context
->node
= oldnode
;
13955 case XPATH_OP_SORT
:
13957 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13959 if ((ctxt
->value
!= NULL
) &&
13960 (ctxt
->value
->type
== XPATH_NODESET
) &&
13961 (ctxt
->value
->nodesetval
!= NULL
) &&
13962 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13964 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
13967 #ifdef LIBXML_XPTR_ENABLED
13968 case XPATH_OP_RANGETO
:{
13969 xmlXPathObjectPtr range
;
13970 xmlXPathObjectPtr res
, obj
;
13971 xmlXPathObjectPtr tmp
;
13972 xmlLocationSetPtr newlocset
= NULL
;
13973 xmlLocationSetPtr oldlocset
;
13974 xmlNodeSetPtr oldset
;
13979 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13983 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13985 * Extract the old locset, and then evaluate the result of the
13986 * expression for all the element in the locset. use it to grow
13989 CHECK_TYPE0(XPATH_LOCATIONSET
);
13990 obj
= valuePop(ctxt
);
13991 oldlocset
= obj
->user
;
13993 if ((oldlocset
== NULL
) || (oldlocset
->locNr
== 0)) {
13994 ctxt
->context
->node
= NULL
;
13995 ctxt
->context
->contextSize
= 0;
13996 ctxt
->context
->proximityPosition
= 0;
13997 total
+= xmlXPathCompOpEval(ctxt
,&comp
->steps
[op
->ch2
]);
13998 res
= valuePop(ctxt
);
14000 xmlXPathReleaseObject(ctxt
->context
, res
);
14002 valuePush(ctxt
, obj
);
14006 newlocset
= xmlXPtrLocationSetCreate(NULL
);
14008 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
14010 * Run the evaluation with a node list made of a
14011 * single item in the nodelocset.
14013 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
14014 ctxt
->context
->contextSize
= oldlocset
->locNr
;
14015 ctxt
->context
->proximityPosition
= i
+ 1;
14016 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
14017 ctxt
->context
->node
);
14018 valuePush(ctxt
, tmp
);
14022 xmlXPathCompOpEval(ctxt
,
14023 &comp
->steps
[op
->ch2
]);
14024 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14025 xmlXPathFreeObject(obj
);
14029 res
= valuePop(ctxt
);
14030 if (res
->type
== XPATH_LOCATIONSET
) {
14031 xmlLocationSetPtr rloc
=
14032 (xmlLocationSetPtr
)res
->user
;
14033 for (j
=0; j
<rloc
->locNr
; j
++) {
14034 range
= xmlXPtrNewRange(
14035 oldlocset
->locTab
[i
]->user
,
14036 oldlocset
->locTab
[i
]->index
,
14037 rloc
->locTab
[j
]->user2
,
14038 rloc
->locTab
[j
]->index2
);
14039 if (range
!= NULL
) {
14040 xmlXPtrLocationSetAdd(newlocset
, range
);
14044 range
= xmlXPtrNewRangeNodeObject(
14045 (xmlNodePtr
)oldlocset
->locTab
[i
]->user
, res
);
14046 if (range
!= NULL
) {
14047 xmlXPtrLocationSetAdd(newlocset
,range
);
14055 xmlXPathReleaseObject(ctxt
->context
, res
);
14057 if (ctxt
->value
== tmp
) {
14058 res
= valuePop(ctxt
);
14059 xmlXPathReleaseObject(ctxt
->context
, res
);
14062 ctxt
->context
->node
= NULL
;
14064 } else { /* Not a location set */
14065 CHECK_TYPE0(XPATH_NODESET
);
14066 obj
= valuePop(ctxt
);
14067 oldset
= obj
->nodesetval
;
14068 ctxt
->context
->node
= NULL
;
14070 newlocset
= xmlXPtrLocationSetCreate(NULL
);
14072 if (oldset
!= NULL
) {
14073 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
14075 * Run the evaluation with a node list made of a single item
14078 ctxt
->context
->node
= oldset
->nodeTab
[i
];
14080 * OPTIMIZE TODO: Avoid recreation for every iteration.
14082 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
14083 ctxt
->context
->node
);
14084 valuePush(ctxt
, tmp
);
14088 xmlXPathCompOpEval(ctxt
,
14089 &comp
->steps
[op
->ch2
]);
14090 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14091 xmlXPathFreeObject(obj
);
14095 res
= valuePop(ctxt
);
14097 xmlXPtrNewRangeNodeObject(oldset
->nodeTab
[i
],
14099 if (range
!= NULL
) {
14100 xmlXPtrLocationSetAdd(newlocset
, range
);
14107 xmlXPathReleaseObject(ctxt
->context
, res
);
14109 if (ctxt
->value
== tmp
) {
14110 res
= valuePop(ctxt
);
14111 xmlXPathReleaseObject(ctxt
->context
, res
);
14114 ctxt
->context
->node
= NULL
;
14120 * The result is used as the new evaluation set.
14122 xmlXPathReleaseObject(ctxt
->context
, obj
);
14123 ctxt
->context
->node
= NULL
;
14124 ctxt
->context
->contextSize
= -1;
14125 ctxt
->context
->proximityPosition
= -1;
14126 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
14129 #endif /* LIBXML_XPTR_ENABLED */
14131 xmlGenericError(xmlGenericErrorContext
,
14132 "XPath: unknown precompiled operation %d\n", op
->op
);
14133 ctxt
->error
= XPATH_INVALID_OPERAND
;
14138 * xmlXPathCompOpEvalToBoolean:
14139 * @ctxt: the XPath parser context
14141 * Evaluates if the expression evaluates to true.
14143 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14146 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
14147 xmlXPathStepOpPtr op
,
14150 xmlXPathObjectPtr resObj
= NULL
;
14153 /* comp = ctxt->comp; */
14157 case XPATH_OP_VALUE
:
14158 resObj
= (xmlXPathObjectPtr
) op
->value4
;
14160 return(xmlXPathEvaluatePredicateResult(ctxt
, resObj
));
14161 return(xmlXPathCastToBoolean(resObj
));
14162 case XPATH_OP_SORT
:
14164 * We don't need sorting for boolean results. Skip this one.
14166 if (op
->ch1
!= -1) {
14167 op
= &ctxt
->comp
->steps
[op
->ch1
];
14171 case XPATH_OP_COLLECT
:
14175 xmlXPathCompOpEval(ctxt
, &ctxt
->comp
->steps
[op
->ch1
]);
14176 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14179 xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 1);
14180 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14183 resObj
= valuePop(ctxt
);
14184 if (resObj
== NULL
)
14189 * Fallback to call xmlXPathCompOpEval().
14191 xmlXPathCompOpEval(ctxt
, op
);
14192 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14195 resObj
= valuePop(ctxt
);
14196 if (resObj
== NULL
)
14204 if (resObj
->type
== XPATH_BOOLEAN
) {
14205 res
= resObj
->boolval
;
14206 } else if (isPredicate
) {
14208 * For predicates a result of type "number" is handled
14211 * "If the result is a number, the result will be converted
14212 * to true if the number is equal to the context position
14213 * and will be converted to false otherwise;"
14215 res
= xmlXPathEvaluatePredicateResult(ctxt
, resObj
);
14217 res
= xmlXPathCastToBoolean(resObj
);
14219 xmlXPathReleaseObject(ctxt
->context
, resObj
);
14226 #ifdef XPATH_STREAMING
14228 * xmlXPathRunStreamEval:
14229 * @ctxt: the XPath parser context with the compiled expression
14231 * Evaluate the Precompiled Streamable XPath expression in the given context.
14234 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt
, xmlPatternPtr comp
,
14235 xmlXPathObjectPtr
*resultSeq
, int toBool
)
14237 int max_depth
, min_depth
;
14240 int eval_all_nodes
;
14241 xmlNodePtr cur
= NULL
, limit
= NULL
;
14242 xmlStreamCtxtPtr patstream
= NULL
;
14246 if ((ctxt
== NULL
) || (comp
== NULL
))
14248 max_depth
= xmlPatternMaxDepth(comp
);
14249 if (max_depth
== -1)
14251 if (max_depth
== -2)
14253 min_depth
= xmlPatternMinDepth(comp
);
14254 if (min_depth
== -1)
14256 from_root
= xmlPatternFromRoot(comp
);
14260 printf("stream eval: depth %d from root %d\n", max_depth
, from_root
);
14264 if (resultSeq
== NULL
)
14266 *resultSeq
= xmlXPathCacheNewNodeSet(ctxt
, NULL
);
14267 if (*resultSeq
== NULL
)
14272 * handle the special cases of "/" amd "." being matched
14274 if (min_depth
== 0) {
14279 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
,
14280 (xmlNodePtr
) ctxt
->doc
);
14282 /* Select "self::node()" */
14285 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, ctxt
->node
);
14288 if (max_depth
== 0) {
14293 cur
= (xmlNodePtr
)ctxt
->doc
;
14294 } else if (ctxt
->node
!= NULL
) {
14295 switch (ctxt
->node
->type
) {
14296 case XML_ELEMENT_NODE
:
14297 case XML_DOCUMENT_NODE
:
14298 case XML_DOCUMENT_FRAG_NODE
:
14299 case XML_HTML_DOCUMENT_NODE
:
14300 #ifdef LIBXML_DOCB_ENABLED
14301 case XML_DOCB_DOCUMENT_NODE
:
14305 case XML_ATTRIBUTE_NODE
:
14306 case XML_TEXT_NODE
:
14307 case XML_CDATA_SECTION_NODE
:
14308 case XML_ENTITY_REF_NODE
:
14309 case XML_ENTITY_NODE
:
14311 case XML_COMMENT_NODE
:
14312 case XML_NOTATION_NODE
:
14314 case XML_DOCUMENT_TYPE_NODE
:
14315 case XML_ELEMENT_DECL
:
14316 case XML_ATTRIBUTE_DECL
:
14317 case XML_ENTITY_DECL
:
14318 case XML_NAMESPACE_DECL
:
14319 case XML_XINCLUDE_START
:
14320 case XML_XINCLUDE_END
:
14329 patstream
= xmlPatternGetStreamCtxt(comp
);
14330 if (patstream
== NULL
) {
14332 * QUESTION TODO: Is this an error?
14337 eval_all_nodes
= xmlStreamWantsAnyNode(patstream
);
14340 ret
= xmlStreamPush(patstream
, NULL
, NULL
);
14342 } else if (ret
== 1) {
14345 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
);
14349 goto scan_children
;
14354 switch (cur
->type
) {
14355 case XML_ELEMENT_NODE
:
14356 case XML_TEXT_NODE
:
14357 case XML_CDATA_SECTION_NODE
:
14358 case XML_COMMENT_NODE
:
14360 if (cur
->type
== XML_ELEMENT_NODE
) {
14361 ret
= xmlStreamPush(patstream
, cur
->name
,
14362 (cur
->ns
? cur
->ns
->href
: NULL
));
14363 } else if (eval_all_nodes
)
14364 ret
= xmlStreamPushNode(patstream
, NULL
, NULL
, cur
->type
);
14370 } else if (ret
== 1) {
14373 if (xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
)
14375 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
14376 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
14379 if ((cur
->children
== NULL
) || (depth
>= max_depth
)) {
14380 ret
= xmlStreamPop(patstream
);
14381 while (cur
->next
!= NULL
) {
14383 if ((cur
->type
!= XML_ENTITY_DECL
) &&
14384 (cur
->type
!= XML_DTD_NODE
))
14393 if (cur
->type
== XML_NAMESPACE_DECL
) break;
14394 if ((cur
->children
!= NULL
) && (depth
< max_depth
)) {
14396 * Do not descend on entities declarations
14398 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
14399 cur
= cur
->children
;
14404 if (cur
->type
!= XML_DTD_NODE
)
14412 while (cur
->next
!= NULL
) {
14414 if ((cur
->type
!= XML_ENTITY_DECL
) &&
14415 (cur
->type
!= XML_DTD_NODE
))
14422 if ((cur
== NULL
) || (cur
== limit
))
14424 if (cur
->type
== XML_ELEMENT_NODE
) {
14425 ret
= xmlStreamPop(patstream
);
14426 } else if ((eval_all_nodes
) &&
14427 ((cur
->type
== XML_TEXT_NODE
) ||
14428 (cur
->type
== XML_CDATA_SECTION_NODE
) ||
14429 (cur
->type
== XML_COMMENT_NODE
) ||
14430 (cur
->type
== XML_PI_NODE
)))
14432 ret
= xmlStreamPop(patstream
);
14434 if (cur
->next
!= NULL
) {
14438 } while (cur
!= NULL
);
14440 } while ((cur
!= NULL
) && (depth
>= 0));
14445 printf("stream eval: checked %d nodes selected %d\n",
14446 nb_nodes
, retObj
->nodesetval
->nodeNr
);
14450 xmlFreeStreamCtxt(patstream
);
14455 xmlFreeStreamCtxt(patstream
);
14458 #endif /* XPATH_STREAMING */
14462 * @ctxt: the XPath parser context with the compiled expression
14463 * @toBool: evaluate to a boolean result
14465 * Evaluate the Precompiled XPath expression in the given context.
14468 xmlXPathRunEval(xmlXPathParserContextPtr ctxt
, int toBool
)
14470 xmlXPathCompExprPtr comp
;
14472 if ((ctxt
== NULL
) || (ctxt
->comp
== NULL
))
14475 if (ctxt
->valueTab
== NULL
) {
14476 /* Allocate the value stack */
14477 ctxt
->valueTab
= (xmlXPathObjectPtr
*)
14478 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
14479 if (ctxt
->valueTab
== NULL
) {
14480 xmlXPathPErrMemory(ctxt
, "creating evaluation context\n");
14484 ctxt
->valueMax
= 10;
14485 ctxt
->value
= NULL
;
14486 ctxt
->valueFrame
= 0;
14488 #ifdef XPATH_STREAMING
14489 if (ctxt
->comp
->stream
) {
14494 * Evaluation to boolean result.
14496 res
= xmlXPathRunStreamEval(ctxt
->context
,
14497 ctxt
->comp
->stream
, NULL
, 1);
14501 xmlXPathObjectPtr resObj
= NULL
;
14504 * Evaluation to a sequence.
14506 res
= xmlXPathRunStreamEval(ctxt
->context
,
14507 ctxt
->comp
->stream
, &resObj
, 0);
14509 if ((res
!= -1) && (resObj
!= NULL
)) {
14510 valuePush(ctxt
, resObj
);
14513 if (resObj
!= NULL
)
14514 xmlXPathReleaseObject(ctxt
->context
, resObj
);
14517 * QUESTION TODO: This falls back to normal XPath evaluation
14518 * if res == -1. Is this intended?
14523 if (comp
->last
< 0) {
14524 xmlGenericError(xmlGenericErrorContext
,
14525 "xmlXPathRunEval: last is less than zero\n");
14529 return(xmlXPathCompOpEvalToBoolean(ctxt
,
14530 &comp
->steps
[comp
->last
], 0));
14532 xmlXPathCompOpEval(ctxt
, &comp
->steps
[comp
->last
]);
14537 /************************************************************************
14539 * Public interfaces *
14541 ************************************************************************/
14544 * xmlXPathEvalPredicate:
14545 * @ctxt: the XPath context
14546 * @res: the Predicate Expression evaluation result
14548 * Evaluate a predicate result for the current node.
14549 * A PredicateExpr is evaluated by evaluating the Expr and converting
14550 * the result to a boolean. If the result is a number, the result will
14551 * be converted to true if the number is equal to the position of the
14552 * context node in the context node list (as returned by the position
14553 * function) and will be converted to false otherwise; if the result
14554 * is not a number, then the result will be converted as if by a call
14555 * to the boolean function.
14557 * Returns 1 if predicate is true, 0 otherwise
14560 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr res
) {
14561 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14562 switch (res
->type
) {
14563 case XPATH_BOOLEAN
:
14564 return(res
->boolval
);
14566 return(res
->floatval
== ctxt
->proximityPosition
);
14567 case XPATH_NODESET
:
14568 case XPATH_XSLT_TREE
:
14569 if (res
->nodesetval
== NULL
)
14571 return(res
->nodesetval
->nodeNr
!= 0);
14573 return((res
->stringval
!= NULL
) &&
14574 (xmlStrlen(res
->stringval
) != 0));
14582 * xmlXPathEvaluatePredicateResult:
14583 * @ctxt: the XPath Parser context
14584 * @res: the Predicate Expression evaluation result
14586 * Evaluate a predicate result for the current node.
14587 * A PredicateExpr is evaluated by evaluating the Expr and converting
14588 * the result to a boolean. If the result is a number, the result will
14589 * be converted to true if the number is equal to the position of the
14590 * context node in the context node list (as returned by the position
14591 * function) and will be converted to false otherwise; if the result
14592 * is not a number, then the result will be converted as if by a call
14593 * to the boolean function.
14595 * Returns 1 if predicate is true, 0 otherwise
14598 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt
,
14599 xmlXPathObjectPtr res
) {
14600 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14601 switch (res
->type
) {
14602 case XPATH_BOOLEAN
:
14603 return(res
->boolval
);
14605 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14606 return((res
->floatval
== ctxt
->context
->proximityPosition
) &&
14607 (!xmlXPathIsNaN(res
->floatval
))); /* MSC pbm Mark Vakoc !*/
14609 return(res
->floatval
== ctxt
->context
->proximityPosition
);
14611 case XPATH_NODESET
:
14612 case XPATH_XSLT_TREE
:
14613 if (res
->nodesetval
== NULL
)
14615 return(res
->nodesetval
->nodeNr
!= 0);
14617 return((res
->stringval
!= NULL
) && (res
->stringval
[0] != 0));
14618 #ifdef LIBXML_XPTR_ENABLED
14619 case XPATH_LOCATIONSET
:{
14620 xmlLocationSetPtr ptr
= res
->user
;
14623 return (ptr
->locNr
!= 0);
14632 #ifdef XPATH_STREAMING
14634 * xmlXPathTryStreamCompile:
14635 * @ctxt: an XPath context
14636 * @str: the XPath expression
14638 * Try to compile the XPath expression as a streamable subset.
14640 * Returns the compiled expression or NULL if failed to compile.
14642 static xmlXPathCompExprPtr
14643 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14645 * Optimization: use streaming patterns when the XPath expression can
14646 * be compiled to a stream lookup
14648 xmlPatternPtr stream
;
14649 xmlXPathCompExprPtr comp
;
14650 xmlDictPtr dict
= NULL
;
14651 const xmlChar
**namespaces
= NULL
;
14655 if ((!xmlStrchr(str
, '[')) && (!xmlStrchr(str
, '(')) &&
14656 (!xmlStrchr(str
, '@'))) {
14657 const xmlChar
*tmp
;
14660 * We don't try to handle expressions using the verbose axis
14661 * specifiers ("::"), just the simplied form at this point.
14662 * Additionally, if there is no list of namespaces available and
14663 * there's a ":" in the expression, indicating a prefixed QName,
14664 * then we won't try to compile either. xmlPatterncompile() needs
14665 * to have a list of namespaces at compilation time in order to
14666 * compile prefixed name tests.
14668 tmp
= xmlStrchr(str
, ':');
14669 if ((tmp
!= NULL
) &&
14670 ((ctxt
== NULL
) || (ctxt
->nsNr
== 0) || (tmp
[1] == ':')))
14673 if (ctxt
!= NULL
) {
14675 if (ctxt
->nsNr
> 0) {
14676 namespaces
= xmlMalloc(2 * (ctxt
->nsNr
+ 1) * sizeof(xmlChar
*));
14677 if (namespaces
== NULL
) {
14678 xmlXPathErrMemory(ctxt
, "allocating namespaces array\n");
14681 for (i
= 0, j
= 0; (j
< ctxt
->nsNr
); j
++) {
14682 ns
= ctxt
->namespaces
[j
];
14683 namespaces
[i
++] = ns
->href
;
14684 namespaces
[i
++] = ns
->prefix
;
14686 namespaces
[i
++] = NULL
;
14687 namespaces
[i
] = NULL
;
14691 stream
= xmlPatterncompile(str
, dict
, XML_PATTERN_XPATH
,
14693 if (namespaces
!= NULL
) {
14694 xmlFree((xmlChar
**)namespaces
);
14696 if ((stream
!= NULL
) && (xmlPatternStreamable(stream
) == 1)) {
14697 comp
= xmlXPathNewCompExpr();
14698 if (comp
== NULL
) {
14699 xmlXPathErrMemory(ctxt
, "allocating streamable expression\n");
14702 comp
->stream
= stream
;
14705 xmlDictReference(comp
->dict
);
14708 xmlFreePattern(stream
);
14712 #endif /* XPATH_STREAMING */
14715 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp
, xmlXPathStepOpPtr op
)
14718 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14719 * internal representation.
14722 if ((op
->ch1
!= -1) &&
14723 (op
->op
== XPATH_OP_COLLECT
/* 11 */))
14725 xmlXPathStepOpPtr prevop
= &comp
->steps
[op
->ch1
];
14727 if ((prevop
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14728 ((xmlXPathAxisVal
) prevop
->value
==
14729 AXIS_DESCENDANT_OR_SELF
) &&
14730 (prevop
->ch2
== -1) &&
14731 ((xmlXPathTestVal
) prevop
->value2
== NODE_TEST_TYPE
) &&
14732 ((xmlXPathTypeVal
) prevop
->value3
== NODE_TYPE_NODE
))
14735 * This is a "descendant-or-self::node()" without predicates.
14736 * Try to eliminate it.
14739 switch ((xmlXPathAxisVal
) op
->value
) {
14741 case AXIS_DESCENDANT
:
14743 * Convert "descendant-or-self::node()/child::" or
14744 * "descendant-or-self::node()/descendant::" to
14747 op
->ch1
= prevop
->ch1
;
14748 op
->value
= AXIS_DESCENDANT
;
14751 case AXIS_DESCENDANT_OR_SELF
:
14753 * Convert "descendant-or-self::node()/self::" or
14754 * "descendant-or-self::node()/descendant-or-self::" to
14755 * to "descendant-or-self::"
14757 op
->ch1
= prevop
->ch1
;
14758 op
->value
= AXIS_DESCENDANT_OR_SELF
;
14768 xmlXPathOptimizeExpression(comp
, &comp
->steps
[op
->ch1
]);
14770 xmlXPathOptimizeExpression(comp
, &comp
->steps
[op
->ch2
]);
14774 * xmlXPathCtxtCompile:
14775 * @ctxt: an XPath context
14776 * @str: the XPath expression
14778 * Compile an XPath expression
14780 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14781 * the caller has to free the object.
14783 xmlXPathCompExprPtr
14784 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14785 xmlXPathParserContextPtr pctxt
;
14786 xmlXPathCompExprPtr comp
;
14788 #ifdef XPATH_STREAMING
14789 comp
= xmlXPathTryStreamCompile(ctxt
, str
);
14796 pctxt
= xmlXPathNewParserContext(str
, ctxt
);
14799 xmlXPathCompileExpr(pctxt
, 1);
14801 if( pctxt
->error
!= XPATH_EXPRESSION_OK
)
14803 xmlXPathFreeParserContext(pctxt
);
14807 if (*pctxt
->cur
!= 0) {
14809 * aleksey: in some cases this line prints *second* error message
14810 * (see bug #78858) and probably this should be fixed.
14811 * However, we are not sure that all error messages are printed
14812 * out in other places. It's not critical so we leave it as-is for now
14814 xmlXPatherror(pctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
14817 comp
= pctxt
->comp
;
14818 pctxt
->comp
= NULL
;
14820 xmlXPathFreeParserContext(pctxt
);
14822 if (comp
!= NULL
) {
14823 comp
->expr
= xmlStrdup(str
);
14824 #ifdef DEBUG_EVAL_COUNTS
14825 comp
->string
= xmlStrdup(str
);
14828 if ((comp
->nbStep
> 1) && (comp
->last
>= 0)) {
14829 xmlXPathOptimizeExpression(comp
, &comp
->steps
[comp
->last
]);
14837 * @str: the XPath expression
14839 * Compile an XPath expression
14841 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14842 * the caller has to free the object.
14844 xmlXPathCompExprPtr
14845 xmlXPathCompile(const xmlChar
*str
) {
14846 return(xmlXPathCtxtCompile(NULL
, str
));
14850 * xmlXPathCompiledEvalInternal:
14851 * @comp: the compiled XPath expression
14852 * @ctxt: the XPath context
14853 * @resObj: the resulting XPath object or NULL
14854 * @toBool: 1 if only a boolean result is requested
14856 * Evaluate the Precompiled XPath expression in the given context.
14857 * The caller has to free @resObj.
14859 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14860 * the caller has to free the object.
14863 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp
,
14864 xmlXPathContextPtr ctxt
,
14865 xmlXPathObjectPtr
*resObj
,
14868 xmlXPathParserContextPtr pctxt
;
14869 #ifndef LIBXML_THREAD_ENABLED
14870 static int reentance
= 0;
14874 CHECK_CTXT_NEG(ctxt
)
14880 #ifndef LIBXML_THREAD_ENABLED
14883 xmlXPathDisableOptimizer
= 1;
14886 #ifdef DEBUG_EVAL_COUNTS
14888 if ((comp
->string
!= NULL
) && (comp
->nb
> 100)) {
14889 fprintf(stderr
, "100 x %s\n", comp
->string
);
14893 pctxt
= xmlXPathCompParserContext(comp
, ctxt
);
14894 res
= xmlXPathRunEval(pctxt
, toBool
);
14897 if (pctxt
->value
== NULL
) {
14898 xmlGenericError(xmlGenericErrorContext
,
14899 "xmlXPathCompiledEval: evaluation failed\n");
14902 *resObj
= valuePop(pctxt
);
14907 * Pop all remaining objects from the stack.
14909 if (pctxt
->valueNr
> 0) {
14910 xmlXPathObjectPtr tmp
;
14914 tmp
= valuePop(pctxt
);
14917 xmlXPathReleaseObject(ctxt
, tmp
);
14919 } while (tmp
!= NULL
);
14920 if ((stack
!= 0) &&
14921 ((toBool
) || ((resObj
) && (*resObj
))))
14923 xmlGenericError(xmlGenericErrorContext
,
14924 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14929 if ((pctxt
->error
!= XPATH_EXPRESSION_OK
) && (resObj
) && (*resObj
)) {
14930 xmlXPathFreeObject(*resObj
);
14933 pctxt
->comp
= NULL
;
14934 xmlXPathFreeParserContext(pctxt
);
14935 #ifndef LIBXML_THREAD_ENABLED
14943 * xmlXPathCompiledEval:
14944 * @comp: the compiled XPath expression
14945 * @ctx: the XPath context
14947 * Evaluate the Precompiled XPath expression in the given context.
14949 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14950 * the caller has to free the object.
14953 xmlXPathCompiledEval(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctx
)
14955 xmlXPathObjectPtr res
= NULL
;
14957 xmlXPathCompiledEvalInternal(comp
, ctx
, &res
, 0);
14962 * xmlXPathCompiledEvalToBoolean:
14963 * @comp: the compiled XPath expression
14964 * @ctxt: the XPath context
14966 * Applies the XPath boolean() function on the result of the given
14967 * compiled expression.
14969 * Returns 1 if the expression evaluated to true, 0 if to false and
14970 * -1 in API and internal errors.
14973 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp
,
14974 xmlXPathContextPtr ctxt
)
14976 return(xmlXPathCompiledEvalInternal(comp
, ctxt
, NULL
, 1));
14980 * xmlXPathEvalExpr:
14981 * @ctxt: the XPath Parser context
14983 * Parse and evaluate an XPath expression in the given context,
14984 * then push the result on the context stack
14987 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt
) {
14988 #ifdef XPATH_STREAMING
14989 xmlXPathCompExprPtr comp
;
14992 if (ctxt
== NULL
) return;
14994 #ifdef XPATH_STREAMING
14995 comp
= xmlXPathTryStreamCompile(ctxt
->context
, ctxt
->base
);
14996 if (comp
!= NULL
) {
14997 if (ctxt
->comp
!= NULL
)
14998 xmlXPathFreeCompExpr(ctxt
->comp
);
15000 if (ctxt
->cur
!= NULL
)
15001 while (*ctxt
->cur
!= 0) ctxt
->cur
++;
15005 xmlXPathCompileExpr(ctxt
, 1);
15006 if ((ctxt
->error
== XPATH_EXPRESSION_OK
) &&
15007 (ctxt
->comp
!= NULL
) &&
15008 (ctxt
->comp
->nbStep
> 1) &&
15009 (ctxt
->comp
->last
>= 0))
15011 xmlXPathOptimizeExpression(ctxt
->comp
,
15012 &ctxt
->comp
->steps
[ctxt
->comp
->last
]);
15016 xmlXPathRunEval(ctxt
, 0);
15021 * @str: the XPath expression
15022 * @ctx: the XPath context
15024 * Evaluate the XPath Location Path in the given context.
15026 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15027 * the caller has to free the object.
15030 xmlXPathEval(const xmlChar
*str
, xmlXPathContextPtr ctx
) {
15031 xmlXPathParserContextPtr ctxt
;
15032 xmlXPathObjectPtr res
, tmp
, init
= NULL
;
15039 ctxt
= xmlXPathNewParserContext(str
, ctx
);
15042 xmlXPathEvalExpr(ctxt
);
15044 if (ctxt
->value
== NULL
) {
15045 xmlGenericError(xmlGenericErrorContext
,
15046 "xmlXPathEval: evaluation failed\n");
15048 } else if ((*ctxt
->cur
!= 0) && (ctxt
->comp
!= NULL
)
15049 #ifdef XPATH_STREAMING
15050 && (ctxt
->comp
->stream
== NULL
)
15053 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
15056 res
= valuePop(ctxt
);
15060 tmp
= valuePop(ctxt
);
15064 xmlXPathReleaseObject(ctx
, tmp
);
15066 } while (tmp
!= NULL
);
15067 if ((stack
!= 0) && (res
!= NULL
)) {
15068 xmlGenericError(xmlGenericErrorContext
,
15069 "xmlXPathEval: %d object left on the stack\n",
15072 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
15073 xmlXPathFreeObject(res
);
15077 xmlXPathFreeParserContext(ctxt
);
15082 * xmlXPathSetContextNode:
15083 * @node: the node to to use as the context node
15084 * @ctx: the XPath context
15086 * Sets 'node' as the context node. The node must be in the same
15087 * document as that associated with the context.
15089 * Returns -1 in case of error or 0 if successful
15092 xmlXPathSetContextNode(xmlNodePtr node
, xmlXPathContextPtr ctx
) {
15093 if ((node
== NULL
) || (ctx
== NULL
))
15096 if (node
->doc
== ctx
->doc
) {
15104 * xmlXPathNodeEval:
15105 * @node: the node to to use as the context node
15106 * @str: the XPath expression
15107 * @ctx: the XPath context
15109 * Evaluate the XPath Location Path in the given context. The node 'node'
15110 * is set as the context node. The context node is not restored.
15112 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15113 * the caller has to free the object.
15116 xmlXPathNodeEval(xmlNodePtr node
, const xmlChar
*str
, xmlXPathContextPtr ctx
) {
15119 if (xmlXPathSetContextNode(node
, ctx
) < 0)
15121 return(xmlXPathEval(str
, ctx
));
15125 * xmlXPathEvalExpression:
15126 * @str: the XPath expression
15127 * @ctxt: the XPath context
15129 * Evaluate the XPath expression in the given context.
15131 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15132 * the caller has to free the object.
15135 xmlXPathEvalExpression(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
15136 xmlXPathParserContextPtr pctxt
;
15137 xmlXPathObjectPtr res
, tmp
;
15144 pctxt
= xmlXPathNewParserContext(str
, ctxt
);
15147 xmlXPathEvalExpr(pctxt
);
15149 if ((*pctxt
->cur
!= 0) || (pctxt
->error
!= XPATH_EXPRESSION_OK
)) {
15150 xmlXPatherror(pctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
15153 res
= valuePop(pctxt
);
15156 tmp
= valuePop(pctxt
);
15158 xmlXPathReleaseObject(ctxt
, tmp
);
15161 } while (tmp
!= NULL
);
15162 if ((stack
!= 0) && (res
!= NULL
)) {
15163 xmlGenericError(xmlGenericErrorContext
,
15164 "xmlXPathEvalExpression: %d object left on the stack\n",
15167 xmlXPathFreeParserContext(pctxt
);
15171 /************************************************************************
15173 * Extra functions not pertaining to the XPath spec *
15175 ************************************************************************/
15177 * xmlXPathEscapeUriFunction:
15178 * @ctxt: the XPath Parser context
15179 * @nargs: the number of arguments
15181 * Implement the escape-uri() XPath function
15182 * string escape-uri(string $str, bool $escape-reserved)
15184 * This function applies the URI escaping rules defined in section 2 of [RFC
15185 * 2396] to the string supplied as $uri-part, which typically represents all
15186 * or part of a URI. The effect of the function is to replace any special
15187 * character in the string by an escape sequence of the form %xx%yy...,
15188 * where xxyy... is the hexadecimal representation of the octets used to
15189 * represent the character in UTF-8.
15191 * The set of characters that are escaped depends on the setting of the
15192 * boolean argument $escape-reserved.
15194 * If $escape-reserved is true, all characters are escaped other than lower
15195 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15196 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15197 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15198 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15201 * If $escape-reserved is false, the behavior differs in that characters
15202 * referred to in [RFC 2396] as reserved characters are not escaped. These
15203 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15205 * [RFC 2396] does not define whether escaped URIs should use lower case or
15206 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15207 * compared using string comparison functions, this function must always use
15208 * the upper-case letters A-F.
15210 * Generally, $escape-reserved should be set to true when escaping a string
15211 * that is to form a single part of a URI, and to false when escaping an
15212 * entire URI or URI reference.
15214 * In the case of non-ascii characters, the string is encoded according to
15215 * utf-8 and then converted according to RFC 2396.
15218 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15219 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15220 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15221 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15225 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
15226 xmlXPathObjectPtr str
;
15227 int escape_reserved
;
15234 escape_reserved
= xmlXPathPopBoolean(ctxt
);
15237 str
= valuePop(ctxt
);
15239 target
= xmlBufCreate();
15245 for (cptr
= str
->stringval
; *cptr
; cptr
++) {
15246 if ((*cptr
>= 'A' && *cptr
<= 'Z') ||
15247 (*cptr
>= 'a' && *cptr
<= 'z') ||
15248 (*cptr
>= '0' && *cptr
<= '9') ||
15249 *cptr
== '-' || *cptr
== '_' || *cptr
== '.' ||
15250 *cptr
== '!' || *cptr
== '~' || *cptr
== '*' ||
15251 *cptr
== '\''|| *cptr
== '(' || *cptr
== ')' ||
15253 ((cptr
[1] >= 'A' && cptr
[1] <= 'F') ||
15254 (cptr
[1] >= 'a' && cptr
[1] <= 'f') ||
15255 (cptr
[1] >= '0' && cptr
[1] <= '9')) &&
15256 ((cptr
[2] >= 'A' && cptr
[2] <= 'F') ||
15257 (cptr
[2] >= 'a' && cptr
[2] <= 'f') ||
15258 (cptr
[2] >= '0' && cptr
[2] <= '9'))) ||
15259 (!escape_reserved
&&
15260 (*cptr
== ';' || *cptr
== '/' || *cptr
== '?' ||
15261 *cptr
== ':' || *cptr
== '@' || *cptr
== '&' ||
15262 *cptr
== '=' || *cptr
== '+' || *cptr
== '$' ||
15264 xmlBufAdd(target
, cptr
, 1);
15266 if ((*cptr
>> 4) < 10)
15267 escape
[1] = '0' + (*cptr
>> 4);
15269 escape
[1] = 'A' - 10 + (*cptr
>> 4);
15270 if ((*cptr
& 0xF) < 10)
15271 escape
[2] = '0' + (*cptr
& 0xF);
15273 escape
[2] = 'A' - 10 + (*cptr
& 0xF);
15275 xmlBufAdd(target
, &escape
[0], 3);
15279 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
15280 xmlBufContent(target
)));
15281 xmlBufFree(target
);
15282 xmlXPathReleaseObject(ctxt
->context
, str
);
15286 * xmlXPathRegisterAllFunctions:
15287 * @ctxt: the XPath context
15289 * Registers all default XPath functions in this context
15292 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt
)
15294 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"boolean",
15295 xmlXPathBooleanFunction
);
15296 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"ceiling",
15297 xmlXPathCeilingFunction
);
15298 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"count",
15299 xmlXPathCountFunction
);
15300 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"concat",
15301 xmlXPathConcatFunction
);
15302 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"contains",
15303 xmlXPathContainsFunction
);
15304 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"id",
15305 xmlXPathIdFunction
);
15306 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"false",
15307 xmlXPathFalseFunction
);
15308 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"floor",
15309 xmlXPathFloorFunction
);
15310 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"last",
15311 xmlXPathLastFunction
);
15312 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"lang",
15313 xmlXPathLangFunction
);
15314 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"local-name",
15315 xmlXPathLocalNameFunction
);
15316 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"not",
15317 xmlXPathNotFunction
);
15318 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"name",
15319 xmlXPathNameFunction
);
15320 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"namespace-uri",
15321 xmlXPathNamespaceURIFunction
);
15322 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"normalize-space",
15323 xmlXPathNormalizeFunction
);
15324 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"number",
15325 xmlXPathNumberFunction
);
15326 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"position",
15327 xmlXPathPositionFunction
);
15328 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"round",
15329 xmlXPathRoundFunction
);
15330 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string",
15331 xmlXPathStringFunction
);
15332 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string-length",
15333 xmlXPathStringLengthFunction
);
15334 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"starts-with",
15335 xmlXPathStartsWithFunction
);
15336 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring",
15337 xmlXPathSubstringFunction
);
15338 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-before",
15339 xmlXPathSubstringBeforeFunction
);
15340 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-after",
15341 xmlXPathSubstringAfterFunction
);
15342 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"sum",
15343 xmlXPathSumFunction
);
15344 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"true",
15345 xmlXPathTrueFunction
);
15346 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"translate",
15347 xmlXPathTranslateFunction
);
15349 xmlXPathRegisterFuncNS(ctxt
, (const xmlChar
*)"escape-uri",
15350 (const xmlChar
*)"http://www.w3.org/2002/08/xquery-functions",
15351 xmlXPathEscapeUriFunction
);
15354 #endif /* LIBXML_XPATH_ENABLED */
15355 #define bottom_xpath
15356 #include "elfgcchack.h"