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"