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)
138 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
140 * xmlXPathCmpNodesExt:
141 * @node1: the first node
142 * @node2: the second node
144 * Compare two nodes w.r.t document order.
145 * This one is optimized for handling of non-element nodes.
147 * Returns -2 in case of error 1 if first point < second point, 0 if
148 * it's the same node, -1 otherwise
151 xmlXPathCmpNodesExt(xmlNodePtr node1
, xmlNodePtr node2
) {
153 int misc
= 0, precedence1
= 0, precedence2
= 0;
154 xmlNodePtr miscNode1
= NULL
, miscNode2
= NULL
;
155 xmlNodePtr cur
, root
;
158 if ((node1
== NULL
) || (node2
== NULL
))
165 * a couple of optimizations which will avoid computations in most cases
167 switch (node1
->type
) {
168 case XML_ELEMENT_NODE
:
169 if (node2
->type
== XML_ELEMENT_NODE
) {
170 if ((0 > (long) node1
->content
) && /* TODO: Would a != 0 suffice here? */
171 (0 > (long) node2
->content
) &&
172 (node1
->doc
== node2
->doc
))
174 l1
= -((long) node1
->content
);
175 l2
= -((long) node2
->content
);
181 goto turtle_comparison
;
184 case XML_ATTRIBUTE_NODE
:
185 precedence1
= 1; /* element is owner */
187 node1
= node1
->parent
;
191 case XML_CDATA_SECTION_NODE
:
192 case XML_COMMENT_NODE
:
196 * Find nearest element node.
198 if (node1
->prev
!= NULL
) {
201 if (node1
->type
== XML_ELEMENT_NODE
) {
202 precedence1
= 3; /* element in prev-sibl axis */
205 if (node1
->prev
== NULL
) {
206 precedence1
= 2; /* element is parent */
208 * URGENT TODO: Are there any cases, where the
209 * parent of such a node is not an element node?
211 node1
= node1
->parent
;
216 precedence1
= 2; /* element is parent */
217 node1
= node1
->parent
;
219 if ((node1
== NULL
) || (node1
->type
!= XML_ELEMENT_NODE
) ||
220 (0 <= (long) node1
->content
)) {
222 * Fallback for whatever case.
230 case XML_NAMESPACE_DECL
:
232 * TODO: why do we return 1 for namespace nodes?
238 switch (node2
->type
) {
239 case XML_ELEMENT_NODE
:
241 case XML_ATTRIBUTE_NODE
:
242 precedence2
= 1; /* element is owner */
244 node2
= node2
->parent
;
248 case XML_CDATA_SECTION_NODE
:
249 case XML_COMMENT_NODE
:
252 if (node2
->prev
!= NULL
) {
255 if (node2
->type
== XML_ELEMENT_NODE
) {
256 precedence2
= 3; /* element in prev-sibl axis */
259 if (node2
->prev
== NULL
) {
260 precedence2
= 2; /* element is parent */
261 node2
= node2
->parent
;
266 precedence2
= 2; /* element is parent */
267 node2
= node2
->parent
;
269 if ((node2
== NULL
) || (node2
->type
!= XML_ELEMENT_NODE
) ||
270 (0 <= (long) node2
->content
))
278 case XML_NAMESPACE_DECL
:
284 if (node1
== node2
) {
285 if (precedence1
== precedence2
) {
287 * The ugly case; but normally there aren't many
288 * adjacent non-element nodes around.
290 cur
= miscNode2
->prev
;
291 while (cur
!= NULL
) {
292 if (cur
== miscNode1
)
294 if (cur
->type
== XML_ELEMENT_NODE
)
301 * Evaluate based on higher precedence wrt to the element.
302 * TODO: This assumes attributes are sorted before content.
303 * Is this 100% correct?
305 if (precedence1
< precedence2
)
312 * Special case: One of the helper-elements is contained by the other.
315 * <node1>Text-1(precedence1 == 2)</node1>
317 * Text-6(precedence2 == 3)
320 if ((precedence2
== 3) && (precedence1
> 1)) {
328 if ((precedence1
== 3) && (precedence2
> 1)) {
339 * Speedup using document order if availble.
341 if ((node1
->type
== XML_ELEMENT_NODE
) &&
342 (node2
->type
== XML_ELEMENT_NODE
) &&
343 (0 > (long) node1
->content
) &&
344 (0 > (long) node2
->content
) &&
345 (node1
->doc
== node2
->doc
)) {
347 l1
= -((long) node1
->content
);
348 l2
= -((long) node2
->content
);
357 if (node1
== node2
->prev
)
359 if (node1
== node2
->next
)
362 * compute depth to root
364 for (depth2
= 0, cur
= node2
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
365 if (cur
->parent
== node1
)
370 for (depth1
= 0, cur
= node1
; cur
->parent
!= NULL
; cur
= cur
->parent
) {
371 if (cur
->parent
== node2
)
376 * Distinct document (or distinct entities :-( ) case.
382 * get the nearest common ancestor.
384 while (depth1
> depth2
) {
386 node1
= node1
->parent
;
388 while (depth2
> depth1
) {
390 node2
= node2
->parent
;
392 while (node1
->parent
!= node2
->parent
) {
393 node1
= node1
->parent
;
394 node2
= node2
->parent
;
395 /* should not happen but just in case ... */
396 if ((node1
== NULL
) || (node2
== NULL
))
402 if (node1
== node2
->prev
)
404 if (node1
== node2
->next
)
407 * Speedup using document order if availble.
409 if ((node1
->type
== XML_ELEMENT_NODE
) &&
410 (node2
->type
== XML_ELEMENT_NODE
) &&
411 (0 > (long) node1
->content
) &&
412 (0 > (long) node2
->content
) &&
413 (node1
->doc
== node2
->doc
)) {
415 l1
= -((long) node1
->content
);
416 l2
= -((long) node2
->content
);
423 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
426 return(-1); /* assume there is no sibling list corruption */
428 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
431 * Wrapper for the Timsort argorithm from timsort.h
434 #define SORT_NAME libxml_domnode
435 #define SORT_TYPE xmlNodePtr
441 * Comparison function for the Timsort implementation
443 * Returns -2 in case of error -1 if first point < second point, 0 if
444 * it's the same node, +1 otherwise
447 int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
);
448 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
449 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
451 int res
= xmlXPathCmpNodesExt(x
, y
);
452 return res
== -2 ? res
: -res
;
455 static int wrap_cmp( xmlNodePtr x
, xmlNodePtr y
)
457 int res
= xmlXPathCmpNodes(x
, y
);
458 return res
== -2 ? res
: -res
;
461 #define SORT_CMP(x, y) (wrap_cmp(x, y))
463 #endif /* WITH_TIM_SORT */
465 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
467 /************************************************************************
469 * Floating point stuff *
471 ************************************************************************/
473 #ifndef TRIO_REPLACE_STDIO
474 #define TRIO_PUBLIC static
479 * The lack of portability of this section of the libc is annoying !
481 double xmlXPathNAN
= 0;
482 double xmlXPathPINF
= 1;
483 double xmlXPathNINF
= -1;
484 static double xmlXPathNZERO
= 0; /* not exported from headers */
485 static int xmlXPathInitialized
= 0;
490 * Initialize the XPath environment
494 if (xmlXPathInitialized
) return;
496 xmlXPathPINF
= trio_pinf();
497 xmlXPathNINF
= trio_ninf();
498 xmlXPathNAN
= trio_nan();
499 xmlXPathNZERO
= trio_nzero();
501 xmlXPathInitialized
= 1;
506 * @val: a double value
508 * Provides a portable isnan() function to detect whether a double
509 * is a NotaNumber. Based on trio code
510 * http://sourceforge.net/projects/ctrio/
512 * Returns 1 if the value is a NaN, 0 otherwise
515 xmlXPathIsNaN(double val
) {
516 return(trio_isnan(val
));
521 * @val: a double value
523 * Provides a portable isinf() function to detect whether a double
524 * is a +Infinite or -Infinite. Based on trio code
525 * http://sourceforge.net/projects/ctrio/
527 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
530 xmlXPathIsInf(double val
) {
531 return(trio_isinf(val
));
534 #endif /* SCHEMAS or XPATH */
535 #ifdef LIBXML_XPATH_ENABLED
538 * @val: a double value
540 * Provides a portable function to detect the sign of a double
541 * Modified from trio code
542 * http://sourceforge.net/projects/ctrio/
544 * Returns 1 if the value is Negative, 0 if positive
547 xmlXPathGetSign(double val
) {
548 return(trio_signbit(val
));
553 * TODO: when compatibility allows remove all "fake node libxslt" strings
554 * the test should just be name[0] = ' '
556 #ifdef DEBUG_XPATH_EXPRESSION
559 #define DEBUG_EVAL_COUNTS
562 static xmlNs xmlXPathXMLNamespaceStruct
= {
570 static xmlNsPtr xmlXPathXMLNamespace
= &xmlXPathXMLNamespaceStruct
;
571 #ifndef LIBXML_THREAD_ENABLED
573 * Optimizer is disabled only when threaded apps are detected while
574 * the library ain't compiled for thread safety.
576 static int xmlXPathDisableOptimizer
= 0;
579 /************************************************************************
581 * Error handling routines *
583 ************************************************************************/
589 * Macro to raise an XPath error and return NULL.
591 #define XP_ERRORNULL(X) \
592 { xmlXPathErr(ctxt, X); return(NULL); }
595 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
597 static const char *xmlXPathErrorMessages
[] = {
600 "Unfinished literal\n",
601 "Start of literal\n",
602 "Expected $ for variable reference\n",
603 "Undefined variable\n",
604 "Invalid predicate\n",
605 "Invalid expression\n",
606 "Missing closing curly brace\n",
607 "Unregistered function\n",
610 "Invalid number of arguments\n",
611 "Invalid context size\n",
612 "Invalid context position\n",
613 "Memory allocation error\n",
616 "Sub resource error\n",
617 "Undefined namespace prefix\n",
619 "Char out of XML range\n",
620 "Invalid or incomplete context\n",
621 "Stack usage error\n",
622 "Forbidden variable\n",
623 "?? Unknown error ??\n" /* Must be last in the list! */
625 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
626 sizeof(xmlXPathErrorMessages[0])) - 1)
629 * @ctxt: an XPath context
630 * @extra: extra informations
632 * Handle a redefinition of attribute error
635 xmlXPathErrMemory(xmlXPathContextPtr ctxt
, const char *extra
)
641 xmlStrPrintf(buf
, 200,
642 "Memory allocation failed : %s\n",
644 ctxt
->lastError
.message
= (char *) xmlStrdup(buf
);
646 ctxt
->lastError
.message
= (char *)
647 xmlStrdup(BAD_CAST
"Memory allocation failed\n");
649 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
650 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
651 if (ctxt
->error
!= NULL
)
652 ctxt
->error(ctxt
->userData
, &ctxt
->lastError
);
655 __xmlRaiseError(NULL
, NULL
, NULL
,
656 NULL
, NULL
, XML_FROM_XPATH
,
657 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
658 extra
, NULL
, NULL
, 0, 0,
659 "Memory allocation failed : %s\n", extra
);
661 __xmlRaiseError(NULL
, NULL
, NULL
,
662 NULL
, NULL
, XML_FROM_XPATH
,
663 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0,
664 NULL
, NULL
, NULL
, 0, 0,
665 "Memory allocation failed\n");
670 * xmlXPathPErrMemory:
671 * @ctxt: an XPath parser context
672 * @extra: extra informations
674 * Handle a redefinition of attribute error
677 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt
, const char *extra
)
680 xmlXPathErrMemory(NULL
, extra
);
682 ctxt
->error
= XPATH_MEMORY_ERROR
;
683 xmlXPathErrMemory(ctxt
->context
, extra
);
689 * @ctxt: a XPath parser context
690 * @error: the error code
692 * Handle an XPath error
695 xmlXPathErr(xmlXPathParserContextPtr ctxt
, int error
)
697 if ((error
< 0) || (error
> MAXERRNO
))
700 __xmlRaiseError(NULL
, NULL
, NULL
,
701 NULL
, NULL
, XML_FROM_XPATH
,
702 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
703 XML_ERR_ERROR
, NULL
, 0,
704 NULL
, NULL
, NULL
, 0, 0,
705 "%s", xmlXPathErrorMessages
[error
]);
709 if (ctxt
->context
== NULL
) {
710 __xmlRaiseError(NULL
, NULL
, NULL
,
711 NULL
, NULL
, XML_FROM_XPATH
,
712 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
713 XML_ERR_ERROR
, NULL
, 0,
714 (const char *) ctxt
->base
, NULL
, NULL
,
715 ctxt
->cur
- ctxt
->base
, 0,
716 "%s", xmlXPathErrorMessages
[error
]);
720 /* cleanup current last error */
721 xmlResetError(&ctxt
->context
->lastError
);
723 ctxt
->context
->lastError
.domain
= XML_FROM_XPATH
;
724 ctxt
->context
->lastError
.code
= error
+ XML_XPATH_EXPRESSION_OK
-
726 ctxt
->context
->lastError
.level
= XML_ERR_ERROR
;
727 ctxt
->context
->lastError
.str1
= (char *) xmlStrdup(ctxt
->base
);
728 ctxt
->context
->lastError
.int1
= ctxt
->cur
- ctxt
->base
;
729 ctxt
->context
->lastError
.node
= ctxt
->context
->debugNode
;
730 if (ctxt
->context
->error
!= NULL
) {
731 ctxt
->context
->error(ctxt
->context
->userData
,
732 &ctxt
->context
->lastError
);
734 __xmlRaiseError(NULL
, NULL
, NULL
,
735 NULL
, ctxt
->context
->debugNode
, XML_FROM_XPATH
,
736 error
+ XML_XPATH_EXPRESSION_OK
- XPATH_EXPRESSION_OK
,
737 XML_ERR_ERROR
, NULL
, 0,
738 (const char *) ctxt
->base
, NULL
, NULL
,
739 ctxt
->cur
- ctxt
->base
, 0,
740 "%s", xmlXPathErrorMessages
[error
]);
747 * @ctxt: the XPath Parser context
748 * @file: the file name
749 * @line: the line number
750 * @no: the error number
752 * Formats an error message.
755 xmlXPatherror(xmlXPathParserContextPtr ctxt
, const char *file ATTRIBUTE_UNUSED
,
756 int line ATTRIBUTE_UNUSED
, int no
) {
757 xmlXPathErr(ctxt
, no
);
760 /************************************************************************
764 ************************************************************************/
769 * Pointer-list for various purposes.
771 typedef struct _xmlPointerList xmlPointerList
;
772 typedef xmlPointerList
*xmlPointerListPtr
;
773 struct _xmlPointerList
{
779 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
780 * and here, we should make the functions public.
783 xmlPointerListAddSize(xmlPointerListPtr list
,
787 if (list
->items
== NULL
) {
788 if (initialSize
<= 0)
790 list
->items
= (void **) xmlMalloc(initialSize
* sizeof(void *));
791 if (list
->items
== NULL
) {
792 xmlXPathErrMemory(NULL
,
793 "xmlPointerListCreate: allocating item\n");
797 list
->size
= initialSize
;
798 } else if (list
->size
<= list
->number
) {
799 if (list
->size
> 50000000) {
800 xmlXPathErrMemory(NULL
,
801 "xmlPointerListAddSize: re-allocating item\n");
805 list
->items
= (void **) xmlRealloc(list
->items
,
806 list
->size
* sizeof(void *));
807 if (list
->items
== NULL
) {
808 xmlXPathErrMemory(NULL
,
809 "xmlPointerListAddSize: re-allocating item\n");
814 list
->items
[list
->number
++] = item
;
819 * xsltPointerListCreate:
821 * Creates an xsltPointerList structure.
823 * Returns a xsltPointerList structure or NULL in case of an error.
825 static xmlPointerListPtr
826 xmlPointerListCreate(int initialSize
)
828 xmlPointerListPtr ret
;
830 ret
= xmlMalloc(sizeof(xmlPointerList
));
832 xmlXPathErrMemory(NULL
,
833 "xmlPointerListCreate: allocating item\n");
836 memset(ret
, 0, sizeof(xmlPointerList
));
837 if (initialSize
> 0) {
838 xmlPointerListAddSize(ret
, NULL
, initialSize
);
845 * xsltPointerListFree:
847 * Frees the xsltPointerList structure. This does not free
848 * the content of the list.
851 xmlPointerListFree(xmlPointerListPtr list
)
855 if (list
->items
!= NULL
)
856 xmlFree(list
->items
);
860 /************************************************************************
864 ************************************************************************/
881 XPATH_OP_RESET
, /* 10 */
883 XPATH_OP_VALUE
, /* 12 */
888 XPATH_OP_FILTER
, /* 17 */
889 XPATH_OP_SORT
/* 18 */
890 #ifdef LIBXML_XPTR_ENABLED
897 AXIS_ANCESTOR_OR_SELF
,
901 AXIS_DESCENDANT_OR_SELF
,
903 AXIS_FOLLOWING_SIBLING
,
907 AXIS_PRECEDING_SIBLING
,
922 NODE_TYPE_COMMENT
= XML_COMMENT_NODE
,
923 NODE_TYPE_TEXT
= XML_TEXT_NODE
,
924 NODE_TYPE_PI
= XML_PI_NODE
927 typedef struct _xmlXPathStepOp xmlXPathStepOp
;
928 typedef xmlXPathStepOp
*xmlXPathStepOpPtr
;
929 struct _xmlXPathStepOp
{
930 xmlXPathOp op
; /* The identifier of the operation */
931 int ch1
; /* First child */
932 int ch2
; /* Second child */
942 struct _xmlXPathCompExpr
{
943 int nbStep
; /* Number of steps in this expression */
944 int maxStep
; /* Maximum number of steps allocated */
945 xmlXPathStepOp
*steps
; /* ops for computation of this expression */
946 int last
; /* index of last step in expression */
947 xmlChar
*expr
; /* the expression being computed */
948 xmlDictPtr dict
; /* the dictionary to use if any */
949 #ifdef DEBUG_EVAL_COUNTS
953 #ifdef XPATH_STREAMING
954 xmlPatternPtr stream
;
958 /************************************************************************
960 * Forward declarations *
962 ************************************************************************/
964 xmlXPathFreeValueTree(xmlNodeSetPtr obj
);
966 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
);
968 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
969 xmlXPathStepOpPtr op
, xmlNodePtr
*first
);
971 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
972 xmlXPathStepOpPtr op
,
975 /************************************************************************
977 * Parser Type functions *
979 ************************************************************************/
982 * xmlXPathNewCompExpr:
984 * Create a new Xpath component
986 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
988 static xmlXPathCompExprPtr
989 xmlXPathNewCompExpr(void) {
990 xmlXPathCompExprPtr cur
;
992 cur
= (xmlXPathCompExprPtr
) xmlMalloc(sizeof(xmlXPathCompExpr
));
994 xmlXPathErrMemory(NULL
, "allocating component\n");
997 memset(cur
, 0, sizeof(xmlXPathCompExpr
));
1000 cur
->steps
= (xmlXPathStepOp
*) xmlMalloc(cur
->maxStep
*
1001 sizeof(xmlXPathStepOp
));
1002 if (cur
->steps
== NULL
) {
1003 xmlXPathErrMemory(NULL
, "allocating steps\n");
1007 memset(cur
->steps
, 0, cur
->maxStep
* sizeof(xmlXPathStepOp
));
1009 #ifdef DEBUG_EVAL_COUNTS
1016 * xmlXPathFreeCompExpr:
1017 * @comp: an XPATH comp
1019 * Free up the memory allocated by @comp
1022 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp
)
1024 xmlXPathStepOpPtr op
;
1029 if (comp
->dict
== NULL
) {
1030 for (i
= 0; i
< comp
->nbStep
; i
++) {
1031 op
= &comp
->steps
[i
];
1032 if (op
->value4
!= NULL
) {
1033 if (op
->op
== XPATH_OP_VALUE
)
1034 xmlXPathFreeObject(op
->value4
);
1036 xmlFree(op
->value4
);
1038 if (op
->value5
!= NULL
)
1039 xmlFree(op
->value5
);
1042 for (i
= 0; i
< comp
->nbStep
; i
++) {
1043 op
= &comp
->steps
[i
];
1044 if (op
->value4
!= NULL
) {
1045 if (op
->op
== XPATH_OP_VALUE
)
1046 xmlXPathFreeObject(op
->value4
);
1049 xmlDictFree(comp
->dict
);
1051 if (comp
->steps
!= NULL
) {
1052 xmlFree(comp
->steps
);
1054 #ifdef DEBUG_EVAL_COUNTS
1055 if (comp
->string
!= NULL
) {
1056 xmlFree(comp
->string
);
1059 #ifdef XPATH_STREAMING
1060 if (comp
->stream
!= NULL
) {
1061 xmlFreePatternList(comp
->stream
);
1064 if (comp
->expr
!= NULL
) {
1065 xmlFree(comp
->expr
);
1072 * xmlXPathCompExprAdd:
1073 * @comp: the compiled expression
1074 * @ch1: first child index
1075 * @ch2: second child index
1077 * @value: the first int value
1078 * @value2: the second int value
1079 * @value3: the third int value
1080 * @value4: the first string value
1081 * @value5: the second string value
1083 * Add a step to an XPath Compiled Expression
1085 * Returns -1 in case of failure, the index otherwise
1088 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp
, int ch1
, int ch2
,
1089 xmlXPathOp op
, int value
,
1090 int value2
, int value3
, void *value4
, void *value5
) {
1091 if (comp
->nbStep
>= comp
->maxStep
) {
1092 xmlXPathStepOp
*real
;
1094 if (comp
->maxStep
>= XPATH_MAX_STEPS
) {
1095 xmlXPathErrMemory(NULL
, "adding step\n");
1099 real
= (xmlXPathStepOp
*) xmlRealloc(comp
->steps
,
1100 comp
->maxStep
* sizeof(xmlXPathStepOp
));
1103 xmlXPathErrMemory(NULL
, "adding step\n");
1108 comp
->last
= comp
->nbStep
;
1109 comp
->steps
[comp
->nbStep
].ch1
= ch1
;
1110 comp
->steps
[comp
->nbStep
].ch2
= ch2
;
1111 comp
->steps
[comp
->nbStep
].op
= op
;
1112 comp
->steps
[comp
->nbStep
].value
= value
;
1113 comp
->steps
[comp
->nbStep
].value2
= value2
;
1114 comp
->steps
[comp
->nbStep
].value3
= value3
;
1115 if ((comp
->dict
!= NULL
) &&
1116 ((op
== XPATH_OP_FUNCTION
) || (op
== XPATH_OP_VARIABLE
) ||
1117 (op
== XPATH_OP_COLLECT
))) {
1118 if (value4
!= NULL
) {
1119 comp
->steps
[comp
->nbStep
].value4
= (xmlChar
*)
1120 (void *)xmlDictLookup(comp
->dict
, value4
, -1);
1123 comp
->steps
[comp
->nbStep
].value4
= NULL
;
1124 if (value5
!= NULL
) {
1125 comp
->steps
[comp
->nbStep
].value5
= (xmlChar
*)
1126 (void *)xmlDictLookup(comp
->dict
, value5
, -1);
1129 comp
->steps
[comp
->nbStep
].value5
= NULL
;
1131 comp
->steps
[comp
->nbStep
].value4
= value4
;
1132 comp
->steps
[comp
->nbStep
].value5
= value5
;
1134 comp
->steps
[comp
->nbStep
].cache
= NULL
;
1135 return(comp
->nbStep
++);
1140 * @comp: the compiled expression
1141 * @op: operation index
1143 * Swaps 2 operations in the compiled expression
1146 xmlXPathCompSwap(xmlXPathStepOpPtr op
) {
1149 #ifndef LIBXML_THREAD_ENABLED
1151 * Since this manipulates possibly shared variables, this is
1152 * disabled if one detects that the library is used in a multithreaded
1155 if (xmlXPathDisableOptimizer
)
1164 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1165 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1166 (op), (val), (val2), (val3), (val4), (val5))
1167 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1168 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1169 (op), (val), (val2), (val3), (val4), (val5))
1171 #define PUSH_LEAVE_EXPR(op, val, val2) \
1172 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1174 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1175 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1177 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1178 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1179 (val), (val2), 0 ,NULL ,NULL)
1181 /************************************************************************
1183 * XPath object cache structures *
1185 ************************************************************************/
1187 /* #define XP_DEFAULT_CACHE_ON */
1189 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1191 typedef struct _xmlXPathContextCache xmlXPathContextCache
;
1192 typedef xmlXPathContextCache
*xmlXPathContextCachePtr
;
1193 struct _xmlXPathContextCache
{
1194 xmlPointerListPtr nodesetObjs
; /* contains xmlXPathObjectPtr */
1195 xmlPointerListPtr stringObjs
; /* contains xmlXPathObjectPtr */
1196 xmlPointerListPtr booleanObjs
; /* contains xmlXPathObjectPtr */
1197 xmlPointerListPtr numberObjs
; /* contains xmlXPathObjectPtr */
1198 xmlPointerListPtr miscObjs
; /* contains xmlXPathObjectPtr */
1204 #ifdef XP_DEBUG_OBJ_USAGE
1206 int dbgCachedNodeset
;
1207 int dbgCachedString
;
1209 int dbgCachedNumber
;
1212 int dbgCachedLocset
;
1214 int dbgCachedXSLTTree
;
1215 int dbgCachedUndefined
;
1219 int dbgReusedNodeset
;
1220 int dbgReusedString
;
1222 int dbgReusedNumber
;
1225 int dbgReusedLocset
;
1227 int dbgReusedXSLTTree
;
1228 int dbgReusedUndefined
;
1233 /************************************************************************
1235 * Debugging related functions *
1237 ************************************************************************/
1240 xmlGenericError(xmlGenericErrorContext, \
1241 "Internal error at %s:%d\n", \
1242 __FILE__, __LINE__);
1244 #ifdef LIBXML_DEBUG_ENABLED
1246 xmlXPathDebugDumpNode(FILE *output
, xmlNodePtr cur
, int depth
) {
1250 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1251 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1252 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1254 fprintf(output
, "%s", shift
);
1255 fprintf(output
, "Node is NULL !\n");
1260 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
1261 (cur
->type
== XML_HTML_DOCUMENT_NODE
)) {
1262 fprintf(output
, "%s", shift
);
1263 fprintf(output
, " /\n");
1264 } else if (cur
->type
== XML_ATTRIBUTE_NODE
)
1265 xmlDebugDumpAttr(output
, (xmlAttrPtr
)cur
, depth
);
1267 xmlDebugDumpOneNode(output
, cur
, depth
);
1270 xmlXPathDebugDumpNodeList(FILE *output
, xmlNodePtr cur
, int depth
) {
1275 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1276 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1277 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1279 fprintf(output
, "%s", shift
);
1280 fprintf(output
, "Node is NULL !\n");
1285 while (cur
!= NULL
) {
1288 xmlDebugDumpOneNode(output
, tmp
, depth
);
1293 xmlXPathDebugDumpNodeSet(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1297 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1298 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1299 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1302 fprintf(output
, "%s", shift
);
1303 fprintf(output
, "NodeSet is NULL !\n");
1309 fprintf(output
, "Set contains %d nodes:\n", cur
->nodeNr
);
1310 for (i
= 0;i
< cur
->nodeNr
;i
++) {
1311 fprintf(output
, "%s", shift
);
1312 fprintf(output
, "%d", i
+ 1);
1313 xmlXPathDebugDumpNode(output
, cur
->nodeTab
[i
], depth
+ 1);
1319 xmlXPathDebugDumpValueTree(FILE *output
, xmlNodeSetPtr cur
, int depth
) {
1323 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1324 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1325 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1327 if ((cur
== NULL
) || (cur
->nodeNr
== 0) || (cur
->nodeTab
[0] == NULL
)) {
1328 fprintf(output
, "%s", shift
);
1329 fprintf(output
, "Value Tree is NULL !\n");
1334 fprintf(output
, "%s", shift
);
1335 fprintf(output
, "%d", i
+ 1);
1336 xmlXPathDebugDumpNodeList(output
, cur
->nodeTab
[0]->children
, depth
+ 1);
1338 #if defined(LIBXML_XPTR_ENABLED)
1340 xmlXPathDebugDumpLocationSet(FILE *output
, xmlLocationSetPtr cur
, int depth
) {
1344 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1345 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1346 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1349 fprintf(output
, "%s", shift
);
1350 fprintf(output
, "LocationSet is NULL !\n");
1355 for (i
= 0;i
< cur
->locNr
;i
++) {
1356 fprintf(output
, "%s", shift
);
1357 fprintf(output
, "%d : ", i
+ 1);
1358 xmlXPathDebugDumpObject(output
, cur
->locTab
[i
], depth
+ 1);
1361 #endif /* LIBXML_XPTR_ENABLED */
1364 * xmlXPathDebugDumpObject:
1365 * @output: the FILE * to dump the output
1366 * @cur: the object to inspect
1367 * @depth: indentation level
1369 * Dump the content of the object for debugging purposes
1372 xmlXPathDebugDumpObject(FILE *output
, xmlXPathObjectPtr cur
, int depth
) {
1376 if (output
== 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;
1383 fprintf(output
, "%s", shift
);
1386 fprintf(output
, "Object is empty (NULL)\n");
1390 case XPATH_UNDEFINED
:
1391 fprintf(output
, "Object is uninitialized\n");
1394 fprintf(output
, "Object is a Node Set :\n");
1395 xmlXPathDebugDumpNodeSet(output
, cur
->nodesetval
, depth
);
1397 case XPATH_XSLT_TREE
:
1398 fprintf(output
, "Object is an XSLT value tree :\n");
1399 xmlXPathDebugDumpValueTree(output
, cur
->nodesetval
, depth
);
1402 fprintf(output
, "Object is a Boolean : ");
1403 if (cur
->boolval
) fprintf(output
, "true\n");
1404 else fprintf(output
, "false\n");
1407 switch (xmlXPathIsInf(cur
->floatval
)) {
1409 fprintf(output
, "Object is a number : Infinity\n");
1412 fprintf(output
, "Object is a number : -Infinity\n");
1415 if (xmlXPathIsNaN(cur
->floatval
)) {
1416 fprintf(output
, "Object is a number : NaN\n");
1417 } else if (cur
->floatval
== 0 && xmlXPathGetSign(cur
->floatval
) != 0) {
1418 fprintf(output
, "Object is a number : 0\n");
1420 fprintf(output
, "Object is a number : %0g\n", cur
->floatval
);
1425 fprintf(output
, "Object is a string : ");
1426 xmlDebugDumpString(output
, cur
->stringval
);
1427 fprintf(output
, "\n");
1430 fprintf(output
, "Object is a point : index %d in node", cur
->index
);
1431 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
, depth
+ 1);
1432 fprintf(output
, "\n");
1435 if ((cur
->user2
== NULL
) ||
1436 ((cur
->user2
== cur
->user
) && (cur
->index
== cur
->index2
))) {
1437 fprintf(output
, "Object is a collapsed range :\n");
1438 fprintf(output
, "%s", shift
);
1439 if (cur
->index
>= 0)
1440 fprintf(output
, "index %d in ", cur
->index
);
1441 fprintf(output
, "node\n");
1442 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1445 fprintf(output
, "Object is a range :\n");
1446 fprintf(output
, "%s", shift
);
1447 fprintf(output
, "From ");
1448 if (cur
->index
>= 0)
1449 fprintf(output
, "index %d in ", cur
->index
);
1450 fprintf(output
, "node\n");
1451 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user
,
1453 fprintf(output
, "%s", shift
);
1454 fprintf(output
, "To ");
1455 if (cur
->index2
>= 0)
1456 fprintf(output
, "index %d in ", cur
->index2
);
1457 fprintf(output
, "node\n");
1458 xmlXPathDebugDumpNode(output
, (xmlNodePtr
) cur
->user2
,
1460 fprintf(output
, "\n");
1463 case XPATH_LOCATIONSET
:
1464 #if defined(LIBXML_XPTR_ENABLED)
1465 fprintf(output
, "Object is a Location Set:\n");
1466 xmlXPathDebugDumpLocationSet(output
,
1467 (xmlLocationSetPtr
) cur
->user
, depth
);
1471 fprintf(output
, "Object is user defined\n");
1477 xmlXPathDebugDumpStepOp(FILE *output
, xmlXPathCompExprPtr comp
,
1478 xmlXPathStepOpPtr op
, int depth
) {
1482 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1483 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1484 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1486 fprintf(output
, "%s", shift
);
1488 fprintf(output
, "Step is NULL\n");
1493 fprintf(output
, "END"); break;
1495 fprintf(output
, "AND"); break;
1497 fprintf(output
, "OR"); break;
1498 case XPATH_OP_EQUAL
:
1500 fprintf(output
, "EQUAL =");
1502 fprintf(output
, "EQUAL !=");
1506 fprintf(output
, "CMP <");
1508 fprintf(output
, "CMP >");
1510 fprintf(output
, "=");
1514 fprintf(output
, "PLUS -");
1515 else if (op
->value
== 1)
1516 fprintf(output
, "PLUS +");
1517 else if (op
->value
== 2)
1518 fprintf(output
, "PLUS unary -");
1519 else if (op
->value
== 3)
1520 fprintf(output
, "PLUS unary - -");
1524 fprintf(output
, "MULT *");
1525 else if (op
->value
== 1)
1526 fprintf(output
, "MULT div");
1528 fprintf(output
, "MULT mod");
1530 case XPATH_OP_UNION
:
1531 fprintf(output
, "UNION"); break;
1533 fprintf(output
, "ROOT"); break;
1535 fprintf(output
, "NODE"); break;
1536 case XPATH_OP_RESET
:
1537 fprintf(output
, "RESET"); break;
1539 fprintf(output
, "SORT"); break;
1540 case XPATH_OP_COLLECT
: {
1541 xmlXPathAxisVal axis
= (xmlXPathAxisVal
)op
->value
;
1542 xmlXPathTestVal test
= (xmlXPathTestVal
)op
->value2
;
1543 xmlXPathTypeVal type
= (xmlXPathTypeVal
)op
->value3
;
1544 const xmlChar
*prefix
= op
->value4
;
1545 const xmlChar
*name
= op
->value5
;
1547 fprintf(output
, "COLLECT ");
1550 fprintf(output
, " 'ancestors' "); break;
1551 case AXIS_ANCESTOR_OR_SELF
:
1552 fprintf(output
, " 'ancestors-or-self' "); break;
1553 case AXIS_ATTRIBUTE
:
1554 fprintf(output
, " 'attributes' "); break;
1556 fprintf(output
, " 'child' "); break;
1557 case AXIS_DESCENDANT
:
1558 fprintf(output
, " 'descendant' "); break;
1559 case AXIS_DESCENDANT_OR_SELF
:
1560 fprintf(output
, " 'descendant-or-self' "); break;
1561 case AXIS_FOLLOWING
:
1562 fprintf(output
, " 'following' "); break;
1563 case AXIS_FOLLOWING_SIBLING
:
1564 fprintf(output
, " 'following-siblings' "); break;
1565 case AXIS_NAMESPACE
:
1566 fprintf(output
, " 'namespace' "); break;
1568 fprintf(output
, " 'parent' "); break;
1569 case AXIS_PRECEDING
:
1570 fprintf(output
, " 'preceding' "); break;
1571 case AXIS_PRECEDING_SIBLING
:
1572 fprintf(output
, " 'preceding-sibling' "); break;
1574 fprintf(output
, " 'self' "); break;
1577 case NODE_TEST_NONE
:
1578 fprintf(output
, "'none' "); break;
1579 case NODE_TEST_TYPE
:
1580 fprintf(output
, "'type' "); break;
1582 fprintf(output
, "'PI' "); break;
1584 fprintf(output
, "'all' "); break;
1586 fprintf(output
, "'namespace' "); break;
1587 case NODE_TEST_NAME
:
1588 fprintf(output
, "'name' "); break;
1591 case NODE_TYPE_NODE
:
1592 fprintf(output
, "'node' "); break;
1593 case NODE_TYPE_COMMENT
:
1594 fprintf(output
, "'comment' "); break;
1595 case NODE_TYPE_TEXT
:
1596 fprintf(output
, "'text' "); break;
1598 fprintf(output
, "'PI' "); break;
1601 fprintf(output
, "%s:", prefix
);
1603 fprintf(output
, "%s", (const char *) name
);
1607 case XPATH_OP_VALUE
: {
1608 xmlXPathObjectPtr object
= (xmlXPathObjectPtr
) op
->value4
;
1610 fprintf(output
, "ELEM ");
1611 xmlXPathDebugDumpObject(output
, object
, 0);
1614 case XPATH_OP_VARIABLE
: {
1615 const xmlChar
*prefix
= op
->value5
;
1616 const xmlChar
*name
= op
->value4
;
1619 fprintf(output
, "VARIABLE %s:%s", prefix
, name
);
1621 fprintf(output
, "VARIABLE %s", name
);
1624 case XPATH_OP_FUNCTION
: {
1625 int nbargs
= op
->value
;
1626 const xmlChar
*prefix
= op
->value5
;
1627 const xmlChar
*name
= op
->value4
;
1630 fprintf(output
, "FUNCTION %s:%s(%d args)",
1631 prefix
, name
, nbargs
);
1633 fprintf(output
, "FUNCTION %s(%d args)", name
, nbargs
);
1636 case XPATH_OP_ARG
: fprintf(output
, "ARG"); break;
1637 case XPATH_OP_PREDICATE
: fprintf(output
, "PREDICATE"); break;
1638 case XPATH_OP_FILTER
: fprintf(output
, "FILTER"); break;
1639 #ifdef LIBXML_XPTR_ENABLED
1640 case XPATH_OP_RANGETO
: fprintf(output
, "RANGETO"); break;
1643 fprintf(output
, "UNKNOWN %d\n", op
->op
); return;
1645 fprintf(output
, "\n");
1648 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch1
], depth
+ 1);
1650 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[op
->ch2
], depth
+ 1);
1654 * xmlXPathDebugDumpCompExpr:
1655 * @output: the FILE * for the output
1656 * @comp: the precompiled XPath expression
1657 * @depth: the indentation level.
1659 * Dumps the tree of the compiled XPath expression.
1662 xmlXPathDebugDumpCompExpr(FILE *output
, xmlXPathCompExprPtr comp
,
1667 if ((output
== NULL
) || (comp
== NULL
)) return;
1669 for (i
= 0;((i
< depth
) && (i
< 25));i
++)
1670 shift
[2 * i
] = shift
[2 * i
+ 1] = ' ';
1671 shift
[2 * i
] = shift
[2 * i
+ 1] = 0;
1673 fprintf(output
, "%s", shift
);
1675 fprintf(output
, "Compiled Expression : %d elements\n",
1678 xmlXPathDebugDumpStepOp(output
, comp
, &comp
->steps
[i
], depth
+ 1);
1681 #ifdef XP_DEBUG_OBJ_USAGE
1684 * XPath object usage related debugging variables.
1686 static int xmlXPathDebugObjCounterUndefined
= 0;
1687 static int xmlXPathDebugObjCounterNodeset
= 0;
1688 static int xmlXPathDebugObjCounterBool
= 0;
1689 static int xmlXPathDebugObjCounterNumber
= 0;
1690 static int xmlXPathDebugObjCounterString
= 0;
1691 static int xmlXPathDebugObjCounterPoint
= 0;
1692 static int xmlXPathDebugObjCounterRange
= 0;
1693 static int xmlXPathDebugObjCounterLocset
= 0;
1694 static int xmlXPathDebugObjCounterUsers
= 0;
1695 static int xmlXPathDebugObjCounterXSLTTree
= 0;
1696 static int xmlXPathDebugObjCounterAll
= 0;
1698 static int xmlXPathDebugObjTotalUndefined
= 0;
1699 static int xmlXPathDebugObjTotalNodeset
= 0;
1700 static int xmlXPathDebugObjTotalBool
= 0;
1701 static int xmlXPathDebugObjTotalNumber
= 0;
1702 static int xmlXPathDebugObjTotalString
= 0;
1703 static int xmlXPathDebugObjTotalPoint
= 0;
1704 static int xmlXPathDebugObjTotalRange
= 0;
1705 static int xmlXPathDebugObjTotalLocset
= 0;
1706 static int xmlXPathDebugObjTotalUsers
= 0;
1707 static int xmlXPathDebugObjTotalXSLTTree
= 0;
1708 static int xmlXPathDebugObjTotalAll
= 0;
1710 static int xmlXPathDebugObjMaxUndefined
= 0;
1711 static int xmlXPathDebugObjMaxNodeset
= 0;
1712 static int xmlXPathDebugObjMaxBool
= 0;
1713 static int xmlXPathDebugObjMaxNumber
= 0;
1714 static int xmlXPathDebugObjMaxString
= 0;
1715 static int xmlXPathDebugObjMaxPoint
= 0;
1716 static int xmlXPathDebugObjMaxRange
= 0;
1717 static int xmlXPathDebugObjMaxLocset
= 0;
1718 static int xmlXPathDebugObjMaxUsers
= 0;
1719 static int xmlXPathDebugObjMaxXSLTTree
= 0;
1720 static int xmlXPathDebugObjMaxAll
= 0;
1722 /* REVISIT TODO: Make this static when committing */
1724 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt
)
1727 if (ctxt
->cache
!= NULL
) {
1728 xmlXPathContextCachePtr cache
=
1729 (xmlXPathContextCachePtr
) ctxt
->cache
;
1731 cache
->dbgCachedAll
= 0;
1732 cache
->dbgCachedNodeset
= 0;
1733 cache
->dbgCachedString
= 0;
1734 cache
->dbgCachedBool
= 0;
1735 cache
->dbgCachedNumber
= 0;
1736 cache
->dbgCachedPoint
= 0;
1737 cache
->dbgCachedRange
= 0;
1738 cache
->dbgCachedLocset
= 0;
1739 cache
->dbgCachedUsers
= 0;
1740 cache
->dbgCachedXSLTTree
= 0;
1741 cache
->dbgCachedUndefined
= 0;
1743 cache
->dbgReusedAll
= 0;
1744 cache
->dbgReusedNodeset
= 0;
1745 cache
->dbgReusedString
= 0;
1746 cache
->dbgReusedBool
= 0;
1747 cache
->dbgReusedNumber
= 0;
1748 cache
->dbgReusedPoint
= 0;
1749 cache
->dbgReusedRange
= 0;
1750 cache
->dbgReusedLocset
= 0;
1751 cache
->dbgReusedUsers
= 0;
1752 cache
->dbgReusedXSLTTree
= 0;
1753 cache
->dbgReusedUndefined
= 0;
1757 xmlXPathDebugObjCounterUndefined
= 0;
1758 xmlXPathDebugObjCounterNodeset
= 0;
1759 xmlXPathDebugObjCounterBool
= 0;
1760 xmlXPathDebugObjCounterNumber
= 0;
1761 xmlXPathDebugObjCounterString
= 0;
1762 xmlXPathDebugObjCounterPoint
= 0;
1763 xmlXPathDebugObjCounterRange
= 0;
1764 xmlXPathDebugObjCounterLocset
= 0;
1765 xmlXPathDebugObjCounterUsers
= 0;
1766 xmlXPathDebugObjCounterXSLTTree
= 0;
1767 xmlXPathDebugObjCounterAll
= 0;
1769 xmlXPathDebugObjTotalUndefined
= 0;
1770 xmlXPathDebugObjTotalNodeset
= 0;
1771 xmlXPathDebugObjTotalBool
= 0;
1772 xmlXPathDebugObjTotalNumber
= 0;
1773 xmlXPathDebugObjTotalString
= 0;
1774 xmlXPathDebugObjTotalPoint
= 0;
1775 xmlXPathDebugObjTotalRange
= 0;
1776 xmlXPathDebugObjTotalLocset
= 0;
1777 xmlXPathDebugObjTotalUsers
= 0;
1778 xmlXPathDebugObjTotalXSLTTree
= 0;
1779 xmlXPathDebugObjTotalAll
= 0;
1781 xmlXPathDebugObjMaxUndefined
= 0;
1782 xmlXPathDebugObjMaxNodeset
= 0;
1783 xmlXPathDebugObjMaxBool
= 0;
1784 xmlXPathDebugObjMaxNumber
= 0;
1785 xmlXPathDebugObjMaxString
= 0;
1786 xmlXPathDebugObjMaxPoint
= 0;
1787 xmlXPathDebugObjMaxRange
= 0;
1788 xmlXPathDebugObjMaxLocset
= 0;
1789 xmlXPathDebugObjMaxUsers
= 0;
1790 xmlXPathDebugObjMaxXSLTTree
= 0;
1791 xmlXPathDebugObjMaxAll
= 0;
1796 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt
,
1797 xmlXPathObjectType objType
)
1802 if (ctxt
->cache
!= NULL
) {
1803 xmlXPathContextCachePtr cache
=
1804 (xmlXPathContextCachePtr
) ctxt
->cache
;
1808 cache
->dbgReusedAll
++;
1810 case XPATH_UNDEFINED
:
1811 cache
->dbgReusedUndefined
++;
1814 cache
->dbgReusedNodeset
++;
1817 cache
->dbgReusedBool
++;
1820 cache
->dbgReusedNumber
++;
1823 cache
->dbgReusedString
++;
1826 cache
->dbgReusedPoint
++;
1829 cache
->dbgReusedRange
++;
1831 case XPATH_LOCATIONSET
:
1832 cache
->dbgReusedLocset
++;
1835 cache
->dbgReusedUsers
++;
1837 case XPATH_XSLT_TREE
:
1838 cache
->dbgReusedXSLTTree
++;
1847 case XPATH_UNDEFINED
:
1849 xmlXPathDebugObjTotalUndefined
++;
1850 xmlXPathDebugObjCounterUndefined
++;
1851 if (xmlXPathDebugObjCounterUndefined
>
1852 xmlXPathDebugObjMaxUndefined
)
1853 xmlXPathDebugObjMaxUndefined
=
1854 xmlXPathDebugObjCounterUndefined
;
1858 xmlXPathDebugObjTotalNodeset
++;
1859 xmlXPathDebugObjCounterNodeset
++;
1860 if (xmlXPathDebugObjCounterNodeset
>
1861 xmlXPathDebugObjMaxNodeset
)
1862 xmlXPathDebugObjMaxNodeset
=
1863 xmlXPathDebugObjCounterNodeset
;
1867 xmlXPathDebugObjTotalBool
++;
1868 xmlXPathDebugObjCounterBool
++;
1869 if (xmlXPathDebugObjCounterBool
>
1870 xmlXPathDebugObjMaxBool
)
1871 xmlXPathDebugObjMaxBool
=
1872 xmlXPathDebugObjCounterBool
;
1876 xmlXPathDebugObjTotalNumber
++;
1877 xmlXPathDebugObjCounterNumber
++;
1878 if (xmlXPathDebugObjCounterNumber
>
1879 xmlXPathDebugObjMaxNumber
)
1880 xmlXPathDebugObjMaxNumber
=
1881 xmlXPathDebugObjCounterNumber
;
1885 xmlXPathDebugObjTotalString
++;
1886 xmlXPathDebugObjCounterString
++;
1887 if (xmlXPathDebugObjCounterString
>
1888 xmlXPathDebugObjMaxString
)
1889 xmlXPathDebugObjMaxString
=
1890 xmlXPathDebugObjCounterString
;
1894 xmlXPathDebugObjTotalPoint
++;
1895 xmlXPathDebugObjCounterPoint
++;
1896 if (xmlXPathDebugObjCounterPoint
>
1897 xmlXPathDebugObjMaxPoint
)
1898 xmlXPathDebugObjMaxPoint
=
1899 xmlXPathDebugObjCounterPoint
;
1903 xmlXPathDebugObjTotalRange
++;
1904 xmlXPathDebugObjCounterRange
++;
1905 if (xmlXPathDebugObjCounterRange
>
1906 xmlXPathDebugObjMaxRange
)
1907 xmlXPathDebugObjMaxRange
=
1908 xmlXPathDebugObjCounterRange
;
1910 case XPATH_LOCATIONSET
:
1912 xmlXPathDebugObjTotalLocset
++;
1913 xmlXPathDebugObjCounterLocset
++;
1914 if (xmlXPathDebugObjCounterLocset
>
1915 xmlXPathDebugObjMaxLocset
)
1916 xmlXPathDebugObjMaxLocset
=
1917 xmlXPathDebugObjCounterLocset
;
1921 xmlXPathDebugObjTotalUsers
++;
1922 xmlXPathDebugObjCounterUsers
++;
1923 if (xmlXPathDebugObjCounterUsers
>
1924 xmlXPathDebugObjMaxUsers
)
1925 xmlXPathDebugObjMaxUsers
=
1926 xmlXPathDebugObjCounterUsers
;
1928 case XPATH_XSLT_TREE
:
1930 xmlXPathDebugObjTotalXSLTTree
++;
1931 xmlXPathDebugObjCounterXSLTTree
++;
1932 if (xmlXPathDebugObjCounterXSLTTree
>
1933 xmlXPathDebugObjMaxXSLTTree
)
1934 xmlXPathDebugObjMaxXSLTTree
=
1935 xmlXPathDebugObjCounterXSLTTree
;
1941 xmlXPathDebugObjTotalAll
++;
1942 xmlXPathDebugObjCounterAll
++;
1943 if (xmlXPathDebugObjCounterAll
>
1944 xmlXPathDebugObjMaxAll
)
1945 xmlXPathDebugObjMaxAll
=
1946 xmlXPathDebugObjCounterAll
;
1950 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt
,
1951 xmlXPathObjectType objType
)
1956 if (ctxt
->cache
!= NULL
) {
1957 xmlXPathContextCachePtr cache
=
1958 (xmlXPathContextCachePtr
) ctxt
->cache
;
1962 cache
->dbgCachedAll
++;
1964 case XPATH_UNDEFINED
:
1965 cache
->dbgCachedUndefined
++;
1968 cache
->dbgCachedNodeset
++;
1971 cache
->dbgCachedBool
++;
1974 cache
->dbgCachedNumber
++;
1977 cache
->dbgCachedString
++;
1980 cache
->dbgCachedPoint
++;
1983 cache
->dbgCachedRange
++;
1985 case XPATH_LOCATIONSET
:
1986 cache
->dbgCachedLocset
++;
1989 cache
->dbgCachedUsers
++;
1991 case XPATH_XSLT_TREE
:
1992 cache
->dbgCachedXSLTTree
++;
2001 case XPATH_UNDEFINED
:
2002 xmlXPathDebugObjCounterUndefined
--;
2005 xmlXPathDebugObjCounterNodeset
--;
2008 xmlXPathDebugObjCounterBool
--;
2011 xmlXPathDebugObjCounterNumber
--;
2014 xmlXPathDebugObjCounterString
--;
2017 xmlXPathDebugObjCounterPoint
--;
2020 xmlXPathDebugObjCounterRange
--;
2022 case XPATH_LOCATIONSET
:
2023 xmlXPathDebugObjCounterLocset
--;
2026 xmlXPathDebugObjCounterUsers
--;
2028 case XPATH_XSLT_TREE
:
2029 xmlXPathDebugObjCounterXSLTTree
--;
2034 xmlXPathDebugObjCounterAll
--;
2037 /* REVISIT TODO: Make this static when committing */
2039 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt
)
2041 int reqAll
, reqNodeset
, reqString
, reqBool
, reqNumber
,
2042 reqXSLTTree
, reqUndefined
;
2043 int caAll
= 0, caNodeset
= 0, caString
= 0, caBool
= 0,
2044 caNumber
= 0, caXSLTTree
= 0, caUndefined
= 0;
2045 int reAll
= 0, reNodeset
= 0, reString
= 0, reBool
= 0,
2046 reNumber
= 0, reXSLTTree
= 0, reUndefined
= 0;
2047 int leftObjs
= xmlXPathDebugObjCounterAll
;
2049 reqAll
= xmlXPathDebugObjTotalAll
;
2050 reqNodeset
= xmlXPathDebugObjTotalNodeset
;
2051 reqString
= xmlXPathDebugObjTotalString
;
2052 reqBool
= xmlXPathDebugObjTotalBool
;
2053 reqNumber
= xmlXPathDebugObjTotalNumber
;
2054 reqXSLTTree
= xmlXPathDebugObjTotalXSLTTree
;
2055 reqUndefined
= xmlXPathDebugObjTotalUndefined
;
2057 printf("# XPath object usage:\n");
2060 if (ctxt
->cache
!= NULL
) {
2061 xmlXPathContextCachePtr cache
=
2062 (xmlXPathContextCachePtr
) ctxt
->cache
;
2064 reAll
= cache
->dbgReusedAll
;
2066 reNodeset
= cache
->dbgReusedNodeset
;
2067 reqNodeset
+= reNodeset
;
2068 reString
= cache
->dbgReusedString
;
2069 reqString
+= reString
;
2070 reBool
= cache
->dbgReusedBool
;
2072 reNumber
= cache
->dbgReusedNumber
;
2073 reqNumber
+= reNumber
;
2074 reXSLTTree
= cache
->dbgReusedXSLTTree
;
2075 reqXSLTTree
+= reXSLTTree
;
2076 reUndefined
= cache
->dbgReusedUndefined
;
2077 reqUndefined
+= reUndefined
;
2079 caAll
= cache
->dbgCachedAll
;
2080 caBool
= cache
->dbgCachedBool
;
2081 caNodeset
= cache
->dbgCachedNodeset
;
2082 caString
= cache
->dbgCachedString
;
2083 caNumber
= cache
->dbgCachedNumber
;
2084 caXSLTTree
= cache
->dbgCachedXSLTTree
;
2085 caUndefined
= cache
->dbgCachedUndefined
;
2087 if (cache
->nodesetObjs
)
2088 leftObjs
-= cache
->nodesetObjs
->number
;
2089 if (cache
->stringObjs
)
2090 leftObjs
-= cache
->stringObjs
->number
;
2091 if (cache
->booleanObjs
)
2092 leftObjs
-= cache
->booleanObjs
->number
;
2093 if (cache
->numberObjs
)
2094 leftObjs
-= cache
->numberObjs
->number
;
2095 if (cache
->miscObjs
)
2096 leftObjs
-= cache
->miscObjs
->number
;
2101 printf("# total : %d\n", reqAll
);
2102 printf("# left : %d\n", leftObjs
);
2103 printf("# created: %d\n", xmlXPathDebugObjTotalAll
);
2104 printf("# reused : %d\n", reAll
);
2105 printf("# max : %d\n", xmlXPathDebugObjMaxAll
);
2107 printf("# node-sets\n");
2108 printf("# total : %d\n", reqNodeset
);
2109 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset
);
2110 printf("# reused : %d\n", reNodeset
);
2111 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset
);
2113 printf("# strings\n");
2114 printf("# total : %d\n", reqString
);
2115 printf("# created: %d\n", xmlXPathDebugObjTotalString
);
2116 printf("# reused : %d\n", reString
);
2117 printf("# max : %d\n", xmlXPathDebugObjMaxString
);
2119 printf("# booleans\n");
2120 printf("# total : %d\n", reqBool
);
2121 printf("# created: %d\n", xmlXPathDebugObjTotalBool
);
2122 printf("# reused : %d\n", reBool
);
2123 printf("# max : %d\n", xmlXPathDebugObjMaxBool
);
2125 printf("# numbers\n");
2126 printf("# total : %d\n", reqNumber
);
2127 printf("# created: %d\n", xmlXPathDebugObjTotalNumber
);
2128 printf("# reused : %d\n", reNumber
);
2129 printf("# max : %d\n", xmlXPathDebugObjMaxNumber
);
2131 printf("# XSLT result tree fragments\n");
2132 printf("# total : %d\n", reqXSLTTree
);
2133 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree
);
2134 printf("# reused : %d\n", reXSLTTree
);
2135 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree
);
2137 printf("# undefined\n");
2138 printf("# total : %d\n", reqUndefined
);
2139 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined
);
2140 printf("# reused : %d\n", reUndefined
);
2141 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined
);
2145 #endif /* XP_DEBUG_OBJ_USAGE */
2147 #endif /* LIBXML_DEBUG_ENABLED */
2149 /************************************************************************
2151 * XPath object caching *
2153 ************************************************************************/
2158 * Create a new object cache
2160 * Returns the xmlXPathCache just allocated.
2162 static xmlXPathContextCachePtr
2163 xmlXPathNewCache(void)
2165 xmlXPathContextCachePtr ret
;
2167 ret
= (xmlXPathContextCachePtr
) xmlMalloc(sizeof(xmlXPathContextCache
));
2169 xmlXPathErrMemory(NULL
, "creating object cache\n");
2172 memset(ret
, 0 , (size_t) sizeof(xmlXPathContextCache
));
2173 ret
->maxNodeset
= 100;
2174 ret
->maxString
= 100;
2175 ret
->maxBoolean
= 100;
2176 ret
->maxNumber
= 100;
2182 xmlXPathCacheFreeObjectList(xmlPointerListPtr list
)
2185 xmlXPathObjectPtr obj
;
2190 for (i
= 0; i
< list
->number
; i
++) {
2191 obj
= list
->items
[i
];
2193 * Note that it is already assured that we don't need to
2194 * look out for namespace nodes in the node-set.
2196 if (obj
->nodesetval
!= NULL
) {
2197 if (obj
->nodesetval
->nodeTab
!= NULL
)
2198 xmlFree(obj
->nodesetval
->nodeTab
);
2199 xmlFree(obj
->nodesetval
);
2202 #ifdef XP_DEBUG_OBJ_USAGE
2203 xmlXPathDebugObjCounterAll
--;
2206 xmlPointerListFree(list
);
2210 xmlXPathFreeCache(xmlXPathContextCachePtr cache
)
2214 if (cache
->nodesetObjs
)
2215 xmlXPathCacheFreeObjectList(cache
->nodesetObjs
);
2216 if (cache
->stringObjs
)
2217 xmlXPathCacheFreeObjectList(cache
->stringObjs
);
2218 if (cache
->booleanObjs
)
2219 xmlXPathCacheFreeObjectList(cache
->booleanObjs
);
2220 if (cache
->numberObjs
)
2221 xmlXPathCacheFreeObjectList(cache
->numberObjs
);
2222 if (cache
->miscObjs
)
2223 xmlXPathCacheFreeObjectList(cache
->miscObjs
);
2228 * xmlXPathContextSetCache:
2230 * @ctxt: the XPath context
2231 * @active: enables/disables (creates/frees) the cache
2232 * @value: a value with semantics dependant on @options
2233 * @options: options (currently only the value 0 is used)
2235 * Creates/frees an object cache on the XPath context.
2236 * If activates XPath objects (xmlXPathObject) will be cached internally
2239 * 0: This will set the XPath object caching:
2241 * This will set the maximum number of XPath objects
2242 * to be cached per slot
2243 * There are 5 slots for: node-set, string, number, boolean, and
2244 * misc objects. Use <0 for the default number (100).
2245 * Other values for @options have currently no effect.
2247 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2250 xmlXPathContextSetCache(xmlXPathContextPtr ctxt
,
2258 xmlXPathContextCachePtr cache
;
2260 if (ctxt
->cache
== NULL
) {
2261 ctxt
->cache
= xmlXPathNewCache();
2262 if (ctxt
->cache
== NULL
)
2265 cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2269 cache
->maxNodeset
= value
;
2270 cache
->maxString
= value
;
2271 cache
->maxNumber
= value
;
2272 cache
->maxBoolean
= value
;
2273 cache
->maxMisc
= value
;
2275 } else if (ctxt
->cache
!= NULL
) {
2276 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
2283 * xmlXPathCacheWrapNodeSet:
2284 * @ctxt: the XPath context
2285 * @val: the NodePtr value
2287 * This is the cached version of xmlXPathWrapNodeSet().
2288 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2290 * Returns the created or reused object.
2292 static xmlXPathObjectPtr
2293 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt
, xmlNodeSetPtr val
)
2295 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2296 xmlXPathContextCachePtr cache
=
2297 (xmlXPathContextCachePtr
) ctxt
->cache
;
2299 if ((cache
->miscObjs
!= NULL
) &&
2300 (cache
->miscObjs
->number
!= 0))
2302 xmlXPathObjectPtr ret
;
2304 ret
= (xmlXPathObjectPtr
)
2305 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2306 ret
->type
= XPATH_NODESET
;
2307 ret
->nodesetval
= val
;
2308 #ifdef XP_DEBUG_OBJ_USAGE
2309 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2315 return(xmlXPathWrapNodeSet(val
));
2320 * xmlXPathCacheWrapString:
2321 * @ctxt: the XPath context
2322 * @val: the xmlChar * value
2324 * This is the cached version of xmlXPathWrapString().
2325 * Wraps the @val string into an XPath object.
2327 * Returns the created or reused object.
2329 static xmlXPathObjectPtr
2330 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt
, xmlChar
*val
)
2332 if ((ctxt
!= NULL
) && (ctxt
->cache
!= NULL
)) {
2333 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2335 if ((cache
->stringObjs
!= NULL
) &&
2336 (cache
->stringObjs
->number
!= 0))
2339 xmlXPathObjectPtr ret
;
2341 ret
= (xmlXPathObjectPtr
)
2342 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2343 ret
->type
= XPATH_STRING
;
2344 ret
->stringval
= val
;
2345 #ifdef XP_DEBUG_OBJ_USAGE
2346 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2349 } else if ((cache
->miscObjs
!= NULL
) &&
2350 (cache
->miscObjs
->number
!= 0))
2352 xmlXPathObjectPtr ret
;
2354 * Fallback to misc-cache.
2356 ret
= (xmlXPathObjectPtr
)
2357 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2359 ret
->type
= XPATH_STRING
;
2360 ret
->stringval
= val
;
2361 #ifdef XP_DEBUG_OBJ_USAGE
2362 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2367 return(xmlXPathWrapString(val
));
2371 * xmlXPathCacheNewNodeSet:
2372 * @ctxt: the XPath context
2373 * @val: the NodePtr value
2375 * This is the cached version of xmlXPathNewNodeSet().
2376 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2377 * it with the single Node @val
2379 * Returns the created or reused object.
2381 static xmlXPathObjectPtr
2382 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt
, xmlNodePtr val
)
2384 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2385 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2387 if ((cache
->nodesetObjs
!= NULL
) &&
2388 (cache
->nodesetObjs
->number
!= 0))
2390 xmlXPathObjectPtr ret
;
2392 * Use the nodset-cache.
2394 ret
= (xmlXPathObjectPtr
)
2395 cache
->nodesetObjs
->items
[--cache
->nodesetObjs
->number
];
2396 ret
->type
= XPATH_NODESET
;
2399 if ((ret
->nodesetval
->nodeMax
== 0) ||
2400 (val
->type
== XML_NAMESPACE_DECL
))
2402 xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
);
2404 ret
->nodesetval
->nodeTab
[0] = val
;
2405 ret
->nodesetval
->nodeNr
= 1;
2408 #ifdef XP_DEBUG_OBJ_USAGE
2409 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2412 } else if ((cache
->miscObjs
!= NULL
) &&
2413 (cache
->miscObjs
->number
!= 0))
2415 xmlXPathObjectPtr ret
;
2417 * Fallback to misc-cache.
2420 ret
= (xmlXPathObjectPtr
)
2421 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2423 ret
->type
= XPATH_NODESET
;
2425 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
2426 if (ret
->nodesetval
== NULL
) {
2427 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
2428 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
2431 #ifdef XP_DEBUG_OBJ_USAGE
2432 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NODESET
);
2437 return(xmlXPathNewNodeSet(val
));
2441 * xmlXPathCacheNewCString:
2442 * @ctxt: the XPath context
2443 * @val: the char * value
2445 * This is the cached version of xmlXPathNewCString().
2446 * Acquire an xmlXPathObjectPtr of type string and of value @val
2448 * Returns the created or reused object.
2450 static xmlXPathObjectPtr
2451 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt
, const char *val
)
2453 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2454 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2456 if ((cache
->stringObjs
!= NULL
) &&
2457 (cache
->stringObjs
->number
!= 0))
2459 xmlXPathObjectPtr ret
;
2461 ret
= (xmlXPathObjectPtr
)
2462 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2464 ret
->type
= XPATH_STRING
;
2465 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2466 #ifdef XP_DEBUG_OBJ_USAGE
2467 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2470 } else if ((cache
->miscObjs
!= NULL
) &&
2471 (cache
->miscObjs
->number
!= 0))
2473 xmlXPathObjectPtr ret
;
2475 ret
= (xmlXPathObjectPtr
)
2476 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2478 ret
->type
= XPATH_STRING
;
2479 ret
->stringval
= xmlStrdup(BAD_CAST val
);
2480 #ifdef XP_DEBUG_OBJ_USAGE
2481 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2486 return(xmlXPathNewCString(val
));
2490 * xmlXPathCacheNewString:
2491 * @ctxt: the XPath context
2492 * @val: the xmlChar * value
2494 * This is the cached version of xmlXPathNewString().
2495 * Acquire an xmlXPathObjectPtr of type string and of value @val
2497 * Returns the created or reused object.
2499 static xmlXPathObjectPtr
2500 xmlXPathCacheNewString(xmlXPathContextPtr ctxt
, const xmlChar
*val
)
2502 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2503 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2505 if ((cache
->stringObjs
!= NULL
) &&
2506 (cache
->stringObjs
->number
!= 0))
2508 xmlXPathObjectPtr ret
;
2510 ret
= (xmlXPathObjectPtr
)
2511 cache
->stringObjs
->items
[--cache
->stringObjs
->number
];
2512 ret
->type
= XPATH_STRING
;
2514 ret
->stringval
= xmlStrdup(val
);
2516 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2517 #ifdef XP_DEBUG_OBJ_USAGE
2518 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2521 } else if ((cache
->miscObjs
!= NULL
) &&
2522 (cache
->miscObjs
->number
!= 0))
2524 xmlXPathObjectPtr ret
;
2526 ret
= (xmlXPathObjectPtr
)
2527 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2529 ret
->type
= XPATH_STRING
;
2531 ret
->stringval
= xmlStrdup(val
);
2533 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
2534 #ifdef XP_DEBUG_OBJ_USAGE
2535 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_STRING
);
2540 return(xmlXPathNewString(val
));
2544 * xmlXPathCacheNewBoolean:
2545 * @ctxt: the XPath context
2546 * @val: the boolean value
2548 * This is the cached version of xmlXPathNewBoolean().
2549 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2551 * Returns the created or reused object.
2553 static xmlXPathObjectPtr
2554 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt
, int val
)
2556 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2557 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2559 if ((cache
->booleanObjs
!= NULL
) &&
2560 (cache
->booleanObjs
->number
!= 0))
2562 xmlXPathObjectPtr ret
;
2564 ret
= (xmlXPathObjectPtr
)
2565 cache
->booleanObjs
->items
[--cache
->booleanObjs
->number
];
2566 ret
->type
= XPATH_BOOLEAN
;
2567 ret
->boolval
= (val
!= 0);
2568 #ifdef XP_DEBUG_OBJ_USAGE
2569 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2572 } else if ((cache
->miscObjs
!= NULL
) &&
2573 (cache
->miscObjs
->number
!= 0))
2575 xmlXPathObjectPtr ret
;
2577 ret
= (xmlXPathObjectPtr
)
2578 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2580 ret
->type
= XPATH_BOOLEAN
;
2581 ret
->boolval
= (val
!= 0);
2582 #ifdef XP_DEBUG_OBJ_USAGE
2583 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_BOOLEAN
);
2588 return(xmlXPathNewBoolean(val
));
2592 * xmlXPathCacheNewFloat:
2593 * @ctxt: the XPath context
2594 * @val: the double value
2596 * This is the cached version of xmlXPathNewFloat().
2597 * Acquires an xmlXPathObjectPtr of type double and of value @val
2599 * Returns the created or reused object.
2601 static xmlXPathObjectPtr
2602 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt
, double val
)
2604 if ((ctxt
!= NULL
) && (ctxt
->cache
)) {
2605 xmlXPathContextCachePtr cache
= (xmlXPathContextCachePtr
) ctxt
->cache
;
2607 if ((cache
->numberObjs
!= NULL
) &&
2608 (cache
->numberObjs
->number
!= 0))
2610 xmlXPathObjectPtr ret
;
2612 ret
= (xmlXPathObjectPtr
)
2613 cache
->numberObjs
->items
[--cache
->numberObjs
->number
];
2614 ret
->type
= XPATH_NUMBER
;
2615 ret
->floatval
= val
;
2616 #ifdef XP_DEBUG_OBJ_USAGE
2617 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2620 } else if ((cache
->miscObjs
!= NULL
) &&
2621 (cache
->miscObjs
->number
!= 0))
2623 xmlXPathObjectPtr ret
;
2625 ret
= (xmlXPathObjectPtr
)
2626 cache
->miscObjs
->items
[--cache
->miscObjs
->number
];
2628 ret
->type
= XPATH_NUMBER
;
2629 ret
->floatval
= val
;
2630 #ifdef XP_DEBUG_OBJ_USAGE
2631 xmlXPathDebugObjUsageRequested(ctxt
, XPATH_NUMBER
);
2636 return(xmlXPathNewFloat(val
));
2640 * xmlXPathCacheConvertString:
2641 * @ctxt: the XPath context
2642 * @val: an XPath object
2644 * This is the cached version of xmlXPathConvertString().
2645 * Converts an existing object to its string() equivalent
2647 * Returns a created or reused object, the old one is freed (cached)
2648 * (or the operation is done directly on @val)
2651 static xmlXPathObjectPtr
2652 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2653 xmlChar
*res
= NULL
;
2656 return(xmlXPathCacheNewCString(ctxt
, ""));
2658 switch (val
->type
) {
2659 case XPATH_UNDEFINED
:
2661 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
2665 case XPATH_XSLT_TREE
:
2666 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
2671 res
= xmlXPathCastBooleanToString(val
->boolval
);
2674 res
= xmlXPathCastNumberToString(val
->floatval
);
2679 case XPATH_LOCATIONSET
:
2683 xmlXPathReleaseObject(ctxt
, val
);
2685 return(xmlXPathCacheNewCString(ctxt
, ""));
2686 return(xmlXPathCacheWrapString(ctxt
, res
));
2690 * xmlXPathCacheObjectCopy:
2691 * @ctxt: the XPath context
2692 * @val: the original object
2694 * This is the cached version of xmlXPathObjectCopy().
2695 * Acquire a copy of a given object
2697 * Returns a created or reused created object.
2699 static xmlXPathObjectPtr
2700 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
)
2705 if (XP_HAS_CACHE(ctxt
)) {
2706 switch (val
->type
) {
2708 return(xmlXPathCacheWrapNodeSet(ctxt
,
2709 xmlXPathNodeSetMerge(NULL
, val
->nodesetval
)));
2711 return(xmlXPathCacheNewString(ctxt
, val
->stringval
));
2713 return(xmlXPathCacheNewBoolean(ctxt
, val
->boolval
));
2715 return(xmlXPathCacheNewFloat(ctxt
, val
->floatval
));
2720 return(xmlXPathObjectCopy(val
));
2724 * xmlXPathCacheConvertBoolean:
2725 * @ctxt: the XPath context
2726 * @val: an XPath object
2728 * This is the cached version of xmlXPathConvertBoolean().
2729 * Converts an existing object to its boolean() equivalent
2731 * Returns a created or reused object, the old one is freed (or the operation
2732 * is done directly on @val)
2734 static xmlXPathObjectPtr
2735 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2736 xmlXPathObjectPtr ret
;
2739 return(xmlXPathCacheNewBoolean(ctxt
, 0));
2740 if (val
->type
== XPATH_BOOLEAN
)
2742 ret
= xmlXPathCacheNewBoolean(ctxt
, xmlXPathCastToBoolean(val
));
2743 xmlXPathReleaseObject(ctxt
, val
);
2748 * xmlXPathCacheConvertNumber:
2749 * @ctxt: the XPath context
2750 * @val: an XPath object
2752 * This is the cached version of xmlXPathConvertNumber().
2753 * Converts an existing object to its number() equivalent
2755 * Returns a created or reused object, the old one is freed (or the operation
2756 * is done directly on @val)
2758 static xmlXPathObjectPtr
2759 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr val
) {
2760 xmlXPathObjectPtr ret
;
2763 return(xmlXPathCacheNewFloat(ctxt
, 0.0));
2764 if (val
->type
== XPATH_NUMBER
)
2766 ret
= xmlXPathCacheNewFloat(ctxt
, xmlXPathCastToNumber(val
));
2767 xmlXPathReleaseObject(ctxt
, val
);
2771 /************************************************************************
2773 * Parser stacks related functions and macros *
2775 ************************************************************************/
2779 * @ctxt: an XPath parser context
2781 * Set the callee evaluation frame
2783 * Returns the previous frame value to be restored once done
2786 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt
) {
2791 ret
= ctxt
->valueFrame
;
2792 ctxt
->valueFrame
= ctxt
->valueNr
;
2798 * @ctxt: an XPath parser context
2799 * @frame: the previous frame value
2801 * Remove the callee evaluation frame
2804 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt
, int frame
) {
2807 if (ctxt
->valueNr
< ctxt
->valueFrame
) {
2808 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2810 ctxt
->valueFrame
= frame
;
2815 * @ctxt: an XPath evaluation context
2817 * Pops the top XPath object from the value stack
2819 * Returns the XPath object just removed
2822 valuePop(xmlXPathParserContextPtr ctxt
)
2824 xmlXPathObjectPtr ret
;
2826 if ((ctxt
== NULL
) || (ctxt
->valueNr
<= 0))
2829 if (ctxt
->valueNr
<= ctxt
->valueFrame
) {
2830 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_STACK_ERROR
);
2835 if (ctxt
->valueNr
> 0)
2836 ctxt
->value
= ctxt
->valueTab
[ctxt
->valueNr
- 1];
2839 ret
= ctxt
->valueTab
[ctxt
->valueNr
];
2840 ctxt
->valueTab
[ctxt
->valueNr
] = NULL
;
2845 * @ctxt: an XPath evaluation context
2846 * @value: the XPath object
2848 * Pushes a new XPath object on top of the value stack
2850 * returns the number of items on the value stack
2853 valuePush(xmlXPathParserContextPtr ctxt
, xmlXPathObjectPtr value
)
2855 if ((ctxt
== NULL
) || (value
== NULL
)) return(-1);
2856 if (ctxt
->valueNr
>= ctxt
->valueMax
) {
2857 xmlXPathObjectPtr
*tmp
;
2859 if (ctxt
->valueMax
>= XPATH_MAX_STACK_DEPTH
) {
2860 xmlXPathErrMemory(NULL
, "XPath stack depth limit reached\n");
2861 ctxt
->error
= XPATH_MEMORY_ERROR
;
2864 tmp
= (xmlXPathObjectPtr
*) xmlRealloc(ctxt
->valueTab
,
2865 2 * ctxt
->valueMax
*
2866 sizeof(ctxt
->valueTab
[0]));
2868 xmlXPathErrMemory(NULL
, "pushing value\n");
2869 ctxt
->error
= XPATH_MEMORY_ERROR
;
2872 ctxt
->valueMax
*= 2;
2873 ctxt
->valueTab
= tmp
;
2875 ctxt
->valueTab
[ctxt
->valueNr
] = value
;
2876 ctxt
->value
= value
;
2877 return (ctxt
->valueNr
++);
2881 * xmlXPathPopBoolean:
2882 * @ctxt: an XPath parser context
2884 * Pops a boolean from the stack, handling conversion if needed.
2885 * Check error with #xmlXPathCheckError.
2887 * Returns the boolean
2890 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt
) {
2891 xmlXPathObjectPtr obj
;
2894 obj
= valuePop(ctxt
);
2896 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2899 if (obj
->type
!= XPATH_BOOLEAN
)
2900 ret
= xmlXPathCastToBoolean(obj
);
2903 xmlXPathReleaseObject(ctxt
->context
, obj
);
2908 * xmlXPathPopNumber:
2909 * @ctxt: an XPath parser context
2911 * Pops a number from the stack, handling conversion if needed.
2912 * Check error with #xmlXPathCheckError.
2914 * Returns the number
2917 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt
) {
2918 xmlXPathObjectPtr obj
;
2921 obj
= valuePop(ctxt
);
2923 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2926 if (obj
->type
!= XPATH_NUMBER
)
2927 ret
= xmlXPathCastToNumber(obj
);
2929 ret
= obj
->floatval
;
2930 xmlXPathReleaseObject(ctxt
->context
, obj
);
2935 * xmlXPathPopString:
2936 * @ctxt: an XPath parser context
2938 * Pops a string from the stack, handling conversion if needed.
2939 * Check error with #xmlXPathCheckError.
2941 * Returns the string
2944 xmlXPathPopString (xmlXPathParserContextPtr ctxt
) {
2945 xmlXPathObjectPtr obj
;
2948 obj
= valuePop(ctxt
);
2950 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2953 ret
= xmlXPathCastToString(obj
); /* this does required strdup */
2954 /* TODO: needs refactoring somewhere else */
2955 if (obj
->stringval
== ret
)
2956 obj
->stringval
= NULL
;
2957 xmlXPathReleaseObject(ctxt
->context
, obj
);
2962 * xmlXPathPopNodeSet:
2963 * @ctxt: an XPath parser context
2965 * Pops a node-set from the stack, handling conversion if needed.
2966 * Check error with #xmlXPathCheckError.
2968 * Returns the node-set
2971 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt
) {
2972 xmlXPathObjectPtr obj
;
2975 if (ctxt
== NULL
) return(NULL
);
2976 if (ctxt
->value
== NULL
) {
2977 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
2980 if (!xmlXPathStackIsNodeSet(ctxt
)) {
2981 xmlXPathSetTypeError(ctxt
);
2984 obj
= valuePop(ctxt
);
2985 ret
= obj
->nodesetval
;
2987 /* to fix memory leak of not clearing obj->user */
2988 if (obj
->boolval
&& obj
->user
!= NULL
)
2989 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
2991 obj
->nodesetval
= NULL
;
2992 xmlXPathReleaseObject(ctxt
->context
, obj
);
2997 * xmlXPathPopExternal:
2998 * @ctxt: an XPath parser context
3000 * Pops an external object from the stack, handling conversion if needed.
3001 * Check error with #xmlXPathCheckError.
3003 * Returns the object
3006 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt
) {
3007 xmlXPathObjectPtr obj
;
3010 if ((ctxt
== NULL
) || (ctxt
->value
== NULL
)) {
3011 xmlXPathSetError(ctxt
, XPATH_INVALID_OPERAND
);
3014 if (ctxt
->value
->type
!= XPATH_USERS
) {
3015 xmlXPathSetTypeError(ctxt
);
3018 obj
= valuePop(ctxt
);
3021 xmlXPathReleaseObject(ctxt
->context
, obj
);
3026 * Macros for accessing the content. Those should be used only by the parser,
3029 * Dirty macros, i.e. one need to make assumption on the context to use them
3031 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3032 * CUR returns the current xmlChar value, i.e. a 8 bit value
3033 * in ISO-Latin or UTF-8.
3034 * This should be used internally by the parser
3035 * only to compare to ASCII values otherwise it would break when
3036 * running with UTF-8 encoding.
3037 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3038 * to compare on ASCII based substring.
3039 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3040 * strings within the parser.
3041 * CURRENT Returns the current char value, with the full decoding of
3042 * UTF-8 if we are using this mode. It returns an int.
3043 * NEXT Skip to the next character, this does the proper decoding
3044 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3045 * It returns the pointer to the current xmlChar.
3048 #define CUR (*ctxt->cur)
3049 #define SKIP(val) ctxt->cur += (val)
3050 #define NXT(val) ctxt->cur[(val)]
3051 #define CUR_PTR ctxt->cur
3052 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3054 #define COPY_BUF(l,b,i,v) \
3055 if (l == 1) b[i++] = (xmlChar) v; \
3056 else i += xmlCopyChar(l,&b[i],v)
3058 #define NEXTL(l) ctxt->cur += l
3060 #define SKIP_BLANKS \
3061 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3063 #define CURRENT (*ctxt->cur)
3064 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3071 #define DBL_EPSILON 1E-9
3074 #define UPPER_DOUBLE 1E9
3075 #define LOWER_DOUBLE 1E-5
3076 #define LOWER_DOUBLE_EXP 5
3078 #define INTEGER_DIGITS DBL_DIG
3079 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3080 #define EXPONENT_DIGITS (3 + 2)
3083 * xmlXPathFormatNumber:
3084 * @number: number to format
3085 * @buffer: output buffer
3086 * @buffersize: size of output buffer
3088 * Convert the number into a string representation.
3091 xmlXPathFormatNumber(double number
, char buffer
[], int buffersize
)
3093 switch (xmlXPathIsInf(number
)) {
3095 if (buffersize
> (int)sizeof("Infinity"))
3096 snprintf(buffer
, buffersize
, "Infinity");
3099 if (buffersize
> (int)sizeof("-Infinity"))
3100 snprintf(buffer
, buffersize
, "-Infinity");
3103 if (xmlXPathIsNaN(number
)) {
3104 if (buffersize
> (int)sizeof("NaN"))
3105 snprintf(buffer
, buffersize
, "NaN");
3106 } else if (number
== 0 && xmlXPathGetSign(number
) != 0) {
3107 snprintf(buffer
, buffersize
, "0");
3108 } else if (number
== ((int) number
)) {
3111 int value
= (int) number
;
3117 snprintf(work
, 29, "%d", value
);
3119 while ((*cur
) && (ptr
- buffer
< buffersize
)) {
3123 if (ptr
- buffer
< buffersize
) {
3125 } else if (buffersize
> 0) {
3131 For the dimension of work,
3132 DBL_DIG is number of significant digits
3133 EXPONENT is only needed for "scientific notation"
3134 3 is sign, decimal point, and terminating zero
3135 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3136 Note that this dimension is slightly (a few characters)
3137 larger than actually necessary.
3139 char work
[DBL_DIG
+ EXPONENT_DIGITS
+ 3 + LOWER_DOUBLE_EXP
];
3140 int integer_place
, fraction_place
;
3142 char *after_fraction
;
3143 double absolute_value
;
3146 absolute_value
= fabs(number
);
3149 * First choose format - scientific or regular floating point.
3150 * In either case, result is in work, and after_fraction points
3151 * just past the fractional part.
3153 if ( ((absolute_value
> UPPER_DOUBLE
) ||
3154 (absolute_value
< LOWER_DOUBLE
)) &&
3155 (absolute_value
!= 0.0) ) {
3156 /* Use scientific notation */
3157 integer_place
= DBL_DIG
+ EXPONENT_DIGITS
+ 1;
3158 fraction_place
= DBL_DIG
- 1;
3159 size
= snprintf(work
, sizeof(work
),"%*.*e",
3160 integer_place
, fraction_place
, number
);
3161 while ((size
> 0) && (work
[size
] != 'e')) size
--;
3165 /* Use regular notation */
3166 if (absolute_value
> 0.0) {
3167 integer_place
= (int)log10(absolute_value
);
3168 if (integer_place
> 0)
3169 fraction_place
= DBL_DIG
- integer_place
- 1;
3171 fraction_place
= DBL_DIG
- integer_place
;
3175 size
= snprintf(work
, sizeof(work
), "%0.*f",
3176 fraction_place
, number
);
3179 /* Remove leading spaces sometimes inserted by snprintf */
3180 while (work
[0] == ' ') {
3181 for (ptr
= &work
[0];(ptr
[0] = ptr
[1]);ptr
++);
3185 /* Remove fractional trailing zeroes */
3186 after_fraction
= work
+ size
;
3187 ptr
= after_fraction
;
3188 while (*(--ptr
) == '0')
3192 while ((*ptr
++ = *after_fraction
++) != 0);
3194 /* Finally copy result back to caller */
3195 size
= strlen(work
) + 1;
3196 if (size
> buffersize
) {
3197 work
[buffersize
- 1] = 0;
3200 memmove(buffer
, work
, size
);
3207 /************************************************************************
3209 * Routines to handle NodeSets *
3211 ************************************************************************/
3214 * xmlXPathOrderDocElems:
3215 * @doc: an input document
3217 * Call this routine to speed up XPath computation on static documents.
3218 * This stamps all the element nodes with the document order
3219 * Like for line information, the order is kept in the element->content
3220 * field, the value stored is actually - the node number (starting at -1)
3221 * to be able to differentiate from line numbers.
3223 * Returns the number of elements found in the document or -1 in case
3227 xmlXPathOrderDocElems(xmlDocPtr doc
) {
3233 cur
= doc
->children
;
3234 while (cur
!= NULL
) {
3235 if (cur
->type
== XML_ELEMENT_NODE
) {
3236 cur
->content
= (void *) (-(++count
));
3237 if (cur
->children
!= NULL
) {
3238 cur
= cur
->children
;
3242 if (cur
->next
!= NULL
) {
3250 if (cur
== (xmlNodePtr
) doc
) {
3254 if (cur
->next
!= NULL
) {
3258 } while (cur
!= NULL
);
3265 * @node1: the first node
3266 * @node2: the second node
3268 * Compare two nodes w.r.t document order
3270 * Returns -2 in case of error 1 if first point < second point, 0 if
3271 * it's the same node, -1 otherwise
3274 xmlXPathCmpNodes(xmlNodePtr node1
, xmlNodePtr node2
) {
3276 int attr1
= 0, attr2
= 0;
3277 xmlNodePtr attrNode1
= NULL
, attrNode2
= NULL
;
3278 xmlNodePtr cur
, root
;
3280 if ((node1
== NULL
) || (node2
== NULL
))
3283 * a couple of optimizations which will avoid computations in most cases
3285 if (node1
== node2
) /* trivial case */
3287 if (node1
->type
== XML_ATTRIBUTE_NODE
) {
3290 node1
= node1
->parent
;
3292 if (node2
->type
== XML_ATTRIBUTE_NODE
) {
3295 node2
= node2
->parent
;
3297 if (node1
== node2
) {
3298 if (attr1
== attr2
) {
3299 /* not required, but we keep attributes in order */
3301 cur
= attrNode2
->prev
;
3302 while (cur
!= NULL
) {
3303 if (cur
== attrNode1
)
3315 if ((node1
->type
== XML_NAMESPACE_DECL
) ||
3316 (node2
->type
== XML_NAMESPACE_DECL
))
3318 if (node1
== node2
->prev
)
3320 if (node1
== node2
->next
)
3324 * Speedup using document order if availble.
3326 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3327 (node2
->type
== XML_ELEMENT_NODE
) &&
3328 (0 > (long) node1
->content
) &&
3329 (0 > (long) node2
->content
) &&
3330 (node1
->doc
== node2
->doc
)) {
3333 l1
= -((long) node1
->content
);
3334 l2
= -((long) node2
->content
);
3342 * compute depth to root
3344 for (depth2
= 0, cur
= node2
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3350 for (depth1
= 0, cur
= node1
;cur
->parent
!= NULL
;cur
= cur
->parent
) {
3356 * Distinct document (or distinct entities :-( ) case.
3362 * get the nearest common ancestor.
3364 while (depth1
> depth2
) {
3366 node1
= node1
->parent
;
3368 while (depth2
> depth1
) {
3370 node2
= node2
->parent
;
3372 while (node1
->parent
!= node2
->parent
) {
3373 node1
= node1
->parent
;
3374 node2
= node2
->parent
;
3375 /* should not happen but just in case ... */
3376 if ((node1
== NULL
) || (node2
== NULL
))
3382 if (node1
== node2
->prev
)
3384 if (node1
== node2
->next
)
3387 * Speedup using document order if availble.
3389 if ((node1
->type
== XML_ELEMENT_NODE
) &&
3390 (node2
->type
== XML_ELEMENT_NODE
) &&
3391 (0 > (long) node1
->content
) &&
3392 (0 > (long) node2
->content
) &&
3393 (node1
->doc
== node2
->doc
)) {
3396 l1
= -((long) node1
->content
);
3397 l2
= -((long) node2
->content
);
3404 for (cur
= node1
->next
;cur
!= NULL
;cur
= cur
->next
)
3407 return(-1); /* assume there is no sibling list corruption */
3411 * xmlXPathNodeSetSort:
3412 * @set: the node set
3414 * Sort the node set in document order
3417 xmlXPathNodeSetSort(xmlNodeSetPtr set
) {
3418 #ifndef WITH_TIM_SORT
3419 int i
, j
, incr
, len
;
3426 #ifndef WITH_TIM_SORT
3428 * Use the old Shell's sort implementation to sort the node-set
3429 * Timsort ought to be quite faster
3432 for (incr
= len
/ 2; incr
> 0; incr
/= 2) {
3433 for (i
= incr
; i
< len
; i
++) {
3436 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3437 if (xmlXPathCmpNodesExt(set
->nodeTab
[j
],
3438 set
->nodeTab
[j
+ incr
]) == -1)
3440 if (xmlXPathCmpNodes(set
->nodeTab
[j
],
3441 set
->nodeTab
[j
+ incr
]) == -1)
3444 tmp
= set
->nodeTab
[j
];
3445 set
->nodeTab
[j
] = set
->nodeTab
[j
+ incr
];
3446 set
->nodeTab
[j
+ incr
] = tmp
;
3453 #else /* WITH_TIM_SORT */
3454 libxml_domnode_tim_sort(set
->nodeTab
, set
->nodeNr
);
3455 #endif /* WITH_TIM_SORT */
3458 #define XML_NODESET_DEFAULT 10
3460 * xmlXPathNodeSetDupNs:
3461 * @node: the parent node of the namespace XPath node
3462 * @ns: the libxml namespace declaration node.
3464 * Namespace node in libxml don't match the XPath semantic. In a node set
3465 * the namespace nodes are duplicated and the next pointer is set to the
3466 * parent node in the XPath semantic.
3468 * Returns the newly created object.
3471 xmlXPathNodeSetDupNs(xmlNodePtr node
, xmlNsPtr ns
) {
3474 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3476 if ((node
== NULL
) || (node
->type
== XML_NAMESPACE_DECL
))
3477 return((xmlNodePtr
) ns
);
3480 * Allocate a new Namespace and fill the fields.
3482 cur
= (xmlNsPtr
) xmlMalloc(sizeof(xmlNs
));
3484 xmlXPathErrMemory(NULL
, "duplicating namespace\n");
3487 memset(cur
, 0, sizeof(xmlNs
));
3488 cur
->type
= XML_NAMESPACE_DECL
;
3489 if (ns
->href
!= NULL
)
3490 cur
->href
= xmlStrdup(ns
->href
);
3491 if (ns
->prefix
!= NULL
)
3492 cur
->prefix
= xmlStrdup(ns
->prefix
);
3493 cur
->next
= (xmlNsPtr
) node
;
3494 return((xmlNodePtr
) cur
);
3498 * xmlXPathNodeSetFreeNs:
3499 * @ns: the XPath namespace node found in a nodeset.
3501 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3502 * the namespace nodes are duplicated and the next pointer is set to the
3503 * parent node in the XPath semantic. Check if such a node needs to be freed
3506 xmlXPathNodeSetFreeNs(xmlNsPtr ns
) {
3507 if ((ns
== NULL
) || (ns
->type
!= XML_NAMESPACE_DECL
))
3510 if ((ns
->next
!= NULL
) && (ns
->next
->type
!= XML_NAMESPACE_DECL
)) {
3511 if (ns
->href
!= NULL
)
3512 xmlFree((xmlChar
*)ns
->href
);
3513 if (ns
->prefix
!= NULL
)
3514 xmlFree((xmlChar
*)ns
->prefix
);
3520 * xmlXPathNodeSetCreate:
3521 * @val: an initial xmlNodePtr, or NULL
3523 * Create a new xmlNodeSetPtr of type double and of value @val
3525 * Returns the newly created object.
3528 xmlXPathNodeSetCreate(xmlNodePtr val
) {
3531 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3533 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3536 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3538 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3539 sizeof(xmlNodePtr
));
3540 if (ret
->nodeTab
== NULL
) {
3541 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3545 memset(ret
->nodeTab
, 0 ,
3546 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3547 ret
->nodeMax
= XML_NODESET_DEFAULT
;
3548 if (val
->type
== XML_NAMESPACE_DECL
) {
3549 xmlNsPtr ns
= (xmlNsPtr
) val
;
3551 ret
->nodeTab
[ret
->nodeNr
++] =
3552 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3554 ret
->nodeTab
[ret
->nodeNr
++] = val
;
3560 * xmlXPathNodeSetCreateSize:
3561 * @size: the initial size of the set
3563 * Create a new xmlNodeSetPtr of type double and of value @val
3565 * Returns the newly created object.
3567 static xmlNodeSetPtr
3568 xmlXPathNodeSetCreateSize(int size
) {
3571 ret
= (xmlNodeSetPtr
) xmlMalloc(sizeof(xmlNodeSet
));
3573 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3576 memset(ret
, 0 , (size_t) sizeof(xmlNodeSet
));
3577 if (size
< XML_NODESET_DEFAULT
)
3578 size
= XML_NODESET_DEFAULT
;
3579 ret
->nodeTab
= (xmlNodePtr
*) xmlMalloc(size
* sizeof(xmlNodePtr
));
3580 if (ret
->nodeTab
== NULL
) {
3581 xmlXPathErrMemory(NULL
, "creating nodeset\n");
3585 memset(ret
->nodeTab
, 0 , size
* (size_t) sizeof(xmlNodePtr
));
3586 ret
->nodeMax
= size
;
3591 * xmlXPathNodeSetContains:
3592 * @cur: the node-set
3595 * checks whether @cur contains @val
3597 * Returns true (1) if @cur contains @val, false (0) otherwise
3600 xmlXPathNodeSetContains (xmlNodeSetPtr cur
, xmlNodePtr val
) {
3603 if ((cur
== NULL
) || (val
== NULL
)) return(0);
3604 if (val
->type
== XML_NAMESPACE_DECL
) {
3605 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3606 if (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
3609 ns1
= (xmlNsPtr
) val
;
3610 ns2
= (xmlNsPtr
) cur
->nodeTab
[i
];
3613 if ((ns1
->next
!= NULL
) && (ns2
->next
== ns1
->next
) &&
3614 (xmlStrEqual(ns1
->prefix
, ns2
->prefix
)))
3619 for (i
= 0; i
< cur
->nodeNr
; i
++) {
3620 if (cur
->nodeTab
[i
] == val
)
3628 * xmlXPathNodeSetAddNs:
3629 * @cur: the initial node set
3630 * @node: the hosting node
3631 * @ns: a the namespace node
3633 * add a new namespace node to an existing NodeSet
3635 * Returns 0 in case of success and -1 in case of error
3638 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur
, xmlNodePtr node
, xmlNsPtr ns
) {
3642 if ((cur
== NULL
) || (ns
== NULL
) || (node
== NULL
) ||
3643 (ns
->type
!= XML_NAMESPACE_DECL
) ||
3644 (node
->type
!= XML_ELEMENT_NODE
))
3647 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3649 * prevent duplicates
3651 for (i
= 0;i
< cur
->nodeNr
;i
++) {
3652 if ((cur
->nodeTab
[i
] != NULL
) &&
3653 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) &&
3654 (((xmlNsPtr
)cur
->nodeTab
[i
])->next
== (xmlNsPtr
) node
) &&
3655 (xmlStrEqual(ns
->prefix
, ((xmlNsPtr
)cur
->nodeTab
[i
])->prefix
)))
3660 * grow the nodeTab if needed
3662 if (cur
->nodeMax
== 0) {
3663 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3664 sizeof(xmlNodePtr
));
3665 if (cur
->nodeTab
== NULL
) {
3666 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3669 memset(cur
->nodeTab
, 0 ,
3670 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3671 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3672 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3675 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3676 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3679 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3680 sizeof(xmlNodePtr
));
3682 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3686 cur
->nodeTab
= temp
;
3688 cur
->nodeTab
[cur
->nodeNr
++] = xmlXPathNodeSetDupNs(node
, ns
);
3693 * xmlXPathNodeSetAdd:
3694 * @cur: the initial node set
3695 * @val: a new xmlNodePtr
3697 * add a new xmlNodePtr to an existing NodeSet
3699 * Returns 0 in case of success, and -1 in case of error
3702 xmlXPathNodeSetAdd(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3705 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3707 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3709 * prevent duplicates
3711 for (i
= 0;i
< cur
->nodeNr
;i
++)
3712 if (cur
->nodeTab
[i
] == val
) return(0);
3715 * grow the nodeTab if needed
3717 if (cur
->nodeMax
== 0) {
3718 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3719 sizeof(xmlNodePtr
));
3720 if (cur
->nodeTab
== NULL
) {
3721 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3724 memset(cur
->nodeTab
, 0 ,
3725 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3726 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3727 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3730 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3731 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3734 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3735 sizeof(xmlNodePtr
));
3737 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3741 cur
->nodeTab
= temp
;
3743 if (val
->type
== XML_NAMESPACE_DECL
) {
3744 xmlNsPtr ns
= (xmlNsPtr
) val
;
3746 cur
->nodeTab
[cur
->nodeNr
++] =
3747 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3749 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3754 * xmlXPathNodeSetAddUnique:
3755 * @cur: the initial node set
3756 * @val: a new xmlNodePtr
3758 * add a new xmlNodePtr to an existing NodeSet, optimized version
3759 * when we are sure the node is not already in the set.
3761 * Returns 0 in case of success and -1 in case of failure
3764 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur
, xmlNodePtr val
) {
3765 if ((cur
== NULL
) || (val
== NULL
)) return(-1);
3767 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3769 * grow the nodeTab if needed
3771 if (cur
->nodeMax
== 0) {
3772 cur
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3773 sizeof(xmlNodePtr
));
3774 if (cur
->nodeTab
== NULL
) {
3775 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3778 memset(cur
->nodeTab
, 0 ,
3779 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3780 cur
->nodeMax
= XML_NODESET_DEFAULT
;
3781 } else if (cur
->nodeNr
== cur
->nodeMax
) {
3784 if (cur
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3785 xmlXPathErrMemory(NULL
, "growing nodeset hit limit\n");
3788 temp
= (xmlNodePtr
*) xmlRealloc(cur
->nodeTab
, cur
->nodeMax
* 2 *
3789 sizeof(xmlNodePtr
));
3791 xmlXPathErrMemory(NULL
, "growing nodeset\n");
3794 cur
->nodeTab
= temp
;
3797 if (val
->type
== XML_NAMESPACE_DECL
) {
3798 xmlNsPtr ns
= (xmlNsPtr
) val
;
3800 cur
->nodeTab
[cur
->nodeNr
++] =
3801 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3803 cur
->nodeTab
[cur
->nodeNr
++] = val
;
3808 * xmlXPathNodeSetMerge:
3809 * @val1: the first NodeSet or NULL
3810 * @val2: the second NodeSet
3812 * Merges two nodesets, all nodes from @val2 are added to @val1
3813 * if @val1 is NULL, a new set is created and copied from @val2
3815 * Returns @val1 once extended or NULL in case of error.
3818 xmlXPathNodeSetMerge(xmlNodeSetPtr val1
, xmlNodeSetPtr val2
) {
3819 int i
, j
, initNr
, skip
;
3822 if (val2
== NULL
) return(val1
);
3824 val1
= xmlXPathNodeSetCreate(NULL
);
3829 * TODO: The optimization won't work in every case, since
3830 * those nasty namespace nodes need to be added with
3831 * xmlXPathNodeSetDupNs() to the set; thus a pure
3832 * memcpy is not possible.
3833 * If there was a flag on the nodesetval, indicating that
3834 * some temporary nodes are in, that would be helpfull.
3837 * Optimization: Create an equally sized node-set
3838 * and memcpy the content.
3840 val1
= xmlXPathNodeSetCreateSize(val2
->nodeNr
);
3843 if (val2
->nodeNr
!= 0) {
3844 if (val2
->nodeNr
== 1)
3845 *(val1
->nodeTab
) = *(val2
->nodeTab
);
3847 memcpy(val1
->nodeTab
, val2
->nodeTab
,
3848 val2
->nodeNr
* sizeof(xmlNodePtr
));
3850 val1
->nodeNr
= val2
->nodeNr
;
3856 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3857 initNr
= val1
->nodeNr
;
3859 for (i
= 0;i
< val2
->nodeNr
;i
++) {
3860 n2
= val2
->nodeTab
[i
];
3862 * check against duplicates
3865 for (j
= 0; j
< initNr
; j
++) {
3866 n1
= val1
->nodeTab
[j
];
3870 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3871 (n2
->type
== XML_NAMESPACE_DECL
)) {
3872 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3873 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3874 ((xmlNsPtr
) n2
)->prefix
)))
3885 * grow the nodeTab if needed
3887 if (val1
->nodeMax
== 0) {
3888 val1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(XML_NODESET_DEFAULT
*
3889 sizeof(xmlNodePtr
));
3890 if (val1
->nodeTab
== NULL
) {
3891 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3894 memset(val1
->nodeTab
, 0 ,
3895 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
3896 val1
->nodeMax
= XML_NODESET_DEFAULT
;
3897 } else if (val1
->nodeNr
== val1
->nodeMax
) {
3900 if (val1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
3901 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
3904 temp
= (xmlNodePtr
*) xmlRealloc(val1
->nodeTab
, val1
->nodeMax
* 2 *
3905 sizeof(xmlNodePtr
));
3907 xmlXPathErrMemory(NULL
, "merging nodeset\n");
3910 val1
->nodeTab
= temp
;
3913 if (n2
->type
== XML_NAMESPACE_DECL
) {
3914 xmlNsPtr ns
= (xmlNsPtr
) n2
;
3916 val1
->nodeTab
[val1
->nodeNr
++] =
3917 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
3919 val1
->nodeTab
[val1
->nodeNr
++] = n2
;
3927 * xmlXPathNodeSetMergeAndClear:
3928 * @set1: the first NodeSet or NULL
3929 * @set2: the second NodeSet
3930 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3932 * Merges two nodesets, all nodes from @set2 are added to @set1
3933 * if @set1 is NULL, a new set is created and copied from @set2.
3934 * Checks for duplicate nodes. Clears set2.
3936 * Returns @set1 once extended or NULL in case of error.
3938 static xmlNodeSetPtr
3939 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
,
3942 if ((set1
== NULL
) && (hasNullEntries
== 0)) {
3944 * Note that doing a memcpy of the list, namespace nodes are
3945 * just assigned to set1, since set2 is cleared anyway.
3947 set1
= xmlXPathNodeSetCreateSize(set2
->nodeNr
);
3950 if (set2
->nodeNr
!= 0) {
3951 memcpy(set1
->nodeTab
, set2
->nodeTab
,
3952 set2
->nodeNr
* sizeof(xmlNodePtr
));
3953 set1
->nodeNr
= set2
->nodeNr
;
3956 int i
, j
, initNbSet1
;
3960 set1
= xmlXPathNodeSetCreate(NULL
);
3964 initNbSet1
= set1
->nodeNr
;
3965 for (i
= 0;i
< set2
->nodeNr
;i
++) {
3966 n2
= set2
->nodeTab
[i
];
3968 * Skip NULLed entries.
3975 for (j
= 0; j
< initNbSet1
; j
++) {
3976 n1
= set1
->nodeTab
[j
];
3979 } else if ((n1
->type
== XML_NAMESPACE_DECL
) &&
3980 (n2
->type
== XML_NAMESPACE_DECL
))
3982 if ((((xmlNsPtr
) n1
)->next
== ((xmlNsPtr
) n2
)->next
) &&
3983 (xmlStrEqual(((xmlNsPtr
) n1
)->prefix
,
3984 ((xmlNsPtr
) n2
)->prefix
)))
3987 * Free the namespace node.
3989 set2
->nodeTab
[i
] = NULL
;
3990 xmlXPathNodeSetFreeNs((xmlNsPtr
) n2
);
3996 * grow the nodeTab if needed
3998 if (set1
->nodeMax
== 0) {
3999 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
4000 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4001 if (set1
->nodeTab
== NULL
) {
4002 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4005 memset(set1
->nodeTab
, 0,
4006 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4007 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4008 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4011 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4012 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4015 temp
= (xmlNodePtr
*) xmlRealloc(
4016 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4018 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4021 set1
->nodeTab
= temp
;
4024 if (n2
->type
== XML_NAMESPACE_DECL
) {
4025 xmlNsPtr ns
= (xmlNsPtr
) n2
;
4027 set1
->nodeTab
[set1
->nodeNr
++] =
4028 xmlXPathNodeSetDupNs((xmlNodePtr
) ns
->next
, ns
);
4030 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4040 * xmlXPathNodeSetMergeAndClearNoDupls:
4041 * @set1: the first NodeSet or NULL
4042 * @set2: the second NodeSet
4043 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4045 * Merges two nodesets, all nodes from @set2 are added to @set1
4046 * if @set1 is NULL, a new set is created and copied from @set2.
4047 * Doesn't chack for duplicate nodes. Clears set2.
4049 * Returns @set1 once extended or NULL in case of error.
4051 static xmlNodeSetPtr
4052 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1
, xmlNodeSetPtr set2
,
4057 if ((set1
== NULL
) && (hasNullEntries
== 0)) {
4059 * Note that doing a memcpy of the list, namespace nodes are
4060 * just assigned to set1, since set2 is cleared anyway.
4062 set1
= xmlXPathNodeSetCreateSize(set2
->nodeNr
);
4065 if (set2
->nodeNr
!= 0) {
4066 memcpy(set1
->nodeTab
, set2
->nodeTab
,
4067 set2
->nodeNr
* sizeof(xmlNodePtr
));
4068 set1
->nodeNr
= set2
->nodeNr
;
4075 set1
= xmlXPathNodeSetCreate(NULL
);
4079 for (i
= 0;i
< set2
->nodeNr
;i
++) {
4080 n2
= set2
->nodeTab
[i
];
4082 * Skip NULLed entries.
4086 if (set1
->nodeMax
== 0) {
4087 set1
->nodeTab
= (xmlNodePtr
*) xmlMalloc(
4088 XML_NODESET_DEFAULT
* sizeof(xmlNodePtr
));
4089 if (set1
->nodeTab
== NULL
) {
4090 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4093 memset(set1
->nodeTab
, 0,
4094 XML_NODESET_DEFAULT
* (size_t) sizeof(xmlNodePtr
));
4095 set1
->nodeMax
= XML_NODESET_DEFAULT
;
4096 } else if (set1
->nodeNr
>= set1
->nodeMax
) {
4099 if (set1
->nodeMax
>= XPATH_MAX_NODESET_LENGTH
) {
4100 xmlXPathErrMemory(NULL
, "merging nodeset hit limit\n");
4103 temp
= (xmlNodePtr
*) xmlRealloc(
4104 set1
->nodeTab
, set1
->nodeMax
* 2 * sizeof(xmlNodePtr
));
4106 xmlXPathErrMemory(NULL
, "merging nodeset\n");
4109 set1
->nodeTab
= temp
;
4112 set1
->nodeTab
[set1
->nodeNr
++] = n2
;
4120 * xmlXPathNodeSetDel:
4121 * @cur: the initial node set
4122 * @val: an xmlNodePtr
4124 * Removes an xmlNodePtr from an existing NodeSet
4127 xmlXPathNodeSetDel(xmlNodeSetPtr cur
, xmlNodePtr val
) {
4130 if (cur
== NULL
) return;
4131 if (val
== NULL
) return;
4134 * find node in nodeTab
4136 for (i
= 0;i
< cur
->nodeNr
;i
++)
4137 if (cur
->nodeTab
[i
] == val
) break;
4139 if (i
>= cur
->nodeNr
) { /* not found */
4141 xmlGenericError(xmlGenericErrorContext
,
4142 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4147 if ((cur
->nodeTab
[i
] != NULL
) &&
4148 (cur
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4149 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[i
]);
4151 for (;i
< cur
->nodeNr
;i
++)
4152 cur
->nodeTab
[i
] = cur
->nodeTab
[i
+ 1];
4153 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4157 * xmlXPathNodeSetRemove:
4158 * @cur: the initial node set
4159 * @val: the index to remove
4161 * Removes an entry from an existing NodeSet list.
4164 xmlXPathNodeSetRemove(xmlNodeSetPtr cur
, int val
) {
4165 if (cur
== NULL
) return;
4166 if (val
>= cur
->nodeNr
) return;
4167 if ((cur
->nodeTab
[val
] != NULL
) &&
4168 (cur
->nodeTab
[val
]->type
== XML_NAMESPACE_DECL
))
4169 xmlXPathNodeSetFreeNs((xmlNsPtr
) cur
->nodeTab
[val
]);
4171 for (;val
< cur
->nodeNr
;val
++)
4172 cur
->nodeTab
[val
] = cur
->nodeTab
[val
+ 1];
4173 cur
->nodeTab
[cur
->nodeNr
] = NULL
;
4177 * xmlXPathFreeNodeSet:
4178 * @obj: the xmlNodeSetPtr to free
4180 * Free the NodeSet compound (not the actual nodes !).
4183 xmlXPathFreeNodeSet(xmlNodeSetPtr obj
) {
4184 if (obj
== NULL
) return;
4185 if (obj
->nodeTab
!= NULL
) {
4188 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4189 for (i
= 0;i
< obj
->nodeNr
;i
++)
4190 if ((obj
->nodeTab
[i
] != NULL
) &&
4191 (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
))
4192 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4193 xmlFree(obj
->nodeTab
);
4199 * xmlXPathNodeSetClear:
4200 * @set: the node set to clear
4202 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4203 * are feed), but does *not* free the list itself. Sets the length of the
4207 xmlXPathNodeSetClear(xmlNodeSetPtr set
, int hasNsNodes
)
4209 if ((set
== NULL
) || (set
->nodeNr
<= 0))
4211 else if (hasNsNodes
) {
4215 for (i
= 0; i
< set
->nodeNr
; i
++) {
4216 node
= set
->nodeTab
[i
];
4217 if ((node
!= NULL
) &&
4218 (node
->type
== XML_NAMESPACE_DECL
))
4219 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4226 * xmlXPathNodeSetClearFromPos:
4227 * @set: the node set to be cleared
4228 * @pos: the start position to clear from
4230 * Clears the list from temporary XPath objects (e.g. namespace nodes
4231 * are feed) starting with the entry at @pos, but does *not* free the list
4232 * itself. Sets the length of the list to @pos.
4235 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set
, int pos
, int hasNsNodes
)
4237 if ((set
== NULL
) || (set
->nodeNr
<= 0) || (pos
>= set
->nodeNr
))
4239 else if ((hasNsNodes
)) {
4243 for (i
= pos
; i
< set
->nodeNr
; i
++) {
4244 node
= set
->nodeTab
[i
];
4245 if ((node
!= NULL
) &&
4246 (node
->type
== XML_NAMESPACE_DECL
))
4247 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
4254 * xmlXPathFreeValueTree:
4255 * @obj: the xmlNodeSetPtr to free
4257 * Free the NodeSet compound and the actual tree, this is different
4258 * from xmlXPathFreeNodeSet()
4261 xmlXPathFreeValueTree(xmlNodeSetPtr obj
) {
4264 if (obj
== NULL
) return;
4266 if (obj
->nodeTab
!= NULL
) {
4267 for (i
= 0;i
< obj
->nodeNr
;i
++) {
4268 if (obj
->nodeTab
[i
] != NULL
) {
4269 if (obj
->nodeTab
[i
]->type
== XML_NAMESPACE_DECL
) {
4270 xmlXPathNodeSetFreeNs((xmlNsPtr
) obj
->nodeTab
[i
]);
4272 xmlFreeNodeList(obj
->nodeTab
[i
]);
4276 xmlFree(obj
->nodeTab
);
4281 #if defined(DEBUG) || defined(DEBUG_STEP)
4283 * xmlGenericErrorContextNodeSet:
4284 * @output: a FILE * for the output
4285 * @obj: the xmlNodeSetPtr to display
4287 * Quick display of a NodeSet
4290 xmlGenericErrorContextNodeSet(FILE *output
, xmlNodeSetPtr obj
) {
4293 if (output
== NULL
) output
= xmlGenericErrorContext
;
4295 fprintf(output
, "NodeSet == NULL !\n");
4298 if (obj
->nodeNr
== 0) {
4299 fprintf(output
, "NodeSet is empty\n");
4302 if (obj
->nodeTab
== NULL
) {
4303 fprintf(output
, " nodeTab == NULL !\n");
4306 for (i
= 0; i
< obj
->nodeNr
; i
++) {
4307 if (obj
->nodeTab
[i
] == NULL
) {
4308 fprintf(output
, " NULL !\n");
4311 if ((obj
->nodeTab
[i
]->type
== XML_DOCUMENT_NODE
) ||
4312 (obj
->nodeTab
[i
]->type
== XML_HTML_DOCUMENT_NODE
))
4313 fprintf(output
, " /");
4314 else if (obj
->nodeTab
[i
]->name
== NULL
)
4315 fprintf(output
, " noname!");
4316 else fprintf(output
, " %s", obj
->nodeTab
[i
]->name
);
4318 fprintf(output
, "\n");
4323 * xmlXPathNewNodeSet:
4324 * @val: the NodePtr value
4326 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4327 * it with the single Node @val
4329 * Returns the newly created object.
4332 xmlXPathNewNodeSet(xmlNodePtr val
) {
4333 xmlXPathObjectPtr ret
;
4335 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4337 xmlXPathErrMemory(NULL
, "creating nodeset\n");
4340 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4341 ret
->type
= XPATH_NODESET
;
4343 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4344 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4345 #ifdef XP_DEBUG_OBJ_USAGE
4346 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4352 * xmlXPathNewValueTree:
4353 * @val: the NodePtr value
4355 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4356 * it with the tree root @val
4358 * Returns the newly created object.
4361 xmlXPathNewValueTree(xmlNodePtr val
) {
4362 xmlXPathObjectPtr ret
;
4364 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4366 xmlXPathErrMemory(NULL
, "creating result value tree\n");
4369 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4370 ret
->type
= XPATH_XSLT_TREE
;
4372 ret
->user
= (void *) val
;
4373 ret
->nodesetval
= xmlXPathNodeSetCreate(val
);
4374 #ifdef XP_DEBUG_OBJ_USAGE
4375 xmlXPathDebugObjUsageRequested(NULL
, XPATH_XSLT_TREE
);
4381 * xmlXPathNewNodeSetList:
4382 * @val: an existing NodeSet
4384 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4385 * it with the Nodeset @val
4387 * Returns the newly created object.
4390 xmlXPathNewNodeSetList(xmlNodeSetPtr val
)
4392 xmlXPathObjectPtr ret
;
4397 else if (val
->nodeTab
== NULL
)
4398 ret
= xmlXPathNewNodeSet(NULL
);
4400 ret
= xmlXPathNewNodeSet(val
->nodeTab
[0]);
4402 for (i
= 1; i
< val
->nodeNr
; ++i
) {
4403 if (xmlXPathNodeSetAddUnique(ret
->nodesetval
, val
->nodeTab
[i
])
4413 * xmlXPathWrapNodeSet:
4414 * @val: the NodePtr value
4416 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4418 * Returns the newly created object.
4421 xmlXPathWrapNodeSet(xmlNodeSetPtr val
) {
4422 xmlXPathObjectPtr ret
;
4424 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
4426 xmlXPathErrMemory(NULL
, "creating node set object\n");
4429 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
4430 ret
->type
= XPATH_NODESET
;
4431 ret
->nodesetval
= val
;
4432 #ifdef XP_DEBUG_OBJ_USAGE
4433 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NODESET
);
4439 * xmlXPathFreeNodeSetList:
4440 * @obj: an existing NodeSetList object
4442 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4443 * the list contrary to xmlXPathFreeObject().
4446 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj
) {
4447 if (obj
== NULL
) return;
4448 #ifdef XP_DEBUG_OBJ_USAGE
4449 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
4455 * xmlXPathDifference:
4456 * @nodes1: a node-set
4457 * @nodes2: a node-set
4459 * Implements the EXSLT - Sets difference() function:
4460 * node-set set:difference (node-set, node-set)
4462 * Returns the difference between the two node sets, or nodes1 if
4466 xmlXPathDifference (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4471 if (xmlXPathNodeSetIsEmpty(nodes2
))
4474 ret
= xmlXPathNodeSetCreate(NULL
);
4475 if (xmlXPathNodeSetIsEmpty(nodes1
))
4478 l1
= xmlXPathNodeSetGetLength(nodes1
);
4480 for (i
= 0; i
< l1
; i
++) {
4481 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4482 if (!xmlXPathNodeSetContains(nodes2
, cur
)) {
4483 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4491 * xmlXPathIntersection:
4492 * @nodes1: a node-set
4493 * @nodes2: a node-set
4495 * Implements the EXSLT - Sets intersection() function:
4496 * node-set set:intersection (node-set, node-set)
4498 * Returns a node set comprising the nodes that are within both the
4499 * node sets passed as arguments
4502 xmlXPathIntersection (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4503 xmlNodeSetPtr ret
= xmlXPathNodeSetCreate(NULL
);
4509 if (xmlXPathNodeSetIsEmpty(nodes1
))
4511 if (xmlXPathNodeSetIsEmpty(nodes2
))
4514 l1
= xmlXPathNodeSetGetLength(nodes1
);
4516 for (i
= 0; i
< l1
; i
++) {
4517 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4518 if (xmlXPathNodeSetContains(nodes2
, cur
)) {
4519 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4527 * xmlXPathDistinctSorted:
4528 * @nodes: a node-set, sorted by document order
4530 * Implements the EXSLT - Sets distinct() function:
4531 * node-set set:distinct (node-set)
4533 * Returns a subset of the nodes contained in @nodes, or @nodes if
4537 xmlXPathDistinctSorted (xmlNodeSetPtr nodes
) {
4539 xmlHashTablePtr hash
;
4544 if (xmlXPathNodeSetIsEmpty(nodes
))
4547 ret
= xmlXPathNodeSetCreate(NULL
);
4550 l
= xmlXPathNodeSetGetLength(nodes
);
4551 hash
= xmlHashCreate (l
);
4552 for (i
= 0; i
< l
; i
++) {
4553 cur
= xmlXPathNodeSetItem(nodes
, i
);
4554 strval
= xmlXPathCastNodeToString(cur
);
4555 if (xmlHashLookup(hash
, strval
) == NULL
) {
4556 xmlHashAddEntry(hash
, strval
, strval
);
4557 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4563 xmlHashFree(hash
, (xmlHashDeallocator
) xmlFree
);
4569 * @nodes: a node-set
4571 * Implements the EXSLT - Sets distinct() function:
4572 * node-set set:distinct (node-set)
4573 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4574 * is called with the sorted node-set
4576 * Returns a subset of the nodes contained in @nodes, or @nodes if
4580 xmlXPathDistinct (xmlNodeSetPtr nodes
) {
4581 if (xmlXPathNodeSetIsEmpty(nodes
))
4584 xmlXPathNodeSetSort(nodes
);
4585 return(xmlXPathDistinctSorted(nodes
));
4589 * xmlXPathHasSameNodes:
4590 * @nodes1: a node-set
4591 * @nodes2: a node-set
4593 * Implements the EXSLT - Sets has-same-nodes function:
4594 * boolean set:has-same-node(node-set, node-set)
4596 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4600 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4604 if (xmlXPathNodeSetIsEmpty(nodes1
) ||
4605 xmlXPathNodeSetIsEmpty(nodes2
))
4608 l
= xmlXPathNodeSetGetLength(nodes1
);
4609 for (i
= 0; i
< l
; i
++) {
4610 cur
= xmlXPathNodeSetItem(nodes1
, i
);
4611 if (xmlXPathNodeSetContains(nodes2
, cur
))
4618 * xmlXPathNodeLeadingSorted:
4619 * @nodes: a node-set, sorted by document order
4622 * Implements the EXSLT - Sets leading() function:
4623 * node-set set:leading (node-set, node-set)
4625 * Returns the nodes in @nodes that precede @node in document order,
4626 * @nodes if @node is NULL or an empty node-set if @nodes
4627 * doesn't contain @node
4630 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4638 ret
= xmlXPathNodeSetCreate(NULL
);
4641 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4642 (!xmlXPathNodeSetContains(nodes
, node
)))
4645 l
= xmlXPathNodeSetGetLength(nodes
);
4646 for (i
= 0; i
< l
; i
++) {
4647 cur
= xmlXPathNodeSetItem(nodes
, i
);
4650 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4657 * xmlXPathNodeLeading:
4658 * @nodes: a node-set
4661 * Implements the EXSLT - Sets leading() function:
4662 * node-set set:leading (node-set, node-set)
4663 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4666 * Returns the nodes in @nodes that precede @node in document order,
4667 * @nodes if @node is NULL or an empty node-set if @nodes
4668 * doesn't contain @node
4671 xmlXPathNodeLeading (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4672 xmlXPathNodeSetSort(nodes
);
4673 return(xmlXPathNodeLeadingSorted(nodes
, node
));
4677 * xmlXPathLeadingSorted:
4678 * @nodes1: a node-set, sorted by document order
4679 * @nodes2: a node-set, sorted by document order
4681 * Implements the EXSLT - Sets leading() function:
4682 * node-set set:leading (node-set, node-set)
4684 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4685 * in document order, @nodes1 if @nodes2 is NULL or empty or
4686 * an empty node-set if @nodes1 doesn't contain @nodes2
4689 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4690 if (xmlXPathNodeSetIsEmpty(nodes2
))
4692 return(xmlXPathNodeLeadingSorted(nodes1
,
4693 xmlXPathNodeSetItem(nodes2
, 1)));
4698 * @nodes1: a node-set
4699 * @nodes2: a node-set
4701 * Implements the EXSLT - Sets leading() function:
4702 * node-set set:leading (node-set, node-set)
4703 * @nodes1 and @nodes2 are sorted by document order, then
4704 * #exslSetsLeadingSorted is called.
4706 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4707 * in document order, @nodes1 if @nodes2 is NULL or empty or
4708 * an empty node-set if @nodes1 doesn't contain @nodes2
4711 xmlXPathLeading (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4712 if (xmlXPathNodeSetIsEmpty(nodes2
))
4714 if (xmlXPathNodeSetIsEmpty(nodes1
))
4715 return(xmlXPathNodeSetCreate(NULL
));
4716 xmlXPathNodeSetSort(nodes1
);
4717 xmlXPathNodeSetSort(nodes2
);
4718 return(xmlXPathNodeLeadingSorted(nodes1
,
4719 xmlXPathNodeSetItem(nodes2
, 1)));
4723 * xmlXPathNodeTrailingSorted:
4724 * @nodes: a node-set, sorted by document order
4727 * Implements the EXSLT - Sets trailing() function:
4728 * node-set set:trailing (node-set, node-set)
4730 * Returns the nodes in @nodes that follow @node in document order,
4731 * @nodes if @node is NULL or an empty node-set if @nodes
4732 * doesn't contain @node
4735 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4743 ret
= xmlXPathNodeSetCreate(NULL
);
4746 if (xmlXPathNodeSetIsEmpty(nodes
) ||
4747 (!xmlXPathNodeSetContains(nodes
, node
)))
4750 l
= xmlXPathNodeSetGetLength(nodes
);
4751 for (i
= l
- 1; i
>= 0; i
--) {
4752 cur
= xmlXPathNodeSetItem(nodes
, i
);
4755 if (xmlXPathNodeSetAddUnique(ret
, cur
) < 0)
4758 xmlXPathNodeSetSort(ret
); /* bug 413451 */
4763 * xmlXPathNodeTrailing:
4764 * @nodes: a node-set
4767 * Implements the EXSLT - Sets trailing() function:
4768 * node-set set:trailing (node-set, node-set)
4769 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4772 * Returns the nodes in @nodes that follow @node in document order,
4773 * @nodes if @node is NULL or an empty node-set if @nodes
4774 * doesn't contain @node
4777 xmlXPathNodeTrailing (xmlNodeSetPtr nodes
, xmlNodePtr node
) {
4778 xmlXPathNodeSetSort(nodes
);
4779 return(xmlXPathNodeTrailingSorted(nodes
, node
));
4783 * xmlXPathTrailingSorted:
4784 * @nodes1: a node-set, sorted by document order
4785 * @nodes2: a node-set, sorted by document order
4787 * Implements the EXSLT - Sets trailing() function:
4788 * node-set set:trailing (node-set, node-set)
4790 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4791 * in document order, @nodes1 if @nodes2 is NULL or empty or
4792 * an empty node-set if @nodes1 doesn't contain @nodes2
4795 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4796 if (xmlXPathNodeSetIsEmpty(nodes2
))
4798 return(xmlXPathNodeTrailingSorted(nodes1
,
4799 xmlXPathNodeSetItem(nodes2
, 0)));
4804 * @nodes1: a node-set
4805 * @nodes2: a node-set
4807 * Implements the EXSLT - Sets trailing() function:
4808 * node-set set:trailing (node-set, node-set)
4809 * @nodes1 and @nodes2 are sorted by document order, then
4810 * #xmlXPathTrailingSorted is called.
4812 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4813 * in document order, @nodes1 if @nodes2 is NULL or empty or
4814 * an empty node-set if @nodes1 doesn't contain @nodes2
4817 xmlXPathTrailing (xmlNodeSetPtr nodes1
, xmlNodeSetPtr nodes2
) {
4818 if (xmlXPathNodeSetIsEmpty(nodes2
))
4820 if (xmlXPathNodeSetIsEmpty(nodes1
))
4821 return(xmlXPathNodeSetCreate(NULL
));
4822 xmlXPathNodeSetSort(nodes1
);
4823 xmlXPathNodeSetSort(nodes2
);
4824 return(xmlXPathNodeTrailingSorted(nodes1
,
4825 xmlXPathNodeSetItem(nodes2
, 0)));
4828 /************************************************************************
4830 * Routines to handle extra functions *
4832 ************************************************************************/
4835 * xmlXPathRegisterFunc:
4836 * @ctxt: the XPath context
4837 * @name: the function name
4838 * @f: the function implementation or NULL
4840 * Register a new function. If @f is NULL it unregisters the function
4842 * Returns 0 in case of success, -1 in case of error
4845 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4846 xmlXPathFunction f
) {
4847 return(xmlXPathRegisterFuncNS(ctxt
, name
, NULL
, f
));
4851 * xmlXPathRegisterFuncNS:
4852 * @ctxt: the XPath context
4853 * @name: the function name
4854 * @ns_uri: the function namespace URI
4855 * @f: the function implementation or NULL
4857 * Register a new function. If @f is NULL it unregisters the function
4859 * Returns 0 in case of success, -1 in case of error
4862 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4863 const xmlChar
*ns_uri
, xmlXPathFunction f
) {
4869 if (ctxt
->funcHash
== NULL
)
4870 ctxt
->funcHash
= xmlHashCreate(0);
4871 if (ctxt
->funcHash
== NULL
)
4874 return(xmlHashRemoveEntry2(ctxt
->funcHash
, name
, ns_uri
, NULL
));
4875 return(xmlHashAddEntry2(ctxt
->funcHash
, name
, ns_uri
, XML_CAST_FPTR(f
)));
4879 * xmlXPathRegisterFuncLookup:
4880 * @ctxt: the XPath context
4881 * @f: the lookup function
4882 * @funcCtxt: the lookup data
4884 * Registers an external mechanism to do function lookup.
4887 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt
,
4888 xmlXPathFuncLookupFunc f
,
4892 ctxt
->funcLookupFunc
= f
;
4893 ctxt
->funcLookupData
= funcCtxt
;
4897 * xmlXPathFunctionLookup:
4898 * @ctxt: the XPath context
4899 * @name: the function name
4901 * Search in the Function array of the context for the given
4904 * Returns the xmlXPathFunction or NULL if not found
4907 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
4911 if (ctxt
->funcLookupFunc
!= NULL
) {
4912 xmlXPathFunction ret
;
4913 xmlXPathFuncLookupFunc f
;
4915 f
= ctxt
->funcLookupFunc
;
4916 ret
= f(ctxt
->funcLookupData
, name
, NULL
);
4920 return(xmlXPathFunctionLookupNS(ctxt
, name
, NULL
));
4924 * xmlXPathFunctionLookupNS:
4925 * @ctxt: the XPath context
4926 * @name: the function name
4927 * @ns_uri: the function namespace URI
4929 * Search in the Function array of the context for the given
4932 * Returns the xmlXPathFunction or NULL if not found
4935 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4936 const xmlChar
*ns_uri
) {
4937 xmlXPathFunction ret
;
4944 if (ctxt
->funcLookupFunc
!= NULL
) {
4945 xmlXPathFuncLookupFunc f
;
4947 f
= ctxt
->funcLookupFunc
;
4948 ret
= f(ctxt
->funcLookupData
, name
, ns_uri
);
4953 if (ctxt
->funcHash
== NULL
)
4956 XML_CAST_FPTR(ret
) = xmlHashLookup2(ctxt
->funcHash
, name
, ns_uri
);
4961 * xmlXPathRegisteredFuncsCleanup:
4962 * @ctxt: the XPath context
4964 * Cleanup the XPath context data associated to registered functions
4967 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt
) {
4971 xmlHashFree(ctxt
->funcHash
, NULL
);
4972 ctxt
->funcHash
= NULL
;
4975 /************************************************************************
4977 * Routines to handle Variables *
4979 ************************************************************************/
4982 * xmlXPathRegisterVariable:
4983 * @ctxt: the XPath context
4984 * @name: the variable name
4985 * @value: the variable value or NULL
4987 * Register a new variable value. If @value is NULL it unregisters
4990 * Returns 0 in case of success, -1 in case of error
4993 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
4994 xmlXPathObjectPtr value
) {
4995 return(xmlXPathRegisterVariableNS(ctxt
, name
, NULL
, value
));
4999 * xmlXPathRegisterVariableNS:
5000 * @ctxt: the XPath context
5001 * @name: the variable name
5002 * @ns_uri: the variable namespace URI
5003 * @value: the variable value or NULL
5005 * Register a new variable value. If @value is NULL it unregisters
5008 * Returns 0 in case of success, -1 in case of error
5011 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5012 const xmlChar
*ns_uri
,
5013 xmlXPathObjectPtr value
) {
5019 if (ctxt
->varHash
== NULL
)
5020 ctxt
->varHash
= xmlHashCreate(0);
5021 if (ctxt
->varHash
== NULL
)
5024 return(xmlHashRemoveEntry2(ctxt
->varHash
, name
, ns_uri
,
5025 (xmlHashDeallocator
)xmlXPathFreeObject
));
5026 return(xmlHashUpdateEntry2(ctxt
->varHash
, name
, ns_uri
,
5028 (xmlHashDeallocator
)xmlXPathFreeObject
));
5032 * xmlXPathRegisterVariableLookup:
5033 * @ctxt: the XPath context
5034 * @f: the lookup function
5035 * @data: the lookup data
5037 * register an external mechanism to do variable lookup
5040 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt
,
5041 xmlXPathVariableLookupFunc f
, void *data
) {
5044 ctxt
->varLookupFunc
= f
;
5045 ctxt
->varLookupData
= data
;
5049 * xmlXPathVariableLookup:
5050 * @ctxt: the XPath context
5051 * @name: the variable name
5053 * Search in the Variable array of the context for the given
5056 * Returns a copy of the value or NULL if not found
5059 xmlXPathVariableLookup(xmlXPathContextPtr ctxt
, const xmlChar
*name
) {
5063 if (ctxt
->varLookupFunc
!= NULL
) {
5064 xmlXPathObjectPtr ret
;
5066 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5067 (ctxt
->varLookupData
, name
, NULL
);
5070 return(xmlXPathVariableLookupNS(ctxt
, name
, NULL
));
5074 * xmlXPathVariableLookupNS:
5075 * @ctxt: the XPath context
5076 * @name: the variable name
5077 * @ns_uri: the variable namespace URI
5079 * Search in the Variable array of the context for the given
5082 * Returns the a copy of the value or NULL if not found
5085 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt
, const xmlChar
*name
,
5086 const xmlChar
*ns_uri
) {
5090 if (ctxt
->varLookupFunc
!= NULL
) {
5091 xmlXPathObjectPtr ret
;
5093 ret
= ((xmlXPathVariableLookupFunc
)ctxt
->varLookupFunc
)
5094 (ctxt
->varLookupData
, name
, ns_uri
);
5095 if (ret
!= NULL
) return(ret
);
5098 if (ctxt
->varHash
== NULL
)
5103 return(xmlXPathCacheObjectCopy(ctxt
, (xmlXPathObjectPtr
)
5104 xmlHashLookup2(ctxt
->varHash
, name
, ns_uri
)));
5108 * xmlXPathRegisteredVariablesCleanup:
5109 * @ctxt: the XPath context
5111 * Cleanup the XPath context data associated to registered variables
5114 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt
) {
5118 xmlHashFree(ctxt
->varHash
, (xmlHashDeallocator
)xmlXPathFreeObject
);
5119 ctxt
->varHash
= NULL
;
5123 * xmlXPathRegisterNs:
5124 * @ctxt: the XPath context
5125 * @prefix: the namespace prefix cannot be NULL or empty string
5126 * @ns_uri: the namespace name
5128 * Register a new namespace. If @ns_uri is NULL it unregisters
5131 * Returns 0 in case of success, -1 in case of error
5134 xmlXPathRegisterNs(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
,
5135 const xmlChar
*ns_uri
) {
5143 if (ctxt
->nsHash
== NULL
)
5144 ctxt
->nsHash
= xmlHashCreate(10);
5145 if (ctxt
->nsHash
== NULL
)
5148 return(xmlHashRemoveEntry(ctxt
->nsHash
, prefix
,
5149 (xmlHashDeallocator
)xmlFree
));
5150 return(xmlHashUpdateEntry(ctxt
->nsHash
, prefix
, (void *) xmlStrdup(ns_uri
),
5151 (xmlHashDeallocator
)xmlFree
));
5156 * @ctxt: the XPath context
5157 * @prefix: the namespace prefix value
5159 * Search in the namespace declaration array of the context for the given
5160 * namespace name associated to the given prefix
5162 * Returns the value or NULL if not found
5165 xmlXPathNsLookup(xmlXPathContextPtr ctxt
, const xmlChar
*prefix
) {
5171 #ifdef XML_XML_NAMESPACE
5172 if (xmlStrEqual(prefix
, (const xmlChar
*) "xml"))
5173 return(XML_XML_NAMESPACE
);
5176 if (ctxt
->namespaces
!= NULL
) {
5179 for (i
= 0;i
< ctxt
->nsNr
;i
++) {
5180 if ((ctxt
->namespaces
[i
] != NULL
) &&
5181 (xmlStrEqual(ctxt
->namespaces
[i
]->prefix
, prefix
)))
5182 return(ctxt
->namespaces
[i
]->href
);
5186 return((const xmlChar
*) xmlHashLookup(ctxt
->nsHash
, prefix
));
5190 * xmlXPathRegisteredNsCleanup:
5191 * @ctxt: the XPath context
5193 * Cleanup the XPath context data associated to registered variables
5196 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt
) {
5200 xmlHashFree(ctxt
->nsHash
, (xmlHashDeallocator
)xmlFree
);
5201 ctxt
->nsHash
= NULL
;
5204 /************************************************************************
5206 * Routines to handle Values *
5208 ************************************************************************/
5210 /* Allocations are terrible, one needs to optimize all this !!! */
5214 * @val: the double value
5216 * Create a new xmlXPathObjectPtr of type double and of value @val
5218 * Returns the newly created object.
5221 xmlXPathNewFloat(double val
) {
5222 xmlXPathObjectPtr ret
;
5224 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5226 xmlXPathErrMemory(NULL
, "creating float object\n");
5229 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5230 ret
->type
= XPATH_NUMBER
;
5231 ret
->floatval
= val
;
5232 #ifdef XP_DEBUG_OBJ_USAGE
5233 xmlXPathDebugObjUsageRequested(NULL
, XPATH_NUMBER
);
5239 * xmlXPathNewBoolean:
5240 * @val: the boolean value
5242 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5244 * Returns the newly created object.
5247 xmlXPathNewBoolean(int val
) {
5248 xmlXPathObjectPtr ret
;
5250 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5252 xmlXPathErrMemory(NULL
, "creating boolean object\n");
5255 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5256 ret
->type
= XPATH_BOOLEAN
;
5257 ret
->boolval
= (val
!= 0);
5258 #ifdef XP_DEBUG_OBJ_USAGE
5259 xmlXPathDebugObjUsageRequested(NULL
, XPATH_BOOLEAN
);
5265 * xmlXPathNewString:
5266 * @val: the xmlChar * value
5268 * Create a new xmlXPathObjectPtr of type string and of value @val
5270 * Returns the newly created object.
5273 xmlXPathNewString(const xmlChar
*val
) {
5274 xmlXPathObjectPtr ret
;
5276 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5278 xmlXPathErrMemory(NULL
, "creating string object\n");
5281 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5282 ret
->type
= XPATH_STRING
;
5284 ret
->stringval
= xmlStrdup(val
);
5286 ret
->stringval
= xmlStrdup((const xmlChar
*)"");
5287 #ifdef XP_DEBUG_OBJ_USAGE
5288 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5294 * xmlXPathWrapString:
5295 * @val: the xmlChar * value
5297 * Wraps the @val string into an XPath object.
5299 * Returns the newly created object.
5302 xmlXPathWrapString (xmlChar
*val
) {
5303 xmlXPathObjectPtr ret
;
5305 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5307 xmlXPathErrMemory(NULL
, "creating string object\n");
5310 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5311 ret
->type
= XPATH_STRING
;
5312 ret
->stringval
= val
;
5313 #ifdef XP_DEBUG_OBJ_USAGE
5314 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5320 * xmlXPathNewCString:
5321 * @val: the char * value
5323 * Create a new xmlXPathObjectPtr of type string and of value @val
5325 * Returns the newly created object.
5328 xmlXPathNewCString(const char *val
) {
5329 xmlXPathObjectPtr ret
;
5331 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5333 xmlXPathErrMemory(NULL
, "creating string object\n");
5336 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5337 ret
->type
= XPATH_STRING
;
5338 ret
->stringval
= xmlStrdup(BAD_CAST val
);
5339 #ifdef XP_DEBUG_OBJ_USAGE
5340 xmlXPathDebugObjUsageRequested(NULL
, XPATH_STRING
);
5346 * xmlXPathWrapCString:
5347 * @val: the char * value
5349 * Wraps a string into an XPath object.
5351 * Returns the newly created object.
5354 xmlXPathWrapCString (char * val
) {
5355 return(xmlXPathWrapString((xmlChar
*)(val
)));
5359 * xmlXPathWrapExternal:
5360 * @val: the user data
5362 * Wraps the @val data into an XPath object.
5364 * Returns the newly created object.
5367 xmlXPathWrapExternal (void *val
) {
5368 xmlXPathObjectPtr ret
;
5370 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5372 xmlXPathErrMemory(NULL
, "creating user object\n");
5375 memset(ret
, 0 , (size_t) sizeof(xmlXPathObject
));
5376 ret
->type
= XPATH_USERS
;
5378 #ifdef XP_DEBUG_OBJ_USAGE
5379 xmlXPathDebugObjUsageRequested(NULL
, XPATH_USERS
);
5385 * xmlXPathObjectCopy:
5386 * @val: the original object
5388 * allocate a new copy of a given object
5390 * Returns the newly created object.
5393 xmlXPathObjectCopy(xmlXPathObjectPtr val
) {
5394 xmlXPathObjectPtr ret
;
5399 ret
= (xmlXPathObjectPtr
) xmlMalloc(sizeof(xmlXPathObject
));
5401 xmlXPathErrMemory(NULL
, "copying object\n");
5404 memcpy(ret
, val
, (size_t) sizeof(xmlXPathObject
));
5405 #ifdef XP_DEBUG_OBJ_USAGE
5406 xmlXPathDebugObjUsageRequested(NULL
, val
->type
);
5408 switch (val
->type
) {
5415 ret
->stringval
= xmlStrdup(val
->stringval
);
5417 case XPATH_XSLT_TREE
:
5420 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5421 this previous handling is no longer correct, and can cause some serious
5422 problems (ref. bug 145547)
5424 if ((val
->nodesetval
!= NULL
) &&
5425 (val
->nodesetval
->nodeTab
!= NULL
)) {
5426 xmlNodePtr cur
, tmp
;
5430 top
= xmlNewDoc(NULL
);
5431 top
->name
= (char *)
5432 xmlStrdup(val
->nodesetval
->nodeTab
[0]->name
);
5436 cur
= val
->nodesetval
->nodeTab
[0]->children
;
5437 while (cur
!= NULL
) {
5438 tmp
= xmlDocCopyNode(cur
, top
, 1);
5439 xmlAddChild((xmlNodePtr
) top
, tmp
);
5444 ret
->nodesetval
= xmlXPathNodeSetCreate((xmlNodePtr
) top
);
5446 ret
->nodesetval
= xmlXPathNodeSetCreate(NULL
);
5447 /* Deallocate the copied tree value */
5451 ret
->nodesetval
= xmlXPathNodeSetMerge(NULL
, val
->nodesetval
);
5452 /* Do not deallocate the copied tree value */
5455 case XPATH_LOCATIONSET
:
5456 #ifdef LIBXML_XPTR_ENABLED
5458 xmlLocationSetPtr loc
= val
->user
;
5459 ret
->user
= (void *) xmlXPtrLocationSetMerge(NULL
, loc
);
5464 ret
->user
= val
->user
;
5466 case XPATH_UNDEFINED
:
5467 xmlGenericError(xmlGenericErrorContext
,
5468 "xmlXPathObjectCopy: unsupported type %d\n",
5476 * xmlXPathFreeObject:
5477 * @obj: the object to free
5479 * Free up an xmlXPathObjectPtr object.
5482 xmlXPathFreeObject(xmlXPathObjectPtr obj
) {
5483 if (obj
== NULL
) return;
5484 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
5487 if (obj
->user
!= NULL
) {
5488 xmlXPathFreeNodeSet(obj
->nodesetval
);
5489 xmlFreeNodeList((xmlNodePtr
) obj
->user
);
5492 obj
->type
= XPATH_XSLT_TREE
; /* TODO: Just for debugging. */
5493 if (obj
->nodesetval
!= NULL
)
5494 xmlXPathFreeValueTree(obj
->nodesetval
);
5496 if (obj
->nodesetval
!= NULL
)
5497 xmlXPathFreeNodeSet(obj
->nodesetval
);
5499 #ifdef LIBXML_XPTR_ENABLED
5500 } else if (obj
->type
== XPATH_LOCATIONSET
) {
5501 if (obj
->user
!= NULL
)
5502 xmlXPtrFreeLocationSet(obj
->user
);
5504 } else if (obj
->type
== XPATH_STRING
) {
5505 if (obj
->stringval
!= NULL
)
5506 xmlFree(obj
->stringval
);
5508 #ifdef XP_DEBUG_OBJ_USAGE
5509 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5515 * xmlXPathReleaseObject:
5516 * @obj: the xmlXPathObjectPtr to free or to cache
5518 * Depending on the state of the cache this frees the given
5519 * XPath object or stores it in the cache.
5522 xmlXPathReleaseObject(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr obj
)
5524 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5525 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5526 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5528 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5532 if ((ctxt
== NULL
) || (ctxt
->cache
== NULL
)) {
5533 xmlXPathFreeObject(obj
);
5535 xmlXPathContextCachePtr cache
=
5536 (xmlXPathContextCachePtr
) ctxt
->cache
;
5538 switch (obj
->type
) {
5540 case XPATH_XSLT_TREE
:
5541 if (obj
->nodesetval
!= NULL
) {
5544 * It looks like the @boolval is used for
5545 * evaluation if this an XSLT Result Tree Fragment.
5546 * TODO: Check if this assumption is correct.
5548 obj
->type
= XPATH_XSLT_TREE
; /* just for debugging */
5549 xmlXPathFreeValueTree(obj
->nodesetval
);
5550 obj
->nodesetval
= NULL
;
5551 } else if ((obj
->nodesetval
->nodeMax
<= 40) &&
5552 (XP_CACHE_WANTS(cache
->nodesetObjs
,
5553 cache
->maxNodeset
)))
5555 XP_CACHE_ADD(cache
->nodesetObjs
, obj
);
5558 xmlXPathFreeNodeSet(obj
->nodesetval
);
5559 obj
->nodesetval
= NULL
;
5564 if (obj
->stringval
!= NULL
)
5565 xmlFree(obj
->stringval
);
5567 if (XP_CACHE_WANTS(cache
->stringObjs
, cache
->maxString
)) {
5568 XP_CACHE_ADD(cache
->stringObjs
, obj
);
5573 if (XP_CACHE_WANTS(cache
->booleanObjs
, cache
->maxBoolean
)) {
5574 XP_CACHE_ADD(cache
->booleanObjs
, obj
);
5579 if (XP_CACHE_WANTS(cache
->numberObjs
, cache
->maxNumber
)) {
5580 XP_CACHE_ADD(cache
->numberObjs
, obj
);
5584 #ifdef LIBXML_XPTR_ENABLED
5585 case XPATH_LOCATIONSET
:
5586 if (obj
->user
!= NULL
) {
5587 xmlXPtrFreeLocationSet(obj
->user
);
5596 * Fallback to adding to the misc-objects slot.
5598 if (XP_CACHE_WANTS(cache
->miscObjs
, cache
->maxMisc
)) {
5599 XP_CACHE_ADD(cache
->miscObjs
, obj
);
5605 #ifdef XP_DEBUG_OBJ_USAGE
5606 xmlXPathDebugObjUsageReleased(ctxt
, obj
->type
);
5609 if (obj
->nodesetval
!= NULL
) {
5610 xmlNodeSetPtr tmpset
= obj
->nodesetval
;
5613 * TODO: Due to those nasty ns-nodes, we need to traverse
5614 * the list and free the ns-nodes.
5615 * URGENT TODO: Check if it's actually slowing things down.
5616 * Maybe we shouldn't try to preserve the list.
5618 if (tmpset
->nodeNr
> 1) {
5622 for (i
= 0; i
< tmpset
->nodeNr
; i
++) {
5623 node
= tmpset
->nodeTab
[i
];
5624 if ((node
!= NULL
) &&
5625 (node
->type
== XML_NAMESPACE_DECL
))
5627 xmlXPathNodeSetFreeNs((xmlNsPtr
) node
);
5630 } else if (tmpset
->nodeNr
== 1) {
5631 if ((tmpset
->nodeTab
[0] != NULL
) &&
5632 (tmpset
->nodeTab
[0]->type
== XML_NAMESPACE_DECL
))
5633 xmlXPathNodeSetFreeNs((xmlNsPtr
) tmpset
->nodeTab
[0]);
5636 memset(obj
, 0, sizeof(xmlXPathObject
));
5637 obj
->nodesetval
= tmpset
;
5639 memset(obj
, 0, sizeof(xmlXPathObject
));
5645 * Cache is full; free the object.
5647 if (obj
->nodesetval
!= NULL
)
5648 xmlXPathFreeNodeSet(obj
->nodesetval
);
5649 #ifdef XP_DEBUG_OBJ_USAGE
5650 xmlXPathDebugObjUsageReleased(NULL
, obj
->type
);
5658 /************************************************************************
5660 * Type Casting Routines *
5662 ************************************************************************/
5665 * xmlXPathCastBooleanToString:
5668 * Converts a boolean to its string value.
5670 * Returns a newly allocated string.
5673 xmlXPathCastBooleanToString (int val
) {
5676 ret
= xmlStrdup((const xmlChar
*) "true");
5678 ret
= xmlStrdup((const xmlChar
*) "false");
5683 * xmlXPathCastNumberToString:
5686 * Converts a number to its string value.
5688 * Returns a newly allocated string.
5691 xmlXPathCastNumberToString (double val
) {
5693 switch (xmlXPathIsInf(val
)) {
5695 ret
= xmlStrdup((const xmlChar
*) "Infinity");
5698 ret
= xmlStrdup((const xmlChar
*) "-Infinity");
5701 if (xmlXPathIsNaN(val
)) {
5702 ret
= xmlStrdup((const xmlChar
*) "NaN");
5703 } else if (val
== 0 && xmlXPathGetSign(val
) != 0) {
5704 ret
= xmlStrdup((const xmlChar
*) "0");
5706 /* could be improved */
5708 xmlXPathFormatNumber(val
, buf
, 99);
5710 ret
= xmlStrdup((const xmlChar
*) buf
);
5717 * xmlXPathCastNodeToString:
5720 * Converts a node to its string value.
5722 * Returns a newly allocated string.
5725 xmlXPathCastNodeToString (xmlNodePtr node
) {
5727 if ((ret
= xmlNodeGetContent(node
)) == NULL
)
5728 ret
= xmlStrdup((const xmlChar
*) "");
5733 * xmlXPathCastNodeSetToString:
5736 * Converts a node-set to its string value.
5738 * Returns a newly allocated string.
5741 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns
) {
5742 if ((ns
== NULL
) || (ns
->nodeNr
== 0) || (ns
->nodeTab
== NULL
))
5743 return(xmlStrdup((const xmlChar
*) ""));
5746 xmlXPathNodeSetSort(ns
);
5747 return(xmlXPathCastNodeToString(ns
->nodeTab
[0]));
5751 * xmlXPathCastToString:
5752 * @val: an XPath object
5754 * Converts an existing object to its string() equivalent
5756 * Returns the allocated string value of the object, NULL in case of error.
5757 * It's up to the caller to free the string memory with xmlFree().
5760 xmlXPathCastToString(xmlXPathObjectPtr val
) {
5761 xmlChar
*ret
= NULL
;
5764 return(xmlStrdup((const xmlChar
*) ""));
5765 switch (val
->type
) {
5766 case XPATH_UNDEFINED
:
5768 xmlGenericError(xmlGenericErrorContext
, "String: undefined\n");
5770 ret
= xmlStrdup((const xmlChar
*) "");
5773 case XPATH_XSLT_TREE
:
5774 ret
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5777 return(xmlStrdup(val
->stringval
));
5779 ret
= xmlXPathCastBooleanToString(val
->boolval
);
5781 case XPATH_NUMBER
: {
5782 ret
= xmlXPathCastNumberToString(val
->floatval
);
5788 case XPATH_LOCATIONSET
:
5790 ret
= xmlStrdup((const xmlChar
*) "");
5797 * xmlXPathConvertString:
5798 * @val: an XPath object
5800 * Converts an existing object to its string() equivalent
5802 * Returns the new object, the old one is freed (or the operation
5803 * is done directly on @val)
5806 xmlXPathConvertString(xmlXPathObjectPtr val
) {
5807 xmlChar
*res
= NULL
;
5810 return(xmlXPathNewCString(""));
5812 switch (val
->type
) {
5813 case XPATH_UNDEFINED
:
5815 xmlGenericError(xmlGenericErrorContext
, "STRING: undefined\n");
5819 case XPATH_XSLT_TREE
:
5820 res
= xmlXPathCastNodeSetToString(val
->nodesetval
);
5825 res
= xmlXPathCastBooleanToString(val
->boolval
);
5828 res
= xmlXPathCastNumberToString(val
->floatval
);
5833 case XPATH_LOCATIONSET
:
5837 xmlXPathFreeObject(val
);
5839 return(xmlXPathNewCString(""));
5840 return(xmlXPathWrapString(res
));
5844 * xmlXPathCastBooleanToNumber:
5847 * Converts a boolean to its number value
5849 * Returns the number value
5852 xmlXPathCastBooleanToNumber(int val
) {
5859 * xmlXPathCastStringToNumber:
5862 * Converts a string to its number value
5864 * Returns the number value
5867 xmlXPathCastStringToNumber(const xmlChar
* val
) {
5868 return(xmlXPathStringEvalNumber(val
));
5872 * xmlXPathCastNodeToNumber:
5875 * Converts a node to its number value
5877 * Returns the number value
5880 xmlXPathCastNodeToNumber (xmlNodePtr node
) {
5885 return(xmlXPathNAN
);
5886 strval
= xmlXPathCastNodeToString(node
);
5888 return(xmlXPathNAN
);
5889 ret
= xmlXPathCastStringToNumber(strval
);
5896 * xmlXPathCastNodeSetToNumber:
5899 * Converts a node-set to its number value
5901 * Returns the number value
5904 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns
) {
5909 return(xmlXPathNAN
);
5910 str
= xmlXPathCastNodeSetToString(ns
);
5911 ret
= xmlXPathCastStringToNumber(str
);
5917 * xmlXPathCastToNumber:
5918 * @val: an XPath object
5920 * Converts an XPath object to its number value
5922 * Returns the number value
5925 xmlXPathCastToNumber(xmlXPathObjectPtr val
) {
5929 return(xmlXPathNAN
);
5930 switch (val
->type
) {
5931 case XPATH_UNDEFINED
:
5933 xmlGenericError(xmlGenericErrorContext
, "NUMBER: undefined\n");
5938 case XPATH_XSLT_TREE
:
5939 ret
= xmlXPathCastNodeSetToNumber(val
->nodesetval
);
5942 ret
= xmlXPathCastStringToNumber(val
->stringval
);
5945 ret
= val
->floatval
;
5948 ret
= xmlXPathCastBooleanToNumber(val
->boolval
);
5953 case XPATH_LOCATIONSET
:
5962 * xmlXPathConvertNumber:
5963 * @val: an XPath object
5965 * Converts an existing object to its number() equivalent
5967 * Returns the new object, the old one is freed (or the operation
5968 * is done directly on @val)
5971 xmlXPathConvertNumber(xmlXPathObjectPtr val
) {
5972 xmlXPathObjectPtr ret
;
5975 return(xmlXPathNewFloat(0.0));
5976 if (val
->type
== XPATH_NUMBER
)
5978 ret
= xmlXPathNewFloat(xmlXPathCastToNumber(val
));
5979 xmlXPathFreeObject(val
);
5984 * xmlXPathCastNumberToBoolean:
5987 * Converts a number to its boolean value
5989 * Returns the boolean value
5992 xmlXPathCastNumberToBoolean (double val
) {
5993 if (xmlXPathIsNaN(val
) || (val
== 0.0))
5999 * xmlXPathCastStringToBoolean:
6002 * Converts a string to its boolean value
6004 * Returns the boolean value
6007 xmlXPathCastStringToBoolean (const xmlChar
*val
) {
6008 if ((val
== NULL
) || (xmlStrlen(val
) == 0))
6014 * xmlXPathCastNodeSetToBoolean:
6017 * Converts a node-set to its boolean value
6019 * Returns the boolean value
6022 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns
) {
6023 if ((ns
== NULL
) || (ns
->nodeNr
== 0))
6029 * xmlXPathCastToBoolean:
6030 * @val: an XPath object
6032 * Converts an XPath object to its boolean value
6034 * Returns the boolean value
6037 xmlXPathCastToBoolean (xmlXPathObjectPtr val
) {
6042 switch (val
->type
) {
6043 case XPATH_UNDEFINED
:
6045 xmlGenericError(xmlGenericErrorContext
, "BOOLEAN: undefined\n");
6050 case XPATH_XSLT_TREE
:
6051 ret
= xmlXPathCastNodeSetToBoolean(val
->nodesetval
);
6054 ret
= xmlXPathCastStringToBoolean(val
->stringval
);
6057 ret
= xmlXPathCastNumberToBoolean(val
->floatval
);
6065 case XPATH_LOCATIONSET
:
6075 * xmlXPathConvertBoolean:
6076 * @val: an XPath object
6078 * Converts an existing object to its boolean() equivalent
6080 * Returns the new object, the old one is freed (or the operation
6081 * is done directly on @val)
6084 xmlXPathConvertBoolean(xmlXPathObjectPtr val
) {
6085 xmlXPathObjectPtr ret
;
6088 return(xmlXPathNewBoolean(0));
6089 if (val
->type
== XPATH_BOOLEAN
)
6091 ret
= xmlXPathNewBoolean(xmlXPathCastToBoolean(val
));
6092 xmlXPathFreeObject(val
);
6096 /************************************************************************
6098 * Routines to handle XPath contexts *
6100 ************************************************************************/
6103 * xmlXPathNewContext:
6104 * @doc: the XML document
6106 * Create a new xmlXPathContext
6108 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6111 xmlXPathNewContext(xmlDocPtr doc
) {
6112 xmlXPathContextPtr ret
;
6114 ret
= (xmlXPathContextPtr
) xmlMalloc(sizeof(xmlXPathContext
));
6116 xmlXPathErrMemory(NULL
, "creating context\n");
6119 memset(ret
, 0 , (size_t) sizeof(xmlXPathContext
));
6123 ret
->varHash
= NULL
;
6129 ret
->funcHash
= xmlHashCreate(0);
6138 ret
->contextSize
= -1;
6139 ret
->proximityPosition
= -1;
6141 #ifdef XP_DEFAULT_CACHE_ON
6142 if (xmlXPathContextSetCache(ret
, 1, -1, 0) == -1) {
6143 xmlXPathFreeContext(ret
);
6148 xmlXPathRegisterAllFunctions(ret
);
6154 * xmlXPathFreeContext:
6155 * @ctxt: the context to free
6157 * Free up an xmlXPathContext
6160 xmlXPathFreeContext(xmlXPathContextPtr ctxt
) {
6161 if (ctxt
== NULL
) return;
6163 if (ctxt
->cache
!= NULL
)
6164 xmlXPathFreeCache((xmlXPathContextCachePtr
) ctxt
->cache
);
6165 xmlXPathRegisteredNsCleanup(ctxt
);
6166 xmlXPathRegisteredFuncsCleanup(ctxt
);
6167 xmlXPathRegisteredVariablesCleanup(ctxt
);
6168 xmlResetError(&ctxt
->lastError
);
6172 /************************************************************************
6174 * Routines to handle XPath parser contexts *
6176 ************************************************************************/
6178 #define CHECK_CTXT(ctxt) \
6179 if (ctxt == NULL) { \
6180 __xmlRaiseError(NULL, NULL, NULL, \
6181 NULL, NULL, XML_FROM_XPATH, \
6182 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6183 __FILE__, __LINE__, \
6184 NULL, NULL, NULL, 0, 0, \
6185 "NULL context pointer\n"); \
6189 #define CHECK_CTXT_NEG(ctxt) \
6190 if (ctxt == NULL) { \
6191 __xmlRaiseError(NULL, NULL, NULL, \
6192 NULL, NULL, XML_FROM_XPATH, \
6193 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6194 __FILE__, __LINE__, \
6195 NULL, NULL, NULL, 0, 0, \
6196 "NULL context pointer\n"); \
6201 #define CHECK_CONTEXT(ctxt) \
6202 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6203 (ctxt->doc->children == NULL)) { \
6204 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6210 * xmlXPathNewParserContext:
6211 * @str: the XPath expression
6212 * @ctxt: the XPath context
6214 * Create a new xmlXPathParserContext
6216 * Returns the xmlXPathParserContext just allocated.
6218 xmlXPathParserContextPtr
6219 xmlXPathNewParserContext(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
6220 xmlXPathParserContextPtr ret
;
6222 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6224 xmlXPathErrMemory(ctxt
, "creating parser context\n");
6227 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6228 ret
->cur
= ret
->base
= str
;
6229 ret
->context
= ctxt
;
6231 ret
->comp
= xmlXPathNewCompExpr();
6232 if (ret
->comp
== NULL
) {
6233 xmlFree(ret
->valueTab
);
6237 if ((ctxt
!= NULL
) && (ctxt
->dict
!= NULL
)) {
6238 ret
->comp
->dict
= ctxt
->dict
;
6239 xmlDictReference(ret
->comp
->dict
);
6246 * xmlXPathCompParserContext:
6247 * @comp: the XPath compiled expression
6248 * @ctxt: the XPath context
6250 * Create a new xmlXPathParserContext when processing a compiled expression
6252 * Returns the xmlXPathParserContext just allocated.
6254 static xmlXPathParserContextPtr
6255 xmlXPathCompParserContext(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctxt
) {
6256 xmlXPathParserContextPtr ret
;
6258 ret
= (xmlXPathParserContextPtr
) xmlMalloc(sizeof(xmlXPathParserContext
));
6260 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6263 memset(ret
, 0 , (size_t) sizeof(xmlXPathParserContext
));
6265 /* Allocate the value stack */
6266 ret
->valueTab
= (xmlXPathObjectPtr
*)
6267 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
6268 if (ret
->valueTab
== NULL
) {
6270 xmlXPathErrMemory(ctxt
, "creating evaluation context\n");
6276 ret
->valueFrame
= 0;
6278 ret
->context
= ctxt
;
6285 * xmlXPathFreeParserContext:
6286 * @ctxt: the context to free
6288 * Free up an xmlXPathParserContext
6291 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt
) {
6292 if (ctxt
->valueTab
!= NULL
) {
6293 xmlFree(ctxt
->valueTab
);
6295 if (ctxt
->comp
!= NULL
) {
6296 #ifdef XPATH_STREAMING
6297 if (ctxt
->comp
->stream
!= NULL
) {
6298 xmlFreePatternList(ctxt
->comp
->stream
);
6299 ctxt
->comp
->stream
= NULL
;
6302 xmlXPathFreeCompExpr(ctxt
->comp
);
6307 /************************************************************************
6309 * The implicit core function library *
6311 ************************************************************************/
6314 * xmlXPathNodeValHash:
6315 * @node: a node pointer
6317 * Function computing the beginning of the string value of the node,
6318 * used to speed up comparisons
6320 * Returns an int usable as a hash
6323 xmlXPathNodeValHash(xmlNodePtr node
) {
6325 const xmlChar
* string
= NULL
;
6326 xmlNodePtr tmp
= NULL
;
6327 unsigned int ret
= 0;
6332 if (node
->type
== XML_DOCUMENT_NODE
) {
6333 tmp
= xmlDocGetRootElement((xmlDocPtr
) node
);
6335 node
= node
->children
;
6343 switch (node
->type
) {
6344 case XML_COMMENT_NODE
:
6346 case XML_CDATA_SECTION_NODE
:
6348 string
= node
->content
;
6353 return(((unsigned int) string
[0]) +
6354 (((unsigned int) string
[1]) << 8));
6355 case XML_NAMESPACE_DECL
:
6356 string
= ((xmlNsPtr
)node
)->href
;
6361 return(((unsigned int) string
[0]) +
6362 (((unsigned int) string
[1]) << 8));
6363 case XML_ATTRIBUTE_NODE
:
6364 tmp
= ((xmlAttrPtr
) node
)->children
;
6366 case XML_ELEMENT_NODE
:
6367 tmp
= node
->children
;
6372 while (tmp
!= NULL
) {
6373 switch (tmp
->type
) {
6374 case XML_COMMENT_NODE
:
6376 case XML_CDATA_SECTION_NODE
:
6378 string
= tmp
->content
;
6380 case XML_NAMESPACE_DECL
:
6381 string
= ((xmlNsPtr
)tmp
)->href
;
6386 if ((string
!= NULL
) && (string
[0] != 0)) {
6388 return(ret
+ (((unsigned int) string
[0]) << 8));
6390 if (string
[1] == 0) {
6392 ret
= (unsigned int) string
[0];
6394 return(((unsigned int) string
[0]) +
6395 (((unsigned int) string
[1]) << 8));
6401 if ((tmp
->children
!= NULL
) && (tmp
->type
!= XML_DTD_NODE
)) {
6402 if (tmp
->children
->type
!= XML_ENTITY_DECL
) {
6403 tmp
= tmp
->children
;
6410 if (tmp
->next
!= NULL
) {
6423 if (tmp
->next
!= NULL
) {
6427 } while (tmp
!= NULL
);
6433 * xmlXPathStringHash:
6436 * Function computing the beginning of the string value of the node,
6437 * used to speed up comparisons
6439 * Returns an int usable as a hash
6442 xmlXPathStringHash(const xmlChar
* string
) {
6444 return((unsigned int) 0);
6447 return(((unsigned int) string
[0]) +
6448 (((unsigned int) string
[1]) << 8));
6452 * xmlXPathCompareNodeSetFloat:
6453 * @ctxt: the XPath Parser context
6454 * @inf: less than (1) or greater than (0)
6455 * @strict: is the comparison strict
6456 * @arg: the node set
6459 * Implement the compare operation between a nodeset and a number
6460 * @ns < @val (1, 1, ...
6461 * @ns <= @val (1, 0, ...
6462 * @ns > @val (0, 1, ...
6463 * @ns >= @val (0, 0, ...
6465 * If one object to be compared is a node-set and the other is a number,
6466 * then the comparison will be true if and only if there is a node in the
6467 * node-set such that the result of performing the comparison on the number
6468 * to be compared and on the result of converting the string-value of that
6469 * node to a number using the number function is true.
6471 * Returns 0 or 1 depending on the results of the test.
6474 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6475 xmlXPathObjectPtr arg
, xmlXPathObjectPtr f
) {
6480 if ((f
== NULL
) || (arg
== NULL
) ||
6481 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6482 xmlXPathReleaseObject(ctxt
->context
, arg
);
6483 xmlXPathReleaseObject(ctxt
->context
, f
);
6486 ns
= arg
->nodesetval
;
6488 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6489 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6492 xmlXPathCacheNewString(ctxt
->context
, str2
));
6494 xmlXPathNumberFunction(ctxt
, 1);
6495 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, f
));
6496 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6502 xmlXPathReleaseObject(ctxt
->context
, arg
);
6503 xmlXPathReleaseObject(ctxt
->context
, f
);
6508 * xmlXPathCompareNodeSetString:
6509 * @ctxt: the XPath Parser context
6510 * @inf: less than (1) or greater than (0)
6511 * @strict: is the comparison strict
6512 * @arg: the node set
6515 * Implement the compare operation between a nodeset and a string
6516 * @ns < @val (1, 1, ...
6517 * @ns <= @val (1, 0, ...
6518 * @ns > @val (0, 1, ...
6519 * @ns >= @val (0, 0, ...
6521 * If one object to be compared is a node-set and the other is a string,
6522 * then the comparison will be true if and only if there is a node in
6523 * the node-set such that the result of performing the comparison on the
6524 * string-value of the node and the other string is true.
6526 * Returns 0 or 1 depending on the results of the test.
6529 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6530 xmlXPathObjectPtr arg
, xmlXPathObjectPtr s
) {
6535 if ((s
== NULL
) || (arg
== NULL
) ||
6536 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
))) {
6537 xmlXPathReleaseObject(ctxt
->context
, arg
);
6538 xmlXPathReleaseObject(ctxt
->context
, s
);
6541 ns
= arg
->nodesetval
;
6543 for (i
= 0;i
< ns
->nodeNr
;i
++) {
6544 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6547 xmlXPathCacheNewString(ctxt
->context
, str2
));
6549 valuePush(ctxt
, xmlXPathCacheObjectCopy(ctxt
->context
, s
));
6550 ret
= xmlXPathCompareValues(ctxt
, inf
, strict
);
6556 xmlXPathReleaseObject(ctxt
->context
, arg
);
6557 xmlXPathReleaseObject(ctxt
->context
, s
);
6562 * xmlXPathCompareNodeSets:
6563 * @inf: less than (1) or greater than (0)
6564 * @strict: is the comparison strict
6565 * @arg1: the first node set object
6566 * @arg2: the second node set object
6568 * Implement the compare operation on nodesets:
6570 * If both objects to be compared are node-sets, then the comparison
6571 * will be true if and only if there is a node in the first node-set
6572 * and a node in the second node-set such that the result of performing
6573 * the comparison on the string-values of the two nodes is true.
6575 * When neither object to be compared is a node-set and the operator
6576 * is <=, <, >= or >, then the objects are compared by converting both
6577 * objects to numbers and comparing the numbers according to IEEE 754.
6579 * The number function converts its argument to a number as follows:
6580 * - a string that consists of optional whitespace followed by an
6581 * optional minus sign followed by a Number followed by whitespace
6582 * is converted to the IEEE 754 number that is nearest (according
6583 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6584 * represented by the string; any other string is converted to NaN
6586 * Conclusion all nodes need to be converted first to their string value
6587 * and then the comparison must be done when possible
6590 xmlXPathCompareNodeSets(int inf
, int strict
,
6591 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6599 if ((arg1
== NULL
) ||
6600 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
))) {
6601 xmlXPathFreeObject(arg2
);
6604 if ((arg2
== NULL
) ||
6605 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
))) {
6606 xmlXPathFreeObject(arg1
);
6607 xmlXPathFreeObject(arg2
);
6611 ns1
= arg1
->nodesetval
;
6612 ns2
= arg2
->nodesetval
;
6614 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0)) {
6615 xmlXPathFreeObject(arg1
);
6616 xmlXPathFreeObject(arg2
);
6619 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0)) {
6620 xmlXPathFreeObject(arg1
);
6621 xmlXPathFreeObject(arg2
);
6625 values2
= (double *) xmlMalloc(ns2
->nodeNr
* sizeof(double));
6626 if (values2
== NULL
) {
6627 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6628 xmlXPathFreeObject(arg1
);
6629 xmlXPathFreeObject(arg2
);
6632 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6633 val1
= xmlXPathCastNodeToNumber(ns1
->nodeTab
[i
]);
6634 if (xmlXPathIsNaN(val1
))
6636 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6638 values2
[j
] = xmlXPathCastNodeToNumber(ns2
->nodeTab
[j
]);
6640 if (xmlXPathIsNaN(values2
[j
]))
6643 ret
= (val1
< values2
[j
]);
6644 else if (inf
&& !strict
)
6645 ret
= (val1
<= values2
[j
]);
6646 else if (!inf
&& strict
)
6647 ret
= (val1
> values2
[j
]);
6648 else if (!inf
&& !strict
)
6649 ret
= (val1
>= values2
[j
]);
6658 xmlXPathFreeObject(arg1
);
6659 xmlXPathFreeObject(arg2
);
6664 * xmlXPathCompareNodeSetValue:
6665 * @ctxt: the XPath Parser context
6666 * @inf: less than (1) or greater than (0)
6667 * @strict: is the comparison strict
6668 * @arg: the node set
6671 * Implement the compare operation between a nodeset and a value
6672 * @ns < @val (1, 1, ...
6673 * @ns <= @val (1, 0, ...
6674 * @ns > @val (0, 1, ...
6675 * @ns >= @val (0, 0, ...
6677 * If one object to be compared is a node-set and the other is a boolean,
6678 * then the comparison will be true if and only if the result of performing
6679 * the comparison on the boolean and on the result of converting
6680 * the node-set to a boolean using the boolean function is true.
6682 * Returns 0 or 1 depending on the results of the test.
6685 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt
, int inf
, int strict
,
6686 xmlXPathObjectPtr arg
, xmlXPathObjectPtr val
) {
6687 if ((val
== NULL
) || (arg
== NULL
) ||
6688 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6693 return(xmlXPathCompareNodeSetFloat(ctxt
, inf
, strict
, arg
, val
));
6695 case XPATH_XSLT_TREE
:
6696 return(xmlXPathCompareNodeSets(inf
, strict
, arg
, val
));
6698 return(xmlXPathCompareNodeSetString(ctxt
, inf
, strict
, arg
, val
));
6700 valuePush(ctxt
, arg
);
6701 xmlXPathBooleanFunction(ctxt
, 1);
6702 valuePush(ctxt
, val
);
6703 return(xmlXPathCompareValues(ctxt
, inf
, strict
));
6711 * xmlXPathEqualNodeSetString:
6712 * @arg: the nodeset object argument
6713 * @str: the string to compare to.
6714 * @neq: flag to show whether for '=' (0) or '!=' (1)
6716 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6717 * If one object to be compared is a node-set and the other is a string,
6718 * then the comparison will be true if and only if there is a node in
6719 * the node-set such that the result of performing the comparison on the
6720 * string-value of the node and the other string is true.
6722 * Returns 0 or 1 depending on the results of the test.
6725 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg
, const xmlChar
* str
, int neq
)
6732 if ((str
== NULL
) || (arg
== NULL
) ||
6733 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6735 ns
= arg
->nodesetval
;
6737 * A NULL nodeset compared with a string is always false
6738 * (since there is no node equal, and no node not equal)
6740 if ((ns
== NULL
) || (ns
->nodeNr
<= 0) )
6742 hash
= xmlXPathStringHash(str
);
6743 for (i
= 0; i
< ns
->nodeNr
; i
++) {
6744 if (xmlXPathNodeValHash(ns
->nodeTab
[i
]) == hash
) {
6745 str2
= xmlNodeGetContent(ns
->nodeTab
[i
]);
6746 if ((str2
!= NULL
) && (xmlStrEqual(str
, str2
))) {
6751 } else if ((str2
== NULL
) && (xmlStrEqual(str
, BAD_CAST
""))) {
6769 * xmlXPathEqualNodeSetFloat:
6770 * @arg: the nodeset object argument
6771 * @f: the float to compare to
6772 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6774 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6775 * If one object to be compared is a node-set and the other is a number,
6776 * then the comparison will be true if and only if there is a node in
6777 * the node-set such that the result of performing the comparison on the
6778 * number to be compared and on the result of converting the string-value
6779 * of that node to a number using the number function is true.
6781 * Returns 0 or 1 depending on the results of the test.
6784 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt
,
6785 xmlXPathObjectPtr arg
, double f
, int neq
) {
6789 xmlXPathObjectPtr val
;
6792 if ((arg
== NULL
) ||
6793 ((arg
->type
!= XPATH_NODESET
) && (arg
->type
!= XPATH_XSLT_TREE
)))
6796 ns
= arg
->nodesetval
;
6798 for (i
=0;i
<ns
->nodeNr
;i
++) {
6799 str2
= xmlXPathCastNodeToString(ns
->nodeTab
[i
]);
6801 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, str2
));
6803 xmlXPathNumberFunction(ctxt
, 1);
6804 val
= valuePop(ctxt
);
6806 xmlXPathReleaseObject(ctxt
->context
, val
);
6807 if (!xmlXPathIsNaN(v
)) {
6808 if ((!neq
) && (v
==f
)) {
6811 } else if ((neq
) && (v
!=f
)) {
6815 } else { /* NaN is unequal to any value */
6828 * xmlXPathEqualNodeSets:
6829 * @arg1: first nodeset object argument
6830 * @arg2: second nodeset object argument
6831 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6833 * Implement the equal / not equal operation on XPath nodesets:
6834 * @arg1 == @arg2 or @arg1 != @arg2
6835 * If both objects to be compared are node-sets, then the comparison
6836 * will be true if and only if there is a node in the first node-set and
6837 * a node in the second node-set such that the result of performing the
6838 * comparison on the string-values of the two nodes is true.
6840 * (needless to say, this is a costly operation)
6842 * Returns 0 or 1 depending on the results of the test.
6845 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
, int neq
) {
6847 unsigned int *hashs1
;
6848 unsigned int *hashs2
;
6855 if ((arg1
== NULL
) ||
6856 ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)))
6858 if ((arg2
== NULL
) ||
6859 ((arg2
->type
!= XPATH_NODESET
) && (arg2
->type
!= XPATH_XSLT_TREE
)))
6862 ns1
= arg1
->nodesetval
;
6863 ns2
= arg2
->nodesetval
;
6865 if ((ns1
== NULL
) || (ns1
->nodeNr
<= 0))
6867 if ((ns2
== NULL
) || (ns2
->nodeNr
<= 0))
6871 * for equal, check if there is a node pertaining to both sets
6874 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6875 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6876 if (ns1
->nodeTab
[i
] == ns2
->nodeTab
[j
])
6879 values1
= (xmlChar
**) xmlMalloc(ns1
->nodeNr
* sizeof(xmlChar
*));
6880 if (values1
== NULL
) {
6881 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6884 hashs1
= (unsigned int *) xmlMalloc(ns1
->nodeNr
* sizeof(unsigned int));
6885 if (hashs1
== NULL
) {
6886 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6890 memset(values1
, 0, ns1
->nodeNr
* sizeof(xmlChar
*));
6891 values2
= (xmlChar
**) xmlMalloc(ns2
->nodeNr
* sizeof(xmlChar
*));
6892 if (values2
== NULL
) {
6893 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6898 hashs2
= (unsigned int *) xmlMalloc(ns2
->nodeNr
* sizeof(unsigned int));
6899 if (hashs2
== NULL
) {
6900 xmlXPathErrMemory(NULL
, "comparing nodesets\n");
6906 memset(values2
, 0, ns2
->nodeNr
* sizeof(xmlChar
*));
6907 for (i
= 0;i
< ns1
->nodeNr
;i
++) {
6908 hashs1
[i
] = xmlXPathNodeValHash(ns1
->nodeTab
[i
]);
6909 for (j
= 0;j
< ns2
->nodeNr
;j
++) {
6911 hashs2
[j
] = xmlXPathNodeValHash(ns2
->nodeTab
[j
]);
6912 if (hashs1
[i
] != hashs2
[j
]) {
6919 if (values1
[i
] == NULL
)
6920 values1
[i
] = xmlNodeGetContent(ns1
->nodeTab
[i
]);
6921 if (values2
[j
] == NULL
)
6922 values2
[j
] = xmlNodeGetContent(ns2
->nodeTab
[j
]);
6923 ret
= xmlStrEqual(values1
[i
], values2
[j
]) ^ neq
;
6931 for (i
= 0;i
< ns1
->nodeNr
;i
++)
6932 if (values1
[i
] != NULL
)
6933 xmlFree(values1
[i
]);
6934 for (j
= 0;j
< ns2
->nodeNr
;j
++)
6935 if (values2
[j
] != NULL
)
6936 xmlFree(values2
[j
]);
6945 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt
,
6946 xmlXPathObjectPtr arg1
, xmlXPathObjectPtr arg2
) {
6949 *At this point we are assured neither arg1 nor arg2
6950 *is a nodeset, so we can just pick the appropriate routine.
6952 switch (arg1
->type
) {
6953 case XPATH_UNDEFINED
:
6955 xmlGenericError(xmlGenericErrorContext
,
6956 "Equal: undefined\n");
6960 switch (arg2
->type
) {
6961 case XPATH_UNDEFINED
:
6963 xmlGenericError(xmlGenericErrorContext
,
6964 "Equal: undefined\n");
6969 xmlGenericError(xmlGenericErrorContext
,
6970 "Equal: %d boolean %d \n",
6971 arg1
->boolval
, arg2
->boolval
);
6973 ret
= (arg1
->boolval
== arg2
->boolval
);
6976 ret
= (arg1
->boolval
==
6977 xmlXPathCastNumberToBoolean(arg2
->floatval
));
6980 if ((arg2
->stringval
== NULL
) ||
6981 (arg2
->stringval
[0] == 0)) ret
= 0;
6984 ret
= (arg1
->boolval
== ret
);
6989 case XPATH_LOCATIONSET
:
6993 case XPATH_XSLT_TREE
:
6998 switch (arg2
->type
) {
6999 case XPATH_UNDEFINED
:
7001 xmlGenericError(xmlGenericErrorContext
,
7002 "Equal: undefined\n");
7006 ret
= (arg2
->boolval
==
7007 xmlXPathCastNumberToBoolean(arg1
->floatval
));
7010 valuePush(ctxt
, arg2
);
7011 xmlXPathNumberFunction(ctxt
, 1);
7012 arg2
= valuePop(ctxt
);
7013 /* no break on purpose */
7015 /* Hand check NaN and Infinity equalities */
7016 if (xmlXPathIsNaN(arg1
->floatval
) ||
7017 xmlXPathIsNaN(arg2
->floatval
)) {
7019 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7020 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7024 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7025 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7029 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7030 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7034 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7035 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7040 ret
= (arg1
->floatval
== arg2
->floatval
);
7046 case XPATH_LOCATIONSET
:
7050 case XPATH_XSLT_TREE
:
7055 switch (arg2
->type
) {
7056 case XPATH_UNDEFINED
:
7058 xmlGenericError(xmlGenericErrorContext
,
7059 "Equal: undefined\n");
7063 if ((arg1
->stringval
== NULL
) ||
7064 (arg1
->stringval
[0] == 0)) ret
= 0;
7067 ret
= (arg2
->boolval
== ret
);
7070 ret
= xmlStrEqual(arg1
->stringval
, arg2
->stringval
);
7073 valuePush(ctxt
, arg1
);
7074 xmlXPathNumberFunction(ctxt
, 1);
7075 arg1
= valuePop(ctxt
);
7076 /* Hand check NaN and Infinity equalities */
7077 if (xmlXPathIsNaN(arg1
->floatval
) ||
7078 xmlXPathIsNaN(arg2
->floatval
)) {
7080 } else if (xmlXPathIsInf(arg1
->floatval
) == 1) {
7081 if (xmlXPathIsInf(arg2
->floatval
) == 1)
7085 } else if (xmlXPathIsInf(arg1
->floatval
) == -1) {
7086 if (xmlXPathIsInf(arg2
->floatval
) == -1)
7090 } else if (xmlXPathIsInf(arg2
->floatval
) == 1) {
7091 if (xmlXPathIsInf(arg1
->floatval
) == 1)
7095 } else if (xmlXPathIsInf(arg2
->floatval
) == -1) {
7096 if (xmlXPathIsInf(arg1
->floatval
) == -1)
7101 ret
= (arg1
->floatval
== arg2
->floatval
);
7107 case XPATH_LOCATIONSET
:
7111 case XPATH_XSLT_TREE
:
7118 case XPATH_LOCATIONSET
:
7122 case XPATH_XSLT_TREE
:
7125 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7126 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7131 * xmlXPathEqualValues:
7132 * @ctxt: the XPath Parser context
7134 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7136 * Returns 0 or 1 depending on the results of the test.
7139 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt
) {
7140 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7143 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7144 arg2
= valuePop(ctxt
);
7145 arg1
= valuePop(ctxt
);
7146 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7148 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7150 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7151 XP_ERROR0(XPATH_INVALID_OPERAND
);
7156 xmlGenericError(xmlGenericErrorContext
,
7157 "Equal: by pointer\n");
7159 xmlXPathFreeObject(arg1
);
7164 *If either argument is a nodeset, it's a 'special case'
7166 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7167 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7169 *Hack it to assure arg1 is the nodeset
7171 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7176 switch (arg2
->type
) {
7177 case XPATH_UNDEFINED
:
7179 xmlGenericError(xmlGenericErrorContext
,
7180 "Equal: undefined\n");
7184 case XPATH_XSLT_TREE
:
7185 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 0);
7188 if ((arg1
->nodesetval
== NULL
) ||
7189 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7192 ret
= (ret
== arg2
->boolval
);
7195 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 0);
7198 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
, 0);
7203 case XPATH_LOCATIONSET
:
7207 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7208 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7212 return (xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7216 * xmlXPathNotEqualValues:
7217 * @ctxt: the XPath Parser context
7219 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7221 * Returns 0 or 1 depending on the results of the test.
7224 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt
) {
7225 xmlXPathObjectPtr arg1
, arg2
, argtmp
;
7228 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7229 arg2
= valuePop(ctxt
);
7230 arg1
= valuePop(ctxt
);
7231 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7233 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7235 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7236 XP_ERROR0(XPATH_INVALID_OPERAND
);
7241 xmlGenericError(xmlGenericErrorContext
,
7242 "NotEqual: by pointer\n");
7244 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7249 *If either argument is a nodeset, it's a 'special case'
7251 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7252 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7254 *Hack it to assure arg1 is the nodeset
7256 if ((arg1
->type
!= XPATH_NODESET
) && (arg1
->type
!= XPATH_XSLT_TREE
)) {
7261 switch (arg2
->type
) {
7262 case XPATH_UNDEFINED
:
7264 xmlGenericError(xmlGenericErrorContext
,
7265 "NotEqual: undefined\n");
7269 case XPATH_XSLT_TREE
:
7270 ret
= xmlXPathEqualNodeSets(arg1
, arg2
, 1);
7273 if ((arg1
->nodesetval
== NULL
) ||
7274 (arg1
->nodesetval
->nodeNr
== 0)) ret
= 0;
7277 ret
= (ret
!= arg2
->boolval
);
7280 ret
= xmlXPathEqualNodeSetFloat(ctxt
, arg1
, arg2
->floatval
, 1);
7283 ret
= xmlXPathEqualNodeSetString(arg1
, arg2
->stringval
,1);
7288 case XPATH_LOCATIONSET
:
7292 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7293 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7297 return (!xmlXPathEqualValuesCommon(ctxt
, arg1
, arg2
));
7301 * xmlXPathCompareValues:
7302 * @ctxt: the XPath Parser context
7303 * @inf: less than (1) or greater than (0)
7304 * @strict: is the comparison strict
7306 * Implement the compare operation on XPath objects:
7307 * @arg1 < @arg2 (1, 1, ...
7308 * @arg1 <= @arg2 (1, 0, ...
7309 * @arg1 > @arg2 (0, 1, ...
7310 * @arg1 >= @arg2 (0, 0, ...
7312 * When neither object to be compared is a node-set and the operator is
7313 * <=, <, >=, >, then the objects are compared by converted both objects
7314 * to numbers and comparing the numbers according to IEEE 754. The <
7315 * comparison will be true if and only if the first number is less than the
7316 * second number. The <= comparison will be true if and only if the first
7317 * number is less than or equal to the second number. The > comparison
7318 * will be true if and only if the first number is greater than the second
7319 * number. The >= comparison will be true if and only if the first number
7320 * is greater than or equal to the second number.
7322 * Returns 1 if the comparison succeeded, 0 if it failed
7325 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt
, int inf
, int strict
) {
7326 int ret
= 0, arg1i
= 0, arg2i
= 0;
7327 xmlXPathObjectPtr arg1
, arg2
;
7329 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(0);
7330 arg2
= valuePop(ctxt
);
7331 arg1
= valuePop(ctxt
);
7332 if ((arg1
== NULL
) || (arg2
== NULL
)) {
7334 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7336 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7337 XP_ERROR0(XPATH_INVALID_OPERAND
);
7340 if ((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
) ||
7341 (arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7343 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7344 * are not freed from within this routine; they will be freed from the
7345 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7347 if (((arg2
->type
== XPATH_NODESET
) || (arg2
->type
== XPATH_XSLT_TREE
)) &&
7348 ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
))){
7349 ret
= xmlXPathCompareNodeSets(inf
, strict
, arg1
, arg2
);
7351 if ((arg1
->type
== XPATH_NODESET
) || (arg1
->type
== XPATH_XSLT_TREE
)) {
7352 ret
= xmlXPathCompareNodeSetValue(ctxt
, inf
, strict
,
7355 ret
= xmlXPathCompareNodeSetValue(ctxt
, !inf
, strict
,
7362 if (arg1
->type
!= XPATH_NUMBER
) {
7363 valuePush(ctxt
, arg1
);
7364 xmlXPathNumberFunction(ctxt
, 1);
7365 arg1
= valuePop(ctxt
);
7367 if (arg1
->type
!= XPATH_NUMBER
) {
7368 xmlXPathFreeObject(arg1
);
7369 xmlXPathFreeObject(arg2
);
7370 XP_ERROR0(XPATH_INVALID_OPERAND
);
7372 if (arg2
->type
!= XPATH_NUMBER
) {
7373 valuePush(ctxt
, arg2
);
7374 xmlXPathNumberFunction(ctxt
, 1);
7375 arg2
= valuePop(ctxt
);
7377 if (arg2
->type
!= XPATH_NUMBER
) {
7378 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7379 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7380 XP_ERROR0(XPATH_INVALID_OPERAND
);
7383 * Add tests for infinity and nan
7384 * => feedback on 3.4 for Inf and NaN
7386 /* Hand check NaN and Infinity comparisons */
7387 if (xmlXPathIsNaN(arg1
->floatval
) || xmlXPathIsNaN(arg2
->floatval
)) {
7390 arg1i
=xmlXPathIsInf(arg1
->floatval
);
7391 arg2i
=xmlXPathIsInf(arg2
->floatval
);
7392 if (inf
&& strict
) {
7393 if ((arg1i
== -1 && arg2i
!= -1) ||
7394 (arg2i
== 1 && arg1i
!= 1)) {
7396 } else if (arg1i
== 0 && arg2i
== 0) {
7397 ret
= (arg1
->floatval
< arg2
->floatval
);
7402 else if (inf
&& !strict
) {
7403 if (arg1i
== -1 || arg2i
== 1) {
7405 } else if (arg1i
== 0 && arg2i
== 0) {
7406 ret
= (arg1
->floatval
<= arg2
->floatval
);
7411 else if (!inf
&& strict
) {
7412 if ((arg1i
== 1 && arg2i
!= 1) ||
7413 (arg2i
== -1 && arg1i
!= -1)) {
7415 } else if (arg1i
== 0 && arg2i
== 0) {
7416 ret
= (arg1
->floatval
> arg2
->floatval
);
7421 else if (!inf
&& !strict
) {
7422 if (arg1i
== 1 || arg2i
== -1) {
7424 } else if (arg1i
== 0 && arg2i
== 0) {
7425 ret
= (arg1
->floatval
>= arg2
->floatval
);
7431 xmlXPathReleaseObject(ctxt
->context
, arg1
);
7432 xmlXPathReleaseObject(ctxt
->context
, arg2
);
7437 * xmlXPathValueFlipSign:
7438 * @ctxt: the XPath Parser context
7440 * Implement the unary - operation on an XPath object
7441 * The numeric operators convert their operands to numbers as if
7442 * by calling the number function.
7445 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt
) {
7446 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return;
7448 CHECK_TYPE(XPATH_NUMBER
);
7449 if (xmlXPathIsNaN(ctxt
->value
->floatval
))
7450 ctxt
->value
->floatval
=xmlXPathNAN
;
7451 else if (xmlXPathIsInf(ctxt
->value
->floatval
) == 1)
7452 ctxt
->value
->floatval
=xmlXPathNINF
;
7453 else if (xmlXPathIsInf(ctxt
->value
->floatval
) == -1)
7454 ctxt
->value
->floatval
=xmlXPathPINF
;
7455 else if (ctxt
->value
->floatval
== 0) {
7456 if (xmlXPathGetSign(ctxt
->value
->floatval
) == 0)
7457 ctxt
->value
->floatval
= xmlXPathNZERO
;
7459 ctxt
->value
->floatval
= 0;
7462 ctxt
->value
->floatval
= - ctxt
->value
->floatval
;
7466 * xmlXPathAddValues:
7467 * @ctxt: the XPath Parser context
7469 * Implement the add operation on XPath objects:
7470 * The numeric operators convert their operands to numbers as if
7471 * by calling the number function.
7474 xmlXPathAddValues(xmlXPathParserContextPtr ctxt
) {
7475 xmlXPathObjectPtr arg
;
7478 arg
= valuePop(ctxt
);
7480 XP_ERROR(XPATH_INVALID_OPERAND
);
7481 val
= xmlXPathCastToNumber(arg
);
7482 xmlXPathReleaseObject(ctxt
->context
, arg
);
7484 CHECK_TYPE(XPATH_NUMBER
);
7485 ctxt
->value
->floatval
+= val
;
7489 * xmlXPathSubValues:
7490 * @ctxt: the XPath Parser context
7492 * Implement the subtraction operation on XPath objects:
7493 * The numeric operators convert their operands to numbers as if
7494 * by calling the number function.
7497 xmlXPathSubValues(xmlXPathParserContextPtr ctxt
) {
7498 xmlXPathObjectPtr arg
;
7501 arg
= valuePop(ctxt
);
7503 XP_ERROR(XPATH_INVALID_OPERAND
);
7504 val
= xmlXPathCastToNumber(arg
);
7505 xmlXPathReleaseObject(ctxt
->context
, arg
);
7507 CHECK_TYPE(XPATH_NUMBER
);
7508 ctxt
->value
->floatval
-= val
;
7512 * xmlXPathMultValues:
7513 * @ctxt: the XPath Parser context
7515 * Implement the multiply operation on XPath objects:
7516 * The numeric operators convert their operands to numbers as if
7517 * by calling the number function.
7520 xmlXPathMultValues(xmlXPathParserContextPtr ctxt
) {
7521 xmlXPathObjectPtr arg
;
7524 arg
= valuePop(ctxt
);
7526 XP_ERROR(XPATH_INVALID_OPERAND
);
7527 val
= xmlXPathCastToNumber(arg
);
7528 xmlXPathReleaseObject(ctxt
->context
, arg
);
7530 CHECK_TYPE(XPATH_NUMBER
);
7531 ctxt
->value
->floatval
*= val
;
7535 * xmlXPathDivValues:
7536 * @ctxt: the XPath Parser context
7538 * Implement the div operation on XPath objects @arg1 / @arg2:
7539 * The numeric operators convert their operands to numbers as if
7540 * by calling the number function.
7543 xmlXPathDivValues(xmlXPathParserContextPtr ctxt
) {
7544 xmlXPathObjectPtr arg
;
7547 arg
= valuePop(ctxt
);
7549 XP_ERROR(XPATH_INVALID_OPERAND
);
7550 val
= xmlXPathCastToNumber(arg
);
7551 xmlXPathReleaseObject(ctxt
->context
, arg
);
7553 CHECK_TYPE(XPATH_NUMBER
);
7554 if (xmlXPathIsNaN(val
) || xmlXPathIsNaN(ctxt
->value
->floatval
))
7555 ctxt
->value
->floatval
= xmlXPathNAN
;
7556 else if (val
== 0 && xmlXPathGetSign(val
) != 0) {
7557 if (ctxt
->value
->floatval
== 0)
7558 ctxt
->value
->floatval
= xmlXPathNAN
;
7559 else if (ctxt
->value
->floatval
> 0)
7560 ctxt
->value
->floatval
= xmlXPathNINF
;
7561 else if (ctxt
->value
->floatval
< 0)
7562 ctxt
->value
->floatval
= xmlXPathPINF
;
7564 else if (val
== 0) {
7565 if (ctxt
->value
->floatval
== 0)
7566 ctxt
->value
->floatval
= xmlXPathNAN
;
7567 else if (ctxt
->value
->floatval
> 0)
7568 ctxt
->value
->floatval
= xmlXPathPINF
;
7569 else if (ctxt
->value
->floatval
< 0)
7570 ctxt
->value
->floatval
= xmlXPathNINF
;
7572 ctxt
->value
->floatval
/= val
;
7576 * xmlXPathModValues:
7577 * @ctxt: the XPath Parser context
7579 * Implement the mod operation on XPath objects: @arg1 / @arg2
7580 * The numeric operators convert their operands to numbers as if
7581 * by calling the number function.
7584 xmlXPathModValues(xmlXPathParserContextPtr ctxt
) {
7585 xmlXPathObjectPtr arg
;
7588 arg
= valuePop(ctxt
);
7590 XP_ERROR(XPATH_INVALID_OPERAND
);
7591 arg2
= xmlXPathCastToNumber(arg
);
7592 xmlXPathReleaseObject(ctxt
->context
, arg
);
7594 CHECK_TYPE(XPATH_NUMBER
);
7595 arg1
= ctxt
->value
->floatval
;
7597 ctxt
->value
->floatval
= xmlXPathNAN
;
7599 ctxt
->value
->floatval
= fmod(arg1
, arg2
);
7603 /************************************************************************
7605 * The traversal functions *
7607 ************************************************************************/
7610 * A traversal function enumerates nodes along an axis.
7611 * Initially it must be called with NULL, and it indicates
7612 * termination on the axis by returning NULL.
7614 typedef xmlNodePtr (*xmlXPathTraversalFunction
)
7615 (xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
);
7618 * xmlXPathTraversalFunctionExt:
7619 * A traversal function enumerates nodes along an axis.
7620 * Initially it must be called with NULL, and it indicates
7621 * termination on the axis by returning NULL.
7622 * The context node of the traversal is specified via @contextNode.
7624 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt
)
7625 (xmlNodePtr cur
, xmlNodePtr contextNode
);
7628 * xmlXPathNodeSetMergeFunction:
7629 * Used for merging node sets in xmlXPathCollectAndTest().
7631 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction
)
7632 (xmlNodeSetPtr
, xmlNodeSetPtr
, int);
7637 * @ctxt: the XPath Parser context
7638 * @cur: the current node in the traversal
7640 * Traversal function for the "self" direction
7641 * The self axis contains just the context node itself
7643 * Returns the next element following that axis
7646 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7647 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7649 return(ctxt
->context
->node
);
7654 * xmlXPathNextChild:
7655 * @ctxt: the XPath Parser context
7656 * @cur: the current node in the traversal
7658 * Traversal function for the "child" direction
7659 * The child axis contains the children of the context node in document order.
7661 * Returns the next element following that axis
7664 xmlXPathNextChild(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7665 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7667 if (ctxt
->context
->node
== NULL
) return(NULL
);
7668 switch (ctxt
->context
->node
->type
) {
7669 case XML_ELEMENT_NODE
:
7671 case XML_CDATA_SECTION_NODE
:
7672 case XML_ENTITY_REF_NODE
:
7673 case XML_ENTITY_NODE
:
7675 case XML_COMMENT_NODE
:
7676 case XML_NOTATION_NODE
:
7678 return(ctxt
->context
->node
->children
);
7679 case XML_DOCUMENT_NODE
:
7680 case XML_DOCUMENT_TYPE_NODE
:
7681 case XML_DOCUMENT_FRAG_NODE
:
7682 case XML_HTML_DOCUMENT_NODE
:
7683 #ifdef LIBXML_DOCB_ENABLED
7684 case XML_DOCB_DOCUMENT_NODE
:
7686 return(((xmlDocPtr
) ctxt
->context
->node
)->children
);
7687 case XML_ELEMENT_DECL
:
7688 case XML_ATTRIBUTE_DECL
:
7689 case XML_ENTITY_DECL
:
7690 case XML_ATTRIBUTE_NODE
:
7691 case XML_NAMESPACE_DECL
:
7692 case XML_XINCLUDE_START
:
7693 case XML_XINCLUDE_END
:
7698 if ((cur
->type
== XML_DOCUMENT_NODE
) ||
7699 (cur
->type
== XML_HTML_DOCUMENT_NODE
))
7705 * xmlXPathNextChildElement:
7706 * @ctxt: the XPath Parser context
7707 * @cur: the current node in the traversal
7709 * Traversal function for the "child" direction and nodes of type element.
7710 * The child axis contains the children of the context node in document order.
7712 * Returns the next element following that axis
7715 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7716 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7718 cur
= ctxt
->context
->node
;
7719 if (cur
== NULL
) return(NULL
);
7721 * Get the first element child.
7723 switch (cur
->type
) {
7724 case XML_ELEMENT_NODE
:
7725 case XML_DOCUMENT_FRAG_NODE
:
7726 case XML_ENTITY_REF_NODE
: /* URGENT TODO: entify-refs as well? */
7727 case XML_ENTITY_NODE
:
7728 cur
= cur
->children
;
7730 if (cur
->type
== XML_ELEMENT_NODE
)
7734 } while ((cur
!= NULL
) &&
7735 (cur
->type
!= XML_ELEMENT_NODE
));
7739 case XML_DOCUMENT_NODE
:
7740 case XML_HTML_DOCUMENT_NODE
:
7741 #ifdef LIBXML_DOCB_ENABLED
7742 case XML_DOCB_DOCUMENT_NODE
:
7744 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7751 * Get the next sibling element node.
7753 switch (cur
->type
) {
7754 case XML_ELEMENT_NODE
:
7756 case XML_ENTITY_REF_NODE
:
7757 case XML_ENTITY_NODE
:
7758 case XML_CDATA_SECTION_NODE
:
7760 case XML_COMMENT_NODE
:
7761 case XML_XINCLUDE_END
:
7763 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7767 if (cur
->next
!= NULL
) {
7768 if (cur
->next
->type
== XML_ELEMENT_NODE
)
7773 } while ((cur
!= NULL
) && (cur
->type
!= XML_ELEMENT_NODE
));
7781 * xmlXPathNextDescendantOrSelfElemParent:
7782 * @ctxt: the XPath Parser context
7783 * @cur: the current node in the traversal
7785 * Traversal function for the "descendant-or-self" axis.
7786 * Additionally it returns only nodes which can be parents of
7790 * Returns the next element following that axis
7793 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur
,
7794 xmlNodePtr contextNode
)
7797 if (contextNode
== NULL
)
7799 switch (contextNode
->type
) {
7800 case XML_ELEMENT_NODE
:
7801 case XML_XINCLUDE_START
:
7802 case XML_DOCUMENT_FRAG_NODE
:
7803 case XML_DOCUMENT_NODE
:
7804 #ifdef LIBXML_DOCB_ENABLED
7805 case XML_DOCB_DOCUMENT_NODE
:
7807 case XML_HTML_DOCUMENT_NODE
:
7808 return(contextNode
);
7814 xmlNodePtr start
= cur
;
7816 while (cur
!= NULL
) {
7817 switch (cur
->type
) {
7818 case XML_ELEMENT_NODE
:
7819 /* TODO: OK to have XInclude here? */
7820 case XML_XINCLUDE_START
:
7821 case XML_DOCUMENT_FRAG_NODE
:
7824 if (cur
->children
!= NULL
) {
7825 cur
= cur
->children
;
7829 /* Not sure if we need those here. */
7830 case XML_DOCUMENT_NODE
:
7831 #ifdef LIBXML_DOCB_ENABLED
7832 case XML_DOCB_DOCUMENT_NODE
:
7834 case XML_HTML_DOCUMENT_NODE
:
7837 return(xmlDocGetRootElement((xmlDocPtr
) cur
));
7843 if ((cur
== NULL
) || (cur
== contextNode
))
7845 if (cur
->next
!= NULL
) {
7858 * xmlXPathNextDescendant:
7859 * @ctxt: the XPath Parser context
7860 * @cur: the current node in the traversal
7862 * Traversal function for the "descendant" direction
7863 * the descendant axis contains the descendants of the context node in document
7864 * order; a descendant is a child or a child of a child and so on.
7866 * Returns the next element following that axis
7869 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7870 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7872 if (ctxt
->context
->node
== NULL
)
7874 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7875 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7878 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
7879 return(ctxt
->context
->doc
->children
);
7880 return(ctxt
->context
->node
->children
);
7883 if (cur
->type
== XML_NAMESPACE_DECL
)
7885 if (cur
->children
!= NULL
) {
7887 * Do not descend on entities declarations
7889 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
7890 cur
= cur
->children
;
7894 if (cur
->type
!= XML_DTD_NODE
)
7899 if (cur
== ctxt
->context
->node
) return(NULL
);
7901 while (cur
->next
!= NULL
) {
7903 if ((cur
->type
!= XML_ENTITY_DECL
) &&
7904 (cur
->type
!= XML_DTD_NODE
))
7910 if (cur
== NULL
) break;
7911 if (cur
== ctxt
->context
->node
) return(NULL
);
7912 if (cur
->next
!= NULL
) {
7916 } while (cur
!= NULL
);
7921 * xmlXPathNextDescendantOrSelf:
7922 * @ctxt: the XPath Parser context
7923 * @cur: the current node in the traversal
7925 * Traversal function for the "descendant-or-self" direction
7926 * the descendant-or-self axis contains the context node and the descendants
7927 * of the context node in document order; thus the context node is the first
7928 * node on the axis, and the first child of the context node is the second node
7931 * Returns the next element following that axis
7934 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7935 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7937 return(ctxt
->context
->node
);
7939 if (ctxt
->context
->node
== NULL
)
7941 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
7942 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
7945 return(xmlXPathNextDescendant(ctxt
, cur
));
7949 * xmlXPathNextParent:
7950 * @ctxt: the XPath Parser context
7951 * @cur: the current node in the traversal
7953 * Traversal function for the "parent" direction
7954 * The parent axis contains the parent of the context node, if there is one.
7956 * Returns the next element following that axis
7959 xmlXPathNextParent(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
7960 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
7962 * the parent of an attribute or namespace node is the element
7963 * to which the attribute or namespace node is attached
7964 * Namespace handling !!!
7967 if (ctxt
->context
->node
== NULL
) return(NULL
);
7968 switch (ctxt
->context
->node
->type
) {
7969 case XML_ELEMENT_NODE
:
7971 case XML_CDATA_SECTION_NODE
:
7972 case XML_ENTITY_REF_NODE
:
7973 case XML_ENTITY_NODE
:
7975 case XML_COMMENT_NODE
:
7976 case XML_NOTATION_NODE
:
7978 case XML_ELEMENT_DECL
:
7979 case XML_ATTRIBUTE_DECL
:
7980 case XML_XINCLUDE_START
:
7981 case XML_XINCLUDE_END
:
7982 case XML_ENTITY_DECL
:
7983 if (ctxt
->context
->node
->parent
== NULL
)
7984 return((xmlNodePtr
) ctxt
->context
->doc
);
7985 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
7986 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
7987 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
7988 BAD_CAST
"fake node libxslt"))))
7990 return(ctxt
->context
->node
->parent
);
7991 case XML_ATTRIBUTE_NODE
: {
7992 xmlAttrPtr att
= (xmlAttrPtr
) ctxt
->context
->node
;
7994 return(att
->parent
);
7996 case XML_DOCUMENT_NODE
:
7997 case XML_DOCUMENT_TYPE_NODE
:
7998 case XML_DOCUMENT_FRAG_NODE
:
7999 case XML_HTML_DOCUMENT_NODE
:
8000 #ifdef LIBXML_DOCB_ENABLED
8001 case XML_DOCB_DOCUMENT_NODE
:
8004 case XML_NAMESPACE_DECL
: {
8005 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8007 if ((ns
->next
!= NULL
) &&
8008 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8009 return((xmlNodePtr
) ns
->next
);
8018 * xmlXPathNextAncestor:
8019 * @ctxt: the XPath Parser context
8020 * @cur: the current node in the traversal
8022 * Traversal function for the "ancestor" direction
8023 * the ancestor axis contains the ancestors of the context node; the ancestors
8024 * of the context node consist of the parent of context node and the parent's
8025 * parent and so on; the nodes are ordered in reverse document order; thus the
8026 * parent is the first node on the axis, and the parent's parent is the second
8029 * Returns the next element following that axis
8032 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8033 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8035 * the parent of an attribute or namespace node is the element
8036 * to which the attribute or namespace node is attached
8040 if (ctxt
->context
->node
== NULL
) return(NULL
);
8041 switch (ctxt
->context
->node
->type
) {
8042 case XML_ELEMENT_NODE
:
8044 case XML_CDATA_SECTION_NODE
:
8045 case XML_ENTITY_REF_NODE
:
8046 case XML_ENTITY_NODE
:
8048 case XML_COMMENT_NODE
:
8050 case XML_ELEMENT_DECL
:
8051 case XML_ATTRIBUTE_DECL
:
8052 case XML_ENTITY_DECL
:
8053 case XML_NOTATION_NODE
:
8054 case XML_XINCLUDE_START
:
8055 case XML_XINCLUDE_END
:
8056 if (ctxt
->context
->node
->parent
== NULL
)
8057 return((xmlNodePtr
) ctxt
->context
->doc
);
8058 if ((ctxt
->context
->node
->parent
->type
== XML_ELEMENT_NODE
) &&
8059 ((ctxt
->context
->node
->parent
->name
[0] == ' ') ||
8060 (xmlStrEqual(ctxt
->context
->node
->parent
->name
,
8061 BAD_CAST
"fake node libxslt"))))
8063 return(ctxt
->context
->node
->parent
);
8064 case XML_ATTRIBUTE_NODE
: {
8065 xmlAttrPtr tmp
= (xmlAttrPtr
) ctxt
->context
->node
;
8067 return(tmp
->parent
);
8069 case XML_DOCUMENT_NODE
:
8070 case XML_DOCUMENT_TYPE_NODE
:
8071 case XML_DOCUMENT_FRAG_NODE
:
8072 case XML_HTML_DOCUMENT_NODE
:
8073 #ifdef LIBXML_DOCB_ENABLED
8074 case XML_DOCB_DOCUMENT_NODE
:
8077 case XML_NAMESPACE_DECL
: {
8078 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8080 if ((ns
->next
!= NULL
) &&
8081 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8082 return((xmlNodePtr
) ns
->next
);
8083 /* Bad, how did that namespace end up here ? */
8089 if (cur
== ctxt
->context
->doc
->children
)
8090 return((xmlNodePtr
) ctxt
->context
->doc
);
8091 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8093 switch (cur
->type
) {
8094 case XML_ELEMENT_NODE
:
8096 case XML_CDATA_SECTION_NODE
:
8097 case XML_ENTITY_REF_NODE
:
8098 case XML_ENTITY_NODE
:
8100 case XML_COMMENT_NODE
:
8101 case XML_NOTATION_NODE
:
8103 case XML_ELEMENT_DECL
:
8104 case XML_ATTRIBUTE_DECL
:
8105 case XML_ENTITY_DECL
:
8106 case XML_XINCLUDE_START
:
8107 case XML_XINCLUDE_END
:
8108 if (cur
->parent
== NULL
)
8110 if ((cur
->parent
->type
== XML_ELEMENT_NODE
) &&
8111 ((cur
->parent
->name
[0] == ' ') ||
8112 (xmlStrEqual(cur
->parent
->name
,
8113 BAD_CAST
"fake node libxslt"))))
8115 return(cur
->parent
);
8116 case XML_ATTRIBUTE_NODE
: {
8117 xmlAttrPtr att
= (xmlAttrPtr
) ctxt
->context
->node
;
8119 return(att
->parent
);
8121 case XML_NAMESPACE_DECL
: {
8122 xmlNsPtr ns
= (xmlNsPtr
) ctxt
->context
->node
;
8124 if ((ns
->next
!= NULL
) &&
8125 (ns
->next
->type
!= XML_NAMESPACE_DECL
))
8126 return((xmlNodePtr
) ns
->next
);
8127 /* Bad, how did that namespace end up here ? */
8130 case XML_DOCUMENT_NODE
:
8131 case XML_DOCUMENT_TYPE_NODE
:
8132 case XML_DOCUMENT_FRAG_NODE
:
8133 case XML_HTML_DOCUMENT_NODE
:
8134 #ifdef LIBXML_DOCB_ENABLED
8135 case XML_DOCB_DOCUMENT_NODE
:
8143 * xmlXPathNextAncestorOrSelf:
8144 * @ctxt: the XPath Parser context
8145 * @cur: the current node in the traversal
8147 * Traversal function for the "ancestor-or-self" direction
8148 * he ancestor-or-self axis contains the context node and ancestors of
8149 * the context node in reverse document order; thus the context node is
8150 * the first node on the axis, and the context node's parent the second;
8151 * parent here is defined the same as with the parent axis.
8153 * Returns the next element following that axis
8156 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8157 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8159 return(ctxt
->context
->node
);
8160 return(xmlXPathNextAncestor(ctxt
, cur
));
8164 * xmlXPathNextFollowingSibling:
8165 * @ctxt: the XPath Parser context
8166 * @cur: the current node in the traversal
8168 * Traversal function for the "following-sibling" direction
8169 * The following-sibling axis contains the following siblings of the context
8170 * node in document order.
8172 * Returns the next element following that axis
8175 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8176 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8177 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8178 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8180 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8183 return(ctxt
->context
->node
->next
);
8188 * xmlXPathNextPrecedingSibling:
8189 * @ctxt: the XPath Parser context
8190 * @cur: the current node in the traversal
8192 * Traversal function for the "preceding-sibling" direction
8193 * The preceding-sibling axis contains the preceding siblings of the context
8194 * node in reverse document order; the first preceding sibling is first on the
8195 * axis; the sibling preceding that node is the second on the axis and so on.
8197 * Returns the next element following that axis
8200 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8201 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8202 if ((ctxt
->context
->node
->type
== XML_ATTRIBUTE_NODE
) ||
8203 (ctxt
->context
->node
->type
== XML_NAMESPACE_DECL
))
8205 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
)
8208 return(ctxt
->context
->node
->prev
);
8209 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
)) {
8212 return(ctxt
->context
->node
->prev
);
8218 * xmlXPathNextFollowing:
8219 * @ctxt: the XPath Parser context
8220 * @cur: the current node in the traversal
8222 * Traversal function for the "following" direction
8223 * The following axis contains all nodes in the same document as the context
8224 * node that are after the context node in document order, excluding any
8225 * descendants and excluding attribute nodes and namespace nodes; the nodes
8226 * are ordered in document order
8228 * Returns the next element following that axis
8231 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8232 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8233 if ((cur
!= NULL
) && (cur
->type
!= XML_ATTRIBUTE_NODE
) &&
8234 (cur
->type
!= XML_NAMESPACE_DECL
) && (cur
->children
!= NULL
))
8235 return(cur
->children
);
8238 cur
= ctxt
->context
->node
;
8239 if (cur
->type
== XML_NAMESPACE_DECL
)
8241 if (cur
->type
== XML_ATTRIBUTE_NODE
)
8244 if (cur
== NULL
) return(NULL
) ; /* ERROR */
8245 if (cur
->next
!= NULL
) return(cur
->next
) ;
8248 if (cur
== NULL
) break;
8249 if (cur
== (xmlNodePtr
) ctxt
->context
->doc
) return(NULL
);
8250 if (cur
->next
!= NULL
) return(cur
->next
);
8251 } while (cur
!= NULL
);
8256 * xmlXPathIsAncestor:
8257 * @ancestor: the ancestor node
8258 * @node: the current node
8260 * Check that @ancestor is a @node's ancestor
8262 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8265 xmlXPathIsAncestor(xmlNodePtr ancestor
, xmlNodePtr node
) {
8266 if ((ancestor
== NULL
) || (node
== NULL
)) return(0);
8267 if (node
->type
== XML_NAMESPACE_DECL
)
8269 if (ancestor
->type
== XML_NAMESPACE_DECL
)
8271 /* nodes need to be in the same document */
8272 if (ancestor
->doc
!= node
->doc
) return(0);
8273 /* avoid searching if ancestor or node is the root node */
8274 if (ancestor
== (xmlNodePtr
) node
->doc
) return(1);
8275 if (node
== (xmlNodePtr
) ancestor
->doc
) return(0);
8276 while (node
->parent
!= NULL
) {
8277 if (node
->parent
== ancestor
)
8279 node
= node
->parent
;
8285 * xmlXPathNextPreceding:
8286 * @ctxt: the XPath Parser context
8287 * @cur: the current node in the traversal
8289 * Traversal function for the "preceding" direction
8290 * the preceding axis contains all nodes in the same document as the context
8291 * node that are before the context node in document order, excluding any
8292 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8293 * ordered in reverse document order
8295 * Returns the next element following that axis
8298 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
)
8300 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8302 cur
= ctxt
->context
->node
;
8303 if (cur
->type
== XML_NAMESPACE_DECL
)
8305 if (cur
->type
== XML_ATTRIBUTE_NODE
)
8306 return(cur
->parent
);
8308 if ((cur
== NULL
) || (cur
->type
== XML_NAMESPACE_DECL
))
8310 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8313 if (cur
->prev
!= NULL
) {
8314 for (cur
= cur
->prev
; cur
->last
!= NULL
; cur
= cur
->last
) ;
8321 if (cur
== ctxt
->context
->doc
->children
)
8323 } while (xmlXPathIsAncestor(cur
, ctxt
->context
->node
));
8328 * xmlXPathNextPrecedingInternal:
8329 * @ctxt: the XPath Parser context
8330 * @cur: the current node in the traversal
8332 * Traversal function for the "preceding" direction
8333 * the preceding axis contains all nodes in the same document as the context
8334 * node that are before the context node in document order, excluding any
8335 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8336 * ordered in reverse document order
8337 * This is a faster implementation but internal only since it requires a
8338 * state kept in the parser context: ctxt->ancestor.
8340 * Returns the next element following that axis
8343 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt
,
8346 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8348 cur
= ctxt
->context
->node
;
8351 if (cur
->type
== XML_NAMESPACE_DECL
)
8353 ctxt
->ancestor
= cur
->parent
;
8355 if (cur
->type
== XML_NAMESPACE_DECL
)
8357 if ((cur
->prev
!= NULL
) && (cur
->prev
->type
== XML_DTD_NODE
))
8359 while (cur
->prev
== NULL
) {
8363 if (cur
== ctxt
->context
->doc
->children
)
8365 if (cur
!= ctxt
->ancestor
)
8367 ctxt
->ancestor
= cur
->parent
;
8370 while (cur
->last
!= NULL
)
8376 * xmlXPathNextNamespace:
8377 * @ctxt: the XPath Parser context
8378 * @cur: the current attribute in the traversal
8380 * Traversal function for the "namespace" direction
8381 * the namespace axis contains the namespace nodes of the context node;
8382 * the order of nodes on this axis is implementation-defined; the axis will
8383 * be empty unless the context node is an element
8385 * We keep the XML namespace node at the end of the list.
8387 * Returns the next element following that axis
8390 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8391 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8392 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
) return(NULL
);
8394 if (ctxt
->context
->tmpNsList
!= NULL
)
8395 xmlFree(ctxt
->context
->tmpNsList
);
8396 ctxt
->context
->tmpNsList
=
8397 xmlGetNsList(ctxt
->context
->doc
, ctxt
->context
->node
);
8398 ctxt
->context
->tmpNsNr
= 0;
8399 if (ctxt
->context
->tmpNsList
!= NULL
) {
8400 while (ctxt
->context
->tmpNsList
[ctxt
->context
->tmpNsNr
] != NULL
) {
8401 ctxt
->context
->tmpNsNr
++;
8404 return((xmlNodePtr
) xmlXPathXMLNamespace
);
8406 if (ctxt
->context
->tmpNsNr
> 0) {
8407 return (xmlNodePtr
)ctxt
->context
->tmpNsList
[--ctxt
->context
->tmpNsNr
];
8409 if (ctxt
->context
->tmpNsList
!= NULL
)
8410 xmlFree(ctxt
->context
->tmpNsList
);
8411 ctxt
->context
->tmpNsList
= NULL
;
8417 * xmlXPathNextAttribute:
8418 * @ctxt: the XPath Parser context
8419 * @cur: the current attribute in the traversal
8421 * Traversal function for the "attribute" direction
8422 * TODO: support DTD inherited default attributes
8424 * Returns the next element following that axis
8427 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt
, xmlNodePtr cur
) {
8428 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
)) return(NULL
);
8429 if (ctxt
->context
->node
== NULL
)
8431 if (ctxt
->context
->node
->type
!= XML_ELEMENT_NODE
)
8434 if (ctxt
->context
->node
== (xmlNodePtr
) ctxt
->context
->doc
)
8436 return((xmlNodePtr
)ctxt
->context
->node
->properties
);
8438 return((xmlNodePtr
)cur
->next
);
8441 /************************************************************************
8443 * NodeTest Functions *
8445 ************************************************************************/
8447 #define IS_FUNCTION 200
8450 /************************************************************************
8452 * Implicit tree core function library *
8454 ************************************************************************/
8458 * @ctxt: the XPath Parser context
8460 * Initialize the context to the root of the document
8463 xmlXPathRoot(xmlXPathParserContextPtr ctxt
) {
8464 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8466 ctxt
->context
->node
= (xmlNodePtr
) ctxt
->context
->doc
;
8467 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8468 ctxt
->context
->node
));
8471 /************************************************************************
8473 * The explicit core function library *
8474 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8476 ************************************************************************/
8480 * xmlXPathLastFunction:
8481 * @ctxt: the XPath Parser context
8482 * @nargs: the number of arguments
8484 * Implement the last() XPath function
8486 * The last function returns the number of nodes in the context node list.
8489 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8491 if (ctxt
->context
->contextSize
>= 0) {
8493 xmlXPathCacheNewFloat(ctxt
->context
,
8494 (double) ctxt
->context
->contextSize
));
8496 xmlGenericError(xmlGenericErrorContext
,
8497 "last() : %d\n", ctxt
->context
->contextSize
);
8500 XP_ERROR(XPATH_INVALID_CTXT_SIZE
);
8505 * xmlXPathPositionFunction:
8506 * @ctxt: the XPath Parser context
8507 * @nargs: the number of arguments
8509 * Implement the position() XPath function
8511 * The position function returns the position of the context node in the
8512 * context node list. The first position is 1, and so the last position
8513 * will be equal to last().
8516 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8518 if (ctxt
->context
->proximityPosition
>= 0) {
8520 xmlXPathCacheNewFloat(ctxt
->context
,
8521 (double) ctxt
->context
->proximityPosition
));
8523 xmlGenericError(xmlGenericErrorContext
, "position() : %d\n",
8524 ctxt
->context
->proximityPosition
);
8527 XP_ERROR(XPATH_INVALID_CTXT_POSITION
);
8532 * xmlXPathCountFunction:
8533 * @ctxt: the XPath Parser context
8534 * @nargs: the number of arguments
8536 * Implement the count() XPath function
8537 * number count(node-set)
8540 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8541 xmlXPathObjectPtr cur
;
8544 if ((ctxt
->value
== NULL
) ||
8545 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8546 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8547 XP_ERROR(XPATH_INVALID_TYPE
);
8548 cur
= valuePop(ctxt
);
8550 if ((cur
== NULL
) || (cur
->nodesetval
== NULL
))
8551 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8552 else if ((cur
->type
== XPATH_NODESET
) || (cur
->type
== XPATH_XSLT_TREE
)) {
8553 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8554 (double) cur
->nodesetval
->nodeNr
));
8556 if ((cur
->nodesetval
->nodeNr
!= 1) ||
8557 (cur
->nodesetval
->nodeTab
== NULL
)) {
8558 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) 0));
8563 tmp
= cur
->nodesetval
->nodeTab
[0];
8564 if ((tmp
!= NULL
) && (tmp
->type
!= XML_NAMESPACE_DECL
)) {
8565 tmp
= tmp
->children
;
8566 while (tmp
!= NULL
) {
8571 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, (double) i
));
8574 xmlXPathReleaseObject(ctxt
->context
, cur
);
8578 * xmlXPathGetElementsByIds:
8579 * @doc: the document
8580 * @ids: a whitespace separated list of IDs
8582 * Selects elements by their unique ID.
8584 * Returns a node-set of selected elements.
8586 static xmlNodeSetPtr
8587 xmlXPathGetElementsByIds (xmlDocPtr doc
, const xmlChar
*ids
) {
8589 const xmlChar
*cur
= ids
;
8592 xmlNodePtr elem
= NULL
;
8594 if (ids
== NULL
) return(NULL
);
8596 ret
= xmlXPathNodeSetCreate(NULL
);
8600 while (IS_BLANK_CH(*cur
)) cur
++;
8602 while ((!IS_BLANK_CH(*cur
)) && (*cur
!= 0))
8605 ID
= xmlStrndup(ids
, cur
- ids
);
8608 * We used to check the fact that the value passed
8609 * was an NCName, but this generated much troubles for
8610 * me and Aleksey Sanin, people blatantly violated that
8611 * constaint, like Visa3D spec.
8612 * if (xmlValidateNCName(ID, 1) == 0)
8614 attr
= xmlGetID(doc
, ID
);
8616 if (attr
->type
== XML_ATTRIBUTE_NODE
)
8617 elem
= attr
->parent
;
8618 else if (attr
->type
== XML_ELEMENT_NODE
)
8619 elem
= (xmlNodePtr
) attr
;
8623 xmlXPathNodeSetAdd(ret
, elem
);
8628 while (IS_BLANK_CH(*cur
)) cur
++;
8635 * xmlXPathIdFunction:
8636 * @ctxt: the XPath Parser context
8637 * @nargs: the number of arguments
8639 * Implement the id() XPath function
8640 * node-set id(object)
8641 * The id function selects elements by their unique ID
8642 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8643 * then the result is the union of the result of applying id to the
8644 * string value of each of the nodes in the argument node-set. When the
8645 * argument to id is of any other type, the argument is converted to a
8646 * string as if by a call to the string function; the string is split
8647 * into a whitespace-separated list of tokens (whitespace is any sequence
8648 * of characters matching the production S); the result is a node-set
8649 * containing the elements in the same document as the context node that
8650 * have a unique ID equal to any of the tokens in the list.
8653 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8656 xmlXPathObjectPtr obj
;
8659 obj
= valuePop(ctxt
);
8660 if (obj
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8661 if ((obj
->type
== XPATH_NODESET
) || (obj
->type
== XPATH_XSLT_TREE
)) {
8665 ret
= xmlXPathNodeSetCreate(NULL
);
8667 * FIXME -- in an out-of-memory condition this will behave badly.
8668 * The solution is not clear -- we already popped an item from
8669 * ctxt, so the object is in a corrupt state.
8672 if (obj
->nodesetval
!= NULL
) {
8673 for (i
= 0; i
< obj
->nodesetval
->nodeNr
; i
++) {
8675 xmlXPathCastNodeToString(obj
->nodesetval
->nodeTab
[i
]);
8676 ns
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, tokens
);
8677 ret
= xmlXPathNodeSetMerge(ret
, ns
);
8678 xmlXPathFreeNodeSet(ns
);
8683 xmlXPathReleaseObject(ctxt
->context
, obj
);
8684 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8687 obj
= xmlXPathCacheConvertString(ctxt
->context
, obj
);
8688 ret
= xmlXPathGetElementsByIds(ctxt
->context
->doc
, obj
->stringval
);
8689 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, ret
));
8690 xmlXPathReleaseObject(ctxt
->context
, obj
);
8695 * xmlXPathLocalNameFunction:
8696 * @ctxt: the XPath Parser context
8697 * @nargs: the number of arguments
8699 * Implement the local-name() XPath function
8700 * string local-name(node-set?)
8701 * The local-name function returns a string containing the local part
8702 * of the name of the node in the argument node-set that is first in
8703 * document order. If the node-set is empty or the first node has no
8704 * name, an empty string is returned. If the argument is omitted it
8705 * defaults to the context node.
8708 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8709 xmlXPathObjectPtr cur
;
8711 if (ctxt
== NULL
) return;
8714 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8715 ctxt
->context
->node
));
8720 if ((ctxt
->value
== NULL
) ||
8721 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8722 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8723 XP_ERROR(XPATH_INVALID_TYPE
);
8724 cur
= valuePop(ctxt
);
8726 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8727 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8729 int i
= 0; /* Should be first in document order !!!!! */
8730 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8731 case XML_ELEMENT_NODE
:
8732 case XML_ATTRIBUTE_NODE
:
8734 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8735 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8738 xmlXPathCacheNewString(ctxt
->context
,
8739 cur
->nodesetval
->nodeTab
[i
]->name
));
8741 case XML_NAMESPACE_DECL
:
8742 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8743 ((xmlNsPtr
)cur
->nodesetval
->nodeTab
[i
])->prefix
));
8746 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8749 xmlXPathReleaseObject(ctxt
->context
, cur
);
8753 * xmlXPathNamespaceURIFunction:
8754 * @ctxt: the XPath Parser context
8755 * @nargs: the number of arguments
8757 * Implement the namespace-uri() XPath function
8758 * string namespace-uri(node-set?)
8759 * The namespace-uri function returns a string containing the
8760 * namespace URI of the expanded name of the node in the argument
8761 * node-set that is first in document order. If the node-set is empty,
8762 * the first node has no name, or the expanded name has no namespace
8763 * URI, an empty string is returned. If the argument is omitted it
8764 * defaults to the context node.
8767 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8768 xmlXPathObjectPtr cur
;
8770 if (ctxt
== NULL
) return;
8773 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8774 ctxt
->context
->node
));
8778 if ((ctxt
->value
== NULL
) ||
8779 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8780 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8781 XP_ERROR(XPATH_INVALID_TYPE
);
8782 cur
= valuePop(ctxt
);
8784 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8785 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8787 int i
= 0; /* Should be first in document order !!!!! */
8788 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8789 case XML_ELEMENT_NODE
:
8790 case XML_ATTRIBUTE_NODE
:
8791 if (cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
)
8792 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8794 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
8795 cur
->nodesetval
->nodeTab
[i
]->ns
->href
));
8798 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8801 xmlXPathReleaseObject(ctxt
->context
, cur
);
8805 * xmlXPathNameFunction:
8806 * @ctxt: the XPath Parser context
8807 * @nargs: the number of arguments
8809 * Implement the name() XPath function
8810 * string name(node-set?)
8811 * The name function returns a string containing a QName representing
8812 * the name of the node in the argument node-set that is first in document
8813 * order. The QName must represent the name with respect to the namespace
8814 * declarations in effect on the node whose name is being represented.
8815 * Typically, this will be the form in which the name occurred in the XML
8816 * source. This need not be the case if there are namespace declarations
8817 * in effect on the node that associate multiple prefixes with the same
8818 * namespace. However, an implementation may include information about
8819 * the original prefix in its representation of nodes; in this case, an
8820 * implementation can ensure that the returned string is always the same
8821 * as the QName used in the XML source. If the argument it omitted it
8822 * defaults to the context node.
8823 * Libxml keep the original prefix so the "real qualified name" used is
8827 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt
, int nargs
)
8829 xmlXPathObjectPtr cur
;
8832 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8833 ctxt
->context
->node
));
8838 if ((ctxt
->value
== NULL
) ||
8839 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
8840 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
8841 XP_ERROR(XPATH_INVALID_TYPE
);
8842 cur
= valuePop(ctxt
);
8844 if ((cur
->nodesetval
== NULL
) || (cur
->nodesetval
->nodeNr
== 0)) {
8845 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
8847 int i
= 0; /* Should be first in document order !!!!! */
8849 switch (cur
->nodesetval
->nodeTab
[i
]->type
) {
8850 case XML_ELEMENT_NODE
:
8851 case XML_ATTRIBUTE_NODE
:
8852 if (cur
->nodesetval
->nodeTab
[i
]->name
[0] == ' ')
8854 xmlXPathCacheNewCString(ctxt
->context
, ""));
8855 else if ((cur
->nodesetval
->nodeTab
[i
]->ns
== NULL
) ||
8856 (cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
== NULL
)) {
8858 xmlXPathCacheNewString(ctxt
->context
,
8859 cur
->nodesetval
->nodeTab
[i
]->name
));
8863 fullname
= xmlBuildQName(cur
->nodesetval
->nodeTab
[i
]->name
,
8864 cur
->nodesetval
->nodeTab
[i
]->ns
->prefix
,
8866 if (fullname
== cur
->nodesetval
->nodeTab
[i
]->name
)
8867 fullname
= xmlStrdup(cur
->nodesetval
->nodeTab
[i
]->name
);
8868 if (fullname
== NULL
) {
8869 XP_ERROR(XPATH_MEMORY_ERROR
);
8871 valuePush(ctxt
, xmlXPathCacheWrapString(
8872 ctxt
->context
, fullname
));
8876 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
8877 cur
->nodesetval
->nodeTab
[i
]));
8878 xmlXPathLocalNameFunction(ctxt
, 1);
8881 xmlXPathReleaseObject(ctxt
->context
, cur
);
8886 * xmlXPathStringFunction:
8887 * @ctxt: the XPath Parser context
8888 * @nargs: the number of arguments
8890 * Implement the string() XPath function
8891 * string string(object?)
8892 * The string function converts an object to a string as follows:
8893 * - A node-set is converted to a string by returning the value of
8894 * the node in the node-set that is first in document order.
8895 * If the node-set is empty, an empty string is returned.
8896 * - A number is converted to a string as follows
8897 * + NaN is converted to the string NaN
8898 * + positive zero is converted to the string 0
8899 * + negative zero is converted to the string 0
8900 * + positive infinity is converted to the string Infinity
8901 * + negative infinity is converted to the string -Infinity
8902 * + if the number is an integer, the number is represented in
8903 * decimal form as a Number with no decimal point and no leading
8904 * zeros, preceded by a minus sign (-) if the number is negative
8905 * + otherwise, the number is represented in decimal form as a
8906 * Number including a decimal point with at least one digit
8907 * before the decimal point and at least one digit after the
8908 * decimal point, preceded by a minus sign (-) if the number
8909 * is negative; there must be no leading zeros before the decimal
8910 * point apart possibly from the one required digit immediately
8911 * before the decimal point; beyond the one required digit
8912 * after the decimal point there must be as many, but only as
8913 * many, more digits as are needed to uniquely distinguish the
8914 * number from all other IEEE 754 numeric values.
8915 * - The boolean false value is converted to the string false.
8916 * The boolean true value is converted to the string true.
8918 * If the argument is omitted, it defaults to a node-set with the
8919 * context node as its only member.
8922 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8923 xmlXPathObjectPtr cur
;
8925 if (ctxt
== NULL
) return;
8928 xmlXPathCacheWrapString(ctxt
->context
,
8929 xmlXPathCastNodeToString(ctxt
->context
->node
)));
8934 cur
= valuePop(ctxt
);
8935 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
8936 valuePush(ctxt
, xmlXPathCacheConvertString(ctxt
->context
, cur
));
8940 * xmlXPathStringLengthFunction:
8941 * @ctxt: the XPath Parser context
8942 * @nargs: the number of arguments
8944 * Implement the string-length() XPath function
8945 * number string-length(string?)
8946 * The string-length returns the number of characters in the string
8947 * (see [3.6 Strings]). If the argument is omitted, it defaults to
8948 * the context node converted to a string, in other words the value
8949 * of the context node.
8952 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8953 xmlXPathObjectPtr cur
;
8956 if ((ctxt
== NULL
) || (ctxt
->context
== NULL
))
8958 if (ctxt
->context
->node
== NULL
) {
8959 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0));
8963 content
= xmlXPathCastNodeToString(ctxt
->context
->node
);
8964 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8965 xmlUTF8Strlen(content
)));
8972 CHECK_TYPE(XPATH_STRING
);
8973 cur
= valuePop(ctxt
);
8974 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
,
8975 xmlUTF8Strlen(cur
->stringval
)));
8976 xmlXPathReleaseObject(ctxt
->context
, cur
);
8980 * xmlXPathConcatFunction:
8981 * @ctxt: the XPath Parser context
8982 * @nargs: the number of arguments
8984 * Implement the concat() XPath function
8985 * string concat(string, string, string*)
8986 * The concat function returns the concatenation of its arguments.
8989 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
8990 xmlXPathObjectPtr cur
, newobj
;
8993 if (ctxt
== NULL
) return;
8999 cur
= valuePop(ctxt
);
9000 if ((cur
== NULL
) || (cur
->type
!= XPATH_STRING
)) {
9001 xmlXPathReleaseObject(ctxt
->context
, cur
);
9008 newobj
= valuePop(ctxt
);
9009 if ((newobj
== NULL
) || (newobj
->type
!= XPATH_STRING
)) {
9010 xmlXPathReleaseObject(ctxt
->context
, newobj
);
9011 xmlXPathReleaseObject(ctxt
->context
, cur
);
9012 XP_ERROR(XPATH_INVALID_TYPE
);
9014 tmp
= xmlStrcat(newobj
->stringval
, cur
->stringval
);
9015 newobj
->stringval
= cur
->stringval
;
9016 cur
->stringval
= tmp
;
9017 xmlXPathReleaseObject(ctxt
->context
, newobj
);
9020 valuePush(ctxt
, cur
);
9024 * xmlXPathContainsFunction:
9025 * @ctxt: the XPath Parser context
9026 * @nargs: the number of arguments
9028 * Implement the contains() XPath function
9029 * boolean contains(string, string)
9030 * The contains function returns true if the first argument string
9031 * contains the second argument string, and otherwise returns false.
9034 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9035 xmlXPathObjectPtr hay
, needle
;
9039 CHECK_TYPE(XPATH_STRING
);
9040 needle
= valuePop(ctxt
);
9042 hay
= valuePop(ctxt
);
9044 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9045 xmlXPathReleaseObject(ctxt
->context
, hay
);
9046 xmlXPathReleaseObject(ctxt
->context
, needle
);
9047 XP_ERROR(XPATH_INVALID_TYPE
);
9049 if (xmlStrstr(hay
->stringval
, needle
->stringval
))
9050 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9052 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9053 xmlXPathReleaseObject(ctxt
->context
, hay
);
9054 xmlXPathReleaseObject(ctxt
->context
, needle
);
9058 * xmlXPathStartsWithFunction:
9059 * @ctxt: the XPath Parser context
9060 * @nargs: the number of arguments
9062 * Implement the starts-with() XPath function
9063 * boolean starts-with(string, string)
9064 * The starts-with function returns true if the first argument string
9065 * starts with the second argument string, and otherwise returns false.
9068 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9069 xmlXPathObjectPtr hay
, needle
;
9074 CHECK_TYPE(XPATH_STRING
);
9075 needle
= valuePop(ctxt
);
9077 hay
= valuePop(ctxt
);
9079 if ((hay
== NULL
) || (hay
->type
!= XPATH_STRING
)) {
9080 xmlXPathReleaseObject(ctxt
->context
, hay
);
9081 xmlXPathReleaseObject(ctxt
->context
, needle
);
9082 XP_ERROR(XPATH_INVALID_TYPE
);
9084 n
= xmlStrlen(needle
->stringval
);
9085 if (xmlStrncmp(hay
->stringval
, needle
->stringval
, n
))
9086 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9088 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9089 xmlXPathReleaseObject(ctxt
->context
, hay
);
9090 xmlXPathReleaseObject(ctxt
->context
, needle
);
9094 * xmlXPathSubstringFunction:
9095 * @ctxt: the XPath Parser context
9096 * @nargs: the number of arguments
9098 * Implement the substring() XPath function
9099 * string substring(string, number, number?)
9100 * The substring function returns the substring of the first argument
9101 * starting at the position specified in the second argument with
9102 * length specified in the third argument. For example,
9103 * substring("12345",2,3) returns "234". If the third argument is not
9104 * specified, it returns the substring starting at the position specified
9105 * in the second argument and continuing to the end of the string. For
9106 * example, substring("12345",2) returns "2345". More precisely, each
9107 * character in the string (see [3.6 Strings]) is considered to have a
9108 * numeric position: the position of the first character is 1, the position
9109 * of the second character is 2 and so on. The returned substring contains
9110 * those characters for which the position of the character is greater than
9111 * or equal to the second argument and, if the third argument is specified,
9112 * less than the sum of the second and third arguments; the comparisons
9113 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9114 * - substring("12345", 1.5, 2.6) returns "234"
9115 * - substring("12345", 0, 3) returns "12"
9116 * - substring("12345", 0 div 0, 3) returns ""
9117 * - substring("12345", 1, 0 div 0) returns ""
9118 * - substring("12345", -42, 1 div 0) returns "12345"
9119 * - substring("12345", -1 div 0, 1 div 0) returns ""
9122 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9123 xmlXPathObjectPtr str
, start
, len
;
9135 * take care of possible last (position) argument
9139 CHECK_TYPE(XPATH_NUMBER
);
9140 len
= valuePop(ctxt
);
9142 xmlXPathReleaseObject(ctxt
->context
, len
);
9146 CHECK_TYPE(XPATH_NUMBER
);
9147 start
= valuePop(ctxt
);
9148 in
= start
->floatval
;
9149 xmlXPathReleaseObject(ctxt
->context
, start
);
9151 CHECK_TYPE(XPATH_STRING
);
9152 str
= valuePop(ctxt
);
9153 m
= xmlUTF8Strlen((const unsigned char *)str
->stringval
);
9156 * If last pos not present, calculate last position
9164 /* Need to check for the special cases where either
9165 * the index is NaN, the length is NaN, or both
9166 * arguments are infinity (relying on Inf + -Inf = NaN)
9168 if (!xmlXPathIsInf(in
) && !xmlXPathIsNaN(in
+ le
)) {
9170 * To meet the requirements of the spec, the arguments
9171 * must be converted to integer format before
9172 * initial index calculations are done
9174 * First we go to integer form, rounding up
9175 * and checking for special cases
9178 if (((double)i
)+0.5 <= in
) i
++;
9180 if (xmlXPathIsInf(le
) == 1) {
9185 else if (xmlXPathIsInf(le
) == -1 || le
< 0.0)
9189 if (((double)l
)+0.5 <= le
) l
++;
9192 /* Now we normalize inidices */
9200 /* number of chars to copy */
9203 ret
= xmlUTF8Strsub(str
->stringval
, i
, l
);
9209 valuePush(ctxt
, xmlXPathCacheNewCString(ctxt
->context
, ""));
9211 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
, ret
));
9214 xmlXPathReleaseObject(ctxt
->context
, str
);
9218 * xmlXPathSubstringBeforeFunction:
9219 * @ctxt: the XPath Parser context
9220 * @nargs: the number of arguments
9222 * Implement the substring-before() XPath function
9223 * string substring-before(string, string)
9224 * The substring-before function returns the substring of the first
9225 * argument string that precedes the first occurrence of the second
9226 * argument string in the first argument string, or the empty string
9227 * if the first argument string does not contain the second argument
9228 * string. For example, substring-before("1999/04/01","/") returns 1999.
9231 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9232 xmlXPathObjectPtr str
;
9233 xmlXPathObjectPtr find
;
9235 const xmlChar
*point
;
9240 find
= valuePop(ctxt
);
9242 str
= valuePop(ctxt
);
9244 target
= xmlBufCreate();
9246 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9248 offset
= (int)(point
- str
->stringval
);
9249 xmlBufAdd(target
, str
->stringval
, offset
);
9251 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9252 xmlBufContent(target
)));
9255 xmlXPathReleaseObject(ctxt
->context
, str
);
9256 xmlXPathReleaseObject(ctxt
->context
, find
);
9260 * xmlXPathSubstringAfterFunction:
9261 * @ctxt: the XPath Parser context
9262 * @nargs: the number of arguments
9264 * Implement the substring-after() XPath function
9265 * string substring-after(string, string)
9266 * The substring-after function returns the substring of the first
9267 * argument string that follows the first occurrence of the second
9268 * argument string in the first argument string, or the empty stringi
9269 * if the first argument string does not contain the second argument
9270 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9271 * and substring-after("1999/04/01","19") returns 99/04/01.
9274 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9275 xmlXPathObjectPtr str
;
9276 xmlXPathObjectPtr find
;
9278 const xmlChar
*point
;
9283 find
= valuePop(ctxt
);
9285 str
= valuePop(ctxt
);
9287 target
= xmlBufCreate();
9289 point
= xmlStrstr(str
->stringval
, find
->stringval
);
9291 offset
= (int)(point
- str
->stringval
) + xmlStrlen(find
->stringval
);
9292 xmlBufAdd(target
, &str
->stringval
[offset
],
9293 xmlStrlen(str
->stringval
) - offset
);
9295 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9296 xmlBufContent(target
)));
9299 xmlXPathReleaseObject(ctxt
->context
, str
);
9300 xmlXPathReleaseObject(ctxt
->context
, find
);
9304 * xmlXPathNormalizeFunction:
9305 * @ctxt: the XPath Parser context
9306 * @nargs: the number of arguments
9308 * Implement the normalize-space() XPath function
9309 * string normalize-space(string?)
9310 * The normalize-space function returns the argument string with white
9311 * space normalized by stripping leading and trailing whitespace
9312 * and replacing sequences of whitespace characters by a single
9313 * space. Whitespace characters are the same allowed by the S production
9314 * in XML. If the argument is omitted, it defaults to the context
9315 * node converted to a string, in other words the value of the context node.
9318 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9319 xmlXPathObjectPtr obj
= NULL
;
9320 xmlChar
*source
= NULL
;
9324 if (ctxt
== NULL
) return;
9326 /* Use current context node */
9328 xmlXPathCacheWrapString(ctxt
->context
,
9329 xmlXPathCastNodeToString(ctxt
->context
->node
)));
9335 CHECK_TYPE(XPATH_STRING
);
9336 obj
= valuePop(ctxt
);
9337 source
= obj
->stringval
;
9339 target
= xmlBufCreate();
9340 if (target
&& source
) {
9342 /* Skip leading whitespaces */
9343 while (IS_BLANK_CH(*source
))
9346 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9349 if (IS_BLANK_CH(*source
)) {
9353 xmlBufAdd(target
, &blank
, 1);
9356 xmlBufAdd(target
, source
, 1);
9360 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9361 xmlBufContent(target
)));
9364 xmlXPathReleaseObject(ctxt
->context
, obj
);
9368 * xmlXPathTranslateFunction:
9369 * @ctxt: the XPath Parser context
9370 * @nargs: the number of arguments
9372 * Implement the translate() XPath function
9373 * string translate(string, string, string)
9374 * The translate function returns the first argument string with
9375 * occurrences of characters in the second argument string replaced
9376 * by the character at the corresponding position in the third argument
9377 * string. For example, translate("bar","abc","ABC") returns the string
9378 * BAr. If there is a character in the second argument string with no
9379 * character at a corresponding position in the third argument string
9380 * (because the second argument string is longer than the third argument
9381 * string), then occurrences of that character in the first argument
9382 * string are removed. For example, translate("--aaa--","abc-","ABC")
9383 * returns "AAA". If a character occurs more than once in second
9384 * argument string, then the first occurrence determines the replacement
9385 * character. If the third argument string is longer than the second
9386 * argument string, then excess characters are ignored.
9389 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9390 xmlXPathObjectPtr str
;
9391 xmlXPathObjectPtr from
;
9392 xmlXPathObjectPtr to
;
9396 const xmlChar
*point
;
9402 to
= valuePop(ctxt
);
9404 from
= valuePop(ctxt
);
9406 str
= valuePop(ctxt
);
9408 target
= xmlBufCreate();
9410 max
= xmlUTF8Strlen(to
->stringval
);
9411 for (cptr
= str
->stringval
; (ch
=*cptr
); ) {
9412 offset
= xmlUTF8Strloc(from
->stringval
, cptr
);
9415 point
= xmlUTF8Strpos(to
->stringval
, offset
);
9417 xmlBufAdd(target
, point
, xmlUTF8Strsize(point
, 1));
9420 xmlBufAdd(target
, cptr
, xmlUTF8Strsize(cptr
, 1));
9422 /* Step to next character in input */
9425 /* if not simple ascii, verify proper format */
9426 if ( (ch
& 0xc0) != 0xc0 ) {
9427 xmlGenericError(xmlGenericErrorContext
,
9428 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9429 /* not asserting an XPath error is probably better */
9432 /* then skip over remaining bytes for this char */
9433 while ( (ch
<<= 1) & 0x80 )
9434 if ( (*cptr
++ & 0xc0) != 0x80 ) {
9435 xmlGenericError(xmlGenericErrorContext
,
9436 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9437 /* not asserting an XPath error is probably better */
9440 if (ch
& 0x80) /* must have had error encountered */
9445 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
9446 xmlBufContent(target
)));
9448 xmlXPathReleaseObject(ctxt
->context
, str
);
9449 xmlXPathReleaseObject(ctxt
->context
, from
);
9450 xmlXPathReleaseObject(ctxt
->context
, to
);
9454 * xmlXPathBooleanFunction:
9455 * @ctxt: the XPath Parser context
9456 * @nargs: the number of arguments
9458 * Implement the boolean() XPath function
9459 * boolean boolean(object)
9460 * The boolean function converts its argument to a boolean as follows:
9461 * - a number is true if and only if it is neither positive or
9462 * negative zero nor NaN
9463 * - a node-set is true if and only if it is non-empty
9464 * - a string is true if and only if its length is non-zero
9467 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9468 xmlXPathObjectPtr cur
;
9471 cur
= valuePop(ctxt
);
9472 if (cur
== NULL
) XP_ERROR(XPATH_INVALID_OPERAND
);
9473 cur
= xmlXPathCacheConvertBoolean(ctxt
->context
, cur
);
9474 valuePush(ctxt
, cur
);
9478 * xmlXPathNotFunction:
9479 * @ctxt: the XPath Parser context
9480 * @nargs: the number of arguments
9482 * Implement the not() XPath function
9483 * boolean not(boolean)
9484 * The not function returns true if its argument is false,
9485 * and false otherwise.
9488 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9491 CHECK_TYPE(XPATH_BOOLEAN
);
9492 ctxt
->value
->boolval
= ! ctxt
->value
->boolval
;
9496 * xmlXPathTrueFunction:
9497 * @ctxt: the XPath Parser context
9498 * @nargs: the number of arguments
9500 * Implement the true() XPath function
9504 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9506 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 1));
9510 * xmlXPathFalseFunction:
9511 * @ctxt: the XPath Parser context
9512 * @nargs: the number of arguments
9514 * Implement the false() XPath function
9518 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9520 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, 0));
9524 * xmlXPathLangFunction:
9525 * @ctxt: the XPath Parser context
9526 * @nargs: the number of arguments
9528 * Implement the lang() XPath function
9529 * boolean lang(string)
9530 * The lang function returns true or false depending on whether the
9531 * language of the context node as specified by xml:lang attributes
9532 * is the same as or is a sublanguage of the language specified by
9533 * the argument string. The language of the context node is determined
9534 * by the value of the xml:lang attribute on the context node, or, if
9535 * the context node has no xml:lang attribute, by the value of the
9536 * xml:lang attribute on the nearest ancestor of the context node that
9537 * has an xml:lang attribute. If there is no such attribute, then lang
9538 * returns false. If there is such an attribute, then lang returns
9539 * true if the attribute value is equal to the argument ignoring case,
9540 * or if there is some suffix starting with - such that the attribute
9541 * value is equal to the argument ignoring that suffix of the attribute
9542 * value and ignoring case.
9545 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9546 xmlXPathObjectPtr val
= NULL
;
9547 const xmlChar
*theLang
= NULL
;
9548 const xmlChar
*lang
;
9554 CHECK_TYPE(XPATH_STRING
);
9555 val
= valuePop(ctxt
);
9556 lang
= val
->stringval
;
9557 theLang
= xmlNodeGetLang(ctxt
->context
->node
);
9558 if ((theLang
!= NULL
) && (lang
!= NULL
)) {
9559 for (i
= 0;lang
[i
] != 0;i
++)
9560 if (toupper(lang
[i
]) != toupper(theLang
[i
]))
9562 if ((theLang
[i
] == 0) || (theLang
[i
] == '-'))
9566 if (theLang
!= NULL
)
9567 xmlFree((void *)theLang
);
9569 xmlXPathReleaseObject(ctxt
->context
, val
);
9570 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
9574 * xmlXPathNumberFunction:
9575 * @ctxt: the XPath Parser context
9576 * @nargs: the number of arguments
9578 * Implement the number() XPath function
9579 * number number(object?)
9582 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9583 xmlXPathObjectPtr cur
;
9586 if (ctxt
== NULL
) return;
9588 if (ctxt
->context
->node
== NULL
) {
9589 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, 0.0));
9591 xmlChar
* content
= xmlNodeGetContent(ctxt
->context
->node
);
9593 res
= xmlXPathStringEvalNumber(content
);
9594 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9601 cur
= valuePop(ctxt
);
9602 valuePush(ctxt
, xmlXPathCacheConvertNumber(ctxt
->context
, cur
));
9606 * xmlXPathSumFunction:
9607 * @ctxt: the XPath Parser context
9608 * @nargs: the number of arguments
9610 * Implement the sum() XPath function
9611 * number sum(node-set)
9612 * The sum function returns the sum of the values of the nodes in
9613 * the argument node-set.
9616 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9617 xmlXPathObjectPtr cur
;
9622 if ((ctxt
->value
== NULL
) ||
9623 ((ctxt
->value
->type
!= XPATH_NODESET
) &&
9624 (ctxt
->value
->type
!= XPATH_XSLT_TREE
)))
9625 XP_ERROR(XPATH_INVALID_TYPE
);
9626 cur
= valuePop(ctxt
);
9628 if ((cur
->nodesetval
!= NULL
) && (cur
->nodesetval
->nodeNr
!= 0)) {
9629 for (i
= 0; i
< cur
->nodesetval
->nodeNr
; i
++) {
9630 res
+= xmlXPathCastNodeToNumber(cur
->nodesetval
->nodeTab
[i
]);
9633 valuePush(ctxt
, xmlXPathCacheNewFloat(ctxt
->context
, res
));
9634 xmlXPathReleaseObject(ctxt
->context
, cur
);
9638 * To assure working code on multiple platforms, we want to only depend
9639 * upon the characteristic truncation of converting a floating point value
9640 * to an integer. Unfortunately, because of the different storage sizes
9641 * of our internal floating point value (double) and integer (int), we
9642 * can't directly convert (see bug 301162). This macro is a messy
9645 #define XTRUNC(f, v) \
9646 f = fmod((v), INT_MAX); \
9647 f = (v) - (f) + (double)((int)(f));
9650 * xmlXPathFloorFunction:
9651 * @ctxt: the XPath Parser context
9652 * @nargs: the number of arguments
9654 * Implement the floor() XPath function
9655 * number floor(number)
9656 * The floor function returns the largest (closest to positive infinity)
9657 * number that is not greater than the argument and that is an integer.
9660 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9665 CHECK_TYPE(XPATH_NUMBER
);
9667 XTRUNC(f
, ctxt
->value
->floatval
);
9668 if (f
!= ctxt
->value
->floatval
) {
9669 if (ctxt
->value
->floatval
> 0)
9670 ctxt
->value
->floatval
= f
;
9672 ctxt
->value
->floatval
= f
- 1;
9677 * xmlXPathCeilingFunction:
9678 * @ctxt: the XPath Parser context
9679 * @nargs: the number of arguments
9681 * Implement the ceiling() XPath function
9682 * number ceiling(number)
9683 * The ceiling function returns the smallest (closest to negative infinity)
9684 * number that is not less than the argument and that is an integer.
9687 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9692 CHECK_TYPE(XPATH_NUMBER
);
9695 ctxt
->value
->floatval
= ceil(ctxt
->value
->floatval
);
9697 XTRUNC(f
, ctxt
->value
->floatval
);
9698 if (f
!= ctxt
->value
->floatval
) {
9699 if (ctxt
->value
->floatval
> 0)
9700 ctxt
->value
->floatval
= f
+ 1;
9702 if (ctxt
->value
->floatval
< 0 && f
== 0)
9703 ctxt
->value
->floatval
= xmlXPathNZERO
;
9705 ctxt
->value
->floatval
= f
;
9713 * xmlXPathRoundFunction:
9714 * @ctxt: the XPath Parser context
9715 * @nargs: the number of arguments
9717 * Implement the round() XPath function
9718 * number round(number)
9719 * The round function returns the number that is closest to the
9720 * argument and that is an integer. If there are two such numbers,
9721 * then the one that is even is returned.
9724 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
9729 CHECK_TYPE(XPATH_NUMBER
);
9731 if ((xmlXPathIsNaN(ctxt
->value
->floatval
)) ||
9732 (xmlXPathIsInf(ctxt
->value
->floatval
) == 1) ||
9733 (xmlXPathIsInf(ctxt
->value
->floatval
) == -1) ||
9734 (ctxt
->value
->floatval
== 0.0))
9737 XTRUNC(f
, ctxt
->value
->floatval
);
9738 if (ctxt
->value
->floatval
< 0) {
9739 if (ctxt
->value
->floatval
< f
- 0.5)
9740 ctxt
->value
->floatval
= f
- 1;
9742 ctxt
->value
->floatval
= f
;
9743 if (ctxt
->value
->floatval
== 0)
9744 ctxt
->value
->floatval
= xmlXPathNZERO
;
9746 if (ctxt
->value
->floatval
< f
+ 0.5)
9747 ctxt
->value
->floatval
= f
;
9749 ctxt
->value
->floatval
= f
+ 1;
9753 /************************************************************************
9757 ************************************************************************/
9760 * a few forward declarations since we use a recursive call based
9763 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
);
9764 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
);
9765 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
);
9766 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt
);
9767 static xmlChar
* xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
,
9771 * xmlXPathCurrentChar:
9772 * @ctxt: the XPath parser context
9773 * @cur: pointer to the beginning of the char
9774 * @len: pointer to the length of the char read
9776 * The current char value, if using UTF-8 this may actually span multiple
9777 * bytes in the input buffer.
9779 * Returns the current char value and its length
9783 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt
, int *len
) {
9793 * We are supposed to handle UTF8, check it's valid
9794 * From rfc2044: encoding of the Unicode values on UTF-8:
9796 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9797 * 0000 0000-0000 007F 0xxxxxxx
9798 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9799 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9801 * Check for the 0x110000 limit too
9805 if ((cur
[1] & 0xc0) != 0x80)
9806 goto encoding_error
;
9807 if ((c
& 0xe0) == 0xe0) {
9809 if ((cur
[2] & 0xc0) != 0x80)
9810 goto encoding_error
;
9811 if ((c
& 0xf0) == 0xf0) {
9812 if (((c
& 0xf8) != 0xf0) ||
9813 ((cur
[3] & 0xc0) != 0x80))
9814 goto encoding_error
;
9817 val
= (cur
[0] & 0x7) << 18;
9818 val
|= (cur
[1] & 0x3f) << 12;
9819 val
|= (cur
[2] & 0x3f) << 6;
9820 val
|= cur
[3] & 0x3f;
9824 val
= (cur
[0] & 0xf) << 12;
9825 val
|= (cur
[1] & 0x3f) << 6;
9826 val
|= cur
[2] & 0x3f;
9831 val
= (cur
[0] & 0x1f) << 6;
9832 val
|= cur
[1] & 0x3f;
9834 if (!IS_CHAR(val
)) {
9835 XP_ERROR0(XPATH_INVALID_CHAR_ERROR
);
9845 * If we detect an UTF8 error that probably means that the
9846 * input encoding didn't get properly advertised in the
9847 * declaration header. Report the error and switch the encoding
9848 * to ISO-Latin-1 (if you don't like this policy, just declare the
9852 XP_ERROR0(XPATH_ENCODING_ERROR
);
9856 * xmlXPathParseNCName:
9857 * @ctxt: the XPath Parser context
9859 * parse an XML namespace non qualified name.
9861 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9863 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9864 * CombiningChar | Extender
9866 * Returns the namespace name or NULL
9870 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt
) {
9875 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9877 * Accelerator for simple ASCII names
9880 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9881 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9884 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9885 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9886 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9887 (*in
== '_') || (*in
== '.') ||
9890 if ((*in
== ' ') || (*in
== '>') || (*in
== '/') ||
9891 (*in
== '[') || (*in
== ']') || (*in
== ':') ||
9892 (*in
== '@') || (*in
== '*')) {
9893 count
= in
- ctxt
->cur
;
9896 ret
= xmlStrndup(ctxt
->cur
, count
);
9901 return(xmlXPathParseNameComplex(ctxt
, 0));
9906 * xmlXPathParseQName:
9907 * @ctxt: the XPath Parser context
9908 * @prefix: a xmlChar **
9910 * parse an XML qualified name
9912 * [NS 5] QName ::= (Prefix ':')? LocalPart
9914 * [NS 6] Prefix ::= NCName
9916 * [NS 7] LocalPart ::= NCName
9918 * Returns the function returns the local part, and prefix is updated
9919 * to get the Prefix if any.
9923 xmlXPathParseQName(xmlXPathParserContextPtr ctxt
, xmlChar
**prefix
) {
9924 xmlChar
*ret
= NULL
;
9927 ret
= xmlXPathParseNCName(ctxt
);
9928 if (ret
&& CUR
== ':') {
9931 ret
= xmlXPathParseNCName(ctxt
);
9937 * xmlXPathParseName:
9938 * @ctxt: the XPath Parser context
9942 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9943 * CombiningChar | Extender
9945 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9947 * Returns the namespace name or NULL
9951 xmlXPathParseName(xmlXPathParserContextPtr ctxt
) {
9956 if ((ctxt
== NULL
) || (ctxt
->cur
== NULL
)) return(NULL
);
9958 * Accelerator for simple ASCII names
9961 if (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9962 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9963 (*in
== '_') || (*in
== ':')) {
9965 while (((*in
>= 0x61) && (*in
<= 0x7A)) ||
9966 ((*in
>= 0x41) && (*in
<= 0x5A)) ||
9967 ((*in
>= 0x30) && (*in
<= 0x39)) ||
9968 (*in
== '_') || (*in
== '-') ||
9969 (*in
== ':') || (*in
== '.'))
9971 if ((*in
> 0) && (*in
< 0x80)) {
9972 count
= in
- ctxt
->cur
;
9973 if (count
> XML_MAX_NAME_LENGTH
) {
9975 XP_ERRORNULL(XPATH_EXPR_ERROR
);
9977 ret
= xmlStrndup(ctxt
->cur
, count
);
9982 return(xmlXPathParseNameComplex(ctxt
, 1));
9986 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt
, int qualified
) {
9987 xmlChar buf
[XML_MAX_NAMELEN
+ 5];
9992 * Handler for more complex cases
9995 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
9996 (c
== '[') || (c
== ']') || (c
== '@') || /* accelerators */
9997 (c
== '*') || /* accelerators */
9998 (!IS_LETTER(c
) && (c
!= '_') &&
9999 ((!qualified
) || (c
!= ':')))) {
10003 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
10004 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
10005 (c
== '.') || (c
== '-') ||
10006 (c
== '_') || ((qualified
) && (c
== ':')) ||
10007 (IS_COMBINING(c
)) ||
10008 (IS_EXTENDER(c
)))) {
10009 COPY_BUF(l
,buf
,len
,c
);
10012 if (len
>= XML_MAX_NAMELEN
) {
10014 * Okay someone managed to make a huge name, so he's ready to pay
10015 * for the processing speed.
10020 if (len
> XML_MAX_NAME_LENGTH
) {
10021 XP_ERRORNULL(XPATH_EXPR_ERROR
);
10023 buffer
= (xmlChar
*) xmlMallocAtomic(max
* sizeof(xmlChar
));
10024 if (buffer
== NULL
) {
10025 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
10027 memcpy(buffer
, buf
, len
);
10028 while ((IS_LETTER(c
)) || (IS_DIGIT(c
)) || /* test bigname.xml */
10029 (c
== '.') || (c
== '-') ||
10030 (c
== '_') || ((qualified
) && (c
== ':')) ||
10031 (IS_COMBINING(c
)) ||
10032 (IS_EXTENDER(c
))) {
10033 if (len
+ 10 > max
) {
10034 if (max
> XML_MAX_NAME_LENGTH
) {
10035 XP_ERRORNULL(XPATH_EXPR_ERROR
);
10038 buffer
= (xmlChar
*) xmlRealloc(buffer
,
10039 max
* sizeof(xmlChar
));
10040 if (buffer
== NULL
) {
10041 XP_ERRORNULL(XPATH_MEMORY_ERROR
);
10044 COPY_BUF(l
,buffer
,len
,c
);
10054 return(xmlStrndup(buf
, len
));
10057 #define MAX_FRAC 20
10060 * These are used as divisors for the fractional part of a number.
10061 * Since the table includes 1.0 (representing '0' fractional digits),
10062 * it must be dimensioned at MAX_FRAC+1 (bug 133921)
10064 static double my_pow10
[MAX_FRAC
+1] = {
10065 1.0, 10.0, 100.0, 1000.0, 10000.0,
10066 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
10067 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
10069 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
10070 1000000000000000000.0, 10000000000000000000.0, 100000000000000000000.0
10074 * xmlXPathStringEvalNumber:
10075 * @str: A string to scan
10077 * [30a] Float ::= Number ('e' Digits?)?
10079 * [30] Number ::= Digits ('.' Digits?)?
10081 * [31] Digits ::= [0-9]+
10083 * Compile a Number in the string
10084 * In complement of the Number expression, this function also handles
10085 * negative values : '-' Number.
10087 * Returns the double value.
10090 xmlXPathStringEvalNumber(const xmlChar
*str
) {
10091 const xmlChar
*cur
= str
;
10096 int is_exponent_negative
= 0;
10098 unsigned long tmp
= 0;
10101 if (cur
== NULL
) return(0);
10102 while (IS_BLANK_CH(*cur
)) cur
++;
10103 if ((*cur
!= '.') && ((*cur
< '0') || (*cur
> '9')) && (*cur
!= '-')) {
10104 return(xmlXPathNAN
);
10113 * tmp/temp is a workaround against a gcc compiler bug
10114 * http://veillard.com/gcc.bug
10117 while ((*cur
>= '0') && (*cur
<= '9')) {
10119 tmp
= (*cur
- '0');
10122 temp
= (double) tmp
;
10127 while ((*cur
>= '0') && (*cur
<= '9')) {
10128 ret
= ret
* 10 + (*cur
- '0');
10136 double fraction
= 0;
10139 if (((*cur
< '0') || (*cur
> '9')) && (!ok
)) {
10140 return(xmlXPathNAN
);
10142 while (((*cur
>= '0') && (*cur
<= '9')) && (frac
< MAX_FRAC
)) {
10144 fraction
= fraction
* 10 + v
;
10148 fraction
/= my_pow10
[frac
];
10149 ret
= ret
+ fraction
;
10150 while ((*cur
>= '0') && (*cur
<= '9'))
10153 if ((*cur
== 'e') || (*cur
== 'E')) {
10156 is_exponent_negative
= 1;
10158 } else if (*cur
== '+') {
10161 while ((*cur
>= '0') && (*cur
<= '9')) {
10162 exponent
= exponent
* 10 + (*cur
- '0');
10166 while (IS_BLANK_CH(*cur
)) cur
++;
10167 if (*cur
!= 0) return(xmlXPathNAN
);
10168 if (isneg
) ret
= -ret
;
10169 if (is_exponent_negative
) exponent
= -exponent
;
10170 ret
*= pow(10.0, (double)exponent
);
10175 * xmlXPathCompNumber:
10176 * @ctxt: the XPath Parser context
10178 * [30] Number ::= Digits ('.' Digits?)?
10180 * [31] Digits ::= [0-9]+
10182 * Compile a Number, then push it on the stack
10186 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt
)
10191 int is_exponent_negative
= 0;
10193 unsigned long tmp
= 0;
10198 if ((CUR
!= '.') && ((CUR
< '0') || (CUR
> '9'))) {
10199 XP_ERROR(XPATH_NUMBER_ERROR
);
10203 * tmp/temp is a workaround against a gcc compiler bug
10204 * http://veillard.com/gcc.bug
10207 while ((CUR
>= '0') && (CUR
<= '9')) {
10212 temp
= (double) tmp
;
10217 while ((CUR
>= '0') && (CUR
<= '9')) {
10218 ret
= ret
* 10 + (CUR
- '0');
10225 double fraction
= 0;
10228 if (((CUR
< '0') || (CUR
> '9')) && (!ok
)) {
10229 XP_ERROR(XPATH_NUMBER_ERROR
);
10231 while ((CUR
>= '0') && (CUR
<= '9') && (frac
< MAX_FRAC
)) {
10233 fraction
= fraction
* 10 + v
;
10237 fraction
/= my_pow10
[frac
];
10238 ret
= ret
+ fraction
;
10239 while ((CUR
>= '0') && (CUR
<= '9'))
10242 if ((CUR
== 'e') || (CUR
== 'E')) {
10245 is_exponent_negative
= 1;
10247 } else if (CUR
== '+') {
10250 while ((CUR
>= '0') && (CUR
<= '9')) {
10251 exponent
= exponent
* 10 + (CUR
- '0');
10254 if (is_exponent_negative
)
10255 exponent
= -exponent
;
10256 ret
*= pow(10.0, (double) exponent
);
10258 PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_NUMBER
, 0, 0,
10259 xmlXPathCacheNewFloat(ctxt
->context
, ret
), NULL
);
10263 * xmlXPathParseLiteral:
10264 * @ctxt: the XPath Parser context
10268 * [29] Literal ::= '"' [^"]* '"'
10271 * Returns the value found or NULL in case of error
10274 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt
) {
10276 xmlChar
*ret
= NULL
;
10281 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10283 if (!IS_CHAR_CH(CUR
)) {
10284 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10286 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10289 } else if (CUR
== '\'') {
10292 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10294 if (!IS_CHAR_CH(CUR
)) {
10295 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR
);
10297 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10301 XP_ERRORNULL(XPATH_START_LITERAL_ERROR
);
10307 * xmlXPathCompLiteral:
10308 * @ctxt: the XPath Parser context
10310 * Parse a Literal and push it on the stack.
10312 * [29] Literal ::= '"' [^"]* '"'
10315 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10318 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt
) {
10320 xmlChar
*ret
= NULL
;
10325 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '"'))
10327 if (!IS_CHAR_CH(CUR
)) {
10328 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10330 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10333 } else if (CUR
== '\'') {
10336 while ((IS_CHAR_CH(CUR
)) && (CUR
!= '\''))
10338 if (!IS_CHAR_CH(CUR
)) {
10339 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR
);
10341 ret
= xmlStrndup(q
, CUR_PTR
- q
);
10345 XP_ERROR(XPATH_START_LITERAL_ERROR
);
10347 if (ret
== NULL
) return;
10348 PUSH_LONG_EXPR(XPATH_OP_VALUE
, XPATH_STRING
, 0, 0,
10349 xmlXPathCacheNewString(ctxt
->context
, ret
), NULL
);
10354 * xmlXPathCompVariableReference:
10355 * @ctxt: the XPath Parser context
10357 * Parse a VariableReference, evaluate it and push it on the stack.
10359 * The variable bindings consist of a mapping from variable names
10360 * to variable values. The value of a variable is an object, which can be
10361 * of any of the types that are possible for the value of an expression,
10362 * and may also be of additional types not specified here.
10364 * Early evaluation is possible since:
10365 * The variable bindings [...] used to evaluate a subexpression are
10366 * always the same as those used to evaluate the containing expression.
10368 * [36] VariableReference ::= '$' QName
10371 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt
) {
10377 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10380 name
= xmlXPathParseQName(ctxt
, &prefix
);
10381 if (name
== NULL
) {
10382 XP_ERROR(XPATH_VARIABLE_REF_ERROR
);
10384 ctxt
->comp
->last
= -1;
10385 PUSH_LONG_EXPR(XPATH_OP_VARIABLE
, 0, 0, 0,
10388 if ((ctxt
->context
!= NULL
) && (ctxt
->context
->flags
& XML_XPATH_NOVAR
)) {
10389 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR
);
10394 * xmlXPathIsNodeType:
10395 * @name: a name string
10397 * Is the name given a NodeType one.
10399 * [38] NodeType ::= 'comment'
10401 * | 'processing-instruction'
10404 * Returns 1 if true 0 otherwise
10407 xmlXPathIsNodeType(const xmlChar
*name
) {
10411 if (xmlStrEqual(name
, BAD_CAST
"node"))
10413 if (xmlStrEqual(name
, BAD_CAST
"text"))
10415 if (xmlStrEqual(name
, BAD_CAST
"comment"))
10417 if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
10423 * xmlXPathCompFunctionCall:
10424 * @ctxt: the XPath Parser context
10426 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10427 * [17] Argument ::= Expr
10429 * Compile a function call, the evaluation of all arguments are
10430 * pushed on the stack
10433 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt
) {
10439 name
= xmlXPathParseQName(ctxt
, &prefix
);
10440 if (name
== NULL
) {
10442 XP_ERROR(XPATH_EXPR_ERROR
);
10446 if (prefix
== NULL
)
10447 xmlGenericError(xmlGenericErrorContext
, "Calling function %s\n",
10450 xmlGenericError(xmlGenericErrorContext
, "Calling function %s:%s\n",
10455 XP_ERROR(XPATH_EXPR_ERROR
);
10461 * Optimization for count(): we don't need the node-set to be sorted.
10463 if ((prefix
== NULL
) && (name
[0] == 'c') &&
10464 xmlStrEqual(name
, BAD_CAST
"count"))
10468 ctxt
->comp
->last
= -1;
10471 int op1
= ctxt
->comp
->last
;
10472 ctxt
->comp
->last
= -1;
10473 xmlXPathCompileExpr(ctxt
, sort
);
10474 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
10479 PUSH_BINARY_EXPR(XPATH_OP_ARG
, op1
, ctxt
->comp
->last
, 0, 0);
10481 if (CUR
== ')') break;
10483 XP_ERROR(XPATH_EXPR_ERROR
);
10489 PUSH_LONG_EXPR(XPATH_OP_FUNCTION
, nbargs
, 0, 0,
10496 * xmlXPathCompPrimaryExpr:
10497 * @ctxt: the XPath Parser context
10499 * [15] PrimaryExpr ::= VariableReference
10505 * Compile a primary expression.
10508 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt
) {
10510 if (CUR
== '$') xmlXPathCompVariableReference(ctxt
);
10511 else if (CUR
== '(') {
10514 xmlXPathCompileExpr(ctxt
, 1);
10517 XP_ERROR(XPATH_EXPR_ERROR
);
10521 } else if (IS_ASCII_DIGIT(CUR
) || (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10522 xmlXPathCompNumber(ctxt
);
10523 } else if ((CUR
== '\'') || (CUR
== '"')) {
10524 xmlXPathCompLiteral(ctxt
);
10526 xmlXPathCompFunctionCall(ctxt
);
10532 * xmlXPathCompFilterExpr:
10533 * @ctxt: the XPath Parser context
10535 * [20] FilterExpr ::= PrimaryExpr
10536 * | FilterExpr Predicate
10538 * Compile a filter expression.
10539 * Square brackets are used to filter expressions in the same way that
10540 * they are used in location paths. It is an error if the expression to
10541 * be filtered does not evaluate to a node-set. The context node list
10542 * used for evaluating the expression in square brackets is the node-set
10543 * to be filtered listed in document order.
10547 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt
) {
10548 xmlXPathCompPrimaryExpr(ctxt
);
10552 while (CUR
== '[') {
10553 xmlXPathCompPredicate(ctxt
, 1);
10561 * xmlXPathScanName:
10562 * @ctxt: the XPath Parser context
10564 * Trickery: parse an XML name but without consuming the input flow
10565 * Needed to avoid insanity in the parser state.
10567 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10568 * CombiningChar | Extender
10570 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10572 * [6] Names ::= Name (S Name)*
10574 * Returns the Name parsed or NULL
10578 xmlXPathScanName(xmlXPathParserContextPtr ctxt
) {
10581 const xmlChar
*cur
;
10587 if ((c
== ' ') || (c
== '>') || (c
== '/') || /* accelerators */
10588 (!IS_LETTER(c
) && (c
!= '_') &&
10593 while ((c
!= ' ') && (c
!= '>') && (c
!= '/') && /* test bigname.xml */
10594 ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
10595 (c
== '.') || (c
== '-') ||
10596 (c
== '_') || (c
== ':') ||
10597 (IS_COMBINING(c
)) ||
10598 (IS_EXTENDER(c
)))) {
10603 ret
= xmlStrndup(cur
, ctxt
->cur
- cur
);
10609 * xmlXPathCompPathExpr:
10610 * @ctxt: the XPath Parser context
10612 * [19] PathExpr ::= LocationPath
10614 * | FilterExpr '/' RelativeLocationPath
10615 * | FilterExpr '//' RelativeLocationPath
10617 * Compile a path expression.
10618 * The / operator and // operators combine an arbitrary expression
10619 * and a relative location path. It is an error if the expression
10620 * does not evaluate to a node-set.
10621 * The / operator does composition in the same way as when / is
10622 * used in a location path. As in location paths, // is short for
10623 * /descendant-or-self::node()/.
10627 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt
) {
10628 int lc
= 1; /* Should we branch to LocationPath ? */
10629 xmlChar
*name
= NULL
; /* we may have to preparse a name to find out */
10632 if ((CUR
== '$') || (CUR
== '(') ||
10633 (IS_ASCII_DIGIT(CUR
)) ||
10634 (CUR
== '\'') || (CUR
== '"') ||
10635 (CUR
== '.' && IS_ASCII_DIGIT(NXT(1)))) {
10637 } else if (CUR
== '*') {
10638 /* relative or absolute location path */
10640 } else if (CUR
== '/') {
10641 /* relative or absolute location path */
10643 } else if (CUR
== '@') {
10644 /* relative abbreviated attribute location path */
10646 } else if (CUR
== '.') {
10647 /* relative abbreviated attribute location path */
10651 * Problem is finding if we have a name here whether it's:
10653 * - a function call in which case it's followed by '('
10654 * - an axis in which case it's followed by ':'
10656 * We do an a priori analysis here rather than having to
10657 * maintain parsed token content through the recursive function
10658 * calls. This looks uglier but makes the code easier to
10659 * read/write/debug.
10662 name
= xmlXPathScanName(ctxt
);
10663 if ((name
!= NULL
) && (xmlStrstr(name
, (xmlChar
*) "::") != NULL
)) {
10665 xmlGenericError(xmlGenericErrorContext
,
10666 "PathExpr: Axis\n");
10670 } else if (name
!= NULL
) {
10671 int len
=xmlStrlen(name
);
10674 while (NXT(len
) != 0) {
10675 if (NXT(len
) == '/') {
10678 xmlGenericError(xmlGenericErrorContext
,
10679 "PathExpr: AbbrRelLocation\n");
10683 } else if (IS_BLANK_CH(NXT(len
))) {
10684 /* ignore blanks */
10686 } else if (NXT(len
) == ':') {
10688 xmlGenericError(xmlGenericErrorContext
,
10689 "PathExpr: AbbrRelLocation\n");
10693 } else if ((NXT(len
) == '(')) {
10694 /* Note Type or Function */
10695 if (xmlXPathIsNodeType(name
)) {
10697 xmlGenericError(xmlGenericErrorContext
,
10698 "PathExpr: Type search\n");
10703 xmlGenericError(xmlGenericErrorContext
,
10704 "PathExpr: function call\n");
10709 } else if ((NXT(len
) == '[')) {
10712 xmlGenericError(xmlGenericErrorContext
,
10713 "PathExpr: AbbrRelLocation\n");
10717 } else if ((NXT(len
) == '<') || (NXT(len
) == '>') ||
10718 (NXT(len
) == '=')) {
10727 if (NXT(len
) == 0) {
10729 xmlGenericError(xmlGenericErrorContext
,
10730 "PathExpr: AbbrRelLocation\n");
10737 /* make sure all cases are covered explicitly */
10738 XP_ERROR(XPATH_EXPR_ERROR
);
10744 PUSH_LEAVE_EXPR(XPATH_OP_ROOT
, 0, 0);
10746 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10748 xmlXPathCompLocationPath(ctxt
);
10750 xmlXPathCompFilterExpr(ctxt
);
10752 if ((CUR
== '/') && (NXT(1) == '/')) {
10756 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
10757 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
10758 PUSH_UNARY_EXPR(XPATH_OP_RESET
, ctxt
->comp
->last
, 1, 0);
10760 xmlXPathCompRelativeLocationPath(ctxt
);
10761 } else if (CUR
== '/') {
10762 xmlXPathCompRelativeLocationPath(ctxt
);
10769 * xmlXPathCompUnionExpr:
10770 * @ctxt: the XPath Parser context
10772 * [18] UnionExpr ::= PathExpr
10773 * | UnionExpr '|' PathExpr
10775 * Compile an union expression.
10779 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt
) {
10780 xmlXPathCompPathExpr(ctxt
);
10783 while (CUR
== '|') {
10784 int op1
= ctxt
->comp
->last
;
10785 PUSH_LEAVE_EXPR(XPATH_OP_NODE
, 0, 0);
10789 xmlXPathCompPathExpr(ctxt
);
10791 PUSH_BINARY_EXPR(XPATH_OP_UNION
, op1
, ctxt
->comp
->last
, 0, 0);
10798 * xmlXPathCompUnaryExpr:
10799 * @ctxt: the XPath Parser context
10801 * [27] UnaryExpr ::= UnionExpr
10804 * Compile an unary expression.
10808 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt
) {
10813 while (CUR
== '-') {
10820 xmlXPathCompUnionExpr(ctxt
);
10824 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 2, 0);
10826 PUSH_UNARY_EXPR(XPATH_OP_PLUS
, ctxt
->comp
->last
, 3, 0);
10831 * xmlXPathCompMultiplicativeExpr:
10832 * @ctxt: the XPath Parser context
10834 * [26] MultiplicativeExpr ::= UnaryExpr
10835 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10836 * | MultiplicativeExpr 'div' UnaryExpr
10837 * | MultiplicativeExpr 'mod' UnaryExpr
10838 * [34] MultiplyOperator ::= '*'
10840 * Compile an Additive expression.
10844 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt
) {
10845 xmlXPathCompUnaryExpr(ctxt
);
10848 while ((CUR
== '*') ||
10849 ((CUR
== 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10850 ((CUR
== 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10852 int op1
= ctxt
->comp
->last
;
10857 } else if (CUR
== 'd') {
10860 } else if (CUR
== 'm') {
10865 xmlXPathCompUnaryExpr(ctxt
);
10867 PUSH_BINARY_EXPR(XPATH_OP_MULT
, op1
, ctxt
->comp
->last
, op
, 0);
10873 * xmlXPathCompAdditiveExpr:
10874 * @ctxt: the XPath Parser context
10876 * [25] AdditiveExpr ::= MultiplicativeExpr
10877 * | AdditiveExpr '+' MultiplicativeExpr
10878 * | AdditiveExpr '-' MultiplicativeExpr
10880 * Compile an Additive expression.
10884 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt
) {
10886 xmlXPathCompMultiplicativeExpr(ctxt
);
10889 while ((CUR
== '+') || (CUR
== '-')) {
10891 int op1
= ctxt
->comp
->last
;
10893 if (CUR
== '+') plus
= 1;
10897 xmlXPathCompMultiplicativeExpr(ctxt
);
10899 PUSH_BINARY_EXPR(XPATH_OP_PLUS
, op1
, ctxt
->comp
->last
, plus
, 0);
10905 * xmlXPathCompRelationalExpr:
10906 * @ctxt: the XPath Parser context
10908 * [24] RelationalExpr ::= AdditiveExpr
10909 * | RelationalExpr '<' AdditiveExpr
10910 * | RelationalExpr '>' AdditiveExpr
10911 * | RelationalExpr '<=' AdditiveExpr
10912 * | RelationalExpr '>=' AdditiveExpr
10914 * A <= B > C is allowed ? Answer from James, yes with
10915 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10916 * which is basically what got implemented.
10918 * Compile a Relational expression, then push the result
10923 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt
) {
10924 xmlXPathCompAdditiveExpr(ctxt
);
10927 while ((CUR
== '<') ||
10929 ((CUR
== '<') && (NXT(1) == '=')) ||
10930 ((CUR
== '>') && (NXT(1) == '='))) {
10932 int op1
= ctxt
->comp
->last
;
10934 if (CUR
== '<') inf
= 1;
10936 if (NXT(1) == '=') strict
= 0;
10941 xmlXPathCompAdditiveExpr(ctxt
);
10943 PUSH_BINARY_EXPR(XPATH_OP_CMP
, op1
, ctxt
->comp
->last
, inf
, strict
);
10949 * xmlXPathCompEqualityExpr:
10950 * @ctxt: the XPath Parser context
10952 * [23] EqualityExpr ::= RelationalExpr
10953 * | EqualityExpr '=' RelationalExpr
10954 * | EqualityExpr '!=' RelationalExpr
10956 * A != B != C is allowed ? Answer from James, yes with
10957 * (RelationalExpr = RelationalExpr) = RelationalExpr
10958 * (RelationalExpr != RelationalExpr) != RelationalExpr
10959 * which is basically what got implemented.
10961 * Compile an Equality expression.
10965 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt
) {
10966 xmlXPathCompRelationalExpr(ctxt
);
10969 while ((CUR
== '=') || ((CUR
== '!') && (NXT(1) == '='))) {
10971 int op1
= ctxt
->comp
->last
;
10973 if (CUR
== '=') eq
= 1;
10978 xmlXPathCompRelationalExpr(ctxt
);
10980 PUSH_BINARY_EXPR(XPATH_OP_EQUAL
, op1
, ctxt
->comp
->last
, eq
, 0);
10986 * xmlXPathCompAndExpr:
10987 * @ctxt: the XPath Parser context
10989 * [22] AndExpr ::= EqualityExpr
10990 * | AndExpr 'and' EqualityExpr
10992 * Compile an AND expression.
10996 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt
) {
10997 xmlXPathCompEqualityExpr(ctxt
);
11000 while ((CUR
== 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11001 int op1
= ctxt
->comp
->last
;
11004 xmlXPathCompEqualityExpr(ctxt
);
11006 PUSH_BINARY_EXPR(XPATH_OP_AND
, op1
, ctxt
->comp
->last
, 0, 0);
11012 * xmlXPathCompileExpr:
11013 * @ctxt: the XPath Parser context
11015 * [14] Expr ::= OrExpr
11016 * [21] OrExpr ::= AndExpr
11017 * | OrExpr 'or' AndExpr
11019 * Parse and compile an expression
11022 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt
, int sort
) {
11023 xmlXPathCompAndExpr(ctxt
);
11026 while ((CUR
== 'o') && (NXT(1) == 'r')) {
11027 int op1
= ctxt
->comp
->last
;
11030 xmlXPathCompAndExpr(ctxt
);
11032 PUSH_BINARY_EXPR(XPATH_OP_OR
, op1
, ctxt
->comp
->last
, 0, 0);
11035 if ((sort
) && (ctxt
->comp
->steps
[ctxt
->comp
->last
].op
!= XPATH_OP_VALUE
)) {
11036 /* more ops could be optimized too */
11038 * This is the main place to eliminate sorting for
11039 * operations which don't require a sorted node-set.
11042 PUSH_UNARY_EXPR(XPATH_OP_SORT
, ctxt
->comp
->last
, 0, 0);
11047 * xmlXPathCompPredicate:
11048 * @ctxt: the XPath Parser context
11049 * @filter: act as a filter
11051 * [8] Predicate ::= '[' PredicateExpr ']'
11052 * [9] PredicateExpr ::= Expr
11054 * Compile a predicate expression
11057 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt
, int filter
) {
11058 int op1
= ctxt
->comp
->last
;
11062 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11067 ctxt
->comp
->last
= -1;
11069 * This call to xmlXPathCompileExpr() will deactivate sorting
11070 * of the predicate result.
11071 * TODO: Sorting is still activated for filters, since I'm not
11072 * sure if needed. Normally sorting should not be needed, since
11073 * a filter can only diminish the number of items in a sequence,
11074 * but won't change its order; so if the initial sequence is sorted,
11075 * subsequent sorting is not needed.
11078 xmlXPathCompileExpr(ctxt
, 0);
11080 xmlXPathCompileExpr(ctxt
, 1);
11084 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR
);
11088 PUSH_BINARY_EXPR(XPATH_OP_FILTER
, op1
, ctxt
->comp
->last
, 0, 0);
11090 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE
, op1
, ctxt
->comp
->last
, 0, 0);
11097 * xmlXPathCompNodeTest:
11098 * @ctxt: the XPath Parser context
11099 * @test: pointer to a xmlXPathTestVal
11100 * @type: pointer to a xmlXPathTypeVal
11101 * @prefix: placeholder for a possible name prefix
11103 * [7] NodeTest ::= NameTest
11104 * | NodeType '(' ')'
11105 * | 'processing-instruction' '(' Literal ')'
11107 * [37] NameTest ::= '*'
11110 * [38] NodeType ::= 'comment'
11112 * | 'processing-instruction'
11115 * Returns the name found and updates @test, @type and @prefix appropriately
11118 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt
, xmlXPathTestVal
*test
,
11119 xmlXPathTypeVal
*type
, const xmlChar
**prefix
,
11123 if ((test
== NULL
) || (type
== NULL
) || (prefix
== NULL
)) {
11127 *type
= (xmlXPathTypeVal
) 0;
11128 *test
= (xmlXPathTestVal
) 0;
11132 if ((name
== NULL
) && (CUR
== '*')) {
11137 *test
= NODE_TEST_ALL
;
11142 name
= xmlXPathParseNCName(ctxt
);
11143 if (name
== NULL
) {
11144 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11147 blanks
= IS_BLANK_CH(CUR
);
11152 * NodeType or PI search
11154 if (xmlStrEqual(name
, BAD_CAST
"comment"))
11155 *type
= NODE_TYPE_COMMENT
;
11156 else if (xmlStrEqual(name
, BAD_CAST
"node"))
11157 *type
= NODE_TYPE_NODE
;
11158 else if (xmlStrEqual(name
, BAD_CAST
"processing-instruction"))
11159 *type
= NODE_TYPE_PI
;
11160 else if (xmlStrEqual(name
, BAD_CAST
"text"))
11161 *type
= NODE_TYPE_TEXT
;
11165 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11168 *test
= NODE_TEST_TYPE
;
11171 if (*type
== NODE_TYPE_PI
) {
11173 * Specific case: search a PI by name.
11179 name
= xmlXPathParseLiteral(ctxt
);
11181 *test
= NODE_TEST_PI
;
11188 XP_ERRORNULL(XPATH_UNCLOSED_ERROR
);
11193 *test
= NODE_TEST_NAME
;
11194 if ((!blanks
) && (CUR
== ':')) {
11198 * Since currently the parser context don't have a
11199 * namespace list associated:
11200 * The namespace name for this prefix can be computed
11201 * only at evaluation time. The compilation is done
11202 * outside of any context.
11205 *prefix
= xmlXPathNsLookup(ctxt
->context
, name
);
11208 if (*prefix
== NULL
) {
11209 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
11220 *test
= NODE_TEST_ALL
;
11224 name
= xmlXPathParseNCName(ctxt
);
11225 if (name
== NULL
) {
11226 XP_ERRORNULL(XPATH_EXPR_ERROR
);
11233 * xmlXPathIsAxisName:
11234 * @name: a preparsed name token
11236 * [6] AxisName ::= 'ancestor'
11237 * | 'ancestor-or-self'
11241 * | 'descendant-or-self'
11243 * | 'following-sibling'
11247 * | 'preceding-sibling'
11250 * Returns the axis or 0
11252 static xmlXPathAxisVal
11253 xmlXPathIsAxisName(const xmlChar
*name
) {
11254 xmlXPathAxisVal ret
= (xmlXPathAxisVal
) 0;
11257 if (xmlStrEqual(name
, BAD_CAST
"ancestor"))
11258 ret
= AXIS_ANCESTOR
;
11259 if (xmlStrEqual(name
, BAD_CAST
"ancestor-or-self"))
11260 ret
= AXIS_ANCESTOR_OR_SELF
;
11261 if (xmlStrEqual(name
, BAD_CAST
"attribute"))
11262 ret
= AXIS_ATTRIBUTE
;
11265 if (xmlStrEqual(name
, BAD_CAST
"child"))
11269 if (xmlStrEqual(name
, BAD_CAST
"descendant"))
11270 ret
= AXIS_DESCENDANT
;
11271 if (xmlStrEqual(name
, BAD_CAST
"descendant-or-self"))
11272 ret
= AXIS_DESCENDANT_OR_SELF
;
11275 if (xmlStrEqual(name
, BAD_CAST
"following"))
11276 ret
= AXIS_FOLLOWING
;
11277 if (xmlStrEqual(name
, BAD_CAST
"following-sibling"))
11278 ret
= AXIS_FOLLOWING_SIBLING
;
11281 if (xmlStrEqual(name
, BAD_CAST
"namespace"))
11282 ret
= AXIS_NAMESPACE
;
11285 if (xmlStrEqual(name
, BAD_CAST
"parent"))
11287 if (xmlStrEqual(name
, BAD_CAST
"preceding"))
11288 ret
= AXIS_PRECEDING
;
11289 if (xmlStrEqual(name
, BAD_CAST
"preceding-sibling"))
11290 ret
= AXIS_PRECEDING_SIBLING
;
11293 if (xmlStrEqual(name
, BAD_CAST
"self"))
11301 * xmlXPathCompStep:
11302 * @ctxt: the XPath Parser context
11304 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11305 * | AbbreviatedStep
11307 * [12] AbbreviatedStep ::= '.' | '..'
11309 * [5] AxisSpecifier ::= AxisName '::'
11310 * | AbbreviatedAxisSpecifier
11312 * [13] AbbreviatedAxisSpecifier ::= '@'?
11314 * Modified for XPtr range support as:
11316 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11317 * | AbbreviatedStep
11318 * | 'range-to' '(' Expr ')' Predicate*
11320 * Compile one step in a Location Path
11321 * A location step of . is short for self::node(). This is
11322 * particularly useful in conjunction with //. For example, the
11323 * location path .//para is short for
11324 * self::node()/descendant-or-self::node()/child::para
11325 * and so will select all para descendant elements of the context
11327 * Similarly, a location step of .. is short for parent::node().
11328 * For example, ../title is short for parent::node()/child::title
11329 * and so will select the title children of the parent of the context
11333 xmlXPathCompStep(xmlXPathParserContextPtr ctxt
) {
11334 #ifdef LIBXML_XPTR_ENABLED
11340 if ((CUR
== '.') && (NXT(1) == '.')) {
11343 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_PARENT
,
11344 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11345 } else if (CUR
== '.') {
11349 xmlChar
*name
= NULL
;
11350 const xmlChar
*prefix
= NULL
;
11351 xmlXPathTestVal test
= (xmlXPathTestVal
) 0;
11352 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) 0;
11353 xmlXPathTypeVal type
= (xmlXPathTypeVal
) 0;
11357 * The modification needed for XPointer change to the production
11359 #ifdef LIBXML_XPTR_ENABLED
11361 name
= xmlXPathParseNCName(ctxt
);
11362 if ((name
!= NULL
) && (xmlStrEqual(name
, BAD_CAST
"range-to"))) {
11363 op2
= ctxt
->comp
->last
;
11367 XP_ERROR(XPATH_EXPR_ERROR
);
11372 xmlXPathCompileExpr(ctxt
, 1);
11373 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11378 XP_ERROR(XPATH_EXPR_ERROR
);
11382 goto eval_predicates
;
11390 name
= xmlXPathParseNCName(ctxt
);
11391 if (name
!= NULL
) {
11392 axis
= xmlXPathIsAxisName(name
);
11395 if ((CUR
== ':') && (NXT(1) == ':')) {
11400 /* an element name can conflict with an axis one :-\ */
11406 } else if (CUR
== '@') {
11408 axis
= AXIS_ATTRIBUTE
;
11414 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
11419 name
= xmlXPathCompNodeTest(ctxt
, &test
, &type
, &prefix
, name
);
11423 if ((prefix
!= NULL
) && (ctxt
->context
!= NULL
) &&
11424 (ctxt
->context
->flags
& XML_XPATH_CHECKNS
)) {
11425 if (xmlXPathNsLookup(ctxt
->context
, prefix
) == NULL
) {
11426 xmlXPathErr(ctxt
, XPATH_UNDEF_PREFIX_ERROR
);
11430 xmlGenericError(xmlGenericErrorContext
,
11431 "Basis : computing new set\n");
11435 xmlGenericError(xmlGenericErrorContext
, "Basis : ");
11436 if (ctxt
->value
== NULL
)
11437 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11438 else if (ctxt
->value
->nodesetval
== NULL
)
11439 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11441 xmlGenericErrorContextNodeSet(stdout
, ctxt
->value
->nodesetval
);
11444 #ifdef LIBXML_XPTR_ENABLED
11447 op1
= ctxt
->comp
->last
;
11448 ctxt
->comp
->last
= -1;
11451 while (CUR
== '[') {
11452 xmlXPathCompPredicate(ctxt
, 0);
11455 #ifdef LIBXML_XPTR_ENABLED
11457 PUSH_BINARY_EXPR(XPATH_OP_RANGETO
, op2
, op1
, 0, 0);
11460 PUSH_FULL_EXPR(XPATH_OP_COLLECT
, op1
, ctxt
->comp
->last
, axis
,
11461 test
, type
, (void *)prefix
, (void *)name
);
11465 xmlGenericError(xmlGenericErrorContext
, "Step : ");
11466 if (ctxt
->value
== NULL
)
11467 xmlGenericError(xmlGenericErrorContext
, "no value\n");
11468 else if (ctxt
->value
->nodesetval
== NULL
)
11469 xmlGenericError(xmlGenericErrorContext
, "Empty\n");
11471 xmlGenericErrorContextNodeSet(xmlGenericErrorContext
,
11472 ctxt
->value
->nodesetval
);
11477 * xmlXPathCompRelativeLocationPath:
11478 * @ctxt: the XPath Parser context
11480 * [3] RelativeLocationPath ::= Step
11481 * | RelativeLocationPath '/' Step
11482 * | AbbreviatedRelativeLocationPath
11483 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11485 * Compile a relative location path.
11488 xmlXPathCompRelativeLocationPath
11489 (xmlXPathParserContextPtr ctxt
) {
11491 if ((CUR
== '/') && (NXT(1) == '/')) {
11494 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11495 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11496 } else if (CUR
== '/') {
11500 xmlXPathCompStep(ctxt
);
11503 while (CUR
== '/') {
11504 if ((CUR
== '/') && (NXT(1) == '/')) {
11507 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11508 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11509 xmlXPathCompStep(ctxt
);
11510 } else if (CUR
== '/') {
11513 xmlXPathCompStep(ctxt
);
11520 * xmlXPathCompLocationPath:
11521 * @ctxt: the XPath Parser context
11523 * [1] LocationPath ::= RelativeLocationPath
11524 * | AbsoluteLocationPath
11525 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11526 * | AbbreviatedAbsoluteLocationPath
11527 * [10] AbbreviatedAbsoluteLocationPath ::=
11528 * '//' RelativeLocationPath
11530 * Compile a location path
11532 * // is short for /descendant-or-self::node()/. For example,
11533 * //para is short for /descendant-or-self::node()/child::para and
11534 * so will select any para element in the document (even a para element
11535 * that is a document element will be selected by //para since the
11536 * document element node is a child of the root node); div//para is
11537 * short for div/descendant-or-self::node()/child::para and so will
11538 * select all para descendants of div children.
11541 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt
) {
11544 xmlXPathCompRelativeLocationPath(ctxt
);
11546 while (CUR
== '/') {
11547 if ((CUR
== '/') && (NXT(1) == '/')) {
11550 PUSH_LONG_EXPR(XPATH_OP_COLLECT
, AXIS_DESCENDANT_OR_SELF
,
11551 NODE_TEST_TYPE
, NODE_TYPE_NODE
, NULL
, NULL
);
11552 xmlXPathCompRelativeLocationPath(ctxt
);
11553 } else if (CUR
== '/') {
11557 ((IS_ASCII_LETTER(CUR
)) || (CUR
== '_') || (CUR
== '.') ||
11558 (CUR
== '@') || (CUR
== '*')))
11559 xmlXPathCompRelativeLocationPath(ctxt
);
11566 /************************************************************************
11568 * XPath precompiled expression evaluation *
11570 ************************************************************************/
11573 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
);
11577 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op
,
11580 xmlGenericError(xmlGenericErrorContext
, "new step : ");
11581 switch (op
->value
) {
11582 case AXIS_ANCESTOR
:
11583 xmlGenericError(xmlGenericErrorContext
, "axis 'ancestors' ");
11585 case AXIS_ANCESTOR_OR_SELF
:
11586 xmlGenericError(xmlGenericErrorContext
,
11587 "axis 'ancestors-or-self' ");
11589 case AXIS_ATTRIBUTE
:
11590 xmlGenericError(xmlGenericErrorContext
, "axis 'attributes' ");
11593 xmlGenericError(xmlGenericErrorContext
, "axis 'child' ");
11595 case AXIS_DESCENDANT
:
11596 xmlGenericError(xmlGenericErrorContext
, "axis 'descendant' ");
11598 case AXIS_DESCENDANT_OR_SELF
:
11599 xmlGenericError(xmlGenericErrorContext
,
11600 "axis 'descendant-or-self' ");
11602 case AXIS_FOLLOWING
:
11603 xmlGenericError(xmlGenericErrorContext
, "axis 'following' ");
11605 case AXIS_FOLLOWING_SIBLING
:
11606 xmlGenericError(xmlGenericErrorContext
,
11607 "axis 'following-siblings' ");
11609 case AXIS_NAMESPACE
:
11610 xmlGenericError(xmlGenericErrorContext
, "axis 'namespace' ");
11613 xmlGenericError(xmlGenericErrorContext
, "axis 'parent' ");
11615 case AXIS_PRECEDING
:
11616 xmlGenericError(xmlGenericErrorContext
, "axis 'preceding' ");
11618 case AXIS_PRECEDING_SIBLING
:
11619 xmlGenericError(xmlGenericErrorContext
,
11620 "axis 'preceding-sibling' ");
11623 xmlGenericError(xmlGenericErrorContext
, "axis 'self' ");
11626 xmlGenericError(xmlGenericErrorContext
,
11627 " context contains %d nodes\n", nbNodes
);
11628 switch (op
->value2
) {
11629 case NODE_TEST_NONE
:
11630 xmlGenericError(xmlGenericErrorContext
,
11631 " searching for none !!!\n");
11633 case NODE_TEST_TYPE
:
11634 xmlGenericError(xmlGenericErrorContext
,
11635 " searching for type %d\n", op
->value3
);
11638 xmlGenericError(xmlGenericErrorContext
,
11639 " searching for PI !!!\n");
11641 case NODE_TEST_ALL
:
11642 xmlGenericError(xmlGenericErrorContext
,
11643 " searching for *\n");
11646 xmlGenericError(xmlGenericErrorContext
,
11647 " searching for namespace %s\n",
11650 case NODE_TEST_NAME
:
11651 xmlGenericError(xmlGenericErrorContext
,
11652 " searching for name %s\n", op
->value5
);
11654 xmlGenericError(xmlGenericErrorContext
,
11655 " with namespace %s\n", op
->value4
);
11658 xmlGenericError(xmlGenericErrorContext
, "Testing : ");
11660 #endif /* DEBUG_STEP */
11663 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt
,
11664 xmlXPathStepOpPtr op
,
11669 if (op
->ch1
!= -1) {
11670 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11672 * Process inner predicates first.
11674 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11676 * TODO: raise an internal error.
11679 contextSize
= xmlXPathCompOpEvalPredicate(ctxt
,
11680 &comp
->steps
[op
->ch1
], set
, contextSize
, hasNsNodes
);
11682 if (contextSize
<= 0)
11685 if (op
->ch2
!= -1) {
11686 xmlXPathContextPtr xpctxt
= ctxt
->context
;
11687 xmlNodePtr contextNode
, oldContextNode
;
11688 xmlDocPtr oldContextDoc
;
11689 int i
, res
, contextPos
= 0, newContextSize
;
11690 xmlXPathStepOpPtr exprOp
;
11691 xmlXPathObjectPtr contextObj
= NULL
, exprRes
= NULL
;
11693 #ifdef LIBXML_XPTR_ENABLED
11695 * URGENT TODO: Check the following:
11696 * We don't expect location sets if evaluating prediates, right?
11697 * Only filters should expect location sets, right?
11702 * "For each node in the node-set to be filtered, the
11703 * PredicateExpr is evaluated with that node as the
11704 * context node, with the number of nodes in the
11705 * node-set as the context size, and with the proximity
11706 * position of the node in the node-set with respect to
11707 * the axis as the context position;"
11708 * @oldset is the node-set" to be filtered.
11711 * "only predicates change the context position and
11712 * context size (see [2.4 Predicates])."
11714 * node-set context pos
11718 * After applying predicate [position() > 1] :
11719 * node-set context pos
11723 oldContextNode
= xpctxt
->node
;
11724 oldContextDoc
= xpctxt
->doc
;
11726 * Get the expression of this predicate.
11728 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11729 newContextSize
= 0;
11730 for (i
= 0; i
< set
->nodeNr
; i
++) {
11731 if (set
->nodeTab
[i
] == NULL
)
11734 contextNode
= set
->nodeTab
[i
];
11735 xpctxt
->node
= contextNode
;
11736 xpctxt
->contextSize
= contextSize
;
11737 xpctxt
->proximityPosition
= ++contextPos
;
11740 * Also set the xpath document in case things like
11741 * key() are evaluated in the predicate.
11743 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11744 (contextNode
->doc
!= NULL
))
11745 xpctxt
->doc
= contextNode
->doc
;
11747 * Evaluate the predicate expression with 1 context node
11748 * at a time; this node is packaged into a node set; this
11749 * node set is handed over to the evaluation mechanism.
11751 if (contextObj
== NULL
)
11752 contextObj
= xmlXPathCacheNewNodeSet(xpctxt
, contextNode
);
11754 if (xmlXPathNodeSetAddUnique(contextObj
->nodesetval
,
11755 contextNode
) < 0) {
11756 ctxt
->error
= XPATH_MEMORY_ERROR
;
11757 goto evaluation_exit
;
11761 valuePush(ctxt
, contextObj
);
11763 res
= xmlXPathCompOpEvalToBoolean(ctxt
, exprOp
, 1);
11765 if ((ctxt
->error
!= XPATH_EXPRESSION_OK
) || (res
== -1)) {
11766 xmlXPathNodeSetClear(set
, hasNsNodes
);
11767 newContextSize
= 0;
11768 goto evaluation_exit
;
11775 * Remove the entry from the initial node set.
11777 set
->nodeTab
[i
] = NULL
;
11778 if (contextNode
->type
== XML_NAMESPACE_DECL
)
11779 xmlXPathNodeSetFreeNs((xmlNsPtr
) contextNode
);
11781 if (ctxt
->value
== contextObj
) {
11783 * Don't free the temporary XPath object holding the
11784 * context node, in order to avoid massive recreation
11785 * inside this loop.
11788 xmlXPathNodeSetClear(contextObj
->nodesetval
, hasNsNodes
);
11791 * TODO: The object was lost in the evaluation machinery.
11792 * Can this happen? Maybe in internal-error cases.
11798 if (contextObj
!= NULL
) {
11799 if (ctxt
->value
== contextObj
)
11801 xmlXPathReleaseObject(xpctxt
, contextObj
);
11804 if (exprRes
!= NULL
)
11805 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11807 * Reset/invalidate the context.
11809 xpctxt
->node
= oldContextNode
;
11810 xpctxt
->doc
= oldContextDoc
;
11811 xpctxt
->contextSize
= -1;
11812 xpctxt
->proximityPosition
= -1;
11813 return(newContextSize
);
11815 return(contextSize
);
11819 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt
,
11820 xmlXPathStepOpPtr op
,
11827 if (op
->ch1
!= -1) {
11828 xmlXPathCompExprPtr comp
= ctxt
->comp
;
11829 if (comp
->steps
[op
->ch1
].op
!= XPATH_OP_PREDICATE
) {
11831 * TODO: raise an internal error.
11834 contextSize
= xmlXPathCompOpEvalPredicate(ctxt
,
11835 &comp
->steps
[op
->ch1
], set
, contextSize
, hasNsNodes
);
11837 if (contextSize
<= 0)
11841 * Check if the node set contains a sufficient number of nodes for
11842 * the requested range.
11844 if (contextSize
< minPos
) {
11845 xmlXPathNodeSetClear(set
, hasNsNodes
);
11848 if (op
->ch2
== -1) {
11850 * TODO: Can this ever happen?
11852 return (contextSize
);
11854 xmlDocPtr oldContextDoc
;
11855 int i
, pos
= 0, newContextSize
= 0, contextPos
= 0, res
;
11856 xmlXPathStepOpPtr exprOp
;
11857 xmlXPathObjectPtr contextObj
= NULL
, exprRes
= NULL
;
11858 xmlNodePtr oldContextNode
, contextNode
= NULL
;
11859 xmlXPathContextPtr xpctxt
= ctxt
->context
;
11862 #ifdef LIBXML_XPTR_ENABLED
11864 * URGENT TODO: Check the following:
11865 * We don't expect location sets if evaluating prediates, right?
11866 * Only filters should expect location sets, right?
11868 #endif /* LIBXML_XPTR_ENABLED */
11871 * Save old context.
11873 oldContextNode
= xpctxt
->node
;
11874 oldContextDoc
= xpctxt
->doc
;
11876 * Get the expression of this predicate.
11878 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
11879 for (i
= 0; i
< set
->nodeNr
; i
++) {
11880 xmlXPathObjectPtr tmp
;
11882 if (set
->nodeTab
[i
] == NULL
)
11885 contextNode
= set
->nodeTab
[i
];
11886 xpctxt
->node
= contextNode
;
11887 xpctxt
->contextSize
= contextSize
;
11888 xpctxt
->proximityPosition
= ++contextPos
;
11891 * Initialize the new set.
11892 * Also set the xpath document in case things like
11893 * key() evaluation are attempted on the predicate
11895 if ((contextNode
->type
!= XML_NAMESPACE_DECL
) &&
11896 (contextNode
->doc
!= NULL
))
11897 xpctxt
->doc
= contextNode
->doc
;
11899 * Evaluate the predicate expression with 1 context node
11900 * at a time; this node is packaged into a node set; this
11901 * node set is handed over to the evaluation mechanism.
11903 if (contextObj
== NULL
)
11904 contextObj
= xmlXPathCacheNewNodeSet(xpctxt
, contextNode
);
11906 if (xmlXPathNodeSetAddUnique(contextObj
->nodesetval
,
11907 contextNode
) < 0) {
11908 ctxt
->error
= XPATH_MEMORY_ERROR
;
11909 goto evaluation_exit
;
11913 frame
= xmlXPathSetFrame(ctxt
);
11914 valuePush(ctxt
, contextObj
);
11915 res
= xmlXPathCompOpEvalToBoolean(ctxt
, exprOp
, 1);
11916 tmp
= valuePop(ctxt
);
11917 xmlXPathPopFrame(ctxt
, frame
);
11919 if ((ctxt
->error
!= XPATH_EXPRESSION_OK
) || (res
== -1)) {
11920 while (tmp
!= contextObj
) {
11922 * Free up the result
11923 * then pop off contextObj, which will be freed later
11925 xmlXPathReleaseObject(xpctxt
, tmp
);
11926 tmp
= valuePop(ctxt
);
11928 goto evaluation_error
;
11930 /* push the result back onto the stack */
11931 valuePush(ctxt
, tmp
);
11936 if (res
&& (pos
>= minPos
) && (pos
<= maxPos
)) {
11938 * Fits in the requested range.
11941 if (minPos
== maxPos
) {
11943 * Only 1 node was requested.
11945 if (contextNode
->type
== XML_NAMESPACE_DECL
) {
11947 * As always: take care of those nasty
11950 set
->nodeTab
[i
] = NULL
;
11952 xmlXPathNodeSetClear(set
, hasNsNodes
);
11954 set
->nodeTab
[0] = contextNode
;
11955 goto evaluation_exit
;
11957 if (pos
== maxPos
) {
11961 xmlXPathNodeSetClearFromPos(set
, i
+1, hasNsNodes
);
11962 goto evaluation_exit
;
11966 * Remove the entry from the initial node set.
11968 set
->nodeTab
[i
] = NULL
;
11969 if (contextNode
->type
== XML_NAMESPACE_DECL
)
11970 xmlXPathNodeSetFreeNs((xmlNsPtr
) contextNode
);
11972 if (exprRes
!= NULL
) {
11973 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
11976 if (ctxt
->value
== contextObj
) {
11978 * Don't free the temporary XPath object holding the
11979 * context node, in order to avoid massive recreation
11980 * inside this loop.
11983 xmlXPathNodeSetClear(contextObj
->nodesetval
, hasNsNodes
);
11986 * The object was lost in the evaluation machinery.
11987 * Can this happen? Maybe in case of internal-errors.
11992 goto evaluation_exit
;
11995 xmlXPathNodeSetClear(set
, hasNsNodes
);
11996 newContextSize
= 0;
11999 if (contextObj
!= NULL
) {
12000 if (ctxt
->value
== contextObj
)
12002 xmlXPathReleaseObject(xpctxt
, contextObj
);
12004 if (exprRes
!= NULL
)
12005 xmlXPathReleaseObject(ctxt
->context
, exprRes
);
12007 * Reset/invalidate the context.
12009 xpctxt
->node
= oldContextNode
;
12010 xpctxt
->doc
= oldContextDoc
;
12011 xpctxt
->contextSize
= -1;
12012 xpctxt
->proximityPosition
= -1;
12013 return(newContextSize
);
12015 return(contextSize
);
12019 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt
,
12020 xmlXPathStepOpPtr op
,
12024 xmlXPathStepOpPtr exprOp
;
12027 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12031 * If not -1, then ch1 will point to:
12032 * 1) For predicates (XPATH_OP_PREDICATE):
12033 * - an inner predicate operator
12034 * 2) For filters (XPATH_OP_FILTER):
12035 * - an inner filter operater OR
12036 * - an expression selecting the node set.
12037 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12039 if ((op
->op
!= XPATH_OP_PREDICATE
) && (op
->op
!= XPATH_OP_FILTER
))
12042 if (op
->ch2
!= -1) {
12043 exprOp
= &ctxt
->comp
->steps
[op
->ch2
];
12047 if ((exprOp
!= NULL
) &&
12048 (exprOp
->op
== XPATH_OP_VALUE
) &&
12049 (exprOp
->value4
!= NULL
) &&
12050 (((xmlXPathObjectPtr
) exprOp
->value4
)->type
== XPATH_NUMBER
))
12053 * We have a "[n]" predicate here.
12054 * TODO: Unfortunately this simplistic test here is not
12055 * able to detect a position() predicate in compound
12056 * expressions like "[@attr = 'a" and position() = 1],
12057 * and even not the usage of position() in
12058 * "[position() = 1]"; thus - obviously - a position-range,
12059 * like it "[position() < 5]", is also not detected.
12060 * Maybe we could rewrite the AST to ease the optimization.
12062 *maxPos
= (int) ((xmlXPathObjectPtr
) exprOp
->value4
)->floatval
;
12064 if (((xmlXPathObjectPtr
) exprOp
->value4
)->floatval
==
12074 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt
,
12075 xmlXPathStepOpPtr op
,
12076 xmlNodePtr
* first
, xmlNodePtr
* last
,
12080 #define XP_TEST_HIT \
12081 if (hasAxisRange != 0) { \
12082 if (++pos == maxPos) { \
12083 if (addNode(seq, cur) < 0) \
12084 ctxt->error = XPATH_MEMORY_ERROR; \
12085 goto axis_range_end; } \
12087 if (addNode(seq, cur) < 0) \
12088 ctxt->error = XPATH_MEMORY_ERROR; \
12089 if (breakOnFirstHit) goto first_hit; }
12091 #define XP_TEST_HIT_NS \
12092 if (hasAxisRange != 0) { \
12093 if (++pos == maxPos) { \
12095 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12096 ctxt->error = XPATH_MEMORY_ERROR; \
12097 goto axis_range_end; } \
12100 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12101 ctxt->error = XPATH_MEMORY_ERROR; \
12102 if (breakOnFirstHit) goto first_hit; }
12104 xmlXPathAxisVal axis
= (xmlXPathAxisVal
) op
->value
;
12105 xmlXPathTestVal test
= (xmlXPathTestVal
) op
->value2
;
12106 xmlXPathTypeVal type
= (xmlXPathTypeVal
) op
->value3
;
12107 const xmlChar
*prefix
= op
->value4
;
12108 const xmlChar
*name
= op
->value5
;
12109 const xmlChar
*URI
= NULL
;
12112 int nbMatches
= 0, prevMatches
= 0;
12114 int total
= 0, hasNsNodes
= 0;
12115 /* The popped object holding the context nodes */
12116 xmlXPathObjectPtr obj
;
12117 /* The set of context nodes for the node tests */
12118 xmlNodeSetPtr contextSeq
;
12120 xmlNodePtr contextNode
;
12121 /* The final resulting node set wrt to all context nodes */
12122 xmlNodeSetPtr outSeq
;
12124 * The temporary resulting node set wrt 1 context node.
12125 * Used to feed predicate evaluation.
12129 /* First predicate operator */
12130 xmlXPathStepOpPtr predOp
;
12131 int maxPos
; /* The requested position() (when a "[n]" predicate) */
12132 int hasPredicateRange
, hasAxisRange
, pos
, size
, newSize
;
12133 int breakOnFirstHit
;
12135 xmlXPathTraversalFunction next
= NULL
;
12136 int (*addNode
) (xmlNodeSetPtr
, xmlNodePtr
);
12137 xmlXPathNodeSetMergeFunction mergeAndClear
;
12138 xmlNodePtr oldContextNode
;
12139 xmlXPathContextPtr xpctxt
= ctxt
->context
;
12142 CHECK_TYPE0(XPATH_NODESET
);
12143 obj
= valuePop(ctxt
);
12145 * Setup namespaces.
12147 if (prefix
!= NULL
) {
12148 URI
= xmlXPathNsLookup(xpctxt
, prefix
);
12150 xmlXPathReleaseObject(xpctxt
, obj
);
12151 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR
);
12157 * MAYBE FUTURE TODO: merging optimizations:
12158 * - If the nodes to be traversed wrt to the initial nodes and
12159 * the current axis cannot overlap, then we could avoid searching
12160 * for duplicates during the merge.
12161 * But the question is how/when to evaluate if they cannot overlap.
12162 * Example: if we know that for two initial nodes, the one is
12163 * not in the ancestor-or-self axis of the other, then we could safely
12164 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12165 * the descendant-or-self axis.
12167 mergeAndClear
= xmlXPathNodeSetMergeAndClear
;
12169 case AXIS_ANCESTOR
:
12171 next
= xmlXPathNextAncestor
;
12173 case AXIS_ANCESTOR_OR_SELF
:
12175 next
= xmlXPathNextAncestorOrSelf
;
12177 case AXIS_ATTRIBUTE
:
12180 next
= xmlXPathNextAttribute
;
12181 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12185 if (((test
== NODE_TEST_NAME
) || (test
== NODE_TEST_ALL
)) &&
12186 (type
== NODE_TYPE_NODE
))
12189 * Optimization if an element node type is 'element'.
12191 next
= xmlXPathNextChildElement
;
12193 next
= xmlXPathNextChild
;
12194 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12196 case AXIS_DESCENDANT
:
12198 next
= xmlXPathNextDescendant
;
12200 case AXIS_DESCENDANT_OR_SELF
:
12202 next
= xmlXPathNextDescendantOrSelf
;
12204 case AXIS_FOLLOWING
:
12206 next
= xmlXPathNextFollowing
;
12208 case AXIS_FOLLOWING_SIBLING
:
12210 next
= xmlXPathNextFollowingSibling
;
12212 case AXIS_NAMESPACE
:
12215 next
= (xmlXPathTraversalFunction
) xmlXPathNextNamespace
;
12216 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12220 next
= xmlXPathNextParent
;
12222 case AXIS_PRECEDING
:
12224 next
= xmlXPathNextPrecedingInternal
;
12226 case AXIS_PRECEDING_SIBLING
:
12228 next
= xmlXPathNextPrecedingSibling
;
12233 next
= xmlXPathNextSelf
;
12234 mergeAndClear
= xmlXPathNodeSetMergeAndClearNoDupls
;
12239 xmlXPathDebugDumpStepAxis(op
,
12240 (obj
->nodesetval
!= NULL
) ? obj
->nodesetval
->nodeNr
: 0);
12243 if (next
== NULL
) {
12244 xmlXPathReleaseObject(xpctxt
, obj
);
12247 contextSeq
= obj
->nodesetval
;
12248 if ((contextSeq
== NULL
) || (contextSeq
->nodeNr
<= 0)) {
12249 xmlXPathReleaseObject(xpctxt
, obj
);
12250 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, NULL
));
12254 * Predicate optimization ---------------------------------------------
12255 * If this step has a last predicate, which contains a position(),
12256 * then we'll optimize (although not exactly "position()", but only
12257 * the short-hand form, i.e., "[n]".
12259 * Example - expression "/foo[parent::bar][1]":
12261 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12263 * PREDICATE -- op->ch2 (predOp)
12264 * PREDICATE -- predOp->ch1 = [parent::bar]
12266 * COLLECT 'parent' 'name' 'node' bar
12268 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12273 hasPredicateRange
= 0;
12275 if (op
->ch2
!= -1) {
12277 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12279 predOp
= &ctxt
->comp
->steps
[op
->ch2
];
12280 if (xmlXPathIsPositionalPredicate(ctxt
, predOp
, &maxPos
)) {
12281 if (predOp
->ch1
!= -1) {
12283 * Use the next inner predicate operator.
12285 predOp
= &ctxt
->comp
->steps
[predOp
->ch1
];
12286 hasPredicateRange
= 1;
12289 * There's no other predicate than the [n] predicate.
12296 breakOnFirstHit
= ((toBool
) && (predOp
== NULL
)) ? 1 : 0;
12298 * Axis traversal -----------------------------------------------------
12302 * - For the attribute axis, the principal node type is attribute.
12303 * - For the namespace axis, the principal node type is namespace.
12304 * - For other axes, the principal node type is element.
12306 * A node test * is true for any node of the
12307 * principal node type. For example, child::* will
12308 * select all element children of the context node
12310 oldContextNode
= xpctxt
->node
;
12311 addNode
= xmlXPathNodeSetAddUnique
;
12314 contextNode
= NULL
;
12318 while (((contextIdx
< contextSeq
->nodeNr
) || (contextNode
!= NULL
)) &&
12319 (ctxt
->error
== XPATH_EXPRESSION_OK
)) {
12320 xpctxt
->node
= contextSeq
->nodeTab
[contextIdx
++];
12323 seq
= xmlXPathNodeSetCreate(NULL
);
12330 * Traverse the axis and test the nodes.
12336 cur
= next(ctxt
, cur
);
12341 * QUESTION TODO: What does the "first" and "last" stuff do?
12343 if ((first
!= NULL
) && (*first
!= NULL
)) {
12346 if (((total
% 256) == 0) &&
12347 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12348 (xmlXPathCmpNodesExt(*first
, cur
) >= 0))
12350 (xmlXPathCmpNodes(*first
, cur
) >= 0))
12356 if ((last
!= NULL
) && (*last
!= NULL
)) {
12359 if (((total
% 256) == 0) &&
12360 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12361 (xmlXPathCmpNodesExt(cur
, *last
) >= 0))
12363 (xmlXPathCmpNodes(cur
, *last
) >= 0))
12373 xmlGenericError(xmlGenericErrorContext
, " %s", cur
->name
);
12377 case NODE_TEST_NONE
:
12381 case NODE_TEST_TYPE
:
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
:
12397 case XML_NAMESPACE_DECL
: {
12398 if (axis
== AXIS_NAMESPACE
) {
12409 } else if (cur
->type
== type
) {
12410 if (cur
->type
== XML_NAMESPACE_DECL
)
12414 } else if ((type
== NODE_TYPE_TEXT
) &&
12415 (cur
->type
== XML_CDATA_SECTION_NODE
))
12421 if ((cur
->type
== XML_PI_NODE
) &&
12422 ((name
== NULL
) || xmlStrEqual(name
, cur
->name
)))
12427 case NODE_TEST_ALL
:
12428 if (axis
== AXIS_ATTRIBUTE
) {
12429 if (cur
->type
== XML_ATTRIBUTE_NODE
)
12431 if (prefix
== NULL
)
12434 } else if ((cur
->ns
!= NULL
) &&
12435 (xmlStrEqual(URI
, cur
->ns
->href
)))
12440 } else if (axis
== AXIS_NAMESPACE
) {
12441 if (cur
->type
== XML_NAMESPACE_DECL
)
12446 if (cur
->type
== XML_ELEMENT_NODE
) {
12447 if (prefix
== NULL
)
12451 } else if ((cur
->ns
!= NULL
) &&
12452 (xmlStrEqual(URI
, cur
->ns
->href
)))
12459 case NODE_TEST_NS
:{
12463 case NODE_TEST_NAME
:
12464 if (axis
== AXIS_ATTRIBUTE
) {
12465 if (cur
->type
!= XML_ATTRIBUTE_NODE
)
12467 } else if (axis
== AXIS_NAMESPACE
) {
12468 if (cur
->type
!= XML_NAMESPACE_DECL
)
12471 if (cur
->type
!= XML_ELEMENT_NODE
)
12474 switch (cur
->type
) {
12475 case XML_ELEMENT_NODE
:
12476 if (xmlStrEqual(name
, cur
->name
)) {
12477 if (prefix
== NULL
) {
12478 if (cur
->ns
== NULL
)
12483 if ((cur
->ns
!= NULL
) &&
12484 (xmlStrEqual(URI
, cur
->ns
->href
)))
12491 case XML_ATTRIBUTE_NODE
:{
12492 xmlAttrPtr attr
= (xmlAttrPtr
) cur
;
12494 if (xmlStrEqual(name
, attr
->name
)) {
12495 if (prefix
== NULL
) {
12496 if ((attr
->ns
== NULL
) ||
12497 (attr
->ns
->prefix
== NULL
))
12502 if ((attr
->ns
!= NULL
) &&
12512 case XML_NAMESPACE_DECL
:
12513 if (cur
->type
== XML_NAMESPACE_DECL
) {
12514 xmlNsPtr ns
= (xmlNsPtr
) cur
;
12516 if ((ns
->prefix
!= NULL
) && (name
!= NULL
)
12517 && (xmlStrEqual(ns
->prefix
, name
)))
12527 } /* switch(test) */
12528 } while ((cur
!= NULL
) && (ctxt
->error
== XPATH_EXPRESSION_OK
));
12530 goto apply_predicates
;
12532 axis_range_end
: /* ----------------------------------------------------- */
12534 * We have a "/foo[n]", and position() = n was reached.
12535 * Note that we can have as well "/foo/::parent::foo[1]", so
12536 * a duplicate-aware merge is still needed.
12537 * Merge with the result.
12539 if (outSeq
== NULL
) {
12543 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12545 * Break if only a true/false result was requested.
12551 first_hit
: /* ---------------------------------------------------------- */
12553 * Break if only a true/false result was requested and
12554 * no predicates existed and a node test succeeded.
12556 if (outSeq
== NULL
) {
12560 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12565 nbMatches
+= seq
->nodeNr
;
12568 apply_predicates
: /* --------------------------------------------------- */
12569 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
12573 * Apply predicates.
12575 if ((predOp
!= NULL
) && (seq
->nodeNr
> 0)) {
12577 * E.g. when we have a "/foo[some expression][n]".
12580 * QUESTION TODO: The old predicate evaluation took into
12581 * account location-sets.
12582 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12583 * Do we expect such a set here?
12584 * All what I learned now from the evaluation semantics
12585 * does not indicate that a location-set will be processed
12586 * here, so this looks OK.
12589 * Iterate over all predicates, starting with the outermost
12591 * TODO: Problem: we cannot execute the inner predicates first
12592 * since we cannot go back *up* the operator tree!
12594 * 1) Use of recursive functions (like is it currently done
12595 * via xmlXPathCompOpEval())
12596 * 2) Add a predicate evaluation information stack to the
12598 * 3) Change the way the operators are linked; we need a
12599 * "parent" field on xmlXPathStepOp
12601 * For the moment, I'll try to solve this with a recursive
12602 * function: xmlXPathCompOpEvalPredicate().
12604 size
= seq
->nodeNr
;
12605 if (hasPredicateRange
!= 0)
12606 newSize
= xmlXPathCompOpEvalPositionalPredicate(ctxt
,
12607 predOp
, seq
, size
, maxPos
, maxPos
, hasNsNodes
);
12609 newSize
= xmlXPathCompOpEvalPredicate(ctxt
,
12610 predOp
, seq
, size
, hasNsNodes
);
12612 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
12617 * Add the filtered set of nodes to the result node set.
12619 if (newSize
== 0) {
12621 * The predicates filtered all nodes out.
12623 xmlXPathNodeSetClear(seq
, hasNsNodes
);
12624 } else if (seq
->nodeNr
> 0) {
12626 * Add to result set.
12628 if (outSeq
== NULL
) {
12629 if (size
!= newSize
) {
12631 * We need to merge and clear here, since
12632 * the sequence will contained NULLed entries.
12634 outSeq
= mergeAndClear(NULL
, seq
, 1);
12640 outSeq
= mergeAndClear(outSeq
, seq
,
12641 (size
!= newSize
) ? 1: 0);
12643 * Break if only a true/false result was requested.
12648 } else if (seq
->nodeNr
> 0) {
12650 * Add to result set.
12652 if (outSeq
== NULL
) {
12656 outSeq
= mergeAndClear(outSeq
, seq
, 0);
12662 if ((obj
->boolval
) && (obj
->user
!= NULL
)) {
12664 * QUESTION TODO: What does this do and why?
12665 * TODO: Do we have to do this also for the "error"
12666 * cleanup further down?
12668 ctxt
->value
->boolval
= 1;
12669 ctxt
->value
->user
= obj
->user
;
12673 xmlXPathReleaseObject(xpctxt
, obj
);
12676 * Ensure we return at least an emtpy set.
12678 if (outSeq
== NULL
) {
12679 if ((seq
!= NULL
) && (seq
->nodeNr
== 0))
12682 outSeq
= xmlXPathNodeSetCreate(NULL
);
12683 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12685 if ((seq
!= NULL
) && (seq
!= outSeq
)) {
12686 xmlXPathFreeNodeSet(seq
);
12689 * Hand over the result. Better to push the set also in
12692 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(xpctxt
, outSeq
));
12694 * Reset the context node.
12696 xpctxt
->node
= oldContextNode
;
12698 * When traversing the namespace axis in "toBool" mode, it's
12699 * possible that tmpNsList wasn't freed.
12701 if (xpctxt
->tmpNsList
!= NULL
) {
12702 xmlFree(xpctxt
->tmpNsList
);
12703 xpctxt
->tmpNsList
= NULL
;
12707 xmlGenericError(xmlGenericErrorContext
,
12708 "\nExamined %d nodes, found %d nodes at that step\n",
12716 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12717 xmlXPathStepOpPtr op
, xmlNodePtr
* first
);
12720 * xmlXPathCompOpEvalFirst:
12721 * @ctxt: the XPath parser context with the compiled expression
12722 * @op: an XPath compiled operation
12723 * @first: the first elem found so far
12725 * Evaluate the Precompiled XPath operation searching only the first
12726 * element in document order
12728 * Returns the number of examined objects.
12731 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt
,
12732 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12734 int total
= 0, cur
;
12735 xmlXPathCompExprPtr comp
;
12736 xmlXPathObjectPtr arg1
, arg2
;
12743 case XPATH_OP_UNION
:
12745 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12748 if ((ctxt
->value
!= NULL
)
12749 && (ctxt
->value
->type
== XPATH_NODESET
)
12750 && (ctxt
->value
->nodesetval
!= NULL
)
12751 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12753 * limit tree traversing to first node in the result
12756 * OPTIMIZE TODO: This implicitely sorts
12757 * the result, even if not needed. E.g. if the argument
12758 * of the count() function, no sorting is needed.
12759 * OPTIMIZE TODO: How do we know if the node-list wasn't
12762 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12763 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12764 *first
= ctxt
->value
->nodesetval
->nodeTab
[0];
12767 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch2
],
12770 CHECK_TYPE0(XPATH_NODESET
);
12771 arg2
= valuePop(ctxt
);
12773 CHECK_TYPE0(XPATH_NODESET
);
12774 arg1
= valuePop(ctxt
);
12776 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12778 valuePush(ctxt
, arg1
);
12779 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12782 xmlXPathCompSwap(op
);
12783 return (total
+ cur
);
12784 case XPATH_OP_ROOT
:
12785 xmlXPathRoot(ctxt
);
12787 case XPATH_OP_NODE
:
12789 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12792 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12794 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12795 ctxt
->context
->node
));
12797 case XPATH_OP_RESET
:
12799 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12802 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12804 ctxt
->context
->node
= NULL
;
12806 case XPATH_OP_COLLECT
:{
12810 total
= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12813 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, first
, NULL
, 0);
12816 case XPATH_OP_VALUE
:
12818 xmlXPathCacheObjectCopy(ctxt
->context
,
12819 (xmlXPathObjectPtr
) op
->value4
));
12821 case XPATH_OP_SORT
:
12824 xmlXPathCompOpEvalFirst(ctxt
, &comp
->steps
[op
->ch1
],
12827 if ((ctxt
->value
!= NULL
)
12828 && (ctxt
->value
->type
== XPATH_NODESET
)
12829 && (ctxt
->value
->nodesetval
!= NULL
)
12830 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12831 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12833 #ifdef XP_OPTIMIZED_FILTER_FIRST
12834 case XPATH_OP_FILTER
:
12835 total
+= xmlXPathCompOpEvalFilterFirst(ctxt
, op
, first
);
12839 return (xmlXPathCompOpEval(ctxt
, op
));
12844 * xmlXPathCompOpEvalLast:
12845 * @ctxt: the XPath parser context with the compiled expression
12846 * @op: an XPath compiled operation
12847 * @last: the last elem found so far
12849 * Evaluate the Precompiled XPath operation searching only the last
12850 * element in document order
12852 * Returns the number of nodes traversed
12855 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
,
12858 int total
= 0, cur
;
12859 xmlXPathCompExprPtr comp
;
12860 xmlXPathObjectPtr arg1
, arg2
;
12871 case XPATH_OP_UNION
:
12872 bakd
= ctxt
->context
->doc
;
12873 bak
= ctxt
->context
->node
;
12874 pp
= ctxt
->context
->proximityPosition
;
12875 cs
= ctxt
->context
->contextSize
;
12877 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
], last
);
12879 if ((ctxt
->value
!= NULL
)
12880 && (ctxt
->value
->type
== XPATH_NODESET
)
12881 && (ctxt
->value
->nodesetval
!= NULL
)
12882 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) {
12884 * limit tree traversing to first node in the result
12886 if (ctxt
->value
->nodesetval
->nodeNr
> 1)
12887 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12889 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->value
->
12890 nodesetval
->nodeNr
-
12893 ctxt
->context
->doc
= bakd
;
12894 ctxt
->context
->node
= bak
;
12895 ctxt
->context
->proximityPosition
= pp
;
12896 ctxt
->context
->contextSize
= cs
;
12898 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch2
], last
);
12900 if ((ctxt
->value
!= NULL
)
12901 && (ctxt
->value
->type
== XPATH_NODESET
)
12902 && (ctxt
->value
->nodesetval
!= NULL
)
12903 && (ctxt
->value
->nodesetval
->nodeNr
>= 1)) { /* TODO: NOP ? */
12905 CHECK_TYPE0(XPATH_NODESET
);
12906 arg2
= valuePop(ctxt
);
12908 CHECK_TYPE0(XPATH_NODESET
);
12909 arg1
= valuePop(ctxt
);
12911 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
12913 valuePush(ctxt
, arg1
);
12914 xmlXPathReleaseObject(ctxt
->context
, arg2
);
12917 xmlXPathCompSwap(op
);
12918 return (total
+ cur
);
12919 case XPATH_OP_ROOT
:
12920 xmlXPathRoot(ctxt
);
12922 case XPATH_OP_NODE
:
12924 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12927 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12929 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
12930 ctxt
->context
->node
));
12932 case XPATH_OP_RESET
:
12934 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12937 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
12939 ctxt
->context
->node
= NULL
;
12941 case XPATH_OP_COLLECT
:{
12945 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
12948 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, last
, 0);
12951 case XPATH_OP_VALUE
:
12953 xmlXPathCacheObjectCopy(ctxt
->context
,
12954 (xmlXPathObjectPtr
) op
->value4
));
12956 case XPATH_OP_SORT
:
12959 xmlXPathCompOpEvalLast(ctxt
, &comp
->steps
[op
->ch1
],
12962 if ((ctxt
->value
!= NULL
)
12963 && (ctxt
->value
->type
== XPATH_NODESET
)
12964 && (ctxt
->value
->nodesetval
!= NULL
)
12965 && (ctxt
->value
->nodesetval
->nodeNr
> 1))
12966 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
12969 return (xmlXPathCompOpEval(ctxt
, op
));
12973 #ifdef XP_OPTIMIZED_FILTER_FIRST
12975 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt
,
12976 xmlXPathStepOpPtr op
, xmlNodePtr
* first
)
12979 xmlXPathCompExprPtr comp
;
12980 xmlXPathObjectPtr res
;
12981 xmlXPathObjectPtr obj
;
12982 xmlNodeSetPtr oldset
;
12983 xmlNodePtr oldnode
;
12990 * Optimization for ()[last()] selection i.e. the last elem
12992 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
12993 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
12994 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
12995 int f
= comp
->steps
[op
->ch2
].ch1
;
12998 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
12999 (comp
->steps
[f
].value5
== NULL
) &&
13000 (comp
->steps
[f
].value
== 0) &&
13001 (comp
->steps
[f
].value4
!= NULL
) &&
13003 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
13004 xmlNodePtr last
= NULL
;
13007 xmlXPathCompOpEvalLast(ctxt
,
13008 &comp
->steps
[op
->ch1
],
13012 * The nodeset should be in document order,
13013 * Keep only the last value
13015 if ((ctxt
->value
!= NULL
) &&
13016 (ctxt
->value
->type
== XPATH_NODESET
) &&
13017 (ctxt
->value
->nodesetval
!= NULL
) &&
13018 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
13019 (ctxt
->value
->nodesetval
->nodeNr
> 1)) {
13020 ctxt
->value
->nodesetval
->nodeTab
[0] =
13021 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->
13026 ctxt
->value
->nodesetval
->nodeNr
= 1;
13027 *first
= *(ctxt
->value
->nodesetval
->nodeTab
);
13034 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13038 if (ctxt
->value
== NULL
)
13041 #ifdef LIBXML_XPTR_ENABLED
13042 oldnode
= ctxt
->context
->node
;
13044 * Hum are we filtering the result of an XPointer expression
13046 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13047 xmlXPathObjectPtr tmp
= NULL
;
13048 xmlLocationSetPtr newlocset
= NULL
;
13049 xmlLocationSetPtr oldlocset
;
13052 * Extract the old locset, and then evaluate the result of the
13053 * expression for all the element in the locset. use it to grow
13056 CHECK_TYPE0(XPATH_LOCATIONSET
);
13057 obj
= valuePop(ctxt
);
13058 oldlocset
= obj
->user
;
13059 ctxt
->context
->node
= NULL
;
13061 if ((oldlocset
== NULL
) || (oldlocset
->locNr
== 0)) {
13062 ctxt
->context
->contextSize
= 0;
13063 ctxt
->context
->proximityPosition
= 0;
13065 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13066 res
= valuePop(ctxt
);
13068 xmlXPathReleaseObject(ctxt
->context
, res
);
13070 valuePush(ctxt
, obj
);
13074 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13076 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13078 * Run the evaluation with a node list made of a
13079 * single item in the nodelocset.
13081 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13082 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13083 ctxt
->context
->proximityPosition
= i
+ 1;
13085 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13086 ctxt
->context
->node
);
13088 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13089 ctxt
->context
->node
) < 0) {
13090 ctxt
->error
= XPATH_MEMORY_ERROR
;
13093 valuePush(ctxt
, tmp
);
13095 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13096 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13097 xmlXPathFreeObject(obj
);
13101 * The result of the evaluation need to be tested to
13102 * decided whether the filter succeeded or not
13104 res
= valuePop(ctxt
);
13105 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13106 xmlXPtrLocationSetAdd(newlocset
,
13107 xmlXPathCacheObjectCopy(ctxt
->context
,
13108 oldlocset
->locTab
[i
]));
13114 xmlXPathReleaseObject(ctxt
->context
, res
);
13116 if (ctxt
->value
== tmp
) {
13118 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13120 * REVISIT TODO: Don't create a temporary nodeset
13121 * for everly iteration.
13123 /* OLD: xmlXPathFreeObject(res); */
13126 ctxt
->context
->node
= NULL
;
13128 * Only put the first node in the result, then leave.
13130 if (newlocset
->locNr
> 0) {
13131 *first
= (xmlNodePtr
) oldlocset
->locTab
[i
]->user
;
13136 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13139 * The result is used as the new evaluation locset.
13141 xmlXPathReleaseObject(ctxt
->context
, obj
);
13142 ctxt
->context
->node
= NULL
;
13143 ctxt
->context
->contextSize
= -1;
13144 ctxt
->context
->proximityPosition
= -1;
13145 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13146 ctxt
->context
->node
= oldnode
;
13149 #endif /* LIBXML_XPTR_ENABLED */
13152 * Extract the old set, and then evaluate the result of the
13153 * expression for all the element in the set. use it to grow
13156 CHECK_TYPE0(XPATH_NODESET
);
13157 obj
= valuePop(ctxt
);
13158 oldset
= obj
->nodesetval
;
13160 oldnode
= ctxt
->context
->node
;
13161 oldDoc
= ctxt
->context
->doc
;
13162 ctxt
->context
->node
= NULL
;
13164 if ((oldset
== NULL
) || (oldset
->nodeNr
== 0)) {
13165 ctxt
->context
->contextSize
= 0;
13166 ctxt
->context
->proximityPosition
= 0;
13167 /* QUESTION TODO: Why was this code commented out?
13170 xmlXPathCompOpEval(ctxt,
13171 &comp->steps[op->ch2]);
13173 res = valuePop(ctxt);
13175 xmlXPathFreeObject(res);
13177 valuePush(ctxt
, obj
);
13178 ctxt
->context
->node
= oldnode
;
13181 xmlNodeSetPtr newset
;
13182 xmlXPathObjectPtr tmp
= NULL
;
13184 * Initialize the new set.
13185 * Also set the xpath document in case things like
13186 * key() evaluation are attempted on the predicate
13188 newset
= xmlXPathNodeSetCreate(NULL
);
13189 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13191 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13193 * Run the evaluation with a node list made of
13194 * a single item in the nodeset.
13196 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13197 if ((oldset
->nodeTab
[i
]->type
!= XML_NAMESPACE_DECL
) &&
13198 (oldset
->nodeTab
[i
]->doc
!= NULL
))
13199 ctxt
->context
->doc
= oldset
->nodeTab
[i
]->doc
;
13201 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13202 ctxt
->context
->node
);
13204 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13205 ctxt
->context
->node
) < 0) {
13206 ctxt
->error
= XPATH_MEMORY_ERROR
;
13209 valuePush(ctxt
, tmp
);
13210 ctxt
->context
->contextSize
= oldset
->nodeNr
;
13211 ctxt
->context
->proximityPosition
= i
+ 1;
13213 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13214 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13215 xmlXPathFreeNodeSet(newset
);
13216 xmlXPathFreeObject(obj
);
13220 * The result of the evaluation needs to be tested to
13221 * decide whether the filter succeeded or not
13223 res
= valuePop(ctxt
);
13224 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13225 if (xmlXPathNodeSetAdd(newset
, oldset
->nodeTab
[i
]) < 0)
13226 ctxt
->error
= XPATH_MEMORY_ERROR
;
13232 xmlXPathReleaseObject(ctxt
->context
, res
);
13234 if (ctxt
->value
== tmp
) {
13237 * Don't free the temporary nodeset
13238 * in order to avoid massive recreation inside this
13241 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13244 ctxt
->context
->node
= NULL
;
13246 * Only put the first node in the result, then leave.
13248 if (newset
->nodeNr
> 0) {
13249 *first
= *(newset
->nodeTab
);
13254 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13257 * The result is used as the new evaluation set.
13259 xmlXPathReleaseObject(ctxt
->context
, obj
);
13260 ctxt
->context
->node
= NULL
;
13261 ctxt
->context
->contextSize
= -1;
13262 ctxt
->context
->proximityPosition
= -1;
13263 /* may want to move this past the '}' later */
13264 ctxt
->context
->doc
= oldDoc
;
13265 valuePush(ctxt
, xmlXPathCacheWrapNodeSet(ctxt
->context
, newset
));
13267 ctxt
->context
->node
= oldnode
;
13270 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13273 * xmlXPathCompOpEval:
13274 * @ctxt: the XPath parser context with the compiled expression
13275 * @op: an XPath compiled operation
13277 * Evaluate the Precompiled XPath operation
13278 * Returns the number of nodes traversed
13281 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt
, xmlXPathStepOpPtr op
)
13285 xmlXPathCompExprPtr comp
;
13286 xmlXPathObjectPtr arg1
, arg2
;
13298 bakd
= ctxt
->context
->doc
;
13299 bak
= ctxt
->context
->node
;
13300 pp
= ctxt
->context
->proximityPosition
;
13301 cs
= ctxt
->context
->contextSize
;
13302 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13304 xmlXPathBooleanFunction(ctxt
, 1);
13305 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 0))
13307 arg2
= valuePop(ctxt
);
13308 ctxt
->context
->doc
= bakd
;
13309 ctxt
->context
->node
= bak
;
13310 ctxt
->context
->proximityPosition
= pp
;
13311 ctxt
->context
->contextSize
= cs
;
13312 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13314 xmlXPathFreeObject(arg2
);
13317 xmlXPathBooleanFunction(ctxt
, 1);
13318 arg1
= valuePop(ctxt
);
13319 arg1
->boolval
&= arg2
->boolval
;
13320 valuePush(ctxt
, arg1
);
13321 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13324 bakd
= ctxt
->context
->doc
;
13325 bak
= ctxt
->context
->node
;
13326 pp
= ctxt
->context
->proximityPosition
;
13327 cs
= ctxt
->context
->contextSize
;
13328 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13330 xmlXPathBooleanFunction(ctxt
, 1);
13331 if ((ctxt
->value
== NULL
) || (ctxt
->value
->boolval
== 1))
13333 arg2
= valuePop(ctxt
);
13334 ctxt
->context
->doc
= bakd
;
13335 ctxt
->context
->node
= bak
;
13336 ctxt
->context
->proximityPosition
= pp
;
13337 ctxt
->context
->contextSize
= cs
;
13338 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13340 xmlXPathFreeObject(arg2
);
13343 xmlXPathBooleanFunction(ctxt
, 1);
13344 arg1
= valuePop(ctxt
);
13345 arg1
->boolval
|= arg2
->boolval
;
13346 valuePush(ctxt
, arg1
);
13347 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13349 case XPATH_OP_EQUAL
:
13350 bakd
= ctxt
->context
->doc
;
13351 bak
= ctxt
->context
->node
;
13352 pp
= ctxt
->context
->proximityPosition
;
13353 cs
= ctxt
->context
->contextSize
;
13354 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13356 ctxt
->context
->doc
= bakd
;
13357 ctxt
->context
->node
= bak
;
13358 ctxt
->context
->proximityPosition
= pp
;
13359 ctxt
->context
->contextSize
= cs
;
13360 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13363 equal
= xmlXPathEqualValues(ctxt
);
13365 equal
= xmlXPathNotEqualValues(ctxt
);
13366 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, equal
));
13369 bakd
= ctxt
->context
->doc
;
13370 bak
= ctxt
->context
->node
;
13371 pp
= ctxt
->context
->proximityPosition
;
13372 cs
= ctxt
->context
->contextSize
;
13373 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13375 ctxt
->context
->doc
= bakd
;
13376 ctxt
->context
->node
= bak
;
13377 ctxt
->context
->proximityPosition
= pp
;
13378 ctxt
->context
->contextSize
= cs
;
13379 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13381 ret
= xmlXPathCompareValues(ctxt
, op
->value
, op
->value2
);
13382 valuePush(ctxt
, xmlXPathCacheNewBoolean(ctxt
->context
, ret
));
13384 case XPATH_OP_PLUS
:
13385 bakd
= ctxt
->context
->doc
;
13386 bak
= ctxt
->context
->node
;
13387 pp
= ctxt
->context
->proximityPosition
;
13388 cs
= ctxt
->context
->contextSize
;
13389 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13391 if (op
->ch2
!= -1) {
13392 ctxt
->context
->doc
= bakd
;
13393 ctxt
->context
->node
= bak
;
13394 ctxt
->context
->proximityPosition
= pp
;
13395 ctxt
->context
->contextSize
= cs
;
13396 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13399 if (op
->value
== 0)
13400 xmlXPathSubValues(ctxt
);
13401 else if (op
->value
== 1)
13402 xmlXPathAddValues(ctxt
);
13403 else if (op
->value
== 2)
13404 xmlXPathValueFlipSign(ctxt
);
13405 else if (op
->value
== 3) {
13407 CHECK_TYPE0(XPATH_NUMBER
);
13410 case XPATH_OP_MULT
:
13411 bakd
= ctxt
->context
->doc
;
13412 bak
= ctxt
->context
->node
;
13413 pp
= ctxt
->context
->proximityPosition
;
13414 cs
= ctxt
->context
->contextSize
;
13415 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13417 ctxt
->context
->doc
= bakd
;
13418 ctxt
->context
->node
= bak
;
13419 ctxt
->context
->proximityPosition
= pp
;
13420 ctxt
->context
->contextSize
= cs
;
13421 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13423 if (op
->value
== 0)
13424 xmlXPathMultValues(ctxt
);
13425 else if (op
->value
== 1)
13426 xmlXPathDivValues(ctxt
);
13427 else if (op
->value
== 2)
13428 xmlXPathModValues(ctxt
);
13430 case XPATH_OP_UNION
:
13431 bakd
= ctxt
->context
->doc
;
13432 bak
= ctxt
->context
->node
;
13433 pp
= ctxt
->context
->proximityPosition
;
13434 cs
= ctxt
->context
->contextSize
;
13435 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13437 ctxt
->context
->doc
= bakd
;
13438 ctxt
->context
->node
= bak
;
13439 ctxt
->context
->proximityPosition
= pp
;
13440 ctxt
->context
->contextSize
= cs
;
13441 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13443 CHECK_TYPE0(XPATH_NODESET
);
13444 arg2
= valuePop(ctxt
);
13446 CHECK_TYPE0(XPATH_NODESET
);
13447 arg1
= valuePop(ctxt
);
13449 if ((arg1
->nodesetval
== NULL
) ||
13450 ((arg2
->nodesetval
!= NULL
) &&
13451 (arg2
->nodesetval
->nodeNr
!= 0)))
13453 arg1
->nodesetval
= xmlXPathNodeSetMerge(arg1
->nodesetval
,
13457 valuePush(ctxt
, arg1
);
13458 xmlXPathReleaseObject(ctxt
->context
, arg2
);
13460 case XPATH_OP_ROOT
:
13461 xmlXPathRoot(ctxt
);
13463 case XPATH_OP_NODE
:
13465 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13468 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13470 valuePush(ctxt
, xmlXPathCacheNewNodeSet(ctxt
->context
,
13471 ctxt
->context
->node
));
13473 case XPATH_OP_RESET
:
13475 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13478 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13480 ctxt
->context
->node
= NULL
;
13482 case XPATH_OP_COLLECT
:{
13486 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13489 total
+= xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 0);
13492 case XPATH_OP_VALUE
:
13494 xmlXPathCacheObjectCopy(ctxt
->context
,
13495 (xmlXPathObjectPtr
) op
->value4
));
13497 case XPATH_OP_VARIABLE
:{
13498 xmlXPathObjectPtr val
;
13502 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13503 if (op
->value5
== NULL
) {
13504 val
= xmlXPathVariableLookup(ctxt
->context
, op
->value4
);
13506 ctxt
->error
= XPATH_UNDEF_VARIABLE_ERROR
;
13509 valuePush(ctxt
, val
);
13511 const xmlChar
*URI
;
13513 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13515 xmlGenericError(xmlGenericErrorContext
,
13516 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13517 (char *) op
->value4
, (char *)op
->value5
);
13518 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13521 val
= xmlXPathVariableLookupNS(ctxt
->context
,
13524 ctxt
->error
= XPATH_UNDEF_VARIABLE_ERROR
;
13527 valuePush(ctxt
, val
);
13531 case XPATH_OP_FUNCTION
:{
13532 xmlXPathFunction func
;
13533 const xmlChar
*oldFunc
, *oldFuncURI
;
13537 frame
= xmlXPathSetFrame(ctxt
);
13538 if (op
->ch1
!= -1) {
13540 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13541 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13542 xmlXPathPopFrame(ctxt
, frame
);
13546 if (ctxt
->valueNr
< ctxt
->valueFrame
+ op
->value
) {
13547 xmlGenericError(xmlGenericErrorContext
,
13548 "xmlXPathCompOpEval: parameter error\n");
13549 ctxt
->error
= XPATH_INVALID_OPERAND
;
13550 xmlXPathPopFrame(ctxt
, frame
);
13553 for (i
= 0; i
< op
->value
; i
++) {
13554 if (ctxt
->valueTab
[(ctxt
->valueNr
- 1) - i
] == NULL
) {
13555 xmlGenericError(xmlGenericErrorContext
,
13556 "xmlXPathCompOpEval: parameter error\n");
13557 ctxt
->error
= XPATH_INVALID_OPERAND
;
13558 xmlXPathPopFrame(ctxt
, frame
);
13562 if (op
->cache
!= NULL
)
13563 XML_CAST_FPTR(func
) = op
->cache
;
13565 const xmlChar
*URI
= NULL
;
13567 if (op
->value5
== NULL
)
13569 xmlXPathFunctionLookup(ctxt
->context
,
13572 URI
= xmlXPathNsLookup(ctxt
->context
, op
->value5
);
13574 xmlGenericError(xmlGenericErrorContext
,
13575 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13576 (char *)op
->value4
, (char *)op
->value5
);
13577 xmlXPathPopFrame(ctxt
, frame
);
13578 ctxt
->error
= XPATH_UNDEF_PREFIX_ERROR
;
13581 func
= xmlXPathFunctionLookupNS(ctxt
->context
,
13584 if (func
== NULL
) {
13585 xmlGenericError(xmlGenericErrorContext
,
13586 "xmlXPathCompOpEval: function %s not found\n",
13587 (char *)op
->value4
);
13588 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR
);
13590 op
->cache
= XML_CAST_FPTR(func
);
13591 op
->cacheURI
= (void *) URI
;
13593 oldFunc
= ctxt
->context
->function
;
13594 oldFuncURI
= ctxt
->context
->functionURI
;
13595 ctxt
->context
->function
= op
->value4
;
13596 ctxt
->context
->functionURI
= op
->cacheURI
;
13597 func(ctxt
, op
->value
);
13598 ctxt
->context
->function
= oldFunc
;
13599 ctxt
->context
->functionURI
= oldFuncURI
;
13600 xmlXPathPopFrame(ctxt
, frame
);
13604 bakd
= ctxt
->context
->doc
;
13605 bak
= ctxt
->context
->node
;
13606 pp
= ctxt
->context
->proximityPosition
;
13607 cs
= ctxt
->context
->contextSize
;
13608 if (op
->ch1
!= -1) {
13609 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13610 ctxt
->context
->contextSize
= cs
;
13611 ctxt
->context
->proximityPosition
= pp
;
13612 ctxt
->context
->node
= bak
;
13613 ctxt
->context
->doc
= bakd
;
13616 if (op
->ch2
!= -1) {
13617 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch2
]);
13618 ctxt
->context
->contextSize
= cs
;
13619 ctxt
->context
->proximityPosition
= pp
;
13620 ctxt
->context
->node
= bak
;
13621 ctxt
->context
->doc
= bakd
;
13625 case XPATH_OP_PREDICATE
:
13626 case XPATH_OP_FILTER
:{
13627 xmlXPathObjectPtr res
;
13628 xmlXPathObjectPtr obj
, tmp
;
13629 xmlNodeSetPtr newset
= NULL
;
13630 xmlNodeSetPtr oldset
;
13631 xmlNodePtr oldnode
;
13636 * Optimization for ()[1] selection i.e. the first elem
13638 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13639 #ifdef XP_OPTIMIZED_FILTER_FIRST
13641 * FILTER TODO: Can we assume that the inner processing
13642 * will result in an ordered list if we have an
13644 * What about an additional field or flag on
13645 * xmlXPathObject like @sorted ? This way we wouln'd need
13646 * to assume anything, so it would be more robust and
13647 * easier to optimize.
13649 ((comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) || /* 18 */
13650 (comp
->steps
[op
->ch1
].op
== XPATH_OP_FILTER
)) && /* 17 */
13652 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13654 (comp
->steps
[op
->ch2
].op
== XPATH_OP_VALUE
)) { /* 12 */
13655 xmlXPathObjectPtr val
;
13657 val
= comp
->steps
[op
->ch2
].value4
;
13658 if ((val
!= NULL
) && (val
->type
== XPATH_NUMBER
) &&
13659 (val
->floatval
== 1.0)) {
13660 xmlNodePtr first
= NULL
;
13663 xmlXPathCompOpEvalFirst(ctxt
,
13664 &comp
->steps
[op
->ch1
],
13668 * The nodeset should be in document order,
13669 * Keep only the first value
13671 if ((ctxt
->value
!= NULL
) &&
13672 (ctxt
->value
->type
== XPATH_NODESET
) &&
13673 (ctxt
->value
->nodesetval
!= NULL
) &&
13674 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13675 ctxt
->value
->nodesetval
->nodeNr
= 1;
13680 * Optimization for ()[last()] selection i.e. the last elem
13682 if ((op
->ch1
!= -1) && (op
->ch2
!= -1) &&
13683 (comp
->steps
[op
->ch1
].op
== XPATH_OP_SORT
) &&
13684 (comp
->steps
[op
->ch2
].op
== XPATH_OP_SORT
)) {
13685 int f
= comp
->steps
[op
->ch2
].ch1
;
13688 (comp
->steps
[f
].op
== XPATH_OP_FUNCTION
) &&
13689 (comp
->steps
[f
].value5
== NULL
) &&
13690 (comp
->steps
[f
].value
== 0) &&
13691 (comp
->steps
[f
].value4
!= NULL
) &&
13693 (comp
->steps
[f
].value4
, BAD_CAST
"last"))) {
13694 xmlNodePtr last
= NULL
;
13697 xmlXPathCompOpEvalLast(ctxt
,
13698 &comp
->steps
[op
->ch1
],
13702 * The nodeset should be in document order,
13703 * Keep only the last value
13705 if ((ctxt
->value
!= NULL
) &&
13706 (ctxt
->value
->type
== XPATH_NODESET
) &&
13707 (ctxt
->value
->nodesetval
!= NULL
) &&
13708 (ctxt
->value
->nodesetval
->nodeTab
!= NULL
) &&
13709 (ctxt
->value
->nodesetval
->nodeNr
> 1)) {
13710 ctxt
->value
->nodesetval
->nodeTab
[0] =
13711 ctxt
->value
->nodesetval
->nodeTab
[ctxt
->
13716 ctxt
->value
->nodesetval
->nodeNr
= 1;
13722 * Process inner predicates first.
13723 * Example "index[parent::book][1]":
13725 * PREDICATE <-- we are here "[1]"
13726 * PREDICATE <-- process "[parent::book]" first
13728 * COLLECT 'parent' 'name' 'node' book
13730 * ELEM Object is a number : 1
13734 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13738 if (ctxt
->value
== NULL
)
13741 oldnode
= ctxt
->context
->node
;
13743 #ifdef LIBXML_XPTR_ENABLED
13745 * Hum are we filtering the result of an XPointer expression
13747 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
13748 xmlLocationSetPtr newlocset
= NULL
;
13749 xmlLocationSetPtr oldlocset
;
13752 * Extract the old locset, and then evaluate the result of the
13753 * expression for all the element in the locset. use it to grow
13756 CHECK_TYPE0(XPATH_LOCATIONSET
);
13757 obj
= valuePop(ctxt
);
13758 oldlocset
= obj
->user
;
13759 ctxt
->context
->node
= NULL
;
13761 if ((oldlocset
== NULL
) || (oldlocset
->locNr
== 0)) {
13762 ctxt
->context
->contextSize
= 0;
13763 ctxt
->context
->proximityPosition
= 0;
13766 xmlXPathCompOpEval(ctxt
,
13767 &comp
->steps
[op
->ch2
]);
13768 res
= valuePop(ctxt
);
13770 xmlXPathReleaseObject(ctxt
->context
, res
);
13772 valuePush(ctxt
, obj
);
13776 newlocset
= xmlXPtrLocationSetCreate(NULL
);
13778 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
13780 * Run the evaluation with a node list made of a
13781 * single item in the nodelocset.
13783 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
13784 ctxt
->context
->contextSize
= oldlocset
->locNr
;
13785 ctxt
->context
->proximityPosition
= i
+ 1;
13786 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13787 ctxt
->context
->node
);
13788 valuePush(ctxt
, tmp
);
13792 xmlXPathCompOpEval(ctxt
,
13793 &comp
->steps
[op
->ch2
]);
13794 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13795 xmlXPathFreeObject(obj
);
13800 * The result of the evaluation need to be tested to
13801 * decided whether the filter succeeded or not
13803 res
= valuePop(ctxt
);
13804 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13805 xmlXPtrLocationSetAdd(newlocset
,
13807 (oldlocset
->locTab
[i
]));
13814 xmlXPathReleaseObject(ctxt
->context
, res
);
13816 if (ctxt
->value
== tmp
) {
13817 res
= valuePop(ctxt
);
13818 xmlXPathReleaseObject(ctxt
->context
, res
);
13821 ctxt
->context
->node
= NULL
;
13825 * The result is used as the new evaluation locset.
13827 xmlXPathReleaseObject(ctxt
->context
, obj
);
13828 ctxt
->context
->node
= NULL
;
13829 ctxt
->context
->contextSize
= -1;
13830 ctxt
->context
->proximityPosition
= -1;
13831 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
13832 ctxt
->context
->node
= oldnode
;
13835 #endif /* LIBXML_XPTR_ENABLED */
13838 * Extract the old set, and then evaluate the result of the
13839 * expression for all the element in the set. use it to grow
13842 CHECK_TYPE0(XPATH_NODESET
);
13843 obj
= valuePop(ctxt
);
13844 oldset
= obj
->nodesetval
;
13846 oldnode
= ctxt
->context
->node
;
13847 oldDoc
= ctxt
->context
->doc
;
13848 ctxt
->context
->node
= NULL
;
13850 if ((oldset
== NULL
) || (oldset
->nodeNr
== 0)) {
13851 ctxt
->context
->contextSize
= 0;
13852 ctxt
->context
->proximityPosition
= 0;
13856 xmlXPathCompOpEval(ctxt,
13857 &comp->steps[op->ch2]);
13859 res = valuePop(ctxt);
13861 xmlXPathFreeObject(res);
13863 valuePush(ctxt
, obj
);
13864 ctxt
->context
->node
= oldnode
;
13869 * Initialize the new set.
13870 * Also set the xpath document in case things like
13871 * key() evaluation are attempted on the predicate
13873 newset
= xmlXPathNodeSetCreate(NULL
);
13876 * "For each node in the node-set to be filtered, the
13877 * PredicateExpr is evaluated with that node as the
13878 * context node, with the number of nodes in the
13879 * node-set as the context size, and with the proximity
13880 * position of the node in the node-set with respect to
13881 * the axis as the context position;"
13882 * @oldset is the node-set" to be filtered.
13885 * "only predicates change the context position and
13886 * context size (see [2.4 Predicates])."
13888 * node-set context pos
13892 * After applying predicate [position() > 1] :
13893 * node-set context pos
13897 * removed the first node in the node-set, then
13898 * the context position of the
13900 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
13902 * Run the evaluation with a node list made of
13903 * a single item in the nodeset.
13905 ctxt
->context
->node
= oldset
->nodeTab
[i
];
13906 if ((oldset
->nodeTab
[i
]->type
!= XML_NAMESPACE_DECL
) &&
13907 (oldset
->nodeTab
[i
]->doc
!= NULL
))
13908 ctxt
->context
->doc
= oldset
->nodeTab
[i
]->doc
;
13910 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
13911 ctxt
->context
->node
);
13913 if (xmlXPathNodeSetAddUnique(tmp
->nodesetval
,
13914 ctxt
->context
->node
) < 0) {
13915 ctxt
->error
= XPATH_MEMORY_ERROR
;
13918 valuePush(ctxt
, tmp
);
13919 ctxt
->context
->contextSize
= oldset
->nodeNr
;
13920 ctxt
->context
->proximityPosition
= i
+ 1;
13922 * Evaluate the predicate against the context node.
13923 * Can/should we optimize position() predicates
13924 * here (e.g. "[1]")?
13928 xmlXPathCompOpEval(ctxt
,
13929 &comp
->steps
[op
->ch2
]);
13930 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
13931 xmlXPathFreeNodeSet(newset
);
13932 xmlXPathFreeObject(obj
);
13937 * The result of the evaluation needs to be tested to
13938 * decide whether the filter succeeded or not
13941 * OPTIMIZE TODO: Can we use
13942 * xmlXPathNodeSetAdd*Unique()* instead?
13944 res
= valuePop(ctxt
);
13945 if (xmlXPathEvaluatePredicateResult(ctxt
, res
)) {
13946 if (xmlXPathNodeSetAdd(newset
, oldset
->nodeTab
[i
])
13948 ctxt
->error
= XPATH_MEMORY_ERROR
;
13955 xmlXPathReleaseObject(ctxt
->context
, res
);
13957 if (ctxt
->value
== tmp
) {
13959 xmlXPathNodeSetClear(tmp
->nodesetval
, 1);
13961 * Don't free the temporary nodeset
13962 * in order to avoid massive recreation inside this
13967 ctxt
->context
->node
= NULL
;
13970 xmlXPathReleaseObject(ctxt
->context
, tmp
);
13972 * The result is used as the new evaluation set.
13974 xmlXPathReleaseObject(ctxt
->context
, obj
);
13975 ctxt
->context
->node
= NULL
;
13976 ctxt
->context
->contextSize
= -1;
13977 ctxt
->context
->proximityPosition
= -1;
13978 /* may want to move this past the '}' later */
13979 ctxt
->context
->doc
= oldDoc
;
13981 xmlXPathCacheWrapNodeSet(ctxt
->context
, newset
));
13983 ctxt
->context
->node
= oldnode
;
13986 case XPATH_OP_SORT
:
13988 total
+= xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
13990 if ((ctxt
->value
!= NULL
) &&
13991 (ctxt
->value
->type
== XPATH_NODESET
) &&
13992 (ctxt
->value
->nodesetval
!= NULL
) &&
13993 (ctxt
->value
->nodesetval
->nodeNr
> 1))
13995 xmlXPathNodeSetSort(ctxt
->value
->nodesetval
);
13998 #ifdef LIBXML_XPTR_ENABLED
13999 case XPATH_OP_RANGETO
:{
14000 xmlXPathObjectPtr range
;
14001 xmlXPathObjectPtr res
, obj
;
14002 xmlXPathObjectPtr tmp
;
14003 xmlLocationSetPtr newlocset
= NULL
;
14004 xmlLocationSetPtr oldlocset
;
14005 xmlNodeSetPtr oldset
;
14010 xmlXPathCompOpEval(ctxt
, &comp
->steps
[op
->ch1
]);
14014 if (ctxt
->value
->type
== XPATH_LOCATIONSET
) {
14016 * Extract the old locset, and then evaluate the result of the
14017 * expression for all the element in the locset. use it to grow
14020 CHECK_TYPE0(XPATH_LOCATIONSET
);
14021 obj
= valuePop(ctxt
);
14022 oldlocset
= obj
->user
;
14024 if ((oldlocset
== NULL
) || (oldlocset
->locNr
== 0)) {
14025 ctxt
->context
->node
= NULL
;
14026 ctxt
->context
->contextSize
= 0;
14027 ctxt
->context
->proximityPosition
= 0;
14028 total
+= xmlXPathCompOpEval(ctxt
,&comp
->steps
[op
->ch2
]);
14029 res
= valuePop(ctxt
);
14031 xmlXPathReleaseObject(ctxt
->context
, res
);
14033 valuePush(ctxt
, obj
);
14037 newlocset
= xmlXPtrLocationSetCreate(NULL
);
14039 for (i
= 0; i
< oldlocset
->locNr
; i
++) {
14041 * Run the evaluation with a node list made of a
14042 * single item in the nodelocset.
14044 ctxt
->context
->node
= oldlocset
->locTab
[i
]->user
;
14045 ctxt
->context
->contextSize
= oldlocset
->locNr
;
14046 ctxt
->context
->proximityPosition
= i
+ 1;
14047 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
14048 ctxt
->context
->node
);
14049 valuePush(ctxt
, tmp
);
14053 xmlXPathCompOpEval(ctxt
,
14054 &comp
->steps
[op
->ch2
]);
14055 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14056 xmlXPathFreeObject(obj
);
14060 res
= valuePop(ctxt
);
14061 if (res
->type
== XPATH_LOCATIONSET
) {
14062 xmlLocationSetPtr rloc
=
14063 (xmlLocationSetPtr
)res
->user
;
14064 for (j
=0; j
<rloc
->locNr
; j
++) {
14065 range
= xmlXPtrNewRange(
14066 oldlocset
->locTab
[i
]->user
,
14067 oldlocset
->locTab
[i
]->index
,
14068 rloc
->locTab
[j
]->user2
,
14069 rloc
->locTab
[j
]->index2
);
14070 if (range
!= NULL
) {
14071 xmlXPtrLocationSetAdd(newlocset
, range
);
14075 range
= xmlXPtrNewRangeNodeObject(
14076 (xmlNodePtr
)oldlocset
->locTab
[i
]->user
, res
);
14077 if (range
!= NULL
) {
14078 xmlXPtrLocationSetAdd(newlocset
,range
);
14086 xmlXPathReleaseObject(ctxt
->context
, res
);
14088 if (ctxt
->value
== tmp
) {
14089 res
= valuePop(ctxt
);
14090 xmlXPathReleaseObject(ctxt
->context
, res
);
14093 ctxt
->context
->node
= NULL
;
14095 } else { /* Not a location set */
14096 CHECK_TYPE0(XPATH_NODESET
);
14097 obj
= valuePop(ctxt
);
14098 oldset
= obj
->nodesetval
;
14099 ctxt
->context
->node
= NULL
;
14101 newlocset
= xmlXPtrLocationSetCreate(NULL
);
14103 if (oldset
!= NULL
) {
14104 for (i
= 0; i
< oldset
->nodeNr
; i
++) {
14106 * Run the evaluation with a node list made of a single item
14109 ctxt
->context
->node
= oldset
->nodeTab
[i
];
14111 * OPTIMIZE TODO: Avoid recreation for every iteration.
14113 tmp
= xmlXPathCacheNewNodeSet(ctxt
->context
,
14114 ctxt
->context
->node
);
14115 valuePush(ctxt
, tmp
);
14119 xmlXPathCompOpEval(ctxt
,
14120 &comp
->steps
[op
->ch2
]);
14121 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
14122 xmlXPathFreeObject(obj
);
14126 res
= valuePop(ctxt
);
14128 xmlXPtrNewRangeNodeObject(oldset
->nodeTab
[i
],
14130 if (range
!= NULL
) {
14131 xmlXPtrLocationSetAdd(newlocset
, range
);
14138 xmlXPathReleaseObject(ctxt
->context
, res
);
14140 if (ctxt
->value
== tmp
) {
14141 res
= valuePop(ctxt
);
14142 xmlXPathReleaseObject(ctxt
->context
, res
);
14145 ctxt
->context
->node
= NULL
;
14151 * The result is used as the new evaluation set.
14153 xmlXPathReleaseObject(ctxt
->context
, obj
);
14154 ctxt
->context
->node
= NULL
;
14155 ctxt
->context
->contextSize
= -1;
14156 ctxt
->context
->proximityPosition
= -1;
14157 valuePush(ctxt
, xmlXPtrWrapLocationSet(newlocset
));
14160 #endif /* LIBXML_XPTR_ENABLED */
14162 xmlGenericError(xmlGenericErrorContext
,
14163 "XPath: unknown precompiled operation %d\n", op
->op
);
14164 ctxt
->error
= XPATH_INVALID_OPERAND
;
14169 * xmlXPathCompOpEvalToBoolean:
14170 * @ctxt: the XPath parser context
14172 * Evaluates if the expression evaluates to true.
14174 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14177 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt
,
14178 xmlXPathStepOpPtr op
,
14181 xmlXPathObjectPtr resObj
= NULL
;
14184 /* comp = ctxt->comp; */
14188 case XPATH_OP_VALUE
:
14189 resObj
= (xmlXPathObjectPtr
) op
->value4
;
14191 return(xmlXPathEvaluatePredicateResult(ctxt
, resObj
));
14192 return(xmlXPathCastToBoolean(resObj
));
14193 case XPATH_OP_SORT
:
14195 * We don't need sorting for boolean results. Skip this one.
14197 if (op
->ch1
!= -1) {
14198 op
= &ctxt
->comp
->steps
[op
->ch1
];
14202 case XPATH_OP_COLLECT
:
14206 xmlXPathCompOpEval(ctxt
, &ctxt
->comp
->steps
[op
->ch1
]);
14207 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14210 xmlXPathNodeCollectAndTest(ctxt
, op
, NULL
, NULL
, 1);
14211 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14214 resObj
= valuePop(ctxt
);
14215 if (resObj
== NULL
)
14220 * Fallback to call xmlXPathCompOpEval().
14222 xmlXPathCompOpEval(ctxt
, op
);
14223 if (ctxt
->error
!= XPATH_EXPRESSION_OK
)
14226 resObj
= valuePop(ctxt
);
14227 if (resObj
== NULL
)
14235 if (resObj
->type
== XPATH_BOOLEAN
) {
14236 res
= resObj
->boolval
;
14237 } else if (isPredicate
) {
14239 * For predicates a result of type "number" is handled
14242 * "If the result is a number, the result will be converted
14243 * to true if the number is equal to the context position
14244 * and will be converted to false otherwise;"
14246 res
= xmlXPathEvaluatePredicateResult(ctxt
, resObj
);
14248 res
= xmlXPathCastToBoolean(resObj
);
14250 xmlXPathReleaseObject(ctxt
->context
, resObj
);
14257 #ifdef XPATH_STREAMING
14259 * xmlXPathRunStreamEval:
14260 * @ctxt: the XPath parser context with the compiled expression
14262 * Evaluate the Precompiled Streamable XPath expression in the given context.
14265 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt
, xmlPatternPtr comp
,
14266 xmlXPathObjectPtr
*resultSeq
, int toBool
)
14268 int max_depth
, min_depth
;
14271 int eval_all_nodes
;
14272 xmlNodePtr cur
= NULL
, limit
= NULL
;
14273 xmlStreamCtxtPtr patstream
= NULL
;
14277 if ((ctxt
== NULL
) || (comp
== NULL
))
14279 max_depth
= xmlPatternMaxDepth(comp
);
14280 if (max_depth
== -1)
14282 if (max_depth
== -2)
14284 min_depth
= xmlPatternMinDepth(comp
);
14285 if (min_depth
== -1)
14287 from_root
= xmlPatternFromRoot(comp
);
14291 printf("stream eval: depth %d from root %d\n", max_depth
, from_root
);
14295 if (resultSeq
== NULL
)
14297 *resultSeq
= xmlXPathCacheNewNodeSet(ctxt
, NULL
);
14298 if (*resultSeq
== NULL
)
14303 * handle the special cases of "/" amd "." being matched
14305 if (min_depth
== 0) {
14310 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
,
14311 (xmlNodePtr
) ctxt
->doc
);
14313 /* Select "self::node()" */
14316 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, ctxt
->node
);
14319 if (max_depth
== 0) {
14324 cur
= (xmlNodePtr
)ctxt
->doc
;
14325 } else if (ctxt
->node
!= NULL
) {
14326 switch (ctxt
->node
->type
) {
14327 case XML_ELEMENT_NODE
:
14328 case XML_DOCUMENT_NODE
:
14329 case XML_DOCUMENT_FRAG_NODE
:
14330 case XML_HTML_DOCUMENT_NODE
:
14331 #ifdef LIBXML_DOCB_ENABLED
14332 case XML_DOCB_DOCUMENT_NODE
:
14336 case XML_ATTRIBUTE_NODE
:
14337 case XML_TEXT_NODE
:
14338 case XML_CDATA_SECTION_NODE
:
14339 case XML_ENTITY_REF_NODE
:
14340 case XML_ENTITY_NODE
:
14342 case XML_COMMENT_NODE
:
14343 case XML_NOTATION_NODE
:
14345 case XML_DOCUMENT_TYPE_NODE
:
14346 case XML_ELEMENT_DECL
:
14347 case XML_ATTRIBUTE_DECL
:
14348 case XML_ENTITY_DECL
:
14349 case XML_NAMESPACE_DECL
:
14350 case XML_XINCLUDE_START
:
14351 case XML_XINCLUDE_END
:
14360 patstream
= xmlPatternGetStreamCtxt(comp
);
14361 if (patstream
== NULL
) {
14363 * QUESTION TODO: Is this an error?
14368 eval_all_nodes
= xmlStreamWantsAnyNode(patstream
);
14371 ret
= xmlStreamPush(patstream
, NULL
, NULL
);
14373 } else if (ret
== 1) {
14376 xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
);
14380 goto scan_children
;
14385 switch (cur
->type
) {
14386 case XML_ELEMENT_NODE
:
14387 case XML_TEXT_NODE
:
14388 case XML_CDATA_SECTION_NODE
:
14389 case XML_COMMENT_NODE
:
14391 if (cur
->type
== XML_ELEMENT_NODE
) {
14392 ret
= xmlStreamPush(patstream
, cur
->name
,
14393 (cur
->ns
? cur
->ns
->href
: NULL
));
14394 } else if (eval_all_nodes
)
14395 ret
= xmlStreamPushNode(patstream
, NULL
, NULL
, cur
->type
);
14401 } else if (ret
== 1) {
14404 if (xmlXPathNodeSetAddUnique((*resultSeq
)->nodesetval
, cur
)
14406 ctxt
->lastError
.domain
= XML_FROM_XPATH
;
14407 ctxt
->lastError
.code
= XML_ERR_NO_MEMORY
;
14410 if ((cur
->children
== NULL
) || (depth
>= max_depth
)) {
14411 ret
= xmlStreamPop(patstream
);
14412 while (cur
->next
!= NULL
) {
14414 if ((cur
->type
!= XML_ENTITY_DECL
) &&
14415 (cur
->type
!= XML_DTD_NODE
))
14424 if (cur
->type
== XML_NAMESPACE_DECL
) break;
14425 if ((cur
->children
!= NULL
) && (depth
< max_depth
)) {
14427 * Do not descend on entities declarations
14429 if (cur
->children
->type
!= XML_ENTITY_DECL
) {
14430 cur
= cur
->children
;
14435 if (cur
->type
!= XML_DTD_NODE
)
14443 while (cur
->next
!= NULL
) {
14445 if ((cur
->type
!= XML_ENTITY_DECL
) &&
14446 (cur
->type
!= XML_DTD_NODE
))
14453 if ((cur
== NULL
) || (cur
== limit
))
14455 if (cur
->type
== XML_ELEMENT_NODE
) {
14456 ret
= xmlStreamPop(patstream
);
14457 } else if ((eval_all_nodes
) &&
14458 ((cur
->type
== XML_TEXT_NODE
) ||
14459 (cur
->type
== XML_CDATA_SECTION_NODE
) ||
14460 (cur
->type
== XML_COMMENT_NODE
) ||
14461 (cur
->type
== XML_PI_NODE
)))
14463 ret
= xmlStreamPop(patstream
);
14465 if (cur
->next
!= NULL
) {
14469 } while (cur
!= NULL
);
14471 } while ((cur
!= NULL
) && (depth
>= 0));
14476 printf("stream eval: checked %d nodes selected %d\n",
14477 nb_nodes
, retObj
->nodesetval
->nodeNr
);
14481 xmlFreeStreamCtxt(patstream
);
14486 xmlFreeStreamCtxt(patstream
);
14489 #endif /* XPATH_STREAMING */
14493 * @ctxt: the XPath parser context with the compiled expression
14494 * @toBool: evaluate to a boolean result
14496 * Evaluate the Precompiled XPath expression in the given context.
14499 xmlXPathRunEval(xmlXPathParserContextPtr ctxt
, int toBool
)
14501 xmlXPathCompExprPtr comp
;
14503 if ((ctxt
== NULL
) || (ctxt
->comp
== NULL
))
14506 if (ctxt
->valueTab
== NULL
) {
14507 /* Allocate the value stack */
14508 ctxt
->valueTab
= (xmlXPathObjectPtr
*)
14509 xmlMalloc(10 * sizeof(xmlXPathObjectPtr
));
14510 if (ctxt
->valueTab
== NULL
) {
14511 xmlXPathPErrMemory(ctxt
, "creating evaluation context\n");
14515 ctxt
->valueMax
= 10;
14516 ctxt
->value
= NULL
;
14517 ctxt
->valueFrame
= 0;
14519 #ifdef XPATH_STREAMING
14520 if (ctxt
->comp
->stream
) {
14525 * Evaluation to boolean result.
14527 res
= xmlXPathRunStreamEval(ctxt
->context
,
14528 ctxt
->comp
->stream
, NULL
, 1);
14532 xmlXPathObjectPtr resObj
= NULL
;
14535 * Evaluation to a sequence.
14537 res
= xmlXPathRunStreamEval(ctxt
->context
,
14538 ctxt
->comp
->stream
, &resObj
, 0);
14540 if ((res
!= -1) && (resObj
!= NULL
)) {
14541 valuePush(ctxt
, resObj
);
14544 if (resObj
!= NULL
)
14545 xmlXPathReleaseObject(ctxt
->context
, resObj
);
14548 * QUESTION TODO: This falls back to normal XPath evaluation
14549 * if res == -1. Is this intended?
14554 if (comp
->last
< 0) {
14555 xmlGenericError(xmlGenericErrorContext
,
14556 "xmlXPathRunEval: last is less than zero\n");
14560 return(xmlXPathCompOpEvalToBoolean(ctxt
,
14561 &comp
->steps
[comp
->last
], 0));
14563 xmlXPathCompOpEval(ctxt
, &comp
->steps
[comp
->last
]);
14568 /************************************************************************
14570 * Public interfaces *
14572 ************************************************************************/
14575 * xmlXPathEvalPredicate:
14576 * @ctxt: the XPath context
14577 * @res: the Predicate Expression evaluation result
14579 * Evaluate a predicate result for the current node.
14580 * A PredicateExpr is evaluated by evaluating the Expr and converting
14581 * the result to a boolean. If the result is a number, the result will
14582 * be converted to true if the number is equal to the position of the
14583 * context node in the context node list (as returned by the position
14584 * function) and will be converted to false otherwise; if the result
14585 * is not a number, then the result will be converted as if by a call
14586 * to the boolean function.
14588 * Returns 1 if predicate is true, 0 otherwise
14591 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt
, xmlXPathObjectPtr res
) {
14592 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14593 switch (res
->type
) {
14594 case XPATH_BOOLEAN
:
14595 return(res
->boolval
);
14597 return(res
->floatval
== ctxt
->proximityPosition
);
14598 case XPATH_NODESET
:
14599 case XPATH_XSLT_TREE
:
14600 if (res
->nodesetval
== NULL
)
14602 return(res
->nodesetval
->nodeNr
!= 0);
14604 return((res
->stringval
!= NULL
) &&
14605 (xmlStrlen(res
->stringval
) != 0));
14613 * xmlXPathEvaluatePredicateResult:
14614 * @ctxt: the XPath Parser context
14615 * @res: the Predicate Expression evaluation result
14617 * Evaluate a predicate result for the current node.
14618 * A PredicateExpr is evaluated by evaluating the Expr and converting
14619 * the result to a boolean. If the result is a number, the result will
14620 * be converted to true if the number is equal to the position of the
14621 * context node in the context node list (as returned by the position
14622 * function) and will be converted to false otherwise; if the result
14623 * is not a number, then the result will be converted as if by a call
14624 * to the boolean function.
14626 * Returns 1 if predicate is true, 0 otherwise
14629 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt
,
14630 xmlXPathObjectPtr res
) {
14631 if ((ctxt
== NULL
) || (res
== NULL
)) return(0);
14632 switch (res
->type
) {
14633 case XPATH_BOOLEAN
:
14634 return(res
->boolval
);
14636 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14637 return((res
->floatval
== ctxt
->context
->proximityPosition
) &&
14638 (!xmlXPathIsNaN(res
->floatval
))); /* MSC pbm Mark Vakoc !*/
14640 return(res
->floatval
== ctxt
->context
->proximityPosition
);
14642 case XPATH_NODESET
:
14643 case XPATH_XSLT_TREE
:
14644 if (res
->nodesetval
== NULL
)
14646 return(res
->nodesetval
->nodeNr
!= 0);
14648 return((res
->stringval
!= NULL
) && (res
->stringval
[0] != 0));
14649 #ifdef LIBXML_XPTR_ENABLED
14650 case XPATH_LOCATIONSET
:{
14651 xmlLocationSetPtr ptr
= res
->user
;
14654 return (ptr
->locNr
!= 0);
14663 #ifdef XPATH_STREAMING
14665 * xmlXPathTryStreamCompile:
14666 * @ctxt: an XPath context
14667 * @str: the XPath expression
14669 * Try to compile the XPath expression as a streamable subset.
14671 * Returns the compiled expression or NULL if failed to compile.
14673 static xmlXPathCompExprPtr
14674 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14676 * Optimization: use streaming patterns when the XPath expression can
14677 * be compiled to a stream lookup
14679 xmlPatternPtr stream
;
14680 xmlXPathCompExprPtr comp
;
14681 xmlDictPtr dict
= NULL
;
14682 const xmlChar
**namespaces
= NULL
;
14686 if ((!xmlStrchr(str
, '[')) && (!xmlStrchr(str
, '(')) &&
14687 (!xmlStrchr(str
, '@'))) {
14688 const xmlChar
*tmp
;
14691 * We don't try to handle expressions using the verbose axis
14692 * specifiers ("::"), just the simplied form at this point.
14693 * Additionally, if there is no list of namespaces available and
14694 * there's a ":" in the expression, indicating a prefixed QName,
14695 * then we won't try to compile either. xmlPatterncompile() needs
14696 * to have a list of namespaces at compilation time in order to
14697 * compile prefixed name tests.
14699 tmp
= xmlStrchr(str
, ':');
14700 if ((tmp
!= NULL
) &&
14701 ((ctxt
== NULL
) || (ctxt
->nsNr
== 0) || (tmp
[1] == ':')))
14704 if (ctxt
!= NULL
) {
14706 if (ctxt
->nsNr
> 0) {
14707 namespaces
= xmlMalloc(2 * (ctxt
->nsNr
+ 1) * sizeof(xmlChar
*));
14708 if (namespaces
== NULL
) {
14709 xmlXPathErrMemory(ctxt
, "allocating namespaces array\n");
14712 for (i
= 0, j
= 0; (j
< ctxt
->nsNr
); j
++) {
14713 ns
= ctxt
->namespaces
[j
];
14714 namespaces
[i
++] = ns
->href
;
14715 namespaces
[i
++] = ns
->prefix
;
14717 namespaces
[i
++] = NULL
;
14718 namespaces
[i
] = NULL
;
14722 stream
= xmlPatterncompile(str
, dict
, XML_PATTERN_XPATH
,
14724 if (namespaces
!= NULL
) {
14725 xmlFree((xmlChar
**)namespaces
);
14727 if ((stream
!= NULL
) && (xmlPatternStreamable(stream
) == 1)) {
14728 comp
= xmlXPathNewCompExpr();
14729 if (comp
== NULL
) {
14730 xmlXPathErrMemory(ctxt
, "allocating streamable expression\n");
14733 comp
->stream
= stream
;
14736 xmlDictReference(comp
->dict
);
14739 xmlFreePattern(stream
);
14743 #endif /* XPATH_STREAMING */
14746 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp
, xmlXPathStepOpPtr op
)
14749 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14750 * internal representation.
14753 if ((op
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14755 (op
->ch2
== -1 /* no predicate */))
14757 xmlXPathStepOpPtr prevop
= &comp
->steps
[op
->ch1
];
14759 if ((prevop
->op
== XPATH_OP_COLLECT
/* 11 */) &&
14760 ((xmlXPathAxisVal
) prevop
->value
==
14761 AXIS_DESCENDANT_OR_SELF
) &&
14762 (prevop
->ch2
== -1) &&
14763 ((xmlXPathTestVal
) prevop
->value2
== NODE_TEST_TYPE
) &&
14764 ((xmlXPathTypeVal
) prevop
->value3
== NODE_TYPE_NODE
))
14767 * This is a "descendant-or-self::node()" without predicates.
14768 * Try to eliminate it.
14771 switch ((xmlXPathAxisVal
) op
->value
) {
14773 case AXIS_DESCENDANT
:
14775 * Convert "descendant-or-self::node()/child::" or
14776 * "descendant-or-self::node()/descendant::" to
14779 op
->ch1
= prevop
->ch1
;
14780 op
->value
= AXIS_DESCENDANT
;
14783 case AXIS_DESCENDANT_OR_SELF
:
14785 * Convert "descendant-or-self::node()/self::" or
14786 * "descendant-or-self::node()/descendant-or-self::" to
14787 * to "descendant-or-self::"
14789 op
->ch1
= prevop
->ch1
;
14790 op
->value
= AXIS_DESCENDANT_OR_SELF
;
14798 /* OP_VALUE has invalid ch1. */
14799 if (op
->op
== XPATH_OP_VALUE
)
14804 xmlXPathOptimizeExpression(comp
, &comp
->steps
[op
->ch1
]);
14806 xmlXPathOptimizeExpression(comp
, &comp
->steps
[op
->ch2
]);
14810 * xmlXPathCtxtCompile:
14811 * @ctxt: an XPath context
14812 * @str: the XPath expression
14814 * Compile an XPath expression
14816 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14817 * the caller has to free the object.
14819 xmlXPathCompExprPtr
14820 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt
, const xmlChar
*str
) {
14821 xmlXPathParserContextPtr pctxt
;
14822 xmlXPathCompExprPtr comp
;
14824 #ifdef XPATH_STREAMING
14825 comp
= xmlXPathTryStreamCompile(ctxt
, str
);
14832 pctxt
= xmlXPathNewParserContext(str
, ctxt
);
14835 xmlXPathCompileExpr(pctxt
, 1);
14837 if( pctxt
->error
!= XPATH_EXPRESSION_OK
)
14839 xmlXPathFreeParserContext(pctxt
);
14843 if (*pctxt
->cur
!= 0) {
14845 * aleksey: in some cases this line prints *second* error message
14846 * (see bug #78858) and probably this should be fixed.
14847 * However, we are not sure that all error messages are printed
14848 * out in other places. It's not critical so we leave it as-is for now
14850 xmlXPatherror(pctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
14853 comp
= pctxt
->comp
;
14854 pctxt
->comp
= NULL
;
14856 xmlXPathFreeParserContext(pctxt
);
14858 if (comp
!= NULL
) {
14859 comp
->expr
= xmlStrdup(str
);
14860 #ifdef DEBUG_EVAL_COUNTS
14861 comp
->string
= xmlStrdup(str
);
14864 if ((comp
->nbStep
> 1) && (comp
->last
>= 0)) {
14865 xmlXPathOptimizeExpression(comp
, &comp
->steps
[comp
->last
]);
14873 * @str: the XPath expression
14875 * Compile an XPath expression
14877 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14878 * the caller has to free the object.
14880 xmlXPathCompExprPtr
14881 xmlXPathCompile(const xmlChar
*str
) {
14882 return(xmlXPathCtxtCompile(NULL
, str
));
14886 * xmlXPathCompiledEvalInternal:
14887 * @comp: the compiled XPath expression
14888 * @ctxt: the XPath context
14889 * @resObj: the resulting XPath object or NULL
14890 * @toBool: 1 if only a boolean result is requested
14892 * Evaluate the Precompiled XPath expression in the given context.
14893 * The caller has to free @resObj.
14895 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14896 * the caller has to free the object.
14899 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp
,
14900 xmlXPathContextPtr ctxt
,
14901 xmlXPathObjectPtr
*resObj
,
14904 xmlXPathParserContextPtr pctxt
;
14905 #ifndef LIBXML_THREAD_ENABLED
14906 static int reentance
= 0;
14910 CHECK_CTXT_NEG(ctxt
)
14916 #ifndef LIBXML_THREAD_ENABLED
14919 xmlXPathDisableOptimizer
= 1;
14922 #ifdef DEBUG_EVAL_COUNTS
14924 if ((comp
->string
!= NULL
) && (comp
->nb
> 100)) {
14925 fprintf(stderr
, "100 x %s\n", comp
->string
);
14929 pctxt
= xmlXPathCompParserContext(comp
, ctxt
);
14930 res
= xmlXPathRunEval(pctxt
, toBool
);
14933 if (pctxt
->value
== NULL
) {
14934 xmlGenericError(xmlGenericErrorContext
,
14935 "xmlXPathCompiledEval: evaluation failed\n");
14938 *resObj
= valuePop(pctxt
);
14943 * Pop all remaining objects from the stack.
14945 if (pctxt
->valueNr
> 0) {
14946 xmlXPathObjectPtr tmp
;
14950 tmp
= valuePop(pctxt
);
14953 xmlXPathReleaseObject(ctxt
, tmp
);
14955 } while (tmp
!= NULL
);
14956 if ((stack
!= 0) &&
14957 ((toBool
) || ((resObj
) && (*resObj
))))
14959 xmlGenericError(xmlGenericErrorContext
,
14960 "xmlXPathCompiledEval: %d objects left on the stack.\n",
14965 if ((pctxt
->error
!= XPATH_EXPRESSION_OK
) && (resObj
) && (*resObj
)) {
14966 xmlXPathFreeObject(*resObj
);
14969 pctxt
->comp
= NULL
;
14970 xmlXPathFreeParserContext(pctxt
);
14971 #ifndef LIBXML_THREAD_ENABLED
14979 * xmlXPathCompiledEval:
14980 * @comp: the compiled XPath expression
14981 * @ctx: the XPath context
14983 * Evaluate the Precompiled XPath expression in the given context.
14985 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14986 * the caller has to free the object.
14989 xmlXPathCompiledEval(xmlXPathCompExprPtr comp
, xmlXPathContextPtr ctx
)
14991 xmlXPathObjectPtr res
= NULL
;
14993 xmlXPathCompiledEvalInternal(comp
, ctx
, &res
, 0);
14998 * xmlXPathCompiledEvalToBoolean:
14999 * @comp: the compiled XPath expression
15000 * @ctxt: the XPath context
15002 * Applies the XPath boolean() function on the result of the given
15003 * compiled expression.
15005 * Returns 1 if the expression evaluated to true, 0 if to false and
15006 * -1 in API and internal errors.
15009 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp
,
15010 xmlXPathContextPtr ctxt
)
15012 return(xmlXPathCompiledEvalInternal(comp
, ctxt
, NULL
, 1));
15016 * xmlXPathEvalExpr:
15017 * @ctxt: the XPath Parser context
15019 * Parse and evaluate an XPath expression in the given context,
15020 * then push the result on the context stack
15023 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt
) {
15024 #ifdef XPATH_STREAMING
15025 xmlXPathCompExprPtr comp
;
15028 if (ctxt
== NULL
) return;
15030 #ifdef XPATH_STREAMING
15031 comp
= xmlXPathTryStreamCompile(ctxt
->context
, ctxt
->base
);
15032 if (comp
!= NULL
) {
15033 if (ctxt
->comp
!= NULL
)
15034 xmlXPathFreeCompExpr(ctxt
->comp
);
15036 if (ctxt
->cur
!= NULL
)
15037 while (*ctxt
->cur
!= 0) ctxt
->cur
++;
15041 xmlXPathCompileExpr(ctxt
, 1);
15042 if ((ctxt
->error
== XPATH_EXPRESSION_OK
) &&
15043 (ctxt
->comp
!= NULL
) &&
15044 (ctxt
->comp
->nbStep
> 1) &&
15045 (ctxt
->comp
->last
>= 0))
15047 xmlXPathOptimizeExpression(ctxt
->comp
,
15048 &ctxt
->comp
->steps
[ctxt
->comp
->last
]);
15052 xmlXPathRunEval(ctxt
, 0);
15057 * @str: the XPath expression
15058 * @ctx: the XPath context
15060 * Evaluate the XPath Location Path in the given context.
15062 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15063 * the caller has to free the object.
15066 xmlXPathEval(const xmlChar
*str
, xmlXPathContextPtr ctx
) {
15067 xmlXPathParserContextPtr ctxt
;
15068 xmlXPathObjectPtr res
, tmp
, init
= NULL
;
15075 ctxt
= xmlXPathNewParserContext(str
, ctx
);
15078 xmlXPathEvalExpr(ctxt
);
15080 if (ctxt
->value
== NULL
) {
15081 xmlGenericError(xmlGenericErrorContext
,
15082 "xmlXPathEval: evaluation failed\n");
15084 } else if ((*ctxt
->cur
!= 0) && (ctxt
->comp
!= NULL
)
15085 #ifdef XPATH_STREAMING
15086 && (ctxt
->comp
->stream
== NULL
)
15089 xmlXPatherror(ctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
15092 res
= valuePop(ctxt
);
15096 tmp
= valuePop(ctxt
);
15100 xmlXPathReleaseObject(ctx
, tmp
);
15102 } while (tmp
!= NULL
);
15103 if ((stack
!= 0) && (res
!= NULL
)) {
15104 xmlGenericError(xmlGenericErrorContext
,
15105 "xmlXPathEval: %d object left on the stack\n",
15108 if (ctxt
->error
!= XPATH_EXPRESSION_OK
) {
15109 xmlXPathFreeObject(res
);
15113 xmlXPathFreeParserContext(ctxt
);
15118 * xmlXPathSetContextNode:
15119 * @node: the node to to use as the context node
15120 * @ctx: the XPath context
15122 * Sets 'node' as the context node. The node must be in the same
15123 * document as that associated with the context.
15125 * Returns -1 in case of error or 0 if successful
15128 xmlXPathSetContextNode(xmlNodePtr node
, xmlXPathContextPtr ctx
) {
15129 if ((node
== NULL
) || (ctx
== NULL
))
15132 if (node
->doc
== ctx
->doc
) {
15140 * xmlXPathNodeEval:
15141 * @node: the node to to use as the context node
15142 * @str: the XPath expression
15143 * @ctx: the XPath context
15145 * Evaluate the XPath Location Path in the given context. The node 'node'
15146 * is set as the context node. The context node is not restored.
15148 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15149 * the caller has to free the object.
15152 xmlXPathNodeEval(xmlNodePtr node
, const xmlChar
*str
, xmlXPathContextPtr ctx
) {
15155 if (xmlXPathSetContextNode(node
, ctx
) < 0)
15157 return(xmlXPathEval(str
, ctx
));
15161 * xmlXPathEvalExpression:
15162 * @str: the XPath expression
15163 * @ctxt: the XPath context
15165 * Evaluate the XPath expression in the given context.
15167 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15168 * the caller has to free the object.
15171 xmlXPathEvalExpression(const xmlChar
*str
, xmlXPathContextPtr ctxt
) {
15172 xmlXPathParserContextPtr pctxt
;
15173 xmlXPathObjectPtr res
, tmp
;
15180 pctxt
= xmlXPathNewParserContext(str
, ctxt
);
15183 xmlXPathEvalExpr(pctxt
);
15185 if ((*pctxt
->cur
!= 0) || (pctxt
->error
!= XPATH_EXPRESSION_OK
)) {
15186 xmlXPatherror(pctxt
, __FILE__
, __LINE__
, XPATH_EXPR_ERROR
);
15189 res
= valuePop(pctxt
);
15192 tmp
= valuePop(pctxt
);
15194 xmlXPathReleaseObject(ctxt
, tmp
);
15197 } while (tmp
!= NULL
);
15198 if ((stack
!= 0) && (res
!= NULL
)) {
15199 xmlGenericError(xmlGenericErrorContext
,
15200 "xmlXPathEvalExpression: %d object left on the stack\n",
15203 xmlXPathFreeParserContext(pctxt
);
15207 /************************************************************************
15209 * Extra functions not pertaining to the XPath spec *
15211 ************************************************************************/
15213 * xmlXPathEscapeUriFunction:
15214 * @ctxt: the XPath Parser context
15215 * @nargs: the number of arguments
15217 * Implement the escape-uri() XPath function
15218 * string escape-uri(string $str, bool $escape-reserved)
15220 * This function applies the URI escaping rules defined in section 2 of [RFC
15221 * 2396] to the string supplied as $uri-part, which typically represents all
15222 * or part of a URI. The effect of the function is to replace any special
15223 * character in the string by an escape sequence of the form %xx%yy...,
15224 * where xxyy... is the hexadecimal representation of the octets used to
15225 * represent the character in UTF-8.
15227 * The set of characters that are escaped depends on the setting of the
15228 * boolean argument $escape-reserved.
15230 * If $escape-reserved is true, all characters are escaped other than lower
15231 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15232 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15233 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15234 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15237 * If $escape-reserved is false, the behavior differs in that characters
15238 * referred to in [RFC 2396] as reserved characters are not escaped. These
15239 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15241 * [RFC 2396] does not define whether escaped URIs should use lower case or
15242 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15243 * compared using string comparison functions, this function must always use
15244 * the upper-case letters A-F.
15246 * Generally, $escape-reserved should be set to true when escaping a string
15247 * that is to form a single part of a URI, and to false when escaping an
15248 * entire URI or URI reference.
15250 * In the case of non-ascii characters, the string is encoded according to
15251 * utf-8 and then converted according to RFC 2396.
15254 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15255 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15256 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15257 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15261 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt
, int nargs
) {
15262 xmlXPathObjectPtr str
;
15263 int escape_reserved
;
15270 escape_reserved
= xmlXPathPopBoolean(ctxt
);
15273 str
= valuePop(ctxt
);
15275 target
= xmlBufCreate();
15281 for (cptr
= str
->stringval
; *cptr
; cptr
++) {
15282 if ((*cptr
>= 'A' && *cptr
<= 'Z') ||
15283 (*cptr
>= 'a' && *cptr
<= 'z') ||
15284 (*cptr
>= '0' && *cptr
<= '9') ||
15285 *cptr
== '-' || *cptr
== '_' || *cptr
== '.' ||
15286 *cptr
== '!' || *cptr
== '~' || *cptr
== '*' ||
15287 *cptr
== '\''|| *cptr
== '(' || *cptr
== ')' ||
15289 ((cptr
[1] >= 'A' && cptr
[1] <= 'F') ||
15290 (cptr
[1] >= 'a' && cptr
[1] <= 'f') ||
15291 (cptr
[1] >= '0' && cptr
[1] <= '9')) &&
15292 ((cptr
[2] >= 'A' && cptr
[2] <= 'F') ||
15293 (cptr
[2] >= 'a' && cptr
[2] <= 'f') ||
15294 (cptr
[2] >= '0' && cptr
[2] <= '9'))) ||
15295 (!escape_reserved
&&
15296 (*cptr
== ';' || *cptr
== '/' || *cptr
== '?' ||
15297 *cptr
== ':' || *cptr
== '@' || *cptr
== '&' ||
15298 *cptr
== '=' || *cptr
== '+' || *cptr
== '$' ||
15300 xmlBufAdd(target
, cptr
, 1);
15302 if ((*cptr
>> 4) < 10)
15303 escape
[1] = '0' + (*cptr
>> 4);
15305 escape
[1] = 'A' - 10 + (*cptr
>> 4);
15306 if ((*cptr
& 0xF) < 10)
15307 escape
[2] = '0' + (*cptr
& 0xF);
15309 escape
[2] = 'A' - 10 + (*cptr
& 0xF);
15311 xmlBufAdd(target
, &escape
[0], 3);
15315 valuePush(ctxt
, xmlXPathCacheNewString(ctxt
->context
,
15316 xmlBufContent(target
)));
15317 xmlBufFree(target
);
15318 xmlXPathReleaseObject(ctxt
->context
, str
);
15322 * xmlXPathRegisterAllFunctions:
15323 * @ctxt: the XPath context
15325 * Registers all default XPath functions in this context
15328 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt
)
15330 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"boolean",
15331 xmlXPathBooleanFunction
);
15332 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"ceiling",
15333 xmlXPathCeilingFunction
);
15334 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"count",
15335 xmlXPathCountFunction
);
15336 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"concat",
15337 xmlXPathConcatFunction
);
15338 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"contains",
15339 xmlXPathContainsFunction
);
15340 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"id",
15341 xmlXPathIdFunction
);
15342 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"false",
15343 xmlXPathFalseFunction
);
15344 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"floor",
15345 xmlXPathFloorFunction
);
15346 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"last",
15347 xmlXPathLastFunction
);
15348 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"lang",
15349 xmlXPathLangFunction
);
15350 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"local-name",
15351 xmlXPathLocalNameFunction
);
15352 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"not",
15353 xmlXPathNotFunction
);
15354 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"name",
15355 xmlXPathNameFunction
);
15356 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"namespace-uri",
15357 xmlXPathNamespaceURIFunction
);
15358 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"normalize-space",
15359 xmlXPathNormalizeFunction
);
15360 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"number",
15361 xmlXPathNumberFunction
);
15362 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"position",
15363 xmlXPathPositionFunction
);
15364 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"round",
15365 xmlXPathRoundFunction
);
15366 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string",
15367 xmlXPathStringFunction
);
15368 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"string-length",
15369 xmlXPathStringLengthFunction
);
15370 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"starts-with",
15371 xmlXPathStartsWithFunction
);
15372 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring",
15373 xmlXPathSubstringFunction
);
15374 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-before",
15375 xmlXPathSubstringBeforeFunction
);
15376 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"substring-after",
15377 xmlXPathSubstringAfterFunction
);
15378 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"sum",
15379 xmlXPathSumFunction
);
15380 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"true",
15381 xmlXPathTrueFunction
);
15382 xmlXPathRegisterFunc(ctxt
, (const xmlChar
*)"translate",
15383 xmlXPathTranslateFunction
);
15385 xmlXPathRegisterFuncNS(ctxt
, (const xmlChar
*)"escape-uri",
15386 (const xmlChar
*)"http://www.w3.org/2002/08/xquery-functions",
15387 xmlXPathEscapeUriFunction
);
15390 #endif /* LIBXML_XPATH_ENABLED */
15391 #define bottom_xpath
15392 #include "elfgcchack.h"