Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/xml2/xpath.c
4389 views
1
/*
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
5
*
6
* Reference: W3C Recommendation 16 November 1999
7
* http://www.w3.org/TR/1999/REC-xpath-19991116
8
* Public reference:
9
* http://www.w3.org/TR/xpath
10
*
11
* See Copyright for the status of this software
12
*
13
* Author: [email protected]
14
*
15
*/
16
17
/* To avoid EBCDIC trouble when parsing on zOS */
18
#if defined(__MVS__)
19
#pragma convert("ISO8859-1")
20
#endif
21
22
#define IN_LIBXML
23
#include "libxml.h"
24
25
#include <limits.h>
26
#include <string.h>
27
#include <stddef.h>
28
#include <math.h>
29
#include <float.h>
30
#include <ctype.h>
31
32
#include <libxml/xmlmemory.h>
33
#include <libxml/tree.h>
34
#include <libxml/xpath.h>
35
#include <libxml/xpathInternals.h>
36
#include <libxml/parserInternals.h>
37
#include <libxml/hash.h>
38
#ifdef LIBXML_XPTR_LOCS_ENABLED
39
#include <libxml/xpointer.h>
40
#endif
41
#ifdef LIBXML_DEBUG_ENABLED
42
#include <libxml/debugXML.h>
43
#endif
44
#include <libxml/xmlerror.h>
45
#include <libxml/threads.h>
46
#ifdef LIBXML_PATTERN_ENABLED
47
#include <libxml/pattern.h>
48
#endif
49
50
#include "private/buf.h"
51
#include "private/error.h"
52
#include "private/xpath.h"
53
54
#ifdef LIBXML_PATTERN_ENABLED
55
#define XPATH_STREAMING
56
#endif
57
58
#define TODO \
59
xmlGenericError(xmlGenericErrorContext, \
60
"Unimplemented block at %s:%d\n", \
61
__FILE__, __LINE__);
62
63
/**
64
* WITH_TIM_SORT:
65
*
66
* Use the Timsort algorithm provided in timsort.h to sort
67
* nodeset as this is a great improvement over the old Shell sort
68
* used in xmlXPathNodeSetSort()
69
*/
70
#define WITH_TIM_SORT
71
72
/*
73
* XP_OPTIMIZED_NON_ELEM_COMPARISON:
74
* If defined, this will use xmlXPathCmpNodesExt() instead of
75
* xmlXPathCmpNodes(). The new function is optimized comparison of
76
* non-element nodes; actually it will speed up comparison only if
77
* xmlXPathOrderDocElems() was called in order to index the elements of
78
* a tree in document order; Libxslt does such an indexing, thus it will
79
* benefit from this optimization.
80
*/
81
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
82
83
/*
84
* XP_OPTIMIZED_FILTER_FIRST:
85
* If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
86
* in a way, that it stop evaluation at the first node.
87
*/
88
#define XP_OPTIMIZED_FILTER_FIRST
89
90
/*
91
* XPATH_MAX_STEPS:
92
* when compiling an XPath expression we arbitrary limit the maximum
93
* number of step operation in the compiled expression. 1000000 is
94
* an insanely large value which should never be reached under normal
95
* circumstances
96
*/
97
#define XPATH_MAX_STEPS 1000000
98
99
/*
100
* XPATH_MAX_STACK_DEPTH:
101
* when evaluating an XPath expression we arbitrary limit the maximum
102
* number of object allowed to be pushed on the stack. 1000000 is
103
* an insanely large value which should never be reached under normal
104
* circumstances
105
*/
106
#define XPATH_MAX_STACK_DEPTH 1000000
107
108
/*
109
* XPATH_MAX_NODESET_LENGTH:
110
* when evaluating an XPath expression nodesets are created and we
111
* arbitrary limit the maximum length of those node set. 10000000 is
112
* an insanely large value which should never be reached under normal
113
* circumstances, one would first need to construct an in memory tree
114
* with more than 10 millions nodes.
115
*/
116
#define XPATH_MAX_NODESET_LENGTH 10000000
117
118
/*
119
* XPATH_MAX_RECRUSION_DEPTH:
120
* Maximum amount of nested functions calls when parsing or evaluating
121
* expressions
122
*/
123
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
124
#define XPATH_MAX_RECURSION_DEPTH 500
125
#elif defined(_WIN32)
126
/* Windows typically limits stack size to 1MB. */
127
#define XPATH_MAX_RECURSION_DEPTH 1000
128
#else
129
#define XPATH_MAX_RECURSION_DEPTH 5000
130
#endif
131
132
/*
133
* TODO:
134
* There are a few spots where some tests are done which depend upon ascii
135
* data. These should be enhanced for full UTF8 support (see particularly
136
* any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
137
*/
138
139
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
140
141
/************************************************************************
142
* *
143
* Floating point stuff *
144
* *
145
************************************************************************/
146
147
double xmlXPathNAN = 0.0;
148
double xmlXPathPINF = 0.0;
149
double xmlXPathNINF = 0.0;
150
151
/**
152
* xmlXPathInit:
153
*
154
* DEPRECATED: Alias for xmlInitParser.
155
*/
156
void
157
xmlXPathInit(void) {
158
xmlInitParser();
159
}
160
161
/**
162
* xmlInitXPathInternal:
163
*
164
* Initialize the XPath environment
165
*/
166
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
167
void
168
xmlInitXPathInternal(void) {
169
#if defined(NAN) && defined(INFINITY)
170
xmlXPathNAN = NAN;
171
xmlXPathPINF = INFINITY;
172
xmlXPathNINF = -INFINITY;
173
#else
174
/* MSVC doesn't allow division by zero in constant expressions. */
175
double zero = 0.0;
176
xmlXPathNAN = 0.0 / zero;
177
xmlXPathPINF = 1.0 / zero;
178
xmlXPathNINF = -xmlXPathPINF;
179
#endif
180
}
181
182
/**
183
* xmlXPathIsNaN:
184
* @val: a double value
185
*
186
* Checks whether a double is a NaN.
187
*
188
* Returns 1 if the value is a NaN, 0 otherwise
189
*/
190
int
191
xmlXPathIsNaN(double val) {
192
#ifdef isnan
193
return isnan(val);
194
#else
195
return !(val == val);
196
#endif
197
}
198
199
/**
200
* xmlXPathIsInf:
201
* @val: a double value
202
*
203
* Checks whether a double is an infinity.
204
*
205
* Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
206
*/
207
int
208
xmlXPathIsInf(double val) {
209
#ifdef isinf
210
return isinf(val) ? (val > 0 ? 1 : -1) : 0;
211
#else
212
if (val >= xmlXPathPINF)
213
return 1;
214
if (val <= -xmlXPathPINF)
215
return -1;
216
return 0;
217
#endif
218
}
219
220
#endif /* SCHEMAS or XPATH */
221
222
#ifdef LIBXML_XPATH_ENABLED
223
224
/*
225
* TODO: when compatibility allows remove all "fake node libxslt" strings
226
* the test should just be name[0] = ' '
227
*/
228
229
static xmlNs xmlXPathXMLNamespaceStruct = {
230
NULL,
231
XML_NAMESPACE_DECL,
232
XML_XML_NAMESPACE,
233
BAD_CAST "xml",
234
NULL,
235
NULL
236
};
237
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
238
#ifndef LIBXML_THREAD_ENABLED
239
/*
240
* Optimizer is disabled only when threaded apps are detected while
241
* the library ain't compiled for thread safety.
242
*/
243
static int xmlXPathDisableOptimizer = 0;
244
#endif
245
246
static void
247
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
248
249
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
250
/**
251
* xmlXPathCmpNodesExt:
252
* @node1: the first node
253
* @node2: the second node
254
*
255
* Compare two nodes w.r.t document order.
256
* This one is optimized for handling of non-element nodes.
257
*
258
* Returns -2 in case of error 1 if first point < second point, 0 if
259
* it's the same node, -1 otherwise
260
*/
261
static int
262
xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
263
int depth1, depth2;
264
int misc = 0, precedence1 = 0, precedence2 = 0;
265
xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
266
xmlNodePtr cur, root;
267
ptrdiff_t l1, l2;
268
269
if ((node1 == NULL) || (node2 == NULL))
270
return(-2);
271
272
if (node1 == node2)
273
return(0);
274
275
/*
276
* a couple of optimizations which will avoid computations in most cases
277
*/
278
switch (node1->type) {
279
case XML_ELEMENT_NODE:
280
if (node2->type == XML_ELEMENT_NODE) {
281
if ((0 > (ptrdiff_t) node1->content) &&
282
(0 > (ptrdiff_t) node2->content) &&
283
(node1->doc == node2->doc))
284
{
285
l1 = -((ptrdiff_t) node1->content);
286
l2 = -((ptrdiff_t) node2->content);
287
if (l1 < l2)
288
return(1);
289
if (l1 > l2)
290
return(-1);
291
} else
292
goto turtle_comparison;
293
}
294
break;
295
case XML_ATTRIBUTE_NODE:
296
precedence1 = 1; /* element is owner */
297
miscNode1 = node1;
298
node1 = node1->parent;
299
misc = 1;
300
break;
301
case XML_TEXT_NODE:
302
case XML_CDATA_SECTION_NODE:
303
case XML_COMMENT_NODE:
304
case XML_PI_NODE: {
305
miscNode1 = node1;
306
/*
307
* Find nearest element node.
308
*/
309
if (node1->prev != NULL) {
310
do {
311
node1 = node1->prev;
312
if (node1->type == XML_ELEMENT_NODE) {
313
precedence1 = 3; /* element in prev-sibl axis */
314
break;
315
}
316
if (node1->prev == NULL) {
317
precedence1 = 2; /* element is parent */
318
/*
319
* URGENT TODO: Are there any cases, where the
320
* parent of such a node is not an element node?
321
*/
322
node1 = node1->parent;
323
break;
324
}
325
} while (1);
326
} else {
327
precedence1 = 2; /* element is parent */
328
node1 = node1->parent;
329
}
330
if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
331
(0 <= (ptrdiff_t) node1->content)) {
332
/*
333
* Fallback for whatever case.
334
*/
335
node1 = miscNode1;
336
precedence1 = 0;
337
} else
338
misc = 1;
339
}
340
break;
341
case XML_NAMESPACE_DECL:
342
/*
343
* TODO: why do we return 1 for namespace nodes?
344
*/
345
return(1);
346
default:
347
break;
348
}
349
switch (node2->type) {
350
case XML_ELEMENT_NODE:
351
break;
352
case XML_ATTRIBUTE_NODE:
353
precedence2 = 1; /* element is owner */
354
miscNode2 = node2;
355
node2 = node2->parent;
356
misc = 1;
357
break;
358
case XML_TEXT_NODE:
359
case XML_CDATA_SECTION_NODE:
360
case XML_COMMENT_NODE:
361
case XML_PI_NODE: {
362
miscNode2 = node2;
363
if (node2->prev != NULL) {
364
do {
365
node2 = node2->prev;
366
if (node2->type == XML_ELEMENT_NODE) {
367
precedence2 = 3; /* element in prev-sibl axis */
368
break;
369
}
370
if (node2->prev == NULL) {
371
precedence2 = 2; /* element is parent */
372
node2 = node2->parent;
373
break;
374
}
375
} while (1);
376
} else {
377
precedence2 = 2; /* element is parent */
378
node2 = node2->parent;
379
}
380
if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
381
(0 <= (ptrdiff_t) node2->content))
382
{
383
node2 = miscNode2;
384
precedence2 = 0;
385
} else
386
misc = 1;
387
}
388
break;
389
case XML_NAMESPACE_DECL:
390
return(1);
391
default:
392
break;
393
}
394
if (misc) {
395
if (node1 == node2) {
396
if (precedence1 == precedence2) {
397
/*
398
* The ugly case; but normally there aren't many
399
* adjacent non-element nodes around.
400
*/
401
cur = miscNode2->prev;
402
while (cur != NULL) {
403
if (cur == miscNode1)
404
return(1);
405
if (cur->type == XML_ELEMENT_NODE)
406
return(-1);
407
cur = cur->prev;
408
}
409
return (-1);
410
} else {
411
/*
412
* Evaluate based on higher precedence wrt to the element.
413
* TODO: This assumes attributes are sorted before content.
414
* Is this 100% correct?
415
*/
416
if (precedence1 < precedence2)
417
return(1);
418
else
419
return(-1);
420
}
421
}
422
/*
423
* Special case: One of the helper-elements is contained by the other.
424
* <foo>
425
* <node2>
426
* <node1>Text-1(precedence1 == 2)</node1>
427
* </node2>
428
* Text-6(precedence2 == 3)
429
* </foo>
430
*/
431
if ((precedence2 == 3) && (precedence1 > 1)) {
432
cur = node1->parent;
433
while (cur) {
434
if (cur == node2)
435
return(1);
436
cur = cur->parent;
437
}
438
}
439
if ((precedence1 == 3) && (precedence2 > 1)) {
440
cur = node2->parent;
441
while (cur) {
442
if (cur == node1)
443
return(-1);
444
cur = cur->parent;
445
}
446
}
447
}
448
449
/*
450
* Speedup using document order if available.
451
*/
452
if ((node1->type == XML_ELEMENT_NODE) &&
453
(node2->type == XML_ELEMENT_NODE) &&
454
(0 > (ptrdiff_t) node1->content) &&
455
(0 > (ptrdiff_t) node2->content) &&
456
(node1->doc == node2->doc)) {
457
458
l1 = -((ptrdiff_t) node1->content);
459
l2 = -((ptrdiff_t) node2->content);
460
if (l1 < l2)
461
return(1);
462
if (l1 > l2)
463
return(-1);
464
}
465
466
turtle_comparison:
467
468
if (node1 == node2->prev)
469
return(1);
470
if (node1 == node2->next)
471
return(-1);
472
/*
473
* compute depth to root
474
*/
475
for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
476
if (cur->parent == node1)
477
return(1);
478
depth2++;
479
}
480
root = cur;
481
for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
482
if (cur->parent == node2)
483
return(-1);
484
depth1++;
485
}
486
/*
487
* Distinct document (or distinct entities :-( ) case.
488
*/
489
if (root != cur) {
490
return(-2);
491
}
492
/*
493
* get the nearest common ancestor.
494
*/
495
while (depth1 > depth2) {
496
depth1--;
497
node1 = node1->parent;
498
}
499
while (depth2 > depth1) {
500
depth2--;
501
node2 = node2->parent;
502
}
503
while (node1->parent != node2->parent) {
504
node1 = node1->parent;
505
node2 = node2->parent;
506
/* should not happen but just in case ... */
507
if ((node1 == NULL) || (node2 == NULL))
508
return(-2);
509
}
510
/*
511
* Find who's first.
512
*/
513
if (node1 == node2->prev)
514
return(1);
515
if (node1 == node2->next)
516
return(-1);
517
/*
518
* Speedup using document order if available.
519
*/
520
if ((node1->type == XML_ELEMENT_NODE) &&
521
(node2->type == XML_ELEMENT_NODE) &&
522
(0 > (ptrdiff_t) node1->content) &&
523
(0 > (ptrdiff_t) node2->content) &&
524
(node1->doc == node2->doc)) {
525
526
l1 = -((ptrdiff_t) node1->content);
527
l2 = -((ptrdiff_t) node2->content);
528
if (l1 < l2)
529
return(1);
530
if (l1 > l2)
531
return(-1);
532
}
533
534
for (cur = node1->next;cur != NULL;cur = cur->next)
535
if (cur == node2)
536
return(1);
537
return(-1); /* assume there is no sibling list corruption */
538
}
539
#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
540
541
/*
542
* Wrapper for the Timsort algorithm from timsort.h
543
*/
544
#ifdef WITH_TIM_SORT
545
#define SORT_NAME libxml_domnode
546
#define SORT_TYPE xmlNodePtr
547
/**
548
* wrap_cmp:
549
* @x: a node
550
* @y: another node
551
*
552
* Comparison function for the Timsort implementation
553
*
554
* Returns -2 in case of error -1 if first point < second point, 0 if
555
* it's the same node, +1 otherwise
556
*/
557
static
558
int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
559
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
560
static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
561
{
562
int res = xmlXPathCmpNodesExt(x, y);
563
return res == -2 ? res : -res;
564
}
565
#else
566
static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
567
{
568
int res = xmlXPathCmpNodes(x, y);
569
return res == -2 ? res : -res;
570
}
571
#endif
572
#define SORT_CMP(x, y) (wrap_cmp(x, y))
573
#include "timsort.h"
574
#endif /* WITH_TIM_SORT */
575
576
/************************************************************************
577
* *
578
* Error handling routines *
579
* *
580
************************************************************************/
581
582
/**
583
* XP_ERRORNULL:
584
* @X: the error code
585
*
586
* Macro to raise an XPath error and return NULL.
587
*/
588
#define XP_ERRORNULL(X) \
589
{ xmlXPathErr(ctxt, X); return(NULL); }
590
591
/*
592
* The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
593
*/
594
static const char* const xmlXPathErrorMessages[] = {
595
"Ok\n",
596
"Number encoding\n",
597
"Unfinished literal\n",
598
"Start of literal\n",
599
"Expected $ for variable reference\n",
600
"Undefined variable\n",
601
"Invalid predicate\n",
602
"Invalid expression\n",
603
"Missing closing curly brace\n",
604
"Unregistered function\n",
605
"Invalid operand\n",
606
"Invalid type\n",
607
"Invalid number of arguments\n",
608
"Invalid context size\n",
609
"Invalid context position\n",
610
"Memory allocation error\n",
611
"Syntax error\n",
612
"Resource error\n",
613
"Sub resource error\n",
614
"Undefined namespace prefix\n",
615
"Encoding error\n",
616
"Char out of XML range\n",
617
"Invalid or incomplete context\n",
618
"Stack usage error\n",
619
"Forbidden variable\n",
620
"Operation limit exceeded\n",
621
"Recursion limit exceeded\n",
622
"?? Unknown error ??\n" /* Must be last in the list! */
623
};
624
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
625
sizeof(xmlXPathErrorMessages[0])) - 1)
626
/**
627
* xmlXPathErrMemory:
628
* @ctxt: an XPath context
629
* @extra: extra information
630
*
631
* Handle a redefinition of attribute error
632
*/
633
static void
634
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
635
{
636
if (ctxt != NULL) {
637
xmlResetError(&ctxt->lastError);
638
if (extra) {
639
xmlChar buf[200];
640
641
xmlStrPrintf(buf, 200,
642
"Memory allocation failed : %s\n",
643
extra);
644
ctxt->lastError.message = (char *) xmlStrdup(buf);
645
} else {
646
ctxt->lastError.message = (char *)
647
xmlStrdup(BAD_CAST "Memory allocation failed\n");
648
}
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);
653
} else {
654
if (extra)
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);
660
else
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");
666
}
667
}
668
669
/**
670
* xmlXPathPErrMemory:
671
* @ctxt: an XPath parser context
672
* @extra: extra information
673
*
674
* Handle a redefinition of attribute error
675
*/
676
static void
677
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
678
{
679
if (ctxt == NULL)
680
xmlXPathErrMemory(NULL, extra);
681
else {
682
ctxt->error = XPATH_MEMORY_ERROR;
683
xmlXPathErrMemory(ctxt->context, extra);
684
}
685
}
686
687
/**
688
* xmlXPathErr:
689
* @ctxt: a XPath parser context
690
* @error: the error code
691
*
692
* Handle an XPath error
693
*/
694
void
695
xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
696
{
697
if ((error < 0) || (error > MAXERRNO))
698
error = MAXERRNO;
699
if (ctxt == NULL) {
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]);
706
return;
707
}
708
/* Only report the first error */
709
if (ctxt->error != 0)
710
return;
711
ctxt->error = error;
712
if (ctxt->context == NULL) {
713
__xmlRaiseError(NULL, NULL, NULL,
714
NULL, NULL, XML_FROM_XPATH,
715
error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
716
XML_ERR_ERROR, NULL, 0,
717
(const char *) ctxt->base, NULL, NULL,
718
ctxt->cur - ctxt->base, 0,
719
"%s", xmlXPathErrorMessages[error]);
720
return;
721
}
722
723
/* cleanup current last error */
724
xmlResetError(&ctxt->context->lastError);
725
726
ctxt->context->lastError.domain = XML_FROM_XPATH;
727
ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
728
XPATH_EXPRESSION_OK;
729
ctxt->context->lastError.level = XML_ERR_ERROR;
730
ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
731
ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
732
ctxt->context->lastError.node = ctxt->context->debugNode;
733
if (ctxt->context->error != NULL) {
734
ctxt->context->error(ctxt->context->userData,
735
&ctxt->context->lastError);
736
} else {
737
__xmlRaiseError(NULL, NULL, NULL,
738
NULL, ctxt->context->debugNode, XML_FROM_XPATH,
739
error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
740
XML_ERR_ERROR, NULL, 0,
741
(const char *) ctxt->base, NULL, NULL,
742
ctxt->cur - ctxt->base, 0,
743
"%s", xmlXPathErrorMessages[error]);
744
}
745
746
}
747
748
/**
749
* xmlXPatherror:
750
* @ctxt: the XPath Parser context
751
* @file: the file name
752
* @line: the line number
753
* @no: the error number
754
*
755
* Formats an error message.
756
*/
757
void
758
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
759
int line ATTRIBUTE_UNUSED, int no) {
760
xmlXPathErr(ctxt, no);
761
}
762
763
/**
764
* xmlXPathCheckOpLimit:
765
* @ctxt: the XPath Parser context
766
* @opCount: the number of operations to be added
767
*
768
* Adds opCount to the running total of operations and returns -1 if the
769
* operation limit is exceeded. Returns 0 otherwise.
770
*/
771
static int
772
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
773
xmlXPathContextPtr xpctxt = ctxt->context;
774
775
if ((opCount > xpctxt->opLimit) ||
776
(xpctxt->opCount > xpctxt->opLimit - opCount)) {
777
xpctxt->opCount = xpctxt->opLimit;
778
xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
779
return(-1);
780
}
781
782
xpctxt->opCount += opCount;
783
return(0);
784
}
785
786
#define OP_LIMIT_EXCEEDED(ctxt, n) \
787
((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
788
789
/************************************************************************
790
* *
791
* Utilities *
792
* *
793
************************************************************************/
794
795
/**
796
* xsltPointerList:
797
*
798
* Pointer-list for various purposes.
799
*/
800
typedef struct _xmlPointerList xmlPointerList;
801
typedef xmlPointerList *xmlPointerListPtr;
802
struct _xmlPointerList {
803
void **items;
804
int number;
805
int size;
806
};
807
/*
808
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
809
* and here, we should make the functions public.
810
*/
811
static int
812
xmlPointerListAddSize(xmlPointerListPtr list,
813
void *item,
814
int initialSize)
815
{
816
if (list->size <= list->number) {
817
void **tmp;
818
size_t newSize;
819
820
if (list->size == 0) {
821
if (initialSize <= 0)
822
initialSize = 1;
823
newSize = initialSize;
824
} else {
825
if (list->size > 50000000) {
826
xmlXPathErrMemory(NULL,
827
"xmlPointerListAddSize: re-allocating item\n");
828
return(-1);
829
}
830
newSize = list->size * 2;
831
}
832
tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
833
if (tmp == NULL) {
834
xmlXPathErrMemory(NULL,
835
"xmlPointerListAddSize: re-allocating item\n");
836
return(-1);
837
}
838
list->items = tmp;
839
list->size = newSize;
840
}
841
list->items[list->number++] = item;
842
return(0);
843
}
844
845
/**
846
* xsltPointerListCreate:
847
*
848
* Creates an xsltPointerList structure.
849
*
850
* Returns a xsltPointerList structure or NULL in case of an error.
851
*/
852
static xmlPointerListPtr
853
xmlPointerListCreate(int initialSize)
854
{
855
xmlPointerListPtr ret;
856
857
ret = xmlMalloc(sizeof(xmlPointerList));
858
if (ret == NULL) {
859
xmlXPathErrMemory(NULL,
860
"xmlPointerListCreate: allocating item\n");
861
return (NULL);
862
}
863
memset(ret, 0, sizeof(xmlPointerList));
864
if (initialSize > 0) {
865
xmlPointerListAddSize(ret, NULL, initialSize);
866
ret->number = 0;
867
}
868
return (ret);
869
}
870
871
/**
872
* xsltPointerListFree:
873
*
874
* Frees the xsltPointerList structure. This does not free
875
* the content of the list.
876
*/
877
static void
878
xmlPointerListFree(xmlPointerListPtr list)
879
{
880
if (list == NULL)
881
return;
882
if (list->items != NULL)
883
xmlFree(list->items);
884
xmlFree(list);
885
}
886
887
/************************************************************************
888
* *
889
* Parser Types *
890
* *
891
************************************************************************/
892
893
/*
894
* Types are private:
895
*/
896
897
typedef enum {
898
XPATH_OP_END=0,
899
XPATH_OP_AND,
900
XPATH_OP_OR,
901
XPATH_OP_EQUAL,
902
XPATH_OP_CMP,
903
XPATH_OP_PLUS,
904
XPATH_OP_MULT,
905
XPATH_OP_UNION,
906
XPATH_OP_ROOT,
907
XPATH_OP_NODE,
908
XPATH_OP_COLLECT,
909
XPATH_OP_VALUE, /* 11 */
910
XPATH_OP_VARIABLE,
911
XPATH_OP_FUNCTION,
912
XPATH_OP_ARG,
913
XPATH_OP_PREDICATE,
914
XPATH_OP_FILTER, /* 16 */
915
XPATH_OP_SORT /* 17 */
916
#ifdef LIBXML_XPTR_LOCS_ENABLED
917
,XPATH_OP_RANGETO
918
#endif
919
} xmlXPathOp;
920
921
typedef enum {
922
AXIS_ANCESTOR = 1,
923
AXIS_ANCESTOR_OR_SELF,
924
AXIS_ATTRIBUTE,
925
AXIS_CHILD,
926
AXIS_DESCENDANT,
927
AXIS_DESCENDANT_OR_SELF,
928
AXIS_FOLLOWING,
929
AXIS_FOLLOWING_SIBLING,
930
AXIS_NAMESPACE,
931
AXIS_PARENT,
932
AXIS_PRECEDING,
933
AXIS_PRECEDING_SIBLING,
934
AXIS_SELF
935
} xmlXPathAxisVal;
936
937
typedef enum {
938
NODE_TEST_NONE = 0,
939
NODE_TEST_TYPE = 1,
940
NODE_TEST_PI = 2,
941
NODE_TEST_ALL = 3,
942
NODE_TEST_NS = 4,
943
NODE_TEST_NAME = 5
944
} xmlXPathTestVal;
945
946
typedef enum {
947
NODE_TYPE_NODE = 0,
948
NODE_TYPE_COMMENT = XML_COMMENT_NODE,
949
NODE_TYPE_TEXT = XML_TEXT_NODE,
950
NODE_TYPE_PI = XML_PI_NODE
951
} xmlXPathTypeVal;
952
953
typedef struct _xmlXPathStepOp xmlXPathStepOp;
954
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
955
struct _xmlXPathStepOp {
956
xmlXPathOp op; /* The identifier of the operation */
957
int ch1; /* First child */
958
int ch2; /* Second child */
959
int value;
960
int value2;
961
int value3;
962
void *value4;
963
void *value5;
964
xmlXPathFunction cache;
965
void *cacheURI;
966
};
967
968
struct _xmlXPathCompExpr {
969
int nbStep; /* Number of steps in this expression */
970
int maxStep; /* Maximum number of steps allocated */
971
xmlXPathStepOp *steps; /* ops for computation of this expression */
972
int last; /* index of last step in expression */
973
xmlChar *expr; /* the expression being computed */
974
xmlDictPtr dict; /* the dictionary to use if any */
975
#ifdef XPATH_STREAMING
976
xmlPatternPtr stream;
977
#endif
978
};
979
980
/************************************************************************
981
* *
982
* Forward declarations *
983
* *
984
************************************************************************/
985
static void
986
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
987
static void
988
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
989
static int
990
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
991
xmlXPathStepOpPtr op, xmlNodePtr *first);
992
static int
993
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
994
xmlXPathStepOpPtr op,
995
int isPredicate);
996
static void
997
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
998
999
/************************************************************************
1000
* *
1001
* Parser Type functions *
1002
* *
1003
************************************************************************/
1004
1005
/**
1006
* xmlXPathNewCompExpr:
1007
*
1008
* Create a new Xpath component
1009
*
1010
* Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
1011
*/
1012
static xmlXPathCompExprPtr
1013
xmlXPathNewCompExpr(void) {
1014
xmlXPathCompExprPtr cur;
1015
1016
cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1017
if (cur == NULL) {
1018
xmlXPathErrMemory(NULL, "allocating component\n");
1019
return(NULL);
1020
}
1021
memset(cur, 0, sizeof(xmlXPathCompExpr));
1022
cur->maxStep = 10;
1023
cur->nbStep = 0;
1024
cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1025
sizeof(xmlXPathStepOp));
1026
if (cur->steps == NULL) {
1027
xmlXPathErrMemory(NULL, "allocating steps\n");
1028
xmlFree(cur);
1029
return(NULL);
1030
}
1031
memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1032
cur->last = -1;
1033
return(cur);
1034
}
1035
1036
/**
1037
* xmlXPathFreeCompExpr:
1038
* @comp: an XPATH comp
1039
*
1040
* Free up the memory allocated by @comp
1041
*/
1042
void
1043
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1044
{
1045
xmlXPathStepOpPtr op;
1046
int i;
1047
1048
if (comp == NULL)
1049
return;
1050
if (comp->dict == NULL) {
1051
for (i = 0; i < comp->nbStep; i++) {
1052
op = &comp->steps[i];
1053
if (op->value4 != NULL) {
1054
if (op->op == XPATH_OP_VALUE)
1055
xmlXPathFreeObject(op->value4);
1056
else
1057
xmlFree(op->value4);
1058
}
1059
if (op->value5 != NULL)
1060
xmlFree(op->value5);
1061
}
1062
} else {
1063
for (i = 0; i < comp->nbStep; i++) {
1064
op = &comp->steps[i];
1065
if (op->value4 != NULL) {
1066
if (op->op == XPATH_OP_VALUE)
1067
xmlXPathFreeObject(op->value4);
1068
}
1069
}
1070
xmlDictFree(comp->dict);
1071
}
1072
if (comp->steps != NULL) {
1073
xmlFree(comp->steps);
1074
}
1075
#ifdef XPATH_STREAMING
1076
if (comp->stream != NULL) {
1077
xmlFreePatternList(comp->stream);
1078
}
1079
#endif
1080
if (comp->expr != NULL) {
1081
xmlFree(comp->expr);
1082
}
1083
1084
xmlFree(comp);
1085
}
1086
1087
/**
1088
* xmlXPathCompExprAdd:
1089
* @comp: the compiled expression
1090
* @ch1: first child index
1091
* @ch2: second child index
1092
* @op: an op
1093
* @value: the first int value
1094
* @value2: the second int value
1095
* @value3: the third int value
1096
* @value4: the first string value
1097
* @value5: the second string value
1098
*
1099
* Add a step to an XPath Compiled Expression
1100
*
1101
* Returns -1 in case of failure, the index otherwise
1102
*/
1103
static int
1104
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
1105
xmlXPathOp op, int value,
1106
int value2, int value3, void *value4, void *value5) {
1107
xmlXPathCompExprPtr comp = ctxt->comp;
1108
if (comp->nbStep >= comp->maxStep) {
1109
xmlXPathStepOp *real;
1110
1111
if (comp->maxStep >= XPATH_MAX_STEPS) {
1112
xmlXPathPErrMemory(ctxt, "adding step\n");
1113
return(-1);
1114
}
1115
comp->maxStep *= 2;
1116
real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1117
comp->maxStep * sizeof(xmlXPathStepOp));
1118
if (real == NULL) {
1119
comp->maxStep /= 2;
1120
xmlXPathPErrMemory(ctxt, "adding step\n");
1121
return(-1);
1122
}
1123
comp->steps = real;
1124
}
1125
comp->last = comp->nbStep;
1126
comp->steps[comp->nbStep].ch1 = ch1;
1127
comp->steps[comp->nbStep].ch2 = ch2;
1128
comp->steps[comp->nbStep].op = op;
1129
comp->steps[comp->nbStep].value = value;
1130
comp->steps[comp->nbStep].value2 = value2;
1131
comp->steps[comp->nbStep].value3 = value3;
1132
if ((comp->dict != NULL) &&
1133
((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1134
(op == XPATH_OP_COLLECT))) {
1135
if (value4 != NULL) {
1136
comp->steps[comp->nbStep].value4 = (xmlChar *)
1137
(void *)xmlDictLookup(comp->dict, value4, -1);
1138
xmlFree(value4);
1139
} else
1140
comp->steps[comp->nbStep].value4 = NULL;
1141
if (value5 != NULL) {
1142
comp->steps[comp->nbStep].value5 = (xmlChar *)
1143
(void *)xmlDictLookup(comp->dict, value5, -1);
1144
xmlFree(value5);
1145
} else
1146
comp->steps[comp->nbStep].value5 = NULL;
1147
} else {
1148
comp->steps[comp->nbStep].value4 = value4;
1149
comp->steps[comp->nbStep].value5 = value5;
1150
}
1151
comp->steps[comp->nbStep].cache = NULL;
1152
return(comp->nbStep++);
1153
}
1154
1155
/**
1156
* xmlXPathCompSwap:
1157
* @comp: the compiled expression
1158
* @op: operation index
1159
*
1160
* Swaps 2 operations in the compiled expression
1161
*/
1162
static void
1163
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1164
int tmp;
1165
1166
#ifndef LIBXML_THREAD_ENABLED
1167
/*
1168
* Since this manipulates possibly shared variables, this is
1169
* disabled if one detects that the library is used in a multithreaded
1170
* application
1171
*/
1172
if (xmlXPathDisableOptimizer)
1173
return;
1174
#endif
1175
1176
tmp = op->ch1;
1177
op->ch1 = op->ch2;
1178
op->ch2 = tmp;
1179
}
1180
1181
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1182
xmlXPathCompExprAdd(ctxt, (op1), (op2), \
1183
(op), (val), (val2), (val3), (val4), (val5))
1184
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1185
xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
1186
(op), (val), (val2), (val3), (val4), (val5))
1187
1188
#define PUSH_LEAVE_EXPR(op, val, val2) \
1189
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1190
1191
#define PUSH_UNARY_EXPR(op, ch, val, val2) \
1192
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1193
1194
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1195
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
1196
(val), (val2), 0 ,NULL ,NULL)
1197
1198
/************************************************************************
1199
* *
1200
* XPath object cache structures *
1201
* *
1202
************************************************************************/
1203
1204
/* #define XP_DEFAULT_CACHE_ON */
1205
1206
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1207
1208
typedef struct _xmlXPathContextCache xmlXPathContextCache;
1209
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1210
struct _xmlXPathContextCache {
1211
xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1212
xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1213
xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1214
xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1215
xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1216
int maxNodeset;
1217
int maxString;
1218
int maxBoolean;
1219
int maxNumber;
1220
int maxMisc;
1221
};
1222
1223
/************************************************************************
1224
* *
1225
* Debugging related functions *
1226
* *
1227
************************************************************************/
1228
1229
#define STRANGE \
1230
xmlGenericError(xmlGenericErrorContext, \
1231
"Internal error at %s:%d\n", \
1232
__FILE__, __LINE__);
1233
1234
#ifdef LIBXML_DEBUG_ENABLED
1235
static void
1236
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1237
int i;
1238
char shift[100];
1239
1240
for (i = 0;((i < depth) && (i < 25));i++)
1241
shift[2 * i] = shift[2 * i + 1] = ' ';
1242
shift[2 * i] = shift[2 * i + 1] = 0;
1243
if (cur == NULL) {
1244
fprintf(output, "%s", shift);
1245
fprintf(output, "Node is NULL !\n");
1246
return;
1247
1248
}
1249
1250
if ((cur->type == XML_DOCUMENT_NODE) ||
1251
(cur->type == XML_HTML_DOCUMENT_NODE)) {
1252
fprintf(output, "%s", shift);
1253
fprintf(output, " /\n");
1254
} else if (cur->type == XML_ATTRIBUTE_NODE)
1255
xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1256
else
1257
xmlDebugDumpOneNode(output, cur, depth);
1258
}
1259
static void
1260
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1261
xmlNodePtr tmp;
1262
int i;
1263
char shift[100];
1264
1265
for (i = 0;((i < depth) && (i < 25));i++)
1266
shift[2 * i] = shift[2 * i + 1] = ' ';
1267
shift[2 * i] = shift[2 * i + 1] = 0;
1268
if (cur == NULL) {
1269
fprintf(output, "%s", shift);
1270
fprintf(output, "Node is NULL !\n");
1271
return;
1272
1273
}
1274
1275
while (cur != NULL) {
1276
tmp = cur;
1277
cur = cur->next;
1278
xmlDebugDumpOneNode(output, tmp, depth);
1279
}
1280
}
1281
1282
static void
1283
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1284
int i;
1285
char shift[100];
1286
1287
for (i = 0;((i < depth) && (i < 25));i++)
1288
shift[2 * i] = shift[2 * i + 1] = ' ';
1289
shift[2 * i] = shift[2 * i + 1] = 0;
1290
1291
if (cur == NULL) {
1292
fprintf(output, "%s", shift);
1293
fprintf(output, "NodeSet is NULL !\n");
1294
return;
1295
1296
}
1297
1298
if (cur != NULL) {
1299
fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1300
for (i = 0;i < cur->nodeNr;i++) {
1301
fprintf(output, "%s", shift);
1302
fprintf(output, "%d", i + 1);
1303
xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1304
}
1305
}
1306
}
1307
1308
static void
1309
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1310
int i;
1311
char shift[100];
1312
1313
for (i = 0;((i < depth) && (i < 25));i++)
1314
shift[2 * i] = shift[2 * i + 1] = ' ';
1315
shift[2 * i] = shift[2 * i + 1] = 0;
1316
1317
if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1318
fprintf(output, "%s", shift);
1319
fprintf(output, "Value Tree is NULL !\n");
1320
return;
1321
1322
}
1323
1324
fprintf(output, "%s", shift);
1325
fprintf(output, "%d", i + 1);
1326
xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1327
}
1328
#if defined(LIBXML_XPTR_LOCS_ENABLED)
1329
static void
1330
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1331
int i;
1332
char shift[100];
1333
1334
for (i = 0;((i < depth) && (i < 25));i++)
1335
shift[2 * i] = shift[2 * i + 1] = ' ';
1336
shift[2 * i] = shift[2 * i + 1] = 0;
1337
1338
if (cur == NULL) {
1339
fprintf(output, "%s", shift);
1340
fprintf(output, "LocationSet is NULL !\n");
1341
return;
1342
1343
}
1344
1345
for (i = 0;i < cur->locNr;i++) {
1346
fprintf(output, "%s", shift);
1347
fprintf(output, "%d : ", i + 1);
1348
xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1349
}
1350
}
1351
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1352
1353
/**
1354
* xmlXPathDebugDumpObject:
1355
* @output: the FILE * to dump the output
1356
* @cur: the object to inspect
1357
* @depth: indentation level
1358
*
1359
* Dump the content of the object for debugging purposes
1360
*/
1361
void
1362
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1363
int i;
1364
char shift[100];
1365
1366
if (output == NULL) return;
1367
1368
for (i = 0;((i < depth) && (i < 25));i++)
1369
shift[2 * i] = shift[2 * i + 1] = ' ';
1370
shift[2 * i] = shift[2 * i + 1] = 0;
1371
1372
1373
fprintf(output, "%s", shift);
1374
1375
if (cur == NULL) {
1376
fprintf(output, "Object is empty (NULL)\n");
1377
return;
1378
}
1379
switch(cur->type) {
1380
case XPATH_UNDEFINED:
1381
fprintf(output, "Object is uninitialized\n");
1382
break;
1383
case XPATH_NODESET:
1384
fprintf(output, "Object is a Node Set :\n");
1385
xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1386
break;
1387
case XPATH_XSLT_TREE:
1388
fprintf(output, "Object is an XSLT value tree :\n");
1389
xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1390
break;
1391
case XPATH_BOOLEAN:
1392
fprintf(output, "Object is a Boolean : ");
1393
if (cur->boolval) fprintf(output, "true\n");
1394
else fprintf(output, "false\n");
1395
break;
1396
case XPATH_NUMBER:
1397
switch (xmlXPathIsInf(cur->floatval)) {
1398
case 1:
1399
fprintf(output, "Object is a number : Infinity\n");
1400
break;
1401
case -1:
1402
fprintf(output, "Object is a number : -Infinity\n");
1403
break;
1404
default:
1405
if (xmlXPathIsNaN(cur->floatval)) {
1406
fprintf(output, "Object is a number : NaN\n");
1407
} else if (cur->floatval == 0) {
1408
/* Omit sign for negative zero. */
1409
fprintf(output, "Object is a number : 0\n");
1410
} else {
1411
fprintf(output, "Object is a number : %0g\n", cur->floatval);
1412
}
1413
}
1414
break;
1415
case XPATH_STRING:
1416
fprintf(output, "Object is a string : ");
1417
xmlDebugDumpString(output, cur->stringval);
1418
fprintf(output, "\n");
1419
break;
1420
#ifdef LIBXML_XPTR_LOCS_ENABLED
1421
case XPATH_POINT:
1422
fprintf(output, "Object is a point : index %d in node", cur->index);
1423
xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1424
fprintf(output, "\n");
1425
break;
1426
case XPATH_RANGE:
1427
if ((cur->user2 == NULL) ||
1428
((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1429
fprintf(output, "Object is a collapsed range :\n");
1430
fprintf(output, "%s", shift);
1431
if (cur->index >= 0)
1432
fprintf(output, "index %d in ", cur->index);
1433
fprintf(output, "node\n");
1434
xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1435
depth + 1);
1436
} else {
1437
fprintf(output, "Object is a range :\n");
1438
fprintf(output, "%s", shift);
1439
fprintf(output, "From ");
1440
if (cur->index >= 0)
1441
fprintf(output, "index %d in ", cur->index);
1442
fprintf(output, "node\n");
1443
xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1444
depth + 1);
1445
fprintf(output, "%s", shift);
1446
fprintf(output, "To ");
1447
if (cur->index2 >= 0)
1448
fprintf(output, "index %d in ", cur->index2);
1449
fprintf(output, "node\n");
1450
xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1451
depth + 1);
1452
fprintf(output, "\n");
1453
}
1454
break;
1455
case XPATH_LOCATIONSET:
1456
fprintf(output, "Object is a Location Set:\n");
1457
xmlXPathDebugDumpLocationSet(output,
1458
(xmlLocationSetPtr) cur->user, depth);
1459
break;
1460
#endif /* LIBXML_XPTR_LOCS_ENABLED */
1461
case XPATH_USERS:
1462
fprintf(output, "Object is user defined\n");
1463
break;
1464
}
1465
}
1466
1467
static void
1468
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1469
xmlXPathStepOpPtr op, int depth) {
1470
int i;
1471
char shift[100];
1472
1473
for (i = 0;((i < depth) && (i < 25));i++)
1474
shift[2 * i] = shift[2 * i + 1] = ' ';
1475
shift[2 * i] = shift[2 * i + 1] = 0;
1476
1477
fprintf(output, "%s", shift);
1478
if (op == NULL) {
1479
fprintf(output, "Step is NULL\n");
1480
return;
1481
}
1482
switch (op->op) {
1483
case XPATH_OP_END:
1484
fprintf(output, "END"); break;
1485
case XPATH_OP_AND:
1486
fprintf(output, "AND"); break;
1487
case XPATH_OP_OR:
1488
fprintf(output, "OR"); break;
1489
case XPATH_OP_EQUAL:
1490
if (op->value)
1491
fprintf(output, "EQUAL =");
1492
else
1493
fprintf(output, "EQUAL !=");
1494
break;
1495
case XPATH_OP_CMP:
1496
if (op->value)
1497
fprintf(output, "CMP <");
1498
else
1499
fprintf(output, "CMP >");
1500
if (!op->value2)
1501
fprintf(output, "=");
1502
break;
1503
case XPATH_OP_PLUS:
1504
if (op->value == 0)
1505
fprintf(output, "PLUS -");
1506
else if (op->value == 1)
1507
fprintf(output, "PLUS +");
1508
else if (op->value == 2)
1509
fprintf(output, "PLUS unary -");
1510
else if (op->value == 3)
1511
fprintf(output, "PLUS unary - -");
1512
break;
1513
case XPATH_OP_MULT:
1514
if (op->value == 0)
1515
fprintf(output, "MULT *");
1516
else if (op->value == 1)
1517
fprintf(output, "MULT div");
1518
else
1519
fprintf(output, "MULT mod");
1520
break;
1521
case XPATH_OP_UNION:
1522
fprintf(output, "UNION"); break;
1523
case XPATH_OP_ROOT:
1524
fprintf(output, "ROOT"); break;
1525
case XPATH_OP_NODE:
1526
fprintf(output, "NODE"); break;
1527
case XPATH_OP_SORT:
1528
fprintf(output, "SORT"); break;
1529
case XPATH_OP_COLLECT: {
1530
xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1531
xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1532
xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1533
const xmlChar *prefix = op->value4;
1534
const xmlChar *name = op->value5;
1535
1536
fprintf(output, "COLLECT ");
1537
switch (axis) {
1538
case AXIS_ANCESTOR:
1539
fprintf(output, " 'ancestors' "); break;
1540
case AXIS_ANCESTOR_OR_SELF:
1541
fprintf(output, " 'ancestors-or-self' "); break;
1542
case AXIS_ATTRIBUTE:
1543
fprintf(output, " 'attributes' "); break;
1544
case AXIS_CHILD:
1545
fprintf(output, " 'child' "); break;
1546
case AXIS_DESCENDANT:
1547
fprintf(output, " 'descendant' "); break;
1548
case AXIS_DESCENDANT_OR_SELF:
1549
fprintf(output, " 'descendant-or-self' "); break;
1550
case AXIS_FOLLOWING:
1551
fprintf(output, " 'following' "); break;
1552
case AXIS_FOLLOWING_SIBLING:
1553
fprintf(output, " 'following-siblings' "); break;
1554
case AXIS_NAMESPACE:
1555
fprintf(output, " 'namespace' "); break;
1556
case AXIS_PARENT:
1557
fprintf(output, " 'parent' "); break;
1558
case AXIS_PRECEDING:
1559
fprintf(output, " 'preceding' "); break;
1560
case AXIS_PRECEDING_SIBLING:
1561
fprintf(output, " 'preceding-sibling' "); break;
1562
case AXIS_SELF:
1563
fprintf(output, " 'self' "); break;
1564
}
1565
switch (test) {
1566
case NODE_TEST_NONE:
1567
fprintf(output, "'none' "); break;
1568
case NODE_TEST_TYPE:
1569
fprintf(output, "'type' "); break;
1570
case NODE_TEST_PI:
1571
fprintf(output, "'PI' "); break;
1572
case NODE_TEST_ALL:
1573
fprintf(output, "'all' "); break;
1574
case NODE_TEST_NS:
1575
fprintf(output, "'namespace' "); break;
1576
case NODE_TEST_NAME:
1577
fprintf(output, "'name' "); break;
1578
}
1579
switch (type) {
1580
case NODE_TYPE_NODE:
1581
fprintf(output, "'node' "); break;
1582
case NODE_TYPE_COMMENT:
1583
fprintf(output, "'comment' "); break;
1584
case NODE_TYPE_TEXT:
1585
fprintf(output, "'text' "); break;
1586
case NODE_TYPE_PI:
1587
fprintf(output, "'PI' "); break;
1588
}
1589
if (prefix != NULL)
1590
fprintf(output, "%s:", prefix);
1591
if (name != NULL)
1592
fprintf(output, "%s", (const char *) name);
1593
break;
1594
1595
}
1596
case XPATH_OP_VALUE: {
1597
xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1598
1599
fprintf(output, "ELEM ");
1600
xmlXPathDebugDumpObject(output, object, 0);
1601
goto finish;
1602
}
1603
case XPATH_OP_VARIABLE: {
1604
const xmlChar *prefix = op->value5;
1605
const xmlChar *name = op->value4;
1606
1607
if (prefix != NULL)
1608
fprintf(output, "VARIABLE %s:%s", prefix, name);
1609
else
1610
fprintf(output, "VARIABLE %s", name);
1611
break;
1612
}
1613
case XPATH_OP_FUNCTION: {
1614
int nbargs = op->value;
1615
const xmlChar *prefix = op->value5;
1616
const xmlChar *name = op->value4;
1617
1618
if (prefix != NULL)
1619
fprintf(output, "FUNCTION %s:%s(%d args)",
1620
prefix, name, nbargs);
1621
else
1622
fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1623
break;
1624
}
1625
case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1626
case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1627
case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1628
#ifdef LIBXML_XPTR_LOCS_ENABLED
1629
case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1630
#endif
1631
default:
1632
fprintf(output, "UNKNOWN %d\n", op->op); return;
1633
}
1634
fprintf(output, "\n");
1635
finish:
1636
if (op->ch1 >= 0)
1637
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1638
if (op->ch2 >= 0)
1639
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1640
}
1641
1642
/**
1643
* xmlXPathDebugDumpCompExpr:
1644
* @output: the FILE * for the output
1645
* @comp: the precompiled XPath expression
1646
* @depth: the indentation level.
1647
*
1648
* Dumps the tree of the compiled XPath expression.
1649
*/
1650
void
1651
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1652
int depth) {
1653
int i;
1654
char shift[100];
1655
1656
if ((output == NULL) || (comp == NULL)) return;
1657
1658
for (i = 0;((i < depth) && (i < 25));i++)
1659
shift[2 * i] = shift[2 * i + 1] = ' ';
1660
shift[2 * i] = shift[2 * i + 1] = 0;
1661
1662
fprintf(output, "%s", shift);
1663
1664
#ifdef XPATH_STREAMING
1665
if (comp->stream) {
1666
fprintf(output, "Streaming Expression\n");
1667
} else
1668
#endif
1669
{
1670
fprintf(output, "Compiled Expression : %d elements\n",
1671
comp->nbStep);
1672
i = comp->last;
1673
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1674
}
1675
}
1676
1677
#endif /* LIBXML_DEBUG_ENABLED */
1678
1679
/************************************************************************
1680
* *
1681
* XPath object caching *
1682
* *
1683
************************************************************************/
1684
1685
/**
1686
* xmlXPathNewCache:
1687
*
1688
* Create a new object cache
1689
*
1690
* Returns the xmlXPathCache just allocated.
1691
*/
1692
static xmlXPathContextCachePtr
1693
xmlXPathNewCache(void)
1694
{
1695
xmlXPathContextCachePtr ret;
1696
1697
ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
1698
if (ret == NULL) {
1699
xmlXPathErrMemory(NULL, "creating object cache\n");
1700
return(NULL);
1701
}
1702
memset(ret, 0 , sizeof(xmlXPathContextCache));
1703
ret->maxNodeset = 100;
1704
ret->maxString = 100;
1705
ret->maxBoolean = 100;
1706
ret->maxNumber = 100;
1707
ret->maxMisc = 100;
1708
return(ret);
1709
}
1710
1711
static void
1712
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
1713
{
1714
int i;
1715
xmlXPathObjectPtr obj;
1716
1717
if (list == NULL)
1718
return;
1719
1720
for (i = 0; i < list->number; i++) {
1721
obj = list->items[i];
1722
/*
1723
* Note that it is already assured that we don't need to
1724
* look out for namespace nodes in the node-set.
1725
*/
1726
if (obj->nodesetval != NULL) {
1727
if (obj->nodesetval->nodeTab != NULL)
1728
xmlFree(obj->nodesetval->nodeTab);
1729
xmlFree(obj->nodesetval);
1730
}
1731
xmlFree(obj);
1732
}
1733
xmlPointerListFree(list);
1734
}
1735
1736
static void
1737
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
1738
{
1739
if (cache == NULL)
1740
return;
1741
if (cache->nodesetObjs)
1742
xmlXPathCacheFreeObjectList(cache->nodesetObjs);
1743
if (cache->stringObjs)
1744
xmlXPathCacheFreeObjectList(cache->stringObjs);
1745
if (cache->booleanObjs)
1746
xmlXPathCacheFreeObjectList(cache->booleanObjs);
1747
if (cache->numberObjs)
1748
xmlXPathCacheFreeObjectList(cache->numberObjs);
1749
if (cache->miscObjs)
1750
xmlXPathCacheFreeObjectList(cache->miscObjs);
1751
xmlFree(cache);
1752
}
1753
1754
/**
1755
* xmlXPathContextSetCache:
1756
*
1757
* @ctxt: the XPath context
1758
* @active: enables/disables (creates/frees) the cache
1759
* @value: a value with semantics dependent on @options
1760
* @options: options (currently only the value 0 is used)
1761
*
1762
* Creates/frees an object cache on the XPath context.
1763
* If activates XPath objects (xmlXPathObject) will be cached internally
1764
* to be reused.
1765
* @options:
1766
* 0: This will set the XPath object caching:
1767
* @value:
1768
* This will set the maximum number of XPath objects
1769
* to be cached per slot
1770
* There are 5 slots for: node-set, string, number, boolean, and
1771
* misc objects. Use <0 for the default number (100).
1772
* Other values for @options have currently no effect.
1773
*
1774
* Returns 0 if the setting succeeded, and -1 on API or internal errors.
1775
*/
1776
int
1777
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
1778
int active,
1779
int value,
1780
int options)
1781
{
1782
if (ctxt == NULL)
1783
return(-1);
1784
if (active) {
1785
xmlXPathContextCachePtr cache;
1786
1787
if (ctxt->cache == NULL) {
1788
ctxt->cache = xmlXPathNewCache();
1789
if (ctxt->cache == NULL)
1790
return(-1);
1791
}
1792
cache = (xmlXPathContextCachePtr) ctxt->cache;
1793
if (options == 0) {
1794
if (value < 0)
1795
value = 100;
1796
cache->maxNodeset = value;
1797
cache->maxString = value;
1798
cache->maxNumber = value;
1799
cache->maxBoolean = value;
1800
cache->maxMisc = value;
1801
}
1802
} else if (ctxt->cache != NULL) {
1803
xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
1804
ctxt->cache = NULL;
1805
}
1806
return(0);
1807
}
1808
1809
/**
1810
* xmlXPathCacheWrapNodeSet:
1811
* @ctxt: the XPath context
1812
* @val: the NodePtr value
1813
*
1814
* This is the cached version of xmlXPathWrapNodeSet().
1815
* Wrap the Nodeset @val in a new xmlXPathObjectPtr
1816
*
1817
* Returns the created or reused object.
1818
*
1819
* In case of error the node set is destroyed and NULL is returned.
1820
*/
1821
static xmlXPathObjectPtr
1822
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
1823
{
1824
if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1825
xmlXPathContextCachePtr cache =
1826
(xmlXPathContextCachePtr) ctxt->cache;
1827
1828
if ((cache->miscObjs != NULL) &&
1829
(cache->miscObjs->number != 0))
1830
{
1831
xmlXPathObjectPtr ret;
1832
1833
ret = (xmlXPathObjectPtr)
1834
cache->miscObjs->items[--cache->miscObjs->number];
1835
ret->type = XPATH_NODESET;
1836
ret->nodesetval = val;
1837
return(ret);
1838
}
1839
}
1840
1841
return(xmlXPathWrapNodeSet(val));
1842
1843
}
1844
1845
/**
1846
* xmlXPathCacheWrapString:
1847
* @ctxt: the XPath context
1848
* @val: the xmlChar * value
1849
*
1850
* This is the cached version of xmlXPathWrapString().
1851
* Wraps the @val string into an XPath object.
1852
*
1853
* Returns the created or reused object.
1854
*/
1855
static xmlXPathObjectPtr
1856
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
1857
{
1858
if ((ctxt != NULL) && (ctxt->cache != NULL)) {
1859
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1860
1861
if ((cache->stringObjs != NULL) &&
1862
(cache->stringObjs->number != 0))
1863
{
1864
1865
xmlXPathObjectPtr ret;
1866
1867
ret = (xmlXPathObjectPtr)
1868
cache->stringObjs->items[--cache->stringObjs->number];
1869
ret->type = XPATH_STRING;
1870
ret->stringval = val;
1871
return(ret);
1872
} else if ((cache->miscObjs != NULL) &&
1873
(cache->miscObjs->number != 0))
1874
{
1875
xmlXPathObjectPtr ret;
1876
/*
1877
* Fallback to misc-cache.
1878
*/
1879
ret = (xmlXPathObjectPtr)
1880
cache->miscObjs->items[--cache->miscObjs->number];
1881
1882
ret->type = XPATH_STRING;
1883
ret->stringval = val;
1884
return(ret);
1885
}
1886
}
1887
return(xmlXPathWrapString(val));
1888
}
1889
1890
/**
1891
* xmlXPathCacheNewNodeSet:
1892
* @ctxt: the XPath context
1893
* @val: the NodePtr value
1894
*
1895
* This is the cached version of xmlXPathNewNodeSet().
1896
* Acquire an xmlXPathObjectPtr of type NodeSet and initialize
1897
* it with the single Node @val
1898
*
1899
* Returns the created or reused object.
1900
*/
1901
static xmlXPathObjectPtr
1902
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
1903
{
1904
if ((ctxt != NULL) && (ctxt->cache)) {
1905
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1906
1907
if ((cache->nodesetObjs != NULL) &&
1908
(cache->nodesetObjs->number != 0))
1909
{
1910
xmlXPathObjectPtr ret;
1911
/*
1912
* Use the nodeset-cache.
1913
*/
1914
ret = (xmlXPathObjectPtr)
1915
cache->nodesetObjs->items[--cache->nodesetObjs->number];
1916
ret->type = XPATH_NODESET;
1917
ret->boolval = 0;
1918
if (val) {
1919
if ((ret->nodesetval->nodeMax == 0) ||
1920
(val->type == XML_NAMESPACE_DECL))
1921
{
1922
/* TODO: Check memory error. */
1923
xmlXPathNodeSetAddUnique(ret->nodesetval, val);
1924
} else {
1925
ret->nodesetval->nodeTab[0] = val;
1926
ret->nodesetval->nodeNr = 1;
1927
}
1928
}
1929
return(ret);
1930
} else if ((cache->miscObjs != NULL) &&
1931
(cache->miscObjs->number != 0))
1932
{
1933
xmlXPathObjectPtr ret;
1934
xmlNodeSetPtr set;
1935
/*
1936
* Fallback to misc-cache.
1937
*/
1938
1939
set = xmlXPathNodeSetCreate(val);
1940
if (set == NULL) {
1941
ctxt->lastError.domain = XML_FROM_XPATH;
1942
ctxt->lastError.code = XML_ERR_NO_MEMORY;
1943
return(NULL);
1944
}
1945
1946
ret = (xmlXPathObjectPtr)
1947
cache->miscObjs->items[--cache->miscObjs->number];
1948
1949
ret->type = XPATH_NODESET;
1950
ret->boolval = 0;
1951
ret->nodesetval = set;
1952
return(ret);
1953
}
1954
}
1955
return(xmlXPathNewNodeSet(val));
1956
}
1957
1958
/**
1959
* xmlXPathCacheNewString:
1960
* @ctxt: the XPath context
1961
* @val: the xmlChar * value
1962
*
1963
* This is the cached version of xmlXPathNewString().
1964
* Acquire an xmlXPathObjectPtr of type string and of value @val
1965
*
1966
* Returns the created or reused object.
1967
*/
1968
static xmlXPathObjectPtr
1969
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
1970
{
1971
if ((ctxt != NULL) && (ctxt->cache)) {
1972
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
1973
1974
if ((cache->stringObjs != NULL) &&
1975
(cache->stringObjs->number != 0))
1976
{
1977
xmlXPathObjectPtr ret;
1978
xmlChar *copy;
1979
1980
if (val == NULL)
1981
val = BAD_CAST "";
1982
copy = xmlStrdup(val);
1983
if (copy == NULL) {
1984
xmlXPathErrMemory(ctxt, NULL);
1985
return(NULL);
1986
}
1987
1988
ret = (xmlXPathObjectPtr)
1989
cache->stringObjs->items[--cache->stringObjs->number];
1990
ret->type = XPATH_STRING;
1991
ret->stringval = copy;
1992
return(ret);
1993
} else if ((cache->miscObjs != NULL) &&
1994
(cache->miscObjs->number != 0))
1995
{
1996
xmlXPathObjectPtr ret;
1997
xmlChar *copy;
1998
1999
if (val == NULL)
2000
val = BAD_CAST "";
2001
copy = xmlStrdup(val);
2002
if (copy == NULL) {
2003
xmlXPathErrMemory(ctxt, NULL);
2004
return(NULL);
2005
}
2006
2007
ret = (xmlXPathObjectPtr)
2008
cache->miscObjs->items[--cache->miscObjs->number];
2009
2010
ret->type = XPATH_STRING;
2011
ret->stringval = copy;
2012
return(ret);
2013
}
2014
}
2015
return(xmlXPathNewString(val));
2016
}
2017
2018
/**
2019
* xmlXPathCacheNewCString:
2020
* @ctxt: the XPath context
2021
* @val: the char * value
2022
*
2023
* This is the cached version of xmlXPathNewCString().
2024
* Acquire an xmlXPathObjectPtr of type string and of value @val
2025
*
2026
* Returns the created or reused object.
2027
*/
2028
static xmlXPathObjectPtr
2029
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2030
{
2031
return xmlXPathCacheNewString(ctxt, BAD_CAST val);
2032
}
2033
2034
/**
2035
* xmlXPathCacheNewBoolean:
2036
* @ctxt: the XPath context
2037
* @val: the boolean value
2038
*
2039
* This is the cached version of xmlXPathNewBoolean().
2040
* Acquires an xmlXPathObjectPtr of type boolean and of value @val
2041
*
2042
* Returns the created or reused object.
2043
*/
2044
static xmlXPathObjectPtr
2045
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2046
{
2047
if ((ctxt != NULL) && (ctxt->cache)) {
2048
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2049
2050
if ((cache->booleanObjs != NULL) &&
2051
(cache->booleanObjs->number != 0))
2052
{
2053
xmlXPathObjectPtr ret;
2054
2055
ret = (xmlXPathObjectPtr)
2056
cache->booleanObjs->items[--cache->booleanObjs->number];
2057
ret->type = XPATH_BOOLEAN;
2058
ret->boolval = (val != 0);
2059
return(ret);
2060
} else if ((cache->miscObjs != NULL) &&
2061
(cache->miscObjs->number != 0))
2062
{
2063
xmlXPathObjectPtr ret;
2064
2065
ret = (xmlXPathObjectPtr)
2066
cache->miscObjs->items[--cache->miscObjs->number];
2067
2068
ret->type = XPATH_BOOLEAN;
2069
ret->boolval = (val != 0);
2070
return(ret);
2071
}
2072
}
2073
return(xmlXPathNewBoolean(val));
2074
}
2075
2076
/**
2077
* xmlXPathCacheNewFloat:
2078
* @ctxt: the XPath context
2079
* @val: the double value
2080
*
2081
* This is the cached version of xmlXPathNewFloat().
2082
* Acquires an xmlXPathObjectPtr of type double and of value @val
2083
*
2084
* Returns the created or reused object.
2085
*/
2086
static xmlXPathObjectPtr
2087
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2088
{
2089
if ((ctxt != NULL) && (ctxt->cache)) {
2090
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2091
2092
if ((cache->numberObjs != NULL) &&
2093
(cache->numberObjs->number != 0))
2094
{
2095
xmlXPathObjectPtr ret;
2096
2097
ret = (xmlXPathObjectPtr)
2098
cache->numberObjs->items[--cache->numberObjs->number];
2099
ret->type = XPATH_NUMBER;
2100
ret->floatval = val;
2101
return(ret);
2102
} else if ((cache->miscObjs != NULL) &&
2103
(cache->miscObjs->number != 0))
2104
{
2105
xmlXPathObjectPtr ret;
2106
2107
ret = (xmlXPathObjectPtr)
2108
cache->miscObjs->items[--cache->miscObjs->number];
2109
2110
ret->type = XPATH_NUMBER;
2111
ret->floatval = val;
2112
return(ret);
2113
}
2114
}
2115
return(xmlXPathNewFloat(val));
2116
}
2117
2118
/**
2119
* xmlXPathCacheConvertString:
2120
* @ctxt: the XPath context
2121
* @val: an XPath object
2122
*
2123
* This is the cached version of xmlXPathConvertString().
2124
* Converts an existing object to its string() equivalent
2125
*
2126
* Returns a created or reused object, the old one is freed (cached)
2127
* (or the operation is done directly on @val)
2128
*/
2129
2130
static xmlXPathObjectPtr
2131
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2132
xmlChar *res = NULL;
2133
2134
if (val == NULL)
2135
return(xmlXPathCacheNewCString(ctxt, ""));
2136
2137
switch (val->type) {
2138
case XPATH_UNDEFINED:
2139
break;
2140
case XPATH_NODESET:
2141
case XPATH_XSLT_TREE:
2142
res = xmlXPathCastNodeSetToString(val->nodesetval);
2143
break;
2144
case XPATH_STRING:
2145
return(val);
2146
case XPATH_BOOLEAN:
2147
res = xmlXPathCastBooleanToString(val->boolval);
2148
break;
2149
case XPATH_NUMBER:
2150
res = xmlXPathCastNumberToString(val->floatval);
2151
break;
2152
case XPATH_USERS:
2153
#ifdef LIBXML_XPTR_LOCS_ENABLED
2154
case XPATH_POINT:
2155
case XPATH_RANGE:
2156
case XPATH_LOCATIONSET:
2157
#endif /* LIBXML_XPTR_LOCS_ENABLED */
2158
TODO;
2159
break;
2160
}
2161
xmlXPathReleaseObject(ctxt, val);
2162
if (res == NULL)
2163
return(xmlXPathCacheNewCString(ctxt, ""));
2164
return(xmlXPathCacheWrapString(ctxt, res));
2165
}
2166
2167
/**
2168
* xmlXPathCacheObjectCopy:
2169
* @ctxt: the XPath context
2170
* @val: the original object
2171
*
2172
* This is the cached version of xmlXPathObjectCopy().
2173
* Acquire a copy of a given object
2174
*
2175
* Returns a created or reused created object.
2176
*/
2177
static xmlXPathObjectPtr
2178
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2179
{
2180
if (val == NULL)
2181
return(NULL);
2182
2183
if (XP_HAS_CACHE(ctxt)) {
2184
switch (val->type) {
2185
case XPATH_NODESET:
2186
return(xmlXPathCacheWrapNodeSet(ctxt,
2187
xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2188
case XPATH_STRING:
2189
return(xmlXPathCacheNewString(ctxt, val->stringval));
2190
case XPATH_BOOLEAN:
2191
return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2192
case XPATH_NUMBER:
2193
return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2194
default:
2195
break;
2196
}
2197
}
2198
return(xmlXPathObjectCopy(val));
2199
}
2200
2201
/**
2202
* xmlXPathCacheConvertBoolean:
2203
* @ctxt: the XPath context
2204
* @val: an XPath object
2205
*
2206
* This is the cached version of xmlXPathConvertBoolean().
2207
* Converts an existing object to its boolean() equivalent
2208
*
2209
* Returns a created or reused object, the old one is freed (or the operation
2210
* is done directly on @val)
2211
*/
2212
static xmlXPathObjectPtr
2213
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2214
xmlXPathObjectPtr ret;
2215
2216
if (val == NULL)
2217
return(xmlXPathCacheNewBoolean(ctxt, 0));
2218
if (val->type == XPATH_BOOLEAN)
2219
return(val);
2220
ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2221
xmlXPathReleaseObject(ctxt, val);
2222
return(ret);
2223
}
2224
2225
/**
2226
* xmlXPathCacheConvertNumber:
2227
* @ctxt: the XPath context
2228
* @val: an XPath object
2229
*
2230
* This is the cached version of xmlXPathConvertNumber().
2231
* Converts an existing object to its number() equivalent
2232
*
2233
* Returns a created or reused object, the old one is freed (or the operation
2234
* is done directly on @val)
2235
*/
2236
static xmlXPathObjectPtr
2237
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2238
xmlXPathObjectPtr ret;
2239
2240
if (val == NULL)
2241
return(xmlXPathCacheNewFloat(ctxt, 0.0));
2242
if (val->type == XPATH_NUMBER)
2243
return(val);
2244
ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2245
xmlXPathReleaseObject(ctxt, val);
2246
return(ret);
2247
}
2248
2249
/************************************************************************
2250
* *
2251
* Parser stacks related functions and macros *
2252
* *
2253
************************************************************************/
2254
2255
/**
2256
* valuePop:
2257
* @ctxt: an XPath evaluation context
2258
*
2259
* Pops the top XPath object from the value stack
2260
*
2261
* Returns the XPath object just removed
2262
*/
2263
xmlXPathObjectPtr
2264
valuePop(xmlXPathParserContextPtr ctxt)
2265
{
2266
xmlXPathObjectPtr ret;
2267
2268
if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2269
return (NULL);
2270
2271
ctxt->valueNr--;
2272
if (ctxt->valueNr > 0)
2273
ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2274
else
2275
ctxt->value = NULL;
2276
ret = ctxt->valueTab[ctxt->valueNr];
2277
ctxt->valueTab[ctxt->valueNr] = NULL;
2278
return (ret);
2279
}
2280
/**
2281
* valuePush:
2282
* @ctxt: an XPath evaluation context
2283
* @value: the XPath object
2284
*
2285
* Pushes a new XPath object on top of the value stack. If value is NULL,
2286
* a memory error is recorded in the parser context.
2287
*
2288
* Returns the number of items on the value stack, or -1 in case of error.
2289
*
2290
* The object is destroyed in case of error.
2291
*/
2292
int
2293
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2294
{
2295
if (ctxt == NULL) return(-1);
2296
if (value == NULL) {
2297
/*
2298
* A NULL value typically indicates that a memory allocation failed,
2299
* so we set ctxt->error here to propagate the error.
2300
*/
2301
ctxt->error = XPATH_MEMORY_ERROR;
2302
return(-1);
2303
}
2304
if (ctxt->valueNr >= ctxt->valueMax) {
2305
xmlXPathObjectPtr *tmp;
2306
2307
if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2308
xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
2309
xmlXPathFreeObject(value);
2310
return (-1);
2311
}
2312
tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2313
2 * ctxt->valueMax *
2314
sizeof(ctxt->valueTab[0]));
2315
if (tmp == NULL) {
2316
xmlXPathPErrMemory(ctxt, "pushing value\n");
2317
xmlXPathFreeObject(value);
2318
return (-1);
2319
}
2320
ctxt->valueMax *= 2;
2321
ctxt->valueTab = tmp;
2322
}
2323
ctxt->valueTab[ctxt->valueNr] = value;
2324
ctxt->value = value;
2325
return (ctxt->valueNr++);
2326
}
2327
2328
/**
2329
* xmlXPathPopBoolean:
2330
* @ctxt: an XPath parser context
2331
*
2332
* Pops a boolean from the stack, handling conversion if needed.
2333
* Check error with #xmlXPathCheckError.
2334
*
2335
* Returns the boolean
2336
*/
2337
int
2338
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2339
xmlXPathObjectPtr obj;
2340
int ret;
2341
2342
obj = valuePop(ctxt);
2343
if (obj == NULL) {
2344
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2345
return(0);
2346
}
2347
if (obj->type != XPATH_BOOLEAN)
2348
ret = xmlXPathCastToBoolean(obj);
2349
else
2350
ret = obj->boolval;
2351
xmlXPathReleaseObject(ctxt->context, obj);
2352
return(ret);
2353
}
2354
2355
/**
2356
* xmlXPathPopNumber:
2357
* @ctxt: an XPath parser context
2358
*
2359
* Pops a number from the stack, handling conversion if needed.
2360
* Check error with #xmlXPathCheckError.
2361
*
2362
* Returns the number
2363
*/
2364
double
2365
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2366
xmlXPathObjectPtr obj;
2367
double ret;
2368
2369
obj = valuePop(ctxt);
2370
if (obj == NULL) {
2371
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2372
return(0);
2373
}
2374
if (obj->type != XPATH_NUMBER)
2375
ret = xmlXPathCastToNumber(obj);
2376
else
2377
ret = obj->floatval;
2378
xmlXPathReleaseObject(ctxt->context, obj);
2379
return(ret);
2380
}
2381
2382
/**
2383
* xmlXPathPopString:
2384
* @ctxt: an XPath parser context
2385
*
2386
* Pops a string from the stack, handling conversion if needed.
2387
* Check error with #xmlXPathCheckError.
2388
*
2389
* Returns the string
2390
*/
2391
xmlChar *
2392
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2393
xmlXPathObjectPtr obj;
2394
xmlChar * ret;
2395
2396
obj = valuePop(ctxt);
2397
if (obj == NULL) {
2398
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2399
return(NULL);
2400
}
2401
ret = xmlXPathCastToString(obj); /* this does required strdup */
2402
/* TODO: needs refactoring somewhere else */
2403
if (obj->stringval == ret)
2404
obj->stringval = NULL;
2405
xmlXPathReleaseObject(ctxt->context, obj);
2406
return(ret);
2407
}
2408
2409
/**
2410
* xmlXPathPopNodeSet:
2411
* @ctxt: an XPath parser context
2412
*
2413
* Pops a node-set from the stack, handling conversion if needed.
2414
* Check error with #xmlXPathCheckError.
2415
*
2416
* Returns the node-set
2417
*/
2418
xmlNodeSetPtr
2419
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2420
xmlXPathObjectPtr obj;
2421
xmlNodeSetPtr ret;
2422
2423
if (ctxt == NULL) return(NULL);
2424
if (ctxt->value == NULL) {
2425
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2426
return(NULL);
2427
}
2428
if (!xmlXPathStackIsNodeSet(ctxt)) {
2429
xmlXPathSetTypeError(ctxt);
2430
return(NULL);
2431
}
2432
obj = valuePop(ctxt);
2433
ret = obj->nodesetval;
2434
#if 0
2435
/* to fix memory leak of not clearing obj->user */
2436
if (obj->boolval && obj->user != NULL)
2437
xmlFreeNodeList((xmlNodePtr) obj->user);
2438
#endif
2439
obj->nodesetval = NULL;
2440
xmlXPathReleaseObject(ctxt->context, obj);
2441
return(ret);
2442
}
2443
2444
/**
2445
* xmlXPathPopExternal:
2446
* @ctxt: an XPath parser context
2447
*
2448
* Pops an external object from the stack, handling conversion if needed.
2449
* Check error with #xmlXPathCheckError.
2450
*
2451
* Returns the object
2452
*/
2453
void *
2454
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
2455
xmlXPathObjectPtr obj;
2456
void * ret;
2457
2458
if ((ctxt == NULL) || (ctxt->value == NULL)) {
2459
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2460
return(NULL);
2461
}
2462
if (ctxt->value->type != XPATH_USERS) {
2463
xmlXPathSetTypeError(ctxt);
2464
return(NULL);
2465
}
2466
obj = valuePop(ctxt);
2467
ret = obj->user;
2468
obj->user = NULL;
2469
xmlXPathReleaseObject(ctxt->context, obj);
2470
return(ret);
2471
}
2472
2473
/*
2474
* Macros for accessing the content. Those should be used only by the parser,
2475
* and not exported.
2476
*
2477
* Dirty macros, i.e. one need to make assumption on the context to use them
2478
*
2479
* CUR_PTR return the current pointer to the xmlChar to be parsed.
2480
* CUR returns the current xmlChar value, i.e. a 8 bit value
2481
* in ISO-Latin or UTF-8.
2482
* This should be used internally by the parser
2483
* only to compare to ASCII values otherwise it would break when
2484
* running with UTF-8 encoding.
2485
* NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
2486
* to compare on ASCII based substring.
2487
* SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
2488
* strings within the parser.
2489
* CURRENT Returns the current char value, with the full decoding of
2490
* UTF-8 if we are using this mode. It returns an int.
2491
* NEXT Skip to the next character, this does the proper decoding
2492
* in UTF-8 mode. It also pop-up unfinished entities on the fly.
2493
* It returns the pointer to the current xmlChar.
2494
*/
2495
2496
#define CUR (*ctxt->cur)
2497
#define SKIP(val) ctxt->cur += (val)
2498
#define NXT(val) ctxt->cur[(val)]
2499
#define CUR_PTR ctxt->cur
2500
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
2501
2502
#define COPY_BUF(l,b,i,v) \
2503
if (l == 1) b[i++] = v; \
2504
else i += xmlCopyChar(l,&b[i],v)
2505
2506
#define NEXTL(l) ctxt->cur += l
2507
2508
#define SKIP_BLANKS \
2509
while (IS_BLANK_CH(*(ctxt->cur))) NEXT
2510
2511
#define CURRENT (*ctxt->cur)
2512
#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
2513
2514
2515
#ifndef DBL_DIG
2516
#define DBL_DIG 16
2517
#endif
2518
#ifndef DBL_EPSILON
2519
#define DBL_EPSILON 1E-9
2520
#endif
2521
2522
#define UPPER_DOUBLE 1E9
2523
#define LOWER_DOUBLE 1E-5
2524
#define LOWER_DOUBLE_EXP 5
2525
2526
#define INTEGER_DIGITS DBL_DIG
2527
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
2528
#define EXPONENT_DIGITS (3 + 2)
2529
2530
/**
2531
* xmlXPathFormatNumber:
2532
* @number: number to format
2533
* @buffer: output buffer
2534
* @buffersize: size of output buffer
2535
*
2536
* Convert the number into a string representation.
2537
*/
2538
static void
2539
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
2540
{
2541
switch (xmlXPathIsInf(number)) {
2542
case 1:
2543
if (buffersize > (int)sizeof("Infinity"))
2544
snprintf(buffer, buffersize, "Infinity");
2545
break;
2546
case -1:
2547
if (buffersize > (int)sizeof("-Infinity"))
2548
snprintf(buffer, buffersize, "-Infinity");
2549
break;
2550
default:
2551
if (xmlXPathIsNaN(number)) {
2552
if (buffersize > (int)sizeof("NaN"))
2553
snprintf(buffer, buffersize, "NaN");
2554
} else if (number == 0) {
2555
/* Omit sign for negative zero. */
2556
snprintf(buffer, buffersize, "0");
2557
} else if ((number > INT_MIN) && (number < INT_MAX) &&
2558
(number == (int) number)) {
2559
char work[30];
2560
char *ptr, *cur;
2561
int value = (int) number;
2562
2563
ptr = &buffer[0];
2564
if (value == 0) {
2565
*ptr++ = '0';
2566
} else {
2567
snprintf(work, 29, "%d", value);
2568
cur = &work[0];
2569
while ((*cur) && (ptr - buffer < buffersize)) {
2570
*ptr++ = *cur++;
2571
}
2572
}
2573
if (ptr - buffer < buffersize) {
2574
*ptr = 0;
2575
} else if (buffersize > 0) {
2576
ptr--;
2577
*ptr = 0;
2578
}
2579
} else {
2580
/*
2581
For the dimension of work,
2582
DBL_DIG is number of significant digits
2583
EXPONENT is only needed for "scientific notation"
2584
3 is sign, decimal point, and terminating zero
2585
LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
2586
Note that this dimension is slightly (a few characters)
2587
larger than actually necessary.
2588
*/
2589
char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
2590
int integer_place, fraction_place;
2591
char *ptr;
2592
char *after_fraction;
2593
double absolute_value;
2594
int size;
2595
2596
absolute_value = fabs(number);
2597
2598
/*
2599
* First choose format - scientific or regular floating point.
2600
* In either case, result is in work, and after_fraction points
2601
* just past the fractional part.
2602
*/
2603
if ( ((absolute_value > UPPER_DOUBLE) ||
2604
(absolute_value < LOWER_DOUBLE)) &&
2605
(absolute_value != 0.0) ) {
2606
/* Use scientific notation */
2607
integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
2608
fraction_place = DBL_DIG - 1;
2609
size = snprintf(work, sizeof(work),"%*.*e",
2610
integer_place, fraction_place, number);
2611
while ((size > 0) && (work[size] != 'e')) size--;
2612
2613
}
2614
else {
2615
/* Use regular notation */
2616
if (absolute_value > 0.0) {
2617
integer_place = (int)log10(absolute_value);
2618
if (integer_place > 0)
2619
fraction_place = DBL_DIG - integer_place - 1;
2620
else
2621
fraction_place = DBL_DIG - integer_place;
2622
} else {
2623
fraction_place = 1;
2624
}
2625
size = snprintf(work, sizeof(work), "%0.*f",
2626
fraction_place, number);
2627
}
2628
2629
/* Remove leading spaces sometimes inserted by snprintf */
2630
while (work[0] == ' ') {
2631
for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
2632
size--;
2633
}
2634
2635
/* Remove fractional trailing zeroes */
2636
after_fraction = work + size;
2637
ptr = after_fraction;
2638
while (*(--ptr) == '0')
2639
;
2640
if (*ptr != '.')
2641
ptr++;
2642
while ((*ptr++ = *after_fraction++) != 0);
2643
2644
/* Finally copy result back to caller */
2645
size = strlen(work) + 1;
2646
if (size > buffersize) {
2647
#if 0 /* avoid compiler warning */
2648
work[buffersize - 1] = 0;
2649
#endif
2650
size = buffersize;
2651
}
2652
memmove(buffer, work, size);
2653
}
2654
break;
2655
}
2656
}
2657
2658
2659
/************************************************************************
2660
* *
2661
* Routines to handle NodeSets *
2662
* *
2663
************************************************************************/
2664
2665
/**
2666
* xmlXPathOrderDocElems:
2667
* @doc: an input document
2668
*
2669
* Call this routine to speed up XPath computation on static documents.
2670
* This stamps all the element nodes with the document order
2671
* Like for line information, the order is kept in the element->content
2672
* field, the value stored is actually - the node number (starting at -1)
2673
* to be able to differentiate from line numbers.
2674
*
2675
* Returns the number of elements found in the document or -1 in case
2676
* of error.
2677
*/
2678
long
2679
xmlXPathOrderDocElems(xmlDocPtr doc) {
2680
ptrdiff_t count = 0;
2681
xmlNodePtr cur;
2682
2683
if (doc == NULL)
2684
return(-1);
2685
cur = doc->children;
2686
while (cur != NULL) {
2687
if (cur->type == XML_ELEMENT_NODE) {
2688
cur->content = (void *) (-(++count));
2689
if (cur->children != NULL) {
2690
cur = cur->children;
2691
continue;
2692
}
2693
}
2694
if (cur->next != NULL) {
2695
cur = cur->next;
2696
continue;
2697
}
2698
do {
2699
cur = cur->parent;
2700
if (cur == NULL)
2701
break;
2702
if (cur == (xmlNodePtr) doc) {
2703
cur = NULL;
2704
break;
2705
}
2706
if (cur->next != NULL) {
2707
cur = cur->next;
2708
break;
2709
}
2710
} while (cur != NULL);
2711
}
2712
return(count);
2713
}
2714
2715
/**
2716
* xmlXPathCmpNodes:
2717
* @node1: the first node
2718
* @node2: the second node
2719
*
2720
* Compare two nodes w.r.t document order
2721
*
2722
* Returns -2 in case of error 1 if first point < second point, 0 if
2723
* it's the same node, -1 otherwise
2724
*/
2725
int
2726
xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
2727
int depth1, depth2;
2728
int attr1 = 0, attr2 = 0;
2729
xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
2730
xmlNodePtr cur, root;
2731
2732
if ((node1 == NULL) || (node2 == NULL))
2733
return(-2);
2734
/*
2735
* a couple of optimizations which will avoid computations in most cases
2736
*/
2737
if (node1 == node2) /* trivial case */
2738
return(0);
2739
if (node1->type == XML_ATTRIBUTE_NODE) {
2740
attr1 = 1;
2741
attrNode1 = node1;
2742
node1 = node1->parent;
2743
}
2744
if (node2->type == XML_ATTRIBUTE_NODE) {
2745
attr2 = 1;
2746
attrNode2 = node2;
2747
node2 = node2->parent;
2748
}
2749
if (node1 == node2) {
2750
if (attr1 == attr2) {
2751
/* not required, but we keep attributes in order */
2752
if (attr1 != 0) {
2753
cur = attrNode2->prev;
2754
while (cur != NULL) {
2755
if (cur == attrNode1)
2756
return (1);
2757
cur = cur->prev;
2758
}
2759
return (-1);
2760
}
2761
return(0);
2762
}
2763
if (attr2 == 1)
2764
return(1);
2765
return(-1);
2766
}
2767
if ((node1->type == XML_NAMESPACE_DECL) ||
2768
(node2->type == XML_NAMESPACE_DECL))
2769
return(1);
2770
if (node1 == node2->prev)
2771
return(1);
2772
if (node1 == node2->next)
2773
return(-1);
2774
2775
/*
2776
* Speedup using document order if available.
2777
*/
2778
if ((node1->type == XML_ELEMENT_NODE) &&
2779
(node2->type == XML_ELEMENT_NODE) &&
2780
(0 > (ptrdiff_t) node1->content) &&
2781
(0 > (ptrdiff_t) node2->content) &&
2782
(node1->doc == node2->doc)) {
2783
ptrdiff_t l1, l2;
2784
2785
l1 = -((ptrdiff_t) node1->content);
2786
l2 = -((ptrdiff_t) node2->content);
2787
if (l1 < l2)
2788
return(1);
2789
if (l1 > l2)
2790
return(-1);
2791
}
2792
2793
/*
2794
* compute depth to root
2795
*/
2796
for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
2797
if (cur->parent == node1)
2798
return(1);
2799
depth2++;
2800
}
2801
root = cur;
2802
for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
2803
if (cur->parent == node2)
2804
return(-1);
2805
depth1++;
2806
}
2807
/*
2808
* Distinct document (or distinct entities :-( ) case.
2809
*/
2810
if (root != cur) {
2811
return(-2);
2812
}
2813
/*
2814
* get the nearest common ancestor.
2815
*/
2816
while (depth1 > depth2) {
2817
depth1--;
2818
node1 = node1->parent;
2819
}
2820
while (depth2 > depth1) {
2821
depth2--;
2822
node2 = node2->parent;
2823
}
2824
while (node1->parent != node2->parent) {
2825
node1 = node1->parent;
2826
node2 = node2->parent;
2827
/* should not happen but just in case ... */
2828
if ((node1 == NULL) || (node2 == NULL))
2829
return(-2);
2830
}
2831
/*
2832
* Find who's first.
2833
*/
2834
if (node1 == node2->prev)
2835
return(1);
2836
if (node1 == node2->next)
2837
return(-1);
2838
/*
2839
* Speedup using document order if available.
2840
*/
2841
if ((node1->type == XML_ELEMENT_NODE) &&
2842
(node2->type == XML_ELEMENT_NODE) &&
2843
(0 > (ptrdiff_t) node1->content) &&
2844
(0 > (ptrdiff_t) node2->content) &&
2845
(node1->doc == node2->doc)) {
2846
ptrdiff_t l1, l2;
2847
2848
l1 = -((ptrdiff_t) node1->content);
2849
l2 = -((ptrdiff_t) node2->content);
2850
if (l1 < l2)
2851
return(1);
2852
if (l1 > l2)
2853
return(-1);
2854
}
2855
2856
for (cur = node1->next;cur != NULL;cur = cur->next)
2857
if (cur == node2)
2858
return(1);
2859
return(-1); /* assume there is no sibling list corruption */
2860
}
2861
2862
/**
2863
* xmlXPathNodeSetSort:
2864
* @set: the node set
2865
*
2866
* Sort the node set in document order
2867
*/
2868
void
2869
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
2870
#ifndef WITH_TIM_SORT
2871
int i, j, incr, len;
2872
xmlNodePtr tmp;
2873
#endif
2874
2875
if (set == NULL)
2876
return;
2877
2878
#ifndef WITH_TIM_SORT
2879
/*
2880
* Use the old Shell's sort implementation to sort the node-set
2881
* Timsort ought to be quite faster
2882
*/
2883
len = set->nodeNr;
2884
for (incr = len / 2; incr > 0; incr /= 2) {
2885
for (i = incr; i < len; i++) {
2886
j = i - incr;
2887
while (j >= 0) {
2888
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
2889
if (xmlXPathCmpNodesExt(set->nodeTab[j],
2890
set->nodeTab[j + incr]) == -1)
2891
#else
2892
if (xmlXPathCmpNodes(set->nodeTab[j],
2893
set->nodeTab[j + incr]) == -1)
2894
#endif
2895
{
2896
tmp = set->nodeTab[j];
2897
set->nodeTab[j] = set->nodeTab[j + incr];
2898
set->nodeTab[j + incr] = tmp;
2899
j -= incr;
2900
} else
2901
break;
2902
}
2903
}
2904
}
2905
#else /* WITH_TIM_SORT */
2906
libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
2907
#endif /* WITH_TIM_SORT */
2908
}
2909
2910
#define XML_NODESET_DEFAULT 10
2911
/**
2912
* xmlXPathNodeSetDupNs:
2913
* @node: the parent node of the namespace XPath node
2914
* @ns: the libxml namespace declaration node.
2915
*
2916
* Namespace node in libxml don't match the XPath semantic. In a node set
2917
* the namespace nodes are duplicated and the next pointer is set to the
2918
* parent node in the XPath semantic.
2919
*
2920
* Returns the newly created object.
2921
*/
2922
static xmlNodePtr
2923
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
2924
xmlNsPtr cur;
2925
2926
if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2927
return(NULL);
2928
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
2929
return((xmlNodePtr) ns);
2930
2931
/*
2932
* Allocate a new Namespace and fill the fields.
2933
*/
2934
cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
2935
if (cur == NULL) {
2936
xmlXPathErrMemory(NULL, "duplicating namespace\n");
2937
return(NULL);
2938
}
2939
memset(cur, 0, sizeof(xmlNs));
2940
cur->type = XML_NAMESPACE_DECL;
2941
if (ns->href != NULL)
2942
cur->href = xmlStrdup(ns->href);
2943
if (ns->prefix != NULL)
2944
cur->prefix = xmlStrdup(ns->prefix);
2945
cur->next = (xmlNsPtr) node;
2946
return((xmlNodePtr) cur);
2947
}
2948
2949
/**
2950
* xmlXPathNodeSetFreeNs:
2951
* @ns: the XPath namespace node found in a nodeset.
2952
*
2953
* Namespace nodes in libxml don't match the XPath semantic. In a node set
2954
* the namespace nodes are duplicated and the next pointer is set to the
2955
* parent node in the XPath semantic. Check if such a node needs to be freed
2956
*/
2957
void
2958
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
2959
if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
2960
return;
2961
2962
if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
2963
if (ns->href != NULL)
2964
xmlFree((xmlChar *)ns->href);
2965
if (ns->prefix != NULL)
2966
xmlFree((xmlChar *)ns->prefix);
2967
xmlFree(ns);
2968
}
2969
}
2970
2971
/**
2972
* xmlXPathNodeSetCreate:
2973
* @val: an initial xmlNodePtr, or NULL
2974
*
2975
* Create a new xmlNodeSetPtr of type double and of value @val
2976
*
2977
* Returns the newly created object.
2978
*/
2979
xmlNodeSetPtr
2980
xmlXPathNodeSetCreate(xmlNodePtr val) {
2981
xmlNodeSetPtr ret;
2982
2983
ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
2984
if (ret == NULL) {
2985
xmlXPathErrMemory(NULL, "creating nodeset\n");
2986
return(NULL);
2987
}
2988
memset(ret, 0 , sizeof(xmlNodeSet));
2989
if (val != NULL) {
2990
ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
2991
sizeof(xmlNodePtr));
2992
if (ret->nodeTab == NULL) {
2993
xmlXPathErrMemory(NULL, "creating nodeset\n");
2994
xmlFree(ret);
2995
return(NULL);
2996
}
2997
memset(ret->nodeTab, 0 ,
2998
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
2999
ret->nodeMax = XML_NODESET_DEFAULT;
3000
if (val->type == XML_NAMESPACE_DECL) {
3001
xmlNsPtr ns = (xmlNsPtr) val;
3002
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3003
3004
if (nsNode == NULL) {
3005
xmlXPathFreeNodeSet(ret);
3006
return(NULL);
3007
}
3008
ret->nodeTab[ret->nodeNr++] = nsNode;
3009
} else
3010
ret->nodeTab[ret->nodeNr++] = val;
3011
}
3012
return(ret);
3013
}
3014
3015
/**
3016
* xmlXPathNodeSetContains:
3017
* @cur: the node-set
3018
* @val: the node
3019
*
3020
* checks whether @cur contains @val
3021
*
3022
* Returns true (1) if @cur contains @val, false (0) otherwise
3023
*/
3024
int
3025
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3026
int i;
3027
3028
if ((cur == NULL) || (val == NULL)) return(0);
3029
if (val->type == XML_NAMESPACE_DECL) {
3030
for (i = 0; i < cur->nodeNr; i++) {
3031
if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3032
xmlNsPtr ns1, ns2;
3033
3034
ns1 = (xmlNsPtr) val;
3035
ns2 = (xmlNsPtr) cur->nodeTab[i];
3036
if (ns1 == ns2)
3037
return(1);
3038
if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3039
(xmlStrEqual(ns1->prefix, ns2->prefix)))
3040
return(1);
3041
}
3042
}
3043
} else {
3044
for (i = 0; i < cur->nodeNr; i++) {
3045
if (cur->nodeTab[i] == val)
3046
return(1);
3047
}
3048
}
3049
return(0);
3050
}
3051
3052
/**
3053
* xmlXPathNodeSetAddNs:
3054
* @cur: the initial node set
3055
* @node: the hosting node
3056
* @ns: a the namespace node
3057
*
3058
* add a new namespace node to an existing NodeSet
3059
*
3060
* Returns 0 in case of success and -1 in case of error
3061
*/
3062
int
3063
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3064
int i;
3065
xmlNodePtr nsNode;
3066
3067
if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3068
(ns->type != XML_NAMESPACE_DECL) ||
3069
(node->type != XML_ELEMENT_NODE))
3070
return(-1);
3071
3072
/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3073
/*
3074
* prevent duplicates
3075
*/
3076
for (i = 0;i < cur->nodeNr;i++) {
3077
if ((cur->nodeTab[i] != NULL) &&
3078
(cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3079
(((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3080
(xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3081
return(0);
3082
}
3083
3084
/*
3085
* grow the nodeTab if needed
3086
*/
3087
if (cur->nodeMax == 0) {
3088
cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3089
sizeof(xmlNodePtr));
3090
if (cur->nodeTab == NULL) {
3091
xmlXPathErrMemory(NULL, "growing nodeset\n");
3092
return(-1);
3093
}
3094
memset(cur->nodeTab, 0 ,
3095
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3096
cur->nodeMax = XML_NODESET_DEFAULT;
3097
} else if (cur->nodeNr == cur->nodeMax) {
3098
xmlNodePtr *temp;
3099
3100
if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3101
xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3102
return(-1);
3103
}
3104
temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3105
sizeof(xmlNodePtr));
3106
if (temp == NULL) {
3107
xmlXPathErrMemory(NULL, "growing nodeset\n");
3108
return(-1);
3109
}
3110
cur->nodeMax *= 2;
3111
cur->nodeTab = temp;
3112
}
3113
nsNode = xmlXPathNodeSetDupNs(node, ns);
3114
if(nsNode == NULL)
3115
return(-1);
3116
cur->nodeTab[cur->nodeNr++] = nsNode;
3117
return(0);
3118
}
3119
3120
/**
3121
* xmlXPathNodeSetAdd:
3122
* @cur: the initial node set
3123
* @val: a new xmlNodePtr
3124
*
3125
* add a new xmlNodePtr to an existing NodeSet
3126
*
3127
* Returns 0 in case of success, and -1 in case of error
3128
*/
3129
int
3130
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3131
int i;
3132
3133
if ((cur == NULL) || (val == NULL)) return(-1);
3134
3135
/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3136
/*
3137
* prevent duplicates
3138
*/
3139
for (i = 0;i < cur->nodeNr;i++)
3140
if (cur->nodeTab[i] == val) return(0);
3141
3142
/*
3143
* grow the nodeTab if needed
3144
*/
3145
if (cur->nodeMax == 0) {
3146
cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3147
sizeof(xmlNodePtr));
3148
if (cur->nodeTab == NULL) {
3149
xmlXPathErrMemory(NULL, "growing nodeset\n");
3150
return(-1);
3151
}
3152
memset(cur->nodeTab, 0 ,
3153
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3154
cur->nodeMax = XML_NODESET_DEFAULT;
3155
} else if (cur->nodeNr == cur->nodeMax) {
3156
xmlNodePtr *temp;
3157
3158
if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3159
xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3160
return(-1);
3161
}
3162
temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3163
sizeof(xmlNodePtr));
3164
if (temp == NULL) {
3165
xmlXPathErrMemory(NULL, "growing nodeset\n");
3166
return(-1);
3167
}
3168
cur->nodeMax *= 2;
3169
cur->nodeTab = temp;
3170
}
3171
if (val->type == XML_NAMESPACE_DECL) {
3172
xmlNsPtr ns = (xmlNsPtr) val;
3173
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3174
3175
if (nsNode == NULL)
3176
return(-1);
3177
cur->nodeTab[cur->nodeNr++] = nsNode;
3178
} else
3179
cur->nodeTab[cur->nodeNr++] = val;
3180
return(0);
3181
}
3182
3183
/**
3184
* xmlXPathNodeSetAddUnique:
3185
* @cur: the initial node set
3186
* @val: a new xmlNodePtr
3187
*
3188
* add a new xmlNodePtr to an existing NodeSet, optimized version
3189
* when we are sure the node is not already in the set.
3190
*
3191
* Returns 0 in case of success and -1 in case of failure
3192
*/
3193
int
3194
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3195
if ((cur == NULL) || (val == NULL)) return(-1);
3196
3197
/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3198
/*
3199
* grow the nodeTab if needed
3200
*/
3201
if (cur->nodeMax == 0) {
3202
cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3203
sizeof(xmlNodePtr));
3204
if (cur->nodeTab == NULL) {
3205
xmlXPathErrMemory(NULL, "growing nodeset\n");
3206
return(-1);
3207
}
3208
memset(cur->nodeTab, 0 ,
3209
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3210
cur->nodeMax = XML_NODESET_DEFAULT;
3211
} else if (cur->nodeNr == cur->nodeMax) {
3212
xmlNodePtr *temp;
3213
3214
if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3215
xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3216
return(-1);
3217
}
3218
temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3219
sizeof(xmlNodePtr));
3220
if (temp == NULL) {
3221
xmlXPathErrMemory(NULL, "growing nodeset\n");
3222
return(-1);
3223
}
3224
cur->nodeTab = temp;
3225
cur->nodeMax *= 2;
3226
}
3227
if (val->type == XML_NAMESPACE_DECL) {
3228
xmlNsPtr ns = (xmlNsPtr) val;
3229
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3230
3231
if (nsNode == NULL)
3232
return(-1);
3233
cur->nodeTab[cur->nodeNr++] = nsNode;
3234
} else
3235
cur->nodeTab[cur->nodeNr++] = val;
3236
return(0);
3237
}
3238
3239
/**
3240
* xmlXPathNodeSetMerge:
3241
* @val1: the first NodeSet or NULL
3242
* @val2: the second NodeSet
3243
*
3244
* Merges two nodesets, all nodes from @val2 are added to @val1
3245
* if @val1 is NULL, a new set is created and copied from @val2
3246
*
3247
* Returns @val1 once extended or NULL in case of error.
3248
*
3249
* Frees @val1 in case of error.
3250
*/
3251
xmlNodeSetPtr
3252
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3253
int i, j, initNr, skip;
3254
xmlNodePtr n1, n2;
3255
3256
if (val2 == NULL) return(val1);
3257
if (val1 == NULL) {
3258
val1 = xmlXPathNodeSetCreate(NULL);
3259
if (val1 == NULL)
3260
return (NULL);
3261
}
3262
3263
/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3264
initNr = val1->nodeNr;
3265
3266
for (i = 0;i < val2->nodeNr;i++) {
3267
n2 = val2->nodeTab[i];
3268
/*
3269
* check against duplicates
3270
*/
3271
skip = 0;
3272
for (j = 0; j < initNr; j++) {
3273
n1 = val1->nodeTab[j];
3274
if (n1 == n2) {
3275
skip = 1;
3276
break;
3277
} else if ((n1->type == XML_NAMESPACE_DECL) &&
3278
(n2->type == XML_NAMESPACE_DECL)) {
3279
if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3280
(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3281
((xmlNsPtr) n2)->prefix)))
3282
{
3283
skip = 1;
3284
break;
3285
}
3286
}
3287
}
3288
if (skip)
3289
continue;
3290
3291
/*
3292
* grow the nodeTab if needed
3293
*/
3294
if (val1->nodeMax == 0) {
3295
val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3296
sizeof(xmlNodePtr));
3297
if (val1->nodeTab == NULL) {
3298
xmlXPathErrMemory(NULL, "merging nodeset\n");
3299
goto error;
3300
}
3301
memset(val1->nodeTab, 0 ,
3302
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3303
val1->nodeMax = XML_NODESET_DEFAULT;
3304
} else if (val1->nodeNr == val1->nodeMax) {
3305
xmlNodePtr *temp;
3306
3307
if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3308
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3309
goto error;
3310
}
3311
temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3312
sizeof(xmlNodePtr));
3313
if (temp == NULL) {
3314
xmlXPathErrMemory(NULL, "merging nodeset\n");
3315
goto error;
3316
}
3317
val1->nodeTab = temp;
3318
val1->nodeMax *= 2;
3319
}
3320
if (n2->type == XML_NAMESPACE_DECL) {
3321
xmlNsPtr ns = (xmlNsPtr) n2;
3322
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3323
3324
if (nsNode == NULL)
3325
goto error;
3326
val1->nodeTab[val1->nodeNr++] = nsNode;
3327
} else
3328
val1->nodeTab[val1->nodeNr++] = n2;
3329
}
3330
3331
return(val1);
3332
3333
error:
3334
xmlXPathFreeNodeSet(val1);
3335
return(NULL);
3336
}
3337
3338
3339
/**
3340
* xmlXPathNodeSetMergeAndClear:
3341
* @set1: the first NodeSet or NULL
3342
* @set2: the second NodeSet
3343
*
3344
* Merges two nodesets, all nodes from @set2 are added to @set1.
3345
* Checks for duplicate nodes. Clears set2.
3346
*
3347
* Returns @set1 once extended or NULL in case of error.
3348
*
3349
* Frees @set1 in case of error.
3350
*/
3351
static xmlNodeSetPtr
3352
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3353
{
3354
{
3355
int i, j, initNbSet1;
3356
xmlNodePtr n1, n2;
3357
3358
initNbSet1 = set1->nodeNr;
3359
for (i = 0;i < set2->nodeNr;i++) {
3360
n2 = set2->nodeTab[i];
3361
/*
3362
* Skip duplicates.
3363
*/
3364
for (j = 0; j < initNbSet1; j++) {
3365
n1 = set1->nodeTab[j];
3366
if (n1 == n2) {
3367
goto skip_node;
3368
} else if ((n1->type == XML_NAMESPACE_DECL) &&
3369
(n2->type == XML_NAMESPACE_DECL))
3370
{
3371
if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3372
(xmlStrEqual(((xmlNsPtr) n1)->prefix,
3373
((xmlNsPtr) n2)->prefix)))
3374
{
3375
/*
3376
* Free the namespace node.
3377
*/
3378
xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
3379
goto skip_node;
3380
}
3381
}
3382
}
3383
/*
3384
* grow the nodeTab if needed
3385
*/
3386
if (set1->nodeMax == 0) {
3387
set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3388
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3389
if (set1->nodeTab == NULL) {
3390
xmlXPathErrMemory(NULL, "merging nodeset\n");
3391
goto error;
3392
}
3393
memset(set1->nodeTab, 0,
3394
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3395
set1->nodeMax = XML_NODESET_DEFAULT;
3396
} else if (set1->nodeNr >= set1->nodeMax) {
3397
xmlNodePtr *temp;
3398
3399
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3400
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3401
goto error;
3402
}
3403
temp = (xmlNodePtr *) xmlRealloc(
3404
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3405
if (temp == NULL) {
3406
xmlXPathErrMemory(NULL, "merging nodeset\n");
3407
goto error;
3408
}
3409
set1->nodeTab = temp;
3410
set1->nodeMax *= 2;
3411
}
3412
set1->nodeTab[set1->nodeNr++] = n2;
3413
skip_node:
3414
set2->nodeTab[i] = NULL;
3415
}
3416
}
3417
set2->nodeNr = 0;
3418
return(set1);
3419
3420
error:
3421
xmlXPathFreeNodeSet(set1);
3422
xmlXPathNodeSetClear(set2, 1);
3423
return(NULL);
3424
}
3425
3426
/**
3427
* xmlXPathNodeSetMergeAndClearNoDupls:
3428
* @set1: the first NodeSet or NULL
3429
* @set2: the second NodeSet
3430
*
3431
* Merges two nodesets, all nodes from @set2 are added to @set1.
3432
* Doesn't check for duplicate nodes. Clears set2.
3433
*
3434
* Returns @set1 once extended or NULL in case of error.
3435
*
3436
* Frees @set1 in case of error.
3437
*/
3438
static xmlNodeSetPtr
3439
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
3440
{
3441
{
3442
int i;
3443
xmlNodePtr n2;
3444
3445
for (i = 0;i < set2->nodeNr;i++) {
3446
n2 = set2->nodeTab[i];
3447
if (set1->nodeMax == 0) {
3448
set1->nodeTab = (xmlNodePtr *) xmlMalloc(
3449
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3450
if (set1->nodeTab == NULL) {
3451
xmlXPathErrMemory(NULL, "merging nodeset\n");
3452
goto error;
3453
}
3454
memset(set1->nodeTab, 0,
3455
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
3456
set1->nodeMax = XML_NODESET_DEFAULT;
3457
} else if (set1->nodeNr >= set1->nodeMax) {
3458
xmlNodePtr *temp;
3459
3460
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3461
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3462
goto error;
3463
}
3464
temp = (xmlNodePtr *) xmlRealloc(
3465
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
3466
if (temp == NULL) {
3467
xmlXPathErrMemory(NULL, "merging nodeset\n");
3468
goto error;
3469
}
3470
set1->nodeTab = temp;
3471
set1->nodeMax *= 2;
3472
}
3473
set1->nodeTab[set1->nodeNr++] = n2;
3474
set2->nodeTab[i] = NULL;
3475
}
3476
}
3477
set2->nodeNr = 0;
3478
return(set1);
3479
3480
error:
3481
xmlXPathFreeNodeSet(set1);
3482
xmlXPathNodeSetClear(set2, 1);
3483
return(NULL);
3484
}
3485
3486
/**
3487
* xmlXPathNodeSetDel:
3488
* @cur: the initial node set
3489
* @val: an xmlNodePtr
3490
*
3491
* Removes an xmlNodePtr from an existing NodeSet
3492
*/
3493
void
3494
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
3495
int i;
3496
3497
if (cur == NULL) return;
3498
if (val == NULL) return;
3499
3500
/*
3501
* find node in nodeTab
3502
*/
3503
for (i = 0;i < cur->nodeNr;i++)
3504
if (cur->nodeTab[i] == val) break;
3505
3506
if (i >= cur->nodeNr) { /* not found */
3507
return;
3508
}
3509
if ((cur->nodeTab[i] != NULL) &&
3510
(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
3511
xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
3512
cur->nodeNr--;
3513
for (;i < cur->nodeNr;i++)
3514
cur->nodeTab[i] = cur->nodeTab[i + 1];
3515
cur->nodeTab[cur->nodeNr] = NULL;
3516
}
3517
3518
/**
3519
* xmlXPathNodeSetRemove:
3520
* @cur: the initial node set
3521
* @val: the index to remove
3522
*
3523
* Removes an entry from an existing NodeSet list.
3524
*/
3525
void
3526
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
3527
if (cur == NULL) return;
3528
if (val >= cur->nodeNr) return;
3529
if ((cur->nodeTab[val] != NULL) &&
3530
(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
3531
xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
3532
cur->nodeNr--;
3533
for (;val < cur->nodeNr;val++)
3534
cur->nodeTab[val] = cur->nodeTab[val + 1];
3535
cur->nodeTab[cur->nodeNr] = NULL;
3536
}
3537
3538
/**
3539
* xmlXPathFreeNodeSet:
3540
* @obj: the xmlNodeSetPtr to free
3541
*
3542
* Free the NodeSet compound (not the actual nodes !).
3543
*/
3544
void
3545
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
3546
if (obj == NULL) return;
3547
if (obj->nodeTab != NULL) {
3548
int i;
3549
3550
/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3551
for (i = 0;i < obj->nodeNr;i++)
3552
if ((obj->nodeTab[i] != NULL) &&
3553
(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
3554
xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3555
xmlFree(obj->nodeTab);
3556
}
3557
xmlFree(obj);
3558
}
3559
3560
/**
3561
* xmlXPathNodeSetClearFromPos:
3562
* @set: the node set to be cleared
3563
* @pos: the start position to clear from
3564
*
3565
* Clears the list from temporary XPath objects (e.g. namespace nodes
3566
* are feed) starting with the entry at @pos, but does *not* free the list
3567
* itself. Sets the length of the list to @pos.
3568
*/
3569
static void
3570
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
3571
{
3572
if ((set == NULL) || (pos >= set->nodeNr))
3573
return;
3574
else if ((hasNsNodes)) {
3575
int i;
3576
xmlNodePtr node;
3577
3578
for (i = pos; i < set->nodeNr; i++) {
3579
node = set->nodeTab[i];
3580
if ((node != NULL) &&
3581
(node->type == XML_NAMESPACE_DECL))
3582
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3583
}
3584
}
3585
set->nodeNr = pos;
3586
}
3587
3588
/**
3589
* xmlXPathNodeSetClear:
3590
* @set: the node set to clear
3591
*
3592
* Clears the list from all temporary XPath objects (e.g. namespace nodes
3593
* are feed), but does *not* free the list itself. Sets the length of the
3594
* list to 0.
3595
*/
3596
static void
3597
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
3598
{
3599
xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
3600
}
3601
3602
/**
3603
* xmlXPathNodeSetKeepLast:
3604
* @set: the node set to be cleared
3605
*
3606
* Move the last node to the first position and clear temporary XPath objects
3607
* (e.g. namespace nodes) from all other nodes. Sets the length of the list
3608
* to 1.
3609
*/
3610
static void
3611
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
3612
{
3613
int i;
3614
xmlNodePtr node;
3615
3616
if ((set == NULL) || (set->nodeNr <= 1))
3617
return;
3618
for (i = 0; i < set->nodeNr - 1; i++) {
3619
node = set->nodeTab[i];
3620
if ((node != NULL) &&
3621
(node->type == XML_NAMESPACE_DECL))
3622
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
3623
}
3624
set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
3625
set->nodeNr = 1;
3626
}
3627
3628
/**
3629
* xmlXPathFreeValueTree:
3630
* @obj: the xmlNodeSetPtr to free
3631
*
3632
* Free the NodeSet compound and the actual tree, this is different
3633
* from xmlXPathFreeNodeSet()
3634
*/
3635
static void
3636
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
3637
int i;
3638
3639
if (obj == NULL) return;
3640
3641
if (obj->nodeTab != NULL) {
3642
for (i = 0;i < obj->nodeNr;i++) {
3643
if (obj->nodeTab[i] != NULL) {
3644
if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3645
xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
3646
} else {
3647
xmlFreeNodeList(obj->nodeTab[i]);
3648
}
3649
}
3650
}
3651
xmlFree(obj->nodeTab);
3652
}
3653
xmlFree(obj);
3654
}
3655
3656
/**
3657
* xmlXPathNewNodeSet:
3658
* @val: the NodePtr value
3659
*
3660
* Create a new xmlXPathObjectPtr of type NodeSet and initialize
3661
* it with the single Node @val
3662
*
3663
* Returns the newly created object.
3664
*/
3665
xmlXPathObjectPtr
3666
xmlXPathNewNodeSet(xmlNodePtr val) {
3667
xmlXPathObjectPtr ret;
3668
3669
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3670
if (ret == NULL) {
3671
xmlXPathErrMemory(NULL, "creating nodeset\n");
3672
return(NULL);
3673
}
3674
memset(ret, 0 , sizeof(xmlXPathObject));
3675
ret->type = XPATH_NODESET;
3676
ret->boolval = 0;
3677
/* TODO: Check memory error. */
3678
ret->nodesetval = xmlXPathNodeSetCreate(val);
3679
/* @@ with_ns to check whether namespace nodes should be looked at @@ */
3680
return(ret);
3681
}
3682
3683
/**
3684
* xmlXPathNewValueTree:
3685
* @val: the NodePtr value
3686
*
3687
* Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
3688
* it with the tree root @val
3689
*
3690
* Returns the newly created object.
3691
*/
3692
xmlXPathObjectPtr
3693
xmlXPathNewValueTree(xmlNodePtr val) {
3694
xmlXPathObjectPtr ret;
3695
3696
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3697
if (ret == NULL) {
3698
xmlXPathErrMemory(NULL, "creating result value tree\n");
3699
return(NULL);
3700
}
3701
memset(ret, 0 , sizeof(xmlXPathObject));
3702
ret->type = XPATH_XSLT_TREE;
3703
ret->boolval = 1;
3704
ret->user = (void *) val;
3705
ret->nodesetval = xmlXPathNodeSetCreate(val);
3706
return(ret);
3707
}
3708
3709
/**
3710
* xmlXPathNewNodeSetList:
3711
* @val: an existing NodeSet
3712
*
3713
* Create a new xmlXPathObjectPtr of type NodeSet and initialize
3714
* it with the Nodeset @val
3715
*
3716
* Returns the newly created object.
3717
*/
3718
xmlXPathObjectPtr
3719
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
3720
{
3721
xmlXPathObjectPtr ret;
3722
int i;
3723
3724
if (val == NULL)
3725
ret = NULL;
3726
else if (val->nodeTab == NULL)
3727
ret = xmlXPathNewNodeSet(NULL);
3728
else {
3729
ret = xmlXPathNewNodeSet(val->nodeTab[0]);
3730
if (ret) {
3731
for (i = 1; i < val->nodeNr; ++i) {
3732
/* TODO: Propagate memory error. */
3733
if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
3734
< 0) break;
3735
}
3736
}
3737
}
3738
3739
return (ret);
3740
}
3741
3742
/**
3743
* xmlXPathWrapNodeSet:
3744
* @val: the NodePtr value
3745
*
3746
* Wrap the Nodeset @val in a new xmlXPathObjectPtr
3747
*
3748
* Returns the newly created object.
3749
*
3750
* In case of error the node set is destroyed and NULL is returned.
3751
*/
3752
xmlXPathObjectPtr
3753
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
3754
xmlXPathObjectPtr ret;
3755
3756
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3757
if (ret == NULL) {
3758
xmlXPathErrMemory(NULL, "creating node set object\n");
3759
xmlXPathFreeNodeSet(val);
3760
return(NULL);
3761
}
3762
memset(ret, 0 , sizeof(xmlXPathObject));
3763
ret->type = XPATH_NODESET;
3764
ret->nodesetval = val;
3765
return(ret);
3766
}
3767
3768
/**
3769
* xmlXPathFreeNodeSetList:
3770
* @obj: an existing NodeSetList object
3771
*
3772
* Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
3773
* the list contrary to xmlXPathFreeObject().
3774
*/
3775
void
3776
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
3777
if (obj == NULL) return;
3778
xmlFree(obj);
3779
}
3780
3781
/**
3782
* xmlXPathDifference:
3783
* @nodes1: a node-set
3784
* @nodes2: a node-set
3785
*
3786
* Implements the EXSLT - Sets difference() function:
3787
* node-set set:difference (node-set, node-set)
3788
*
3789
* Returns the difference between the two node sets, or nodes1 if
3790
* nodes2 is empty
3791
*/
3792
xmlNodeSetPtr
3793
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3794
xmlNodeSetPtr ret;
3795
int i, l1;
3796
xmlNodePtr cur;
3797
3798
if (xmlXPathNodeSetIsEmpty(nodes2))
3799
return(nodes1);
3800
3801
/* TODO: Check memory error. */
3802
ret = xmlXPathNodeSetCreate(NULL);
3803
if (xmlXPathNodeSetIsEmpty(nodes1))
3804
return(ret);
3805
3806
l1 = xmlXPathNodeSetGetLength(nodes1);
3807
3808
for (i = 0; i < l1; i++) {
3809
cur = xmlXPathNodeSetItem(nodes1, i);
3810
if (!xmlXPathNodeSetContains(nodes2, cur)) {
3811
/* TODO: Propagate memory error. */
3812
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3813
break;
3814
}
3815
}
3816
return(ret);
3817
}
3818
3819
/**
3820
* xmlXPathIntersection:
3821
* @nodes1: a node-set
3822
* @nodes2: a node-set
3823
*
3824
* Implements the EXSLT - Sets intersection() function:
3825
* node-set set:intersection (node-set, node-set)
3826
*
3827
* Returns a node set comprising the nodes that are within both the
3828
* node sets passed as arguments
3829
*/
3830
xmlNodeSetPtr
3831
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3832
xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
3833
int i, l1;
3834
xmlNodePtr cur;
3835
3836
if (ret == NULL)
3837
return(ret);
3838
if (xmlXPathNodeSetIsEmpty(nodes1))
3839
return(ret);
3840
if (xmlXPathNodeSetIsEmpty(nodes2))
3841
return(ret);
3842
3843
l1 = xmlXPathNodeSetGetLength(nodes1);
3844
3845
for (i = 0; i < l1; i++) {
3846
cur = xmlXPathNodeSetItem(nodes1, i);
3847
if (xmlXPathNodeSetContains(nodes2, cur)) {
3848
/* TODO: Propagate memory error. */
3849
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3850
break;
3851
}
3852
}
3853
return(ret);
3854
}
3855
3856
/**
3857
* xmlXPathDistinctSorted:
3858
* @nodes: a node-set, sorted by document order
3859
*
3860
* Implements the EXSLT - Sets distinct() function:
3861
* node-set set:distinct (node-set)
3862
*
3863
* Returns a subset of the nodes contained in @nodes, or @nodes if
3864
* it is empty
3865
*/
3866
xmlNodeSetPtr
3867
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
3868
xmlNodeSetPtr ret;
3869
xmlHashTablePtr hash;
3870
int i, l;
3871
xmlChar * strval;
3872
xmlNodePtr cur;
3873
3874
if (xmlXPathNodeSetIsEmpty(nodes))
3875
return(nodes);
3876
3877
ret = xmlXPathNodeSetCreate(NULL);
3878
if (ret == NULL)
3879
return(ret);
3880
l = xmlXPathNodeSetGetLength(nodes);
3881
hash = xmlHashCreate (l);
3882
for (i = 0; i < l; i++) {
3883
cur = xmlXPathNodeSetItem(nodes, i);
3884
strval = xmlXPathCastNodeToString(cur);
3885
if (xmlHashLookup(hash, strval) == NULL) {
3886
if (xmlHashAddEntry(hash, strval, strval) < 0) {
3887
xmlFree(strval);
3888
goto error;
3889
}
3890
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3891
goto error;
3892
} else {
3893
xmlFree(strval);
3894
}
3895
}
3896
xmlHashFree(hash, xmlHashDefaultDeallocator);
3897
return(ret);
3898
3899
error:
3900
xmlHashFree(hash, xmlHashDefaultDeallocator);
3901
xmlXPathFreeNodeSet(ret);
3902
return(NULL);
3903
}
3904
3905
/**
3906
* xmlXPathDistinct:
3907
* @nodes: a node-set
3908
*
3909
* Implements the EXSLT - Sets distinct() function:
3910
* node-set set:distinct (node-set)
3911
* @nodes is sorted by document order, then #exslSetsDistinctSorted
3912
* is called with the sorted node-set
3913
*
3914
* Returns a subset of the nodes contained in @nodes, or @nodes if
3915
* it is empty
3916
*/
3917
xmlNodeSetPtr
3918
xmlXPathDistinct (xmlNodeSetPtr nodes) {
3919
if (xmlXPathNodeSetIsEmpty(nodes))
3920
return(nodes);
3921
3922
xmlXPathNodeSetSort(nodes);
3923
return(xmlXPathDistinctSorted(nodes));
3924
}
3925
3926
/**
3927
* xmlXPathHasSameNodes:
3928
* @nodes1: a node-set
3929
* @nodes2: a node-set
3930
*
3931
* Implements the EXSLT - Sets has-same-nodes function:
3932
* boolean set:has-same-node(node-set, node-set)
3933
*
3934
* Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
3935
* otherwise
3936
*/
3937
int
3938
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
3939
int i, l;
3940
xmlNodePtr cur;
3941
3942
if (xmlXPathNodeSetIsEmpty(nodes1) ||
3943
xmlXPathNodeSetIsEmpty(nodes2))
3944
return(0);
3945
3946
l = xmlXPathNodeSetGetLength(nodes1);
3947
for (i = 0; i < l; i++) {
3948
cur = xmlXPathNodeSetItem(nodes1, i);
3949
if (xmlXPathNodeSetContains(nodes2, cur))
3950
return(1);
3951
}
3952
return(0);
3953
}
3954
3955
/**
3956
* xmlXPathNodeLeadingSorted:
3957
* @nodes: a node-set, sorted by document order
3958
* @node: a node
3959
*
3960
* Implements the EXSLT - Sets leading() function:
3961
* node-set set:leading (node-set, node-set)
3962
*
3963
* Returns the nodes in @nodes that precede @node in document order,
3964
* @nodes if @node is NULL or an empty node-set if @nodes
3965
* doesn't contain @node
3966
*/
3967
xmlNodeSetPtr
3968
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
3969
int i, l;
3970
xmlNodePtr cur;
3971
xmlNodeSetPtr ret;
3972
3973
if (node == NULL)
3974
return(nodes);
3975
3976
ret = xmlXPathNodeSetCreate(NULL);
3977
if (ret == NULL)
3978
return(ret);
3979
if (xmlXPathNodeSetIsEmpty(nodes) ||
3980
(!xmlXPathNodeSetContains(nodes, node)))
3981
return(ret);
3982
3983
l = xmlXPathNodeSetGetLength(nodes);
3984
for (i = 0; i < l; i++) {
3985
cur = xmlXPathNodeSetItem(nodes, i);
3986
if (cur == node)
3987
break;
3988
/* TODO: Propagate memory error. */
3989
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
3990
break;
3991
}
3992
return(ret);
3993
}
3994
3995
/**
3996
* xmlXPathNodeLeading:
3997
* @nodes: a node-set
3998
* @node: a node
3999
*
4000
* Implements the EXSLT - Sets leading() function:
4001
* node-set set:leading (node-set, node-set)
4002
* @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4003
* is called.
4004
*
4005
* Returns the nodes in @nodes that precede @node in document order,
4006
* @nodes if @node is NULL or an empty node-set if @nodes
4007
* doesn't contain @node
4008
*/
4009
xmlNodeSetPtr
4010
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4011
xmlXPathNodeSetSort(nodes);
4012
return(xmlXPathNodeLeadingSorted(nodes, node));
4013
}
4014
4015
/**
4016
* xmlXPathLeadingSorted:
4017
* @nodes1: a node-set, sorted by document order
4018
* @nodes2: a node-set, sorted by document order
4019
*
4020
* Implements the EXSLT - Sets leading() function:
4021
* node-set set:leading (node-set, node-set)
4022
*
4023
* Returns the nodes in @nodes1 that precede the first node in @nodes2
4024
* in document order, @nodes1 if @nodes2 is NULL or empty or
4025
* an empty node-set if @nodes1 doesn't contain @nodes2
4026
*/
4027
xmlNodeSetPtr
4028
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4029
if (xmlXPathNodeSetIsEmpty(nodes2))
4030
return(nodes1);
4031
return(xmlXPathNodeLeadingSorted(nodes1,
4032
xmlXPathNodeSetItem(nodes2, 1)));
4033
}
4034
4035
/**
4036
* xmlXPathLeading:
4037
* @nodes1: a node-set
4038
* @nodes2: a node-set
4039
*
4040
* Implements the EXSLT - Sets leading() function:
4041
* node-set set:leading (node-set, node-set)
4042
* @nodes1 and @nodes2 are sorted by document order, then
4043
* #exslSetsLeadingSorted is called.
4044
*
4045
* Returns the nodes in @nodes1 that precede the first node in @nodes2
4046
* in document order, @nodes1 if @nodes2 is NULL or empty or
4047
* an empty node-set if @nodes1 doesn't contain @nodes2
4048
*/
4049
xmlNodeSetPtr
4050
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4051
if (xmlXPathNodeSetIsEmpty(nodes2))
4052
return(nodes1);
4053
if (xmlXPathNodeSetIsEmpty(nodes1))
4054
return(xmlXPathNodeSetCreate(NULL));
4055
xmlXPathNodeSetSort(nodes1);
4056
xmlXPathNodeSetSort(nodes2);
4057
return(xmlXPathNodeLeadingSorted(nodes1,
4058
xmlXPathNodeSetItem(nodes2, 1)));
4059
}
4060
4061
/**
4062
* xmlXPathNodeTrailingSorted:
4063
* @nodes: a node-set, sorted by document order
4064
* @node: a node
4065
*
4066
* Implements the EXSLT - Sets trailing() function:
4067
* node-set set:trailing (node-set, node-set)
4068
*
4069
* Returns the nodes in @nodes that follow @node in document order,
4070
* @nodes if @node is NULL or an empty node-set if @nodes
4071
* doesn't contain @node
4072
*/
4073
xmlNodeSetPtr
4074
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4075
int i, l;
4076
xmlNodePtr cur;
4077
xmlNodeSetPtr ret;
4078
4079
if (node == NULL)
4080
return(nodes);
4081
4082
ret = xmlXPathNodeSetCreate(NULL);
4083
if (ret == NULL)
4084
return(ret);
4085
if (xmlXPathNodeSetIsEmpty(nodes) ||
4086
(!xmlXPathNodeSetContains(nodes, node)))
4087
return(ret);
4088
4089
l = xmlXPathNodeSetGetLength(nodes);
4090
for (i = l - 1; i >= 0; i--) {
4091
cur = xmlXPathNodeSetItem(nodes, i);
4092
if (cur == node)
4093
break;
4094
/* TODO: Propagate memory error. */
4095
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4096
break;
4097
}
4098
xmlXPathNodeSetSort(ret); /* bug 413451 */
4099
return(ret);
4100
}
4101
4102
/**
4103
* xmlXPathNodeTrailing:
4104
* @nodes: a node-set
4105
* @node: a node
4106
*
4107
* Implements the EXSLT - Sets trailing() function:
4108
* node-set set:trailing (node-set, node-set)
4109
* @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4110
* is called.
4111
*
4112
* Returns the nodes in @nodes that follow @node in document order,
4113
* @nodes if @node is NULL or an empty node-set if @nodes
4114
* doesn't contain @node
4115
*/
4116
xmlNodeSetPtr
4117
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4118
xmlXPathNodeSetSort(nodes);
4119
return(xmlXPathNodeTrailingSorted(nodes, node));
4120
}
4121
4122
/**
4123
* xmlXPathTrailingSorted:
4124
* @nodes1: a node-set, sorted by document order
4125
* @nodes2: a node-set, sorted by document order
4126
*
4127
* Implements the EXSLT - Sets trailing() function:
4128
* node-set set:trailing (node-set, node-set)
4129
*
4130
* Returns the nodes in @nodes1 that follow the first node in @nodes2
4131
* in document order, @nodes1 if @nodes2 is NULL or empty or
4132
* an empty node-set if @nodes1 doesn't contain @nodes2
4133
*/
4134
xmlNodeSetPtr
4135
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4136
if (xmlXPathNodeSetIsEmpty(nodes2))
4137
return(nodes1);
4138
return(xmlXPathNodeTrailingSorted(nodes1,
4139
xmlXPathNodeSetItem(nodes2, 0)));
4140
}
4141
4142
/**
4143
* xmlXPathTrailing:
4144
* @nodes1: a node-set
4145
* @nodes2: a node-set
4146
*
4147
* Implements the EXSLT - Sets trailing() function:
4148
* node-set set:trailing (node-set, node-set)
4149
* @nodes1 and @nodes2 are sorted by document order, then
4150
* #xmlXPathTrailingSorted is called.
4151
*
4152
* Returns the nodes in @nodes1 that follow the first node in @nodes2
4153
* in document order, @nodes1 if @nodes2 is NULL or empty or
4154
* an empty node-set if @nodes1 doesn't contain @nodes2
4155
*/
4156
xmlNodeSetPtr
4157
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4158
if (xmlXPathNodeSetIsEmpty(nodes2))
4159
return(nodes1);
4160
if (xmlXPathNodeSetIsEmpty(nodes1))
4161
return(xmlXPathNodeSetCreate(NULL));
4162
xmlXPathNodeSetSort(nodes1);
4163
xmlXPathNodeSetSort(nodes2);
4164
return(xmlXPathNodeTrailingSorted(nodes1,
4165
xmlXPathNodeSetItem(nodes2, 0)));
4166
}
4167
4168
/************************************************************************
4169
* *
4170
* Routines to handle extra functions *
4171
* *
4172
************************************************************************/
4173
4174
/**
4175
* xmlXPathRegisterFunc:
4176
* @ctxt: the XPath context
4177
* @name: the function name
4178
* @f: the function implementation or NULL
4179
*
4180
* Register a new function. If @f is NULL it unregisters the function
4181
*
4182
* Returns 0 in case of success, -1 in case of error
4183
*/
4184
int
4185
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4186
xmlXPathFunction f) {
4187
return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4188
}
4189
4190
/**
4191
* xmlXPathRegisterFuncNS:
4192
* @ctxt: the XPath context
4193
* @name: the function name
4194
* @ns_uri: the function namespace URI
4195
* @f: the function implementation or NULL
4196
*
4197
* Register a new function. If @f is NULL it unregisters the function
4198
*
4199
* Returns 0 in case of success, -1 in case of error
4200
*/
4201
int
4202
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4203
const xmlChar *ns_uri, xmlXPathFunction f) {
4204
if (ctxt == NULL)
4205
return(-1);
4206
if (name == NULL)
4207
return(-1);
4208
4209
if (ctxt->funcHash == NULL)
4210
ctxt->funcHash = xmlHashCreate(0);
4211
if (ctxt->funcHash == NULL)
4212
return(-1);
4213
if (f == NULL)
4214
return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4215
XML_IGNORE_FPTR_CAST_WARNINGS
4216
return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
4217
XML_POP_WARNINGS
4218
}
4219
4220
/**
4221
* xmlXPathRegisterFuncLookup:
4222
* @ctxt: the XPath context
4223
* @f: the lookup function
4224
* @funcCtxt: the lookup data
4225
*
4226
* Registers an external mechanism to do function lookup.
4227
*/
4228
void
4229
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4230
xmlXPathFuncLookupFunc f,
4231
void *funcCtxt) {
4232
if (ctxt == NULL)
4233
return;
4234
ctxt->funcLookupFunc = f;
4235
ctxt->funcLookupData = funcCtxt;
4236
}
4237
4238
/**
4239
* xmlXPathFunctionLookup:
4240
* @ctxt: the XPath context
4241
* @name: the function name
4242
*
4243
* Search in the Function array of the context for the given
4244
* function.
4245
*
4246
* Returns the xmlXPathFunction or NULL if not found
4247
*/
4248
xmlXPathFunction
4249
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4250
if (ctxt == NULL)
4251
return (NULL);
4252
4253
if (ctxt->funcLookupFunc != NULL) {
4254
xmlXPathFunction ret;
4255
xmlXPathFuncLookupFunc f;
4256
4257
f = ctxt->funcLookupFunc;
4258
ret = f(ctxt->funcLookupData, name, NULL);
4259
if (ret != NULL)
4260
return(ret);
4261
}
4262
return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4263
}
4264
4265
/**
4266
* xmlXPathFunctionLookupNS:
4267
* @ctxt: the XPath context
4268
* @name: the function name
4269
* @ns_uri: the function namespace URI
4270
*
4271
* Search in the Function array of the context for the given
4272
* function.
4273
*
4274
* Returns the xmlXPathFunction or NULL if not found
4275
*/
4276
xmlXPathFunction
4277
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4278
const xmlChar *ns_uri) {
4279
xmlXPathFunction ret;
4280
4281
if (ctxt == NULL)
4282
return(NULL);
4283
if (name == NULL)
4284
return(NULL);
4285
4286
if (ctxt->funcLookupFunc != NULL) {
4287
xmlXPathFuncLookupFunc f;
4288
4289
f = ctxt->funcLookupFunc;
4290
ret = f(ctxt->funcLookupData, name, ns_uri);
4291
if (ret != NULL)
4292
return(ret);
4293
}
4294
4295
if (ctxt->funcHash == NULL)
4296
return(NULL);
4297
4298
XML_IGNORE_FPTR_CAST_WARNINGS
4299
ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4300
XML_POP_WARNINGS
4301
return(ret);
4302
}
4303
4304
/**
4305
* xmlXPathRegisteredFuncsCleanup:
4306
* @ctxt: the XPath context
4307
*
4308
* Cleanup the XPath context data associated to registered functions
4309
*/
4310
void
4311
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4312
if (ctxt == NULL)
4313
return;
4314
4315
xmlHashFree(ctxt->funcHash, NULL);
4316
ctxt->funcHash = NULL;
4317
}
4318
4319
/************************************************************************
4320
* *
4321
* Routines to handle Variables *
4322
* *
4323
************************************************************************/
4324
4325
/**
4326
* xmlXPathRegisterVariable:
4327
* @ctxt: the XPath context
4328
* @name: the variable name
4329
* @value: the variable value or NULL
4330
*
4331
* Register a new variable value. If @value is NULL it unregisters
4332
* the variable
4333
*
4334
* Returns 0 in case of success, -1 in case of error
4335
*/
4336
int
4337
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
4338
xmlXPathObjectPtr value) {
4339
return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
4340
}
4341
4342
/**
4343
* xmlXPathRegisterVariableNS:
4344
* @ctxt: the XPath context
4345
* @name: the variable name
4346
* @ns_uri: the variable namespace URI
4347
* @value: the variable value or NULL
4348
*
4349
* Register a new variable value. If @value is NULL it unregisters
4350
* the variable
4351
*
4352
* Returns 0 in case of success, -1 in case of error
4353
*/
4354
int
4355
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4356
const xmlChar *ns_uri,
4357
xmlXPathObjectPtr value) {
4358
if (ctxt == NULL)
4359
return(-1);
4360
if (name == NULL)
4361
return(-1);
4362
4363
if (ctxt->varHash == NULL)
4364
ctxt->varHash = xmlHashCreate(0);
4365
if (ctxt->varHash == NULL)
4366
return(-1);
4367
if (value == NULL)
4368
return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
4369
xmlXPathFreeObjectEntry));
4370
return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
4371
(void *) value, xmlXPathFreeObjectEntry));
4372
}
4373
4374
/**
4375
* xmlXPathRegisterVariableLookup:
4376
* @ctxt: the XPath context
4377
* @f: the lookup function
4378
* @data: the lookup data
4379
*
4380
* register an external mechanism to do variable lookup
4381
*/
4382
void
4383
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
4384
xmlXPathVariableLookupFunc f, void *data) {
4385
if (ctxt == NULL)
4386
return;
4387
ctxt->varLookupFunc = f;
4388
ctxt->varLookupData = data;
4389
}
4390
4391
/**
4392
* xmlXPathVariableLookup:
4393
* @ctxt: the XPath context
4394
* @name: the variable name
4395
*
4396
* Search in the Variable array of the context for the given
4397
* variable value.
4398
*
4399
* Returns a copy of the value or NULL if not found
4400
*/
4401
xmlXPathObjectPtr
4402
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4403
if (ctxt == NULL)
4404
return(NULL);
4405
4406
if (ctxt->varLookupFunc != NULL) {
4407
xmlXPathObjectPtr ret;
4408
4409
ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4410
(ctxt->varLookupData, name, NULL);
4411
return(ret);
4412
}
4413
return(xmlXPathVariableLookupNS(ctxt, name, NULL));
4414
}
4415
4416
/**
4417
* xmlXPathVariableLookupNS:
4418
* @ctxt: the XPath context
4419
* @name: the variable name
4420
* @ns_uri: the variable namespace URI
4421
*
4422
* Search in the Variable array of the context for the given
4423
* variable value.
4424
*
4425
* Returns the a copy of the value or NULL if not found
4426
*/
4427
xmlXPathObjectPtr
4428
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4429
const xmlChar *ns_uri) {
4430
if (ctxt == NULL)
4431
return(NULL);
4432
4433
if (ctxt->varLookupFunc != NULL) {
4434
xmlXPathObjectPtr ret;
4435
4436
ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
4437
(ctxt->varLookupData, name, ns_uri);
4438
if (ret != NULL) return(ret);
4439
}
4440
4441
if (ctxt->varHash == NULL)
4442
return(NULL);
4443
if (name == NULL)
4444
return(NULL);
4445
4446
return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
4447
xmlHashLookup2(ctxt->varHash, name, ns_uri)));
4448
}
4449
4450
/**
4451
* xmlXPathRegisteredVariablesCleanup:
4452
* @ctxt: the XPath context
4453
*
4454
* Cleanup the XPath context data associated to registered variables
4455
*/
4456
void
4457
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
4458
if (ctxt == NULL)
4459
return;
4460
4461
xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
4462
ctxt->varHash = NULL;
4463
}
4464
4465
/**
4466
* xmlXPathRegisterNs:
4467
* @ctxt: the XPath context
4468
* @prefix: the namespace prefix cannot be NULL or empty string
4469
* @ns_uri: the namespace name
4470
*
4471
* Register a new namespace. If @ns_uri is NULL it unregisters
4472
* the namespace
4473
*
4474
* Returns 0 in case of success, -1 in case of error
4475
*/
4476
int
4477
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
4478
const xmlChar *ns_uri) {
4479
xmlChar *copy;
4480
4481
if (ctxt == NULL)
4482
return(-1);
4483
if (prefix == NULL)
4484
return(-1);
4485
if (prefix[0] == 0)
4486
return(-1);
4487
4488
if (ctxt->nsHash == NULL)
4489
ctxt->nsHash = xmlHashCreate(10);
4490
if (ctxt->nsHash == NULL)
4491
return(-1);
4492
if (ns_uri == NULL)
4493
return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
4494
xmlHashDefaultDeallocator));
4495
4496
copy = xmlStrdup(ns_uri);
4497
if (copy == NULL)
4498
return(-1);
4499
if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
4500
xmlHashDefaultDeallocator) < 0) {
4501
xmlFree(copy);
4502
return(-1);
4503
}
4504
4505
return(0);
4506
}
4507
4508
/**
4509
* xmlXPathNsLookup:
4510
* @ctxt: the XPath context
4511
* @prefix: the namespace prefix value
4512
*
4513
* Search in the namespace declaration array of the context for the given
4514
* namespace name associated to the given prefix
4515
*
4516
* Returns the value or NULL if not found
4517
*/
4518
const xmlChar *
4519
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
4520
if (ctxt == NULL)
4521
return(NULL);
4522
if (prefix == NULL)
4523
return(NULL);
4524
4525
#ifdef XML_XML_NAMESPACE
4526
if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
4527
return(XML_XML_NAMESPACE);
4528
#endif
4529
4530
if (ctxt->namespaces != NULL) {
4531
int i;
4532
4533
for (i = 0;i < ctxt->nsNr;i++) {
4534
if ((ctxt->namespaces[i] != NULL) &&
4535
(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
4536
return(ctxt->namespaces[i]->href);
4537
}
4538
}
4539
4540
return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
4541
}
4542
4543
/**
4544
* xmlXPathRegisteredNsCleanup:
4545
* @ctxt: the XPath context
4546
*
4547
* Cleanup the XPath context data associated to registered variables
4548
*/
4549
void
4550
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
4551
if (ctxt == NULL)
4552
return;
4553
4554
xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
4555
ctxt->nsHash = NULL;
4556
}
4557
4558
/************************************************************************
4559
* *
4560
* Routines to handle Values *
4561
* *
4562
************************************************************************/
4563
4564
/* Allocations are terrible, one needs to optimize all this !!! */
4565
4566
/**
4567
* xmlXPathNewFloat:
4568
* @val: the double value
4569
*
4570
* Create a new xmlXPathObjectPtr of type double and of value @val
4571
*
4572
* Returns the newly created object.
4573
*/
4574
xmlXPathObjectPtr
4575
xmlXPathNewFloat(double val) {
4576
xmlXPathObjectPtr ret;
4577
4578
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4579
if (ret == NULL) {
4580
xmlXPathErrMemory(NULL, "creating float object\n");
4581
return(NULL);
4582
}
4583
memset(ret, 0 , sizeof(xmlXPathObject));
4584
ret->type = XPATH_NUMBER;
4585
ret->floatval = val;
4586
return(ret);
4587
}
4588
4589
/**
4590
* xmlXPathNewBoolean:
4591
* @val: the boolean value
4592
*
4593
* Create a new xmlXPathObjectPtr of type boolean and of value @val
4594
*
4595
* Returns the newly created object.
4596
*/
4597
xmlXPathObjectPtr
4598
xmlXPathNewBoolean(int val) {
4599
xmlXPathObjectPtr ret;
4600
4601
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4602
if (ret == NULL) {
4603
xmlXPathErrMemory(NULL, "creating boolean object\n");
4604
return(NULL);
4605
}
4606
memset(ret, 0 , sizeof(xmlXPathObject));
4607
ret->type = XPATH_BOOLEAN;
4608
ret->boolval = (val != 0);
4609
return(ret);
4610
}
4611
4612
/**
4613
* xmlXPathNewString:
4614
* @val: the xmlChar * value
4615
*
4616
* Create a new xmlXPathObjectPtr of type string and of value @val
4617
*
4618
* Returns the newly created object.
4619
*/
4620
xmlXPathObjectPtr
4621
xmlXPathNewString(const xmlChar *val) {
4622
xmlXPathObjectPtr ret;
4623
4624
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4625
if (ret == NULL) {
4626
xmlXPathErrMemory(NULL, "creating string object\n");
4627
return(NULL);
4628
}
4629
memset(ret, 0 , sizeof(xmlXPathObject));
4630
ret->type = XPATH_STRING;
4631
if (val == NULL)
4632
val = BAD_CAST "";
4633
ret->stringval = xmlStrdup(val);
4634
if (ret->stringval == NULL) {
4635
xmlFree(ret);
4636
return(NULL);
4637
}
4638
return(ret);
4639
}
4640
4641
/**
4642
* xmlXPathWrapString:
4643
* @val: the xmlChar * value
4644
*
4645
* Wraps the @val string into an XPath object.
4646
*
4647
* Returns the newly created object.
4648
*
4649
* Frees @val in case of error.
4650
*/
4651
xmlXPathObjectPtr
4652
xmlXPathWrapString (xmlChar *val) {
4653
xmlXPathObjectPtr ret;
4654
4655
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4656
if (ret == NULL) {
4657
xmlXPathErrMemory(NULL, "creating string object\n");
4658
xmlFree(val);
4659
return(NULL);
4660
}
4661
memset(ret, 0 , sizeof(xmlXPathObject));
4662
ret->type = XPATH_STRING;
4663
ret->stringval = val;
4664
return(ret);
4665
}
4666
4667
/**
4668
* xmlXPathNewCString:
4669
* @val: the char * value
4670
*
4671
* Create a new xmlXPathObjectPtr of type string and of value @val
4672
*
4673
* Returns the newly created object.
4674
*/
4675
xmlXPathObjectPtr
4676
xmlXPathNewCString(const char *val) {
4677
return(xmlXPathNewString(BAD_CAST val));
4678
}
4679
4680
/**
4681
* xmlXPathWrapCString:
4682
* @val: the char * value
4683
*
4684
* Wraps a string into an XPath object.
4685
*
4686
* Returns the newly created object.
4687
*/
4688
xmlXPathObjectPtr
4689
xmlXPathWrapCString (char * val) {
4690
return(xmlXPathWrapString((xmlChar *)(val)));
4691
}
4692
4693
/**
4694
* xmlXPathWrapExternal:
4695
* @val: the user data
4696
*
4697
* Wraps the @val data into an XPath object.
4698
*
4699
* Returns the newly created object.
4700
*/
4701
xmlXPathObjectPtr
4702
xmlXPathWrapExternal (void *val) {
4703
xmlXPathObjectPtr ret;
4704
4705
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4706
if (ret == NULL) {
4707
xmlXPathErrMemory(NULL, "creating user object\n");
4708
return(NULL);
4709
}
4710
memset(ret, 0 , sizeof(xmlXPathObject));
4711
ret->type = XPATH_USERS;
4712
ret->user = val;
4713
return(ret);
4714
}
4715
4716
/**
4717
* xmlXPathObjectCopy:
4718
* @val: the original object
4719
*
4720
* allocate a new copy of a given object
4721
*
4722
* Returns the newly created object.
4723
*/
4724
xmlXPathObjectPtr
4725
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
4726
xmlXPathObjectPtr ret;
4727
4728
if (val == NULL)
4729
return(NULL);
4730
4731
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4732
if (ret == NULL) {
4733
xmlXPathErrMemory(NULL, "copying object\n");
4734
return(NULL);
4735
}
4736
memcpy(ret, val , sizeof(xmlXPathObject));
4737
switch (val->type) {
4738
case XPATH_BOOLEAN:
4739
case XPATH_NUMBER:
4740
#ifdef LIBXML_XPTR_LOCS_ENABLED
4741
case XPATH_POINT:
4742
case XPATH_RANGE:
4743
#endif /* LIBXML_XPTR_LOCS_ENABLED */
4744
break;
4745
case XPATH_STRING:
4746
ret->stringval = xmlStrdup(val->stringval);
4747
if (ret->stringval == NULL) {
4748
xmlFree(ret);
4749
return(NULL);
4750
}
4751
break;
4752
case XPATH_XSLT_TREE:
4753
#if 0
4754
/*
4755
Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
4756
this previous handling is no longer correct, and can cause some serious
4757
problems (ref. bug 145547)
4758
*/
4759
if ((val->nodesetval != NULL) &&
4760
(val->nodesetval->nodeTab != NULL)) {
4761
xmlNodePtr cur, tmp;
4762
xmlDocPtr top;
4763
4764
ret->boolval = 1;
4765
top = xmlNewDoc(NULL);
4766
top->name = (char *)
4767
xmlStrdup(val->nodesetval->nodeTab[0]->name);
4768
ret->user = top;
4769
if (top != NULL) {
4770
top->doc = top;
4771
cur = val->nodesetval->nodeTab[0]->children;
4772
while (cur != NULL) {
4773
tmp = xmlDocCopyNode(cur, top, 1);
4774
xmlAddChild((xmlNodePtr) top, tmp);
4775
cur = cur->next;
4776
}
4777
}
4778
4779
ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
4780
} else
4781
ret->nodesetval = xmlXPathNodeSetCreate(NULL);
4782
/* Deallocate the copied tree value */
4783
break;
4784
#endif
4785
case XPATH_NODESET:
4786
/* TODO: Check memory error. */
4787
ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
4788
/* Do not deallocate the copied tree value */
4789
ret->boolval = 0;
4790
break;
4791
#ifdef LIBXML_XPTR_LOCS_ENABLED
4792
case XPATH_LOCATIONSET:
4793
{
4794
xmlLocationSetPtr loc = val->user;
4795
ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
4796
break;
4797
}
4798
#endif
4799
case XPATH_USERS:
4800
ret->user = val->user;
4801
break;
4802
case XPATH_UNDEFINED:
4803
xmlGenericError(xmlGenericErrorContext,
4804
"xmlXPathObjectCopy: unsupported type %d\n",
4805
val->type);
4806
break;
4807
}
4808
return(ret);
4809
}
4810
4811
/**
4812
* xmlXPathFreeObject:
4813
* @obj: the object to free
4814
*
4815
* Free up an xmlXPathObjectPtr object.
4816
*/
4817
void
4818
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
4819
if (obj == NULL) return;
4820
if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
4821
if (obj->boolval) {
4822
#if 0
4823
if (obj->user != NULL) {
4824
xmlXPathFreeNodeSet(obj->nodesetval);
4825
xmlFreeNodeList((xmlNodePtr) obj->user);
4826
} else
4827
#endif
4828
obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
4829
if (obj->nodesetval != NULL)
4830
xmlXPathFreeValueTree(obj->nodesetval);
4831
} else {
4832
if (obj->nodesetval != NULL)
4833
xmlXPathFreeNodeSet(obj->nodesetval);
4834
}
4835
#ifdef LIBXML_XPTR_LOCS_ENABLED
4836
} else if (obj->type == XPATH_LOCATIONSET) {
4837
if (obj->user != NULL)
4838
xmlXPtrFreeLocationSet(obj->user);
4839
#endif
4840
} else if (obj->type == XPATH_STRING) {
4841
if (obj->stringval != NULL)
4842
xmlFree(obj->stringval);
4843
}
4844
xmlFree(obj);
4845
}
4846
4847
static void
4848
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
4849
xmlXPathFreeObject((xmlXPathObjectPtr) obj);
4850
}
4851
4852
/**
4853
* xmlXPathReleaseObject:
4854
* @obj: the xmlXPathObjectPtr to free or to cache
4855
*
4856
* Depending on the state of the cache this frees the given
4857
* XPath object or stores it in the cache.
4858
*/
4859
static void
4860
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
4861
{
4862
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
4863
sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
4864
if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
4865
4866
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
4867
4868
if (obj == NULL)
4869
return;
4870
if ((ctxt == NULL) || (ctxt->cache == NULL)) {
4871
xmlXPathFreeObject(obj);
4872
} else {
4873
xmlXPathContextCachePtr cache =
4874
(xmlXPathContextCachePtr) ctxt->cache;
4875
4876
switch (obj->type) {
4877
case XPATH_NODESET:
4878
case XPATH_XSLT_TREE:
4879
if (obj->nodesetval != NULL) {
4880
if (obj->boolval) {
4881
/*
4882
* It looks like the @boolval is used for
4883
* evaluation if this an XSLT Result Tree Fragment.
4884
* TODO: Check if this assumption is correct.
4885
*/
4886
obj->type = XPATH_XSLT_TREE; /* just for debugging */
4887
xmlXPathFreeValueTree(obj->nodesetval);
4888
obj->nodesetval = NULL;
4889
} else if ((obj->nodesetval->nodeMax <= 40) &&
4890
(XP_CACHE_WANTS(cache->nodesetObjs,
4891
cache->maxNodeset)))
4892
{
4893
XP_CACHE_ADD(cache->nodesetObjs, obj);
4894
goto obj_cached;
4895
} else {
4896
xmlXPathFreeNodeSet(obj->nodesetval);
4897
obj->nodesetval = NULL;
4898
}
4899
}
4900
break;
4901
case XPATH_STRING:
4902
if (obj->stringval != NULL)
4903
xmlFree(obj->stringval);
4904
4905
if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
4906
XP_CACHE_ADD(cache->stringObjs, obj);
4907
goto obj_cached;
4908
}
4909
break;
4910
case XPATH_BOOLEAN:
4911
if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
4912
XP_CACHE_ADD(cache->booleanObjs, obj);
4913
goto obj_cached;
4914
}
4915
break;
4916
case XPATH_NUMBER:
4917
if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
4918
XP_CACHE_ADD(cache->numberObjs, obj);
4919
goto obj_cached;
4920
}
4921
break;
4922
#ifdef LIBXML_XPTR_LOCS_ENABLED
4923
case XPATH_LOCATIONSET:
4924
if (obj->user != NULL) {
4925
xmlXPtrFreeLocationSet(obj->user);
4926
}
4927
goto free_obj;
4928
#endif
4929
default:
4930
goto free_obj;
4931
}
4932
4933
/*
4934
* Fallback to adding to the misc-objects slot.
4935
*/
4936
if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
4937
XP_CACHE_ADD(cache->miscObjs, obj);
4938
} else
4939
goto free_obj;
4940
4941
obj_cached:
4942
if (obj->nodesetval != NULL) {
4943
xmlNodeSetPtr tmpset = obj->nodesetval;
4944
4945
/*
4946
* TODO: Due to those nasty ns-nodes, we need to traverse
4947
* the list and free the ns-nodes.
4948
* URGENT TODO: Check if it's actually slowing things down.
4949
* Maybe we shouldn't try to preserve the list.
4950
*/
4951
if (tmpset->nodeNr > 1) {
4952
int i;
4953
xmlNodePtr node;
4954
4955
for (i = 0; i < tmpset->nodeNr; i++) {
4956
node = tmpset->nodeTab[i];
4957
if ((node != NULL) &&
4958
(node->type == XML_NAMESPACE_DECL))
4959
{
4960
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4961
}
4962
}
4963
} else if (tmpset->nodeNr == 1) {
4964
if ((tmpset->nodeTab[0] != NULL) &&
4965
(tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
4966
xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
4967
}
4968
tmpset->nodeNr = 0;
4969
memset(obj, 0, sizeof(xmlXPathObject));
4970
obj->nodesetval = tmpset;
4971
} else
4972
memset(obj, 0, sizeof(xmlXPathObject));
4973
4974
return;
4975
4976
free_obj:
4977
/*
4978
* Cache is full; free the object.
4979
*/
4980
if (obj->nodesetval != NULL)
4981
xmlXPathFreeNodeSet(obj->nodesetval);
4982
xmlFree(obj);
4983
}
4984
return;
4985
}
4986
4987
4988
/************************************************************************
4989
* *
4990
* Type Casting Routines *
4991
* *
4992
************************************************************************/
4993
4994
/**
4995
* xmlXPathCastBooleanToString:
4996
* @val: a boolean
4997
*
4998
* Converts a boolean to its string value.
4999
*
5000
* Returns a newly allocated string.
5001
*/
5002
xmlChar *
5003
xmlXPathCastBooleanToString (int val) {
5004
xmlChar *ret;
5005
if (val)
5006
ret = xmlStrdup((const xmlChar *) "true");
5007
else
5008
ret = xmlStrdup((const xmlChar *) "false");
5009
return(ret);
5010
}
5011
5012
/**
5013
* xmlXPathCastNumberToString:
5014
* @val: a number
5015
*
5016
* Converts a number to its string value.
5017
*
5018
* Returns a newly allocated string.
5019
*/
5020
xmlChar *
5021
xmlXPathCastNumberToString (double val) {
5022
xmlChar *ret;
5023
switch (xmlXPathIsInf(val)) {
5024
case 1:
5025
ret = xmlStrdup((const xmlChar *) "Infinity");
5026
break;
5027
case -1:
5028
ret = xmlStrdup((const xmlChar *) "-Infinity");
5029
break;
5030
default:
5031
if (xmlXPathIsNaN(val)) {
5032
ret = xmlStrdup((const xmlChar *) "NaN");
5033
} else if (val == 0) {
5034
/* Omit sign for negative zero. */
5035
ret = xmlStrdup((const xmlChar *) "0");
5036
} else {
5037
/* could be improved */
5038
char buf[100];
5039
xmlXPathFormatNumber(val, buf, 99);
5040
buf[99] = 0;
5041
ret = xmlStrdup((const xmlChar *) buf);
5042
}
5043
}
5044
return(ret);
5045
}
5046
5047
/**
5048
* xmlXPathCastNodeToString:
5049
* @node: a node
5050
*
5051
* Converts a node to its string value.
5052
*
5053
* Returns a newly allocated string.
5054
*/
5055
xmlChar *
5056
xmlXPathCastNodeToString (xmlNodePtr node) {
5057
xmlChar *ret;
5058
if ((ret = xmlNodeGetContent(node)) == NULL)
5059
ret = xmlStrdup((const xmlChar *) "");
5060
return(ret);
5061
}
5062
5063
/**
5064
* xmlXPathCastNodeSetToString:
5065
* @ns: a node-set
5066
*
5067
* Converts a node-set to its string value.
5068
*
5069
* Returns a newly allocated string.
5070
*/
5071
xmlChar *
5072
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5073
if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5074
return(xmlStrdup((const xmlChar *) ""));
5075
5076
if (ns->nodeNr > 1)
5077
xmlXPathNodeSetSort(ns);
5078
return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5079
}
5080
5081
/**
5082
* xmlXPathCastToString:
5083
* @val: an XPath object
5084
*
5085
* Converts an existing object to its string() equivalent
5086
*
5087
* Returns the allocated string value of the object, NULL in case of error.
5088
* It's up to the caller to free the string memory with xmlFree().
5089
*/
5090
xmlChar *
5091
xmlXPathCastToString(xmlXPathObjectPtr val) {
5092
xmlChar *ret = NULL;
5093
5094
if (val == NULL)
5095
return(xmlStrdup((const xmlChar *) ""));
5096
switch (val->type) {
5097
case XPATH_UNDEFINED:
5098
ret = xmlStrdup((const xmlChar *) "");
5099
break;
5100
case XPATH_NODESET:
5101
case XPATH_XSLT_TREE:
5102
ret = xmlXPathCastNodeSetToString(val->nodesetval);
5103
break;
5104
case XPATH_STRING:
5105
return(xmlStrdup(val->stringval));
5106
case XPATH_BOOLEAN:
5107
ret = xmlXPathCastBooleanToString(val->boolval);
5108
break;
5109
case XPATH_NUMBER: {
5110
ret = xmlXPathCastNumberToString(val->floatval);
5111
break;
5112
}
5113
case XPATH_USERS:
5114
#ifdef LIBXML_XPTR_LOCS_ENABLED
5115
case XPATH_POINT:
5116
case XPATH_RANGE:
5117
case XPATH_LOCATIONSET:
5118
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5119
TODO
5120
ret = xmlStrdup((const xmlChar *) "");
5121
break;
5122
}
5123
return(ret);
5124
}
5125
5126
/**
5127
* xmlXPathConvertString:
5128
* @val: an XPath object
5129
*
5130
* Converts an existing object to its string() equivalent
5131
*
5132
* Returns the new object, the old one is freed (or the operation
5133
* is done directly on @val)
5134
*/
5135
xmlXPathObjectPtr
5136
xmlXPathConvertString(xmlXPathObjectPtr val) {
5137
xmlChar *res = NULL;
5138
5139
if (val == NULL)
5140
return(xmlXPathNewCString(""));
5141
5142
switch (val->type) {
5143
case XPATH_UNDEFINED:
5144
break;
5145
case XPATH_NODESET:
5146
case XPATH_XSLT_TREE:
5147
res = xmlXPathCastNodeSetToString(val->nodesetval);
5148
break;
5149
case XPATH_STRING:
5150
return(val);
5151
case XPATH_BOOLEAN:
5152
res = xmlXPathCastBooleanToString(val->boolval);
5153
break;
5154
case XPATH_NUMBER:
5155
res = xmlXPathCastNumberToString(val->floatval);
5156
break;
5157
case XPATH_USERS:
5158
#ifdef LIBXML_XPTR_LOCS_ENABLED
5159
case XPATH_POINT:
5160
case XPATH_RANGE:
5161
case XPATH_LOCATIONSET:
5162
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5163
TODO;
5164
break;
5165
}
5166
xmlXPathFreeObject(val);
5167
if (res == NULL)
5168
return(xmlXPathNewCString(""));
5169
return(xmlXPathWrapString(res));
5170
}
5171
5172
/**
5173
* xmlXPathCastBooleanToNumber:
5174
* @val: a boolean
5175
*
5176
* Converts a boolean to its number value
5177
*
5178
* Returns the number value
5179
*/
5180
double
5181
xmlXPathCastBooleanToNumber(int val) {
5182
if (val)
5183
return(1.0);
5184
return(0.0);
5185
}
5186
5187
/**
5188
* xmlXPathCastStringToNumber:
5189
* @val: a string
5190
*
5191
* Converts a string to its number value
5192
*
5193
* Returns the number value
5194
*/
5195
double
5196
xmlXPathCastStringToNumber(const xmlChar * val) {
5197
return(xmlXPathStringEvalNumber(val));
5198
}
5199
5200
/**
5201
* xmlXPathCastNodeToNumber:
5202
* @node: a node
5203
*
5204
* Converts a node to its number value
5205
*
5206
* Returns the number value
5207
*/
5208
double
5209
xmlXPathCastNodeToNumber (xmlNodePtr node) {
5210
xmlChar *strval;
5211
double ret;
5212
5213
if (node == NULL)
5214
return(xmlXPathNAN);
5215
strval = xmlXPathCastNodeToString(node);
5216
if (strval == NULL)
5217
return(xmlXPathNAN);
5218
ret = xmlXPathCastStringToNumber(strval);
5219
xmlFree(strval);
5220
5221
return(ret);
5222
}
5223
5224
/**
5225
* xmlXPathCastNodeSetToNumber:
5226
* @ns: a node-set
5227
*
5228
* Converts a node-set to its number value
5229
*
5230
* Returns the number value
5231
*/
5232
double
5233
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5234
xmlChar *str;
5235
double ret;
5236
5237
if (ns == NULL)
5238
return(xmlXPathNAN);
5239
str = xmlXPathCastNodeSetToString(ns);
5240
ret = xmlXPathCastStringToNumber(str);
5241
xmlFree(str);
5242
return(ret);
5243
}
5244
5245
/**
5246
* xmlXPathCastToNumber:
5247
* @val: an XPath object
5248
*
5249
* Converts an XPath object to its number value
5250
*
5251
* Returns the number value
5252
*/
5253
double
5254
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5255
double ret = 0.0;
5256
5257
if (val == NULL)
5258
return(xmlXPathNAN);
5259
switch (val->type) {
5260
case XPATH_UNDEFINED:
5261
ret = xmlXPathNAN;
5262
break;
5263
case XPATH_NODESET:
5264
case XPATH_XSLT_TREE:
5265
ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5266
break;
5267
case XPATH_STRING:
5268
ret = xmlXPathCastStringToNumber(val->stringval);
5269
break;
5270
case XPATH_NUMBER:
5271
ret = val->floatval;
5272
break;
5273
case XPATH_BOOLEAN:
5274
ret = xmlXPathCastBooleanToNumber(val->boolval);
5275
break;
5276
case XPATH_USERS:
5277
#ifdef LIBXML_XPTR_LOCS_ENABLED
5278
case XPATH_POINT:
5279
case XPATH_RANGE:
5280
case XPATH_LOCATIONSET:
5281
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5282
TODO;
5283
ret = xmlXPathNAN;
5284
break;
5285
}
5286
return(ret);
5287
}
5288
5289
/**
5290
* xmlXPathConvertNumber:
5291
* @val: an XPath object
5292
*
5293
* Converts an existing object to its number() equivalent
5294
*
5295
* Returns the new object, the old one is freed (or the operation
5296
* is done directly on @val)
5297
*/
5298
xmlXPathObjectPtr
5299
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5300
xmlXPathObjectPtr ret;
5301
5302
if (val == NULL)
5303
return(xmlXPathNewFloat(0.0));
5304
if (val->type == XPATH_NUMBER)
5305
return(val);
5306
ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
5307
xmlXPathFreeObject(val);
5308
return(ret);
5309
}
5310
5311
/**
5312
* xmlXPathCastNumberToBoolean:
5313
* @val: a number
5314
*
5315
* Converts a number to its boolean value
5316
*
5317
* Returns the boolean value
5318
*/
5319
int
5320
xmlXPathCastNumberToBoolean (double val) {
5321
if (xmlXPathIsNaN(val) || (val == 0.0))
5322
return(0);
5323
return(1);
5324
}
5325
5326
/**
5327
* xmlXPathCastStringToBoolean:
5328
* @val: a string
5329
*
5330
* Converts a string to its boolean value
5331
*
5332
* Returns the boolean value
5333
*/
5334
int
5335
xmlXPathCastStringToBoolean (const xmlChar *val) {
5336
if ((val == NULL) || (xmlStrlen(val) == 0))
5337
return(0);
5338
return(1);
5339
}
5340
5341
/**
5342
* xmlXPathCastNodeSetToBoolean:
5343
* @ns: a node-set
5344
*
5345
* Converts a node-set to its boolean value
5346
*
5347
* Returns the boolean value
5348
*/
5349
int
5350
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
5351
if ((ns == NULL) || (ns->nodeNr == 0))
5352
return(0);
5353
return(1);
5354
}
5355
5356
/**
5357
* xmlXPathCastToBoolean:
5358
* @val: an XPath object
5359
*
5360
* Converts an XPath object to its boolean value
5361
*
5362
* Returns the boolean value
5363
*/
5364
int
5365
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
5366
int ret = 0;
5367
5368
if (val == NULL)
5369
return(0);
5370
switch (val->type) {
5371
case XPATH_UNDEFINED:
5372
ret = 0;
5373
break;
5374
case XPATH_NODESET:
5375
case XPATH_XSLT_TREE:
5376
ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
5377
break;
5378
case XPATH_STRING:
5379
ret = xmlXPathCastStringToBoolean(val->stringval);
5380
break;
5381
case XPATH_NUMBER:
5382
ret = xmlXPathCastNumberToBoolean(val->floatval);
5383
break;
5384
case XPATH_BOOLEAN:
5385
ret = val->boolval;
5386
break;
5387
case XPATH_USERS:
5388
#ifdef LIBXML_XPTR_LOCS_ENABLED
5389
case XPATH_POINT:
5390
case XPATH_RANGE:
5391
case XPATH_LOCATIONSET:
5392
#endif /* LIBXML_XPTR_LOCS_ENABLED */
5393
TODO;
5394
ret = 0;
5395
break;
5396
}
5397
return(ret);
5398
}
5399
5400
5401
/**
5402
* xmlXPathConvertBoolean:
5403
* @val: an XPath object
5404
*
5405
* Converts an existing object to its boolean() equivalent
5406
*
5407
* Returns the new object, the old one is freed (or the operation
5408
* is done directly on @val)
5409
*/
5410
xmlXPathObjectPtr
5411
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
5412
xmlXPathObjectPtr ret;
5413
5414
if (val == NULL)
5415
return(xmlXPathNewBoolean(0));
5416
if (val->type == XPATH_BOOLEAN)
5417
return(val);
5418
ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
5419
xmlXPathFreeObject(val);
5420
return(ret);
5421
}
5422
5423
/************************************************************************
5424
* *
5425
* Routines to handle XPath contexts *
5426
* *
5427
************************************************************************/
5428
5429
/**
5430
* xmlXPathNewContext:
5431
* @doc: the XML document
5432
*
5433
* Create a new xmlXPathContext
5434
*
5435
* Returns the xmlXPathContext just allocated. The caller will need to free it.
5436
*/
5437
xmlXPathContextPtr
5438
xmlXPathNewContext(xmlDocPtr doc) {
5439
xmlXPathContextPtr ret;
5440
5441
ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
5442
if (ret == NULL) {
5443
xmlXPathErrMemory(NULL, "creating context\n");
5444
return(NULL);
5445
}
5446
memset(ret, 0 , sizeof(xmlXPathContext));
5447
ret->doc = doc;
5448
ret->node = NULL;
5449
5450
ret->varHash = NULL;
5451
5452
ret->nb_types = 0;
5453
ret->max_types = 0;
5454
ret->types = NULL;
5455
5456
ret->funcHash = xmlHashCreate(0);
5457
5458
ret->nb_axis = 0;
5459
ret->max_axis = 0;
5460
ret->axis = NULL;
5461
5462
ret->nsHash = NULL;
5463
ret->user = NULL;
5464
5465
ret->contextSize = -1;
5466
ret->proximityPosition = -1;
5467
5468
#ifdef XP_DEFAULT_CACHE_ON
5469
if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
5470
xmlXPathFreeContext(ret);
5471
return(NULL);
5472
}
5473
#endif
5474
5475
xmlXPathRegisterAllFunctions(ret);
5476
5477
return(ret);
5478
}
5479
5480
/**
5481
* xmlXPathFreeContext:
5482
* @ctxt: the context to free
5483
*
5484
* Free up an xmlXPathContext
5485
*/
5486
void
5487
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
5488
if (ctxt == NULL) return;
5489
5490
if (ctxt->cache != NULL)
5491
xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
5492
xmlXPathRegisteredNsCleanup(ctxt);
5493
xmlXPathRegisteredFuncsCleanup(ctxt);
5494
xmlXPathRegisteredVariablesCleanup(ctxt);
5495
xmlResetError(&ctxt->lastError);
5496
xmlFree(ctxt);
5497
}
5498
5499
/************************************************************************
5500
* *
5501
* Routines to handle XPath parser contexts *
5502
* *
5503
************************************************************************/
5504
5505
#define CHECK_CTXT(ctxt) \
5506
if (ctxt == NULL) { \
5507
__xmlRaiseError(NULL, NULL, NULL, \
5508
NULL, NULL, XML_FROM_XPATH, \
5509
XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
5510
__FILE__, __LINE__, \
5511
NULL, NULL, NULL, 0, 0, \
5512
"NULL context pointer\n"); \
5513
return(NULL); \
5514
} \
5515
5516
#define CHECK_CTXT_NEG(ctxt) \
5517
if (ctxt == NULL) { \
5518
__xmlRaiseError(NULL, NULL, NULL, \
5519
NULL, NULL, XML_FROM_XPATH, \
5520
XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
5521
__FILE__, __LINE__, \
5522
NULL, NULL, NULL, 0, 0, \
5523
"NULL context pointer\n"); \
5524
return(-1); \
5525
} \
5526
5527
5528
#define CHECK_CONTEXT(ctxt) \
5529
if ((ctxt == NULL) || (ctxt->doc == NULL) || \
5530
(ctxt->doc->children == NULL)) { \
5531
xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
5532
return(NULL); \
5533
}
5534
5535
5536
/**
5537
* xmlXPathNewParserContext:
5538
* @str: the XPath expression
5539
* @ctxt: the XPath context
5540
*
5541
* Create a new xmlXPathParserContext
5542
*
5543
* Returns the xmlXPathParserContext just allocated.
5544
*/
5545
xmlXPathParserContextPtr
5546
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
5547
xmlXPathParserContextPtr ret;
5548
5549
ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5550
if (ret == NULL) {
5551
xmlXPathErrMemory(ctxt, "creating parser context\n");
5552
return(NULL);
5553
}
5554
memset(ret, 0 , sizeof(xmlXPathParserContext));
5555
ret->cur = ret->base = str;
5556
ret->context = ctxt;
5557
5558
ret->comp = xmlXPathNewCompExpr();
5559
if (ret->comp == NULL) {
5560
xmlFree(ret->valueTab);
5561
xmlFree(ret);
5562
return(NULL);
5563
}
5564
if ((ctxt != NULL) && (ctxt->dict != NULL)) {
5565
ret->comp->dict = ctxt->dict;
5566
xmlDictReference(ret->comp->dict);
5567
}
5568
5569
return(ret);
5570
}
5571
5572
/**
5573
* xmlXPathCompParserContext:
5574
* @comp: the XPath compiled expression
5575
* @ctxt: the XPath context
5576
*
5577
* Create a new xmlXPathParserContext when processing a compiled expression
5578
*
5579
* Returns the xmlXPathParserContext just allocated.
5580
*/
5581
static xmlXPathParserContextPtr
5582
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
5583
xmlXPathParserContextPtr ret;
5584
5585
ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
5586
if (ret == NULL) {
5587
xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5588
return(NULL);
5589
}
5590
memset(ret, 0 , sizeof(xmlXPathParserContext));
5591
5592
/* Allocate the value stack */
5593
ret->valueTab = (xmlXPathObjectPtr *)
5594
xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
5595
if (ret->valueTab == NULL) {
5596
xmlFree(ret);
5597
xmlXPathErrMemory(ctxt, "creating evaluation context\n");
5598
return(NULL);
5599
}
5600
ret->valueNr = 0;
5601
ret->valueMax = 10;
5602
ret->value = NULL;
5603
5604
ret->context = ctxt;
5605
ret->comp = comp;
5606
5607
return(ret);
5608
}
5609
5610
/**
5611
* xmlXPathFreeParserContext:
5612
* @ctxt: the context to free
5613
*
5614
* Free up an xmlXPathParserContext
5615
*/
5616
void
5617
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
5618
int i;
5619
5620
if (ctxt->valueTab != NULL) {
5621
for (i = 0; i < ctxt->valueNr; i++) {
5622
if (ctxt->context)
5623
xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
5624
else
5625
xmlXPathFreeObject(ctxt->valueTab[i]);
5626
}
5627
xmlFree(ctxt->valueTab);
5628
}
5629
if (ctxt->comp != NULL) {
5630
#ifdef XPATH_STREAMING
5631
if (ctxt->comp->stream != NULL) {
5632
xmlFreePatternList(ctxt->comp->stream);
5633
ctxt->comp->stream = NULL;
5634
}
5635
#endif
5636
xmlXPathFreeCompExpr(ctxt->comp);
5637
}
5638
xmlFree(ctxt);
5639
}
5640
5641
/************************************************************************
5642
* *
5643
* The implicit core function library *
5644
* *
5645
************************************************************************/
5646
5647
/**
5648
* xmlXPathNodeValHash:
5649
* @node: a node pointer
5650
*
5651
* Function computing the beginning of the string value of the node,
5652
* used to speed up comparisons
5653
*
5654
* Returns an int usable as a hash
5655
*/
5656
static unsigned int
5657
xmlXPathNodeValHash(xmlNodePtr node) {
5658
int len = 2;
5659
const xmlChar * string = NULL;
5660
xmlNodePtr tmp = NULL;
5661
unsigned int ret = 0;
5662
5663
if (node == NULL)
5664
return(0);
5665
5666
if (node->type == XML_DOCUMENT_NODE) {
5667
tmp = xmlDocGetRootElement((xmlDocPtr) node);
5668
if (tmp == NULL)
5669
node = node->children;
5670
else
5671
node = tmp;
5672
5673
if (node == NULL)
5674
return(0);
5675
}
5676
5677
switch (node->type) {
5678
case XML_COMMENT_NODE:
5679
case XML_PI_NODE:
5680
case XML_CDATA_SECTION_NODE:
5681
case XML_TEXT_NODE:
5682
string = node->content;
5683
if (string == NULL)
5684
return(0);
5685
if (string[0] == 0)
5686
return(0);
5687
return(string[0] + (string[1] << 8));
5688
case XML_NAMESPACE_DECL:
5689
string = ((xmlNsPtr)node)->href;
5690
if (string == NULL)
5691
return(0);
5692
if (string[0] == 0)
5693
return(0);
5694
return(string[0] + (string[1] << 8));
5695
case XML_ATTRIBUTE_NODE:
5696
tmp = ((xmlAttrPtr) node)->children;
5697
break;
5698
case XML_ELEMENT_NODE:
5699
tmp = node->children;
5700
break;
5701
default:
5702
return(0);
5703
}
5704
while (tmp != NULL) {
5705
switch (tmp->type) {
5706
case XML_CDATA_SECTION_NODE:
5707
case XML_TEXT_NODE:
5708
string = tmp->content;
5709
break;
5710
default:
5711
string = NULL;
5712
break;
5713
}
5714
if ((string != NULL) && (string[0] != 0)) {
5715
if (len == 1) {
5716
return(ret + (string[0] << 8));
5717
}
5718
if (string[1] == 0) {
5719
len = 1;
5720
ret = string[0];
5721
} else {
5722
return(string[0] + (string[1] << 8));
5723
}
5724
}
5725
/*
5726
* Skip to next node
5727
*/
5728
if ((tmp->children != NULL) &&
5729
(tmp->type != XML_DTD_NODE) &&
5730
(tmp->type != XML_ENTITY_REF_NODE) &&
5731
(tmp->children->type != XML_ENTITY_DECL)) {
5732
tmp = tmp->children;
5733
continue;
5734
}
5735
if (tmp == node)
5736
break;
5737
5738
if (tmp->next != NULL) {
5739
tmp = tmp->next;
5740
continue;
5741
}
5742
5743
do {
5744
tmp = tmp->parent;
5745
if (tmp == NULL)
5746
break;
5747
if (tmp == node) {
5748
tmp = NULL;
5749
break;
5750
}
5751
if (tmp->next != NULL) {
5752
tmp = tmp->next;
5753
break;
5754
}
5755
} while (tmp != NULL);
5756
}
5757
return(ret);
5758
}
5759
5760
/**
5761
* xmlXPathStringHash:
5762
* @string: a string
5763
*
5764
* Function computing the beginning of the string value of the node,
5765
* used to speed up comparisons
5766
*
5767
* Returns an int usable as a hash
5768
*/
5769
static unsigned int
5770
xmlXPathStringHash(const xmlChar * string) {
5771
if (string == NULL)
5772
return(0);
5773
if (string[0] == 0)
5774
return(0);
5775
return(string[0] + (string[1] << 8));
5776
}
5777
5778
/**
5779
* xmlXPathCompareNodeSetFloat:
5780
* @ctxt: the XPath Parser context
5781
* @inf: less than (1) or greater than (0)
5782
* @strict: is the comparison strict
5783
* @arg: the node set
5784
* @f: the value
5785
*
5786
* Implement the compare operation between a nodeset and a number
5787
* @ns < @val (1, 1, ...
5788
* @ns <= @val (1, 0, ...
5789
* @ns > @val (0, 1, ...
5790
* @ns >= @val (0, 0, ...
5791
*
5792
* If one object to be compared is a node-set and the other is a number,
5793
* then the comparison will be true if and only if there is a node in the
5794
* node-set such that the result of performing the comparison on the number
5795
* to be compared and on the result of converting the string-value of that
5796
* node to a number using the number function is true.
5797
*
5798
* Returns 0 or 1 depending on the results of the test.
5799
*/
5800
static int
5801
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
5802
xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
5803
int i, ret = 0;
5804
xmlNodeSetPtr ns;
5805
xmlChar *str2;
5806
5807
if ((f == NULL) || (arg == NULL) ||
5808
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5809
xmlXPathReleaseObject(ctxt->context, arg);
5810
xmlXPathReleaseObject(ctxt->context, f);
5811
return(0);
5812
}
5813
ns = arg->nodesetval;
5814
if (ns != NULL) {
5815
for (i = 0;i < ns->nodeNr;i++) {
5816
str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5817
if (str2 != NULL) {
5818
valuePush(ctxt,
5819
xmlXPathCacheNewString(ctxt->context, str2));
5820
xmlFree(str2);
5821
xmlXPathNumberFunction(ctxt, 1);
5822
valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
5823
ret = xmlXPathCompareValues(ctxt, inf, strict);
5824
if (ret)
5825
break;
5826
}
5827
}
5828
}
5829
xmlXPathReleaseObject(ctxt->context, arg);
5830
xmlXPathReleaseObject(ctxt->context, f);
5831
return(ret);
5832
}
5833
5834
/**
5835
* xmlXPathCompareNodeSetString:
5836
* @ctxt: the XPath Parser context
5837
* @inf: less than (1) or greater than (0)
5838
* @strict: is the comparison strict
5839
* @arg: the node set
5840
* @s: the value
5841
*
5842
* Implement the compare operation between a nodeset and a string
5843
* @ns < @val (1, 1, ...
5844
* @ns <= @val (1, 0, ...
5845
* @ns > @val (0, 1, ...
5846
* @ns >= @val (0, 0, ...
5847
*
5848
* If one object to be compared is a node-set and the other is a string,
5849
* then the comparison will be true if and only if there is a node in
5850
* the node-set such that the result of performing the comparison on the
5851
* string-value of the node and the other string is true.
5852
*
5853
* Returns 0 or 1 depending on the results of the test.
5854
*/
5855
static int
5856
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
5857
xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
5858
int i, ret = 0;
5859
xmlNodeSetPtr ns;
5860
xmlChar *str2;
5861
5862
if ((s == NULL) || (arg == NULL) ||
5863
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
5864
xmlXPathReleaseObject(ctxt->context, arg);
5865
xmlXPathReleaseObject(ctxt->context, s);
5866
return(0);
5867
}
5868
ns = arg->nodesetval;
5869
if (ns != NULL) {
5870
for (i = 0;i < ns->nodeNr;i++) {
5871
str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
5872
if (str2 != NULL) {
5873
valuePush(ctxt,
5874
xmlXPathCacheNewString(ctxt->context, str2));
5875
xmlFree(str2);
5876
valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
5877
ret = xmlXPathCompareValues(ctxt, inf, strict);
5878
if (ret)
5879
break;
5880
}
5881
}
5882
}
5883
xmlXPathReleaseObject(ctxt->context, arg);
5884
xmlXPathReleaseObject(ctxt->context, s);
5885
return(ret);
5886
}
5887
5888
/**
5889
* xmlXPathCompareNodeSets:
5890
* @inf: less than (1) or greater than (0)
5891
* @strict: is the comparison strict
5892
* @arg1: the first node set object
5893
* @arg2: the second node set object
5894
*
5895
* Implement the compare operation on nodesets:
5896
*
5897
* If both objects to be compared are node-sets, then the comparison
5898
* will be true if and only if there is a node in the first node-set
5899
* and a node in the second node-set such that the result of performing
5900
* the comparison on the string-values of the two nodes is true.
5901
* ....
5902
* When neither object to be compared is a node-set and the operator
5903
* is <=, <, >= or >, then the objects are compared by converting both
5904
* objects to numbers and comparing the numbers according to IEEE 754.
5905
* ....
5906
* The number function converts its argument to a number as follows:
5907
* - a string that consists of optional whitespace followed by an
5908
* optional minus sign followed by a Number followed by whitespace
5909
* is converted to the IEEE 754 number that is nearest (according
5910
* to the IEEE 754 round-to-nearest rule) to the mathematical value
5911
* represented by the string; any other string is converted to NaN
5912
*
5913
* Conclusion all nodes need to be converted first to their string value
5914
* and then the comparison must be done when possible
5915
*/
5916
static int
5917
xmlXPathCompareNodeSets(int inf, int strict,
5918
xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
5919
int i, j, init = 0;
5920
double val1;
5921
double *values2;
5922
int ret = 0;
5923
xmlNodeSetPtr ns1;
5924
xmlNodeSetPtr ns2;
5925
5926
if ((arg1 == NULL) ||
5927
((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
5928
xmlXPathFreeObject(arg2);
5929
return(0);
5930
}
5931
if ((arg2 == NULL) ||
5932
((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
5933
xmlXPathFreeObject(arg1);
5934
xmlXPathFreeObject(arg2);
5935
return(0);
5936
}
5937
5938
ns1 = arg1->nodesetval;
5939
ns2 = arg2->nodesetval;
5940
5941
if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
5942
xmlXPathFreeObject(arg1);
5943
xmlXPathFreeObject(arg2);
5944
return(0);
5945
}
5946
if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
5947
xmlXPathFreeObject(arg1);
5948
xmlXPathFreeObject(arg2);
5949
return(0);
5950
}
5951
5952
values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
5953
if (values2 == NULL) {
5954
/* TODO: Propagate memory error. */
5955
xmlXPathErrMemory(NULL, "comparing nodesets\n");
5956
xmlXPathFreeObject(arg1);
5957
xmlXPathFreeObject(arg2);
5958
return(0);
5959
}
5960
for (i = 0;i < ns1->nodeNr;i++) {
5961
val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
5962
if (xmlXPathIsNaN(val1))
5963
continue;
5964
for (j = 0;j < ns2->nodeNr;j++) {
5965
if (init == 0) {
5966
values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
5967
}
5968
if (xmlXPathIsNaN(values2[j]))
5969
continue;
5970
if (inf && strict)
5971
ret = (val1 < values2[j]);
5972
else if (inf && !strict)
5973
ret = (val1 <= values2[j]);
5974
else if (!inf && strict)
5975
ret = (val1 > values2[j]);
5976
else if (!inf && !strict)
5977
ret = (val1 >= values2[j]);
5978
if (ret)
5979
break;
5980
}
5981
if (ret)
5982
break;
5983
init = 1;
5984
}
5985
xmlFree(values2);
5986
xmlXPathFreeObject(arg1);
5987
xmlXPathFreeObject(arg2);
5988
return(ret);
5989
}
5990
5991
/**
5992
* xmlXPathCompareNodeSetValue:
5993
* @ctxt: the XPath Parser context
5994
* @inf: less than (1) or greater than (0)
5995
* @strict: is the comparison strict
5996
* @arg: the node set
5997
* @val: the value
5998
*
5999
* Implement the compare operation between a nodeset and a value
6000
* @ns < @val (1, 1, ...
6001
* @ns <= @val (1, 0, ...
6002
* @ns > @val (0, 1, ...
6003
* @ns >= @val (0, 0, ...
6004
*
6005
* If one object to be compared is a node-set and the other is a boolean,
6006
* then the comparison will be true if and only if the result of performing
6007
* the comparison on the boolean and on the result of converting
6008
* the node-set to a boolean using the boolean function is true.
6009
*
6010
* Returns 0 or 1 depending on the results of the test.
6011
*/
6012
static int
6013
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6014
xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6015
if ((val == NULL) || (arg == NULL) ||
6016
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6017
return(0);
6018
6019
switch(val->type) {
6020
case XPATH_NUMBER:
6021
return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6022
case XPATH_NODESET:
6023
case XPATH_XSLT_TREE:
6024
return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6025
case XPATH_STRING:
6026
return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6027
case XPATH_BOOLEAN:
6028
valuePush(ctxt, arg);
6029
xmlXPathBooleanFunction(ctxt, 1);
6030
valuePush(ctxt, val);
6031
return(xmlXPathCompareValues(ctxt, inf, strict));
6032
default:
6033
xmlGenericError(xmlGenericErrorContext,
6034
"xmlXPathCompareNodeSetValue: Can't compare node set "
6035
"and object of type %d\n",
6036
val->type);
6037
xmlXPathReleaseObject(ctxt->context, arg);
6038
xmlXPathReleaseObject(ctxt->context, val);
6039
XP_ERROR0(XPATH_INVALID_TYPE);
6040
}
6041
return(0);
6042
}
6043
6044
/**
6045
* xmlXPathEqualNodeSetString:
6046
* @arg: the nodeset object argument
6047
* @str: the string to compare to.
6048
* @neq: flag to show whether for '=' (0) or '!=' (1)
6049
*
6050
* Implement the equal operation on XPath objects content: @arg1 == @arg2
6051
* If one object to be compared is a node-set and the other is a string,
6052
* then the comparison will be true if and only if there is a node in
6053
* the node-set such that the result of performing the comparison on the
6054
* string-value of the node and the other string is true.
6055
*
6056
* Returns 0 or 1 depending on the results of the test.
6057
*/
6058
static int
6059
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6060
{
6061
int i;
6062
xmlNodeSetPtr ns;
6063
xmlChar *str2;
6064
unsigned int hash;
6065
6066
if ((str == NULL) || (arg == NULL) ||
6067
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6068
return (0);
6069
ns = arg->nodesetval;
6070
/*
6071
* A NULL nodeset compared with a string is always false
6072
* (since there is no node equal, and no node not equal)
6073
*/
6074
if ((ns == NULL) || (ns->nodeNr <= 0) )
6075
return (0);
6076
hash = xmlXPathStringHash(str);
6077
for (i = 0; i < ns->nodeNr; i++) {
6078
if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6079
str2 = xmlNodeGetContent(ns->nodeTab[i]);
6080
if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6081
xmlFree(str2);
6082
if (neq)
6083
continue;
6084
return (1);
6085
} else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6086
if (neq)
6087
continue;
6088
return (1);
6089
} else if (neq) {
6090
if (str2 != NULL)
6091
xmlFree(str2);
6092
return (1);
6093
}
6094
if (str2 != NULL)
6095
xmlFree(str2);
6096
} else if (neq)
6097
return (1);
6098
}
6099
return (0);
6100
}
6101
6102
/**
6103
* xmlXPathEqualNodeSetFloat:
6104
* @arg: the nodeset object argument
6105
* @f: the float to compare to
6106
* @neq: flag to show whether to compare '=' (0) or '!=' (1)
6107
*
6108
* Implement the equal operation on XPath objects content: @arg1 == @arg2
6109
* If one object to be compared is a node-set and the other is a number,
6110
* then the comparison will be true if and only if there is a node in
6111
* the node-set such that the result of performing the comparison on the
6112
* number to be compared and on the result of converting the string-value
6113
* of that node to a number using the number function is true.
6114
*
6115
* Returns 0 or 1 depending on the results of the test.
6116
*/
6117
static int
6118
xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6119
xmlXPathObjectPtr arg, double f, int neq) {
6120
int i, ret=0;
6121
xmlNodeSetPtr ns;
6122
xmlChar *str2;
6123
xmlXPathObjectPtr val;
6124
double v;
6125
6126
if ((arg == NULL) ||
6127
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6128
return(0);
6129
6130
ns = arg->nodesetval;
6131
if (ns != NULL) {
6132
for (i=0;i<ns->nodeNr;i++) {
6133
str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6134
if (str2 != NULL) {
6135
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6136
xmlFree(str2);
6137
xmlXPathNumberFunction(ctxt, 1);
6138
CHECK_ERROR0;
6139
val = valuePop(ctxt);
6140
v = val->floatval;
6141
xmlXPathReleaseObject(ctxt->context, val);
6142
if (!xmlXPathIsNaN(v)) {
6143
if ((!neq) && (v==f)) {
6144
ret = 1;
6145
break;
6146
} else if ((neq) && (v!=f)) {
6147
ret = 1;
6148
break;
6149
}
6150
} else { /* NaN is unequal to any value */
6151
if (neq)
6152
ret = 1;
6153
}
6154
}
6155
}
6156
}
6157
6158
return(ret);
6159
}
6160
6161
6162
/**
6163
* xmlXPathEqualNodeSets:
6164
* @arg1: first nodeset object argument
6165
* @arg2: second nodeset object argument
6166
* @neq: flag to show whether to test '=' (0) or '!=' (1)
6167
*
6168
* Implement the equal / not equal operation on XPath nodesets:
6169
* @arg1 == @arg2 or @arg1 != @arg2
6170
* If both objects to be compared are node-sets, then the comparison
6171
* will be true if and only if there is a node in the first node-set and
6172
* a node in the second node-set such that the result of performing the
6173
* comparison on the string-values of the two nodes is true.
6174
*
6175
* (needless to say, this is a costly operation)
6176
*
6177
* Returns 0 or 1 depending on the results of the test.
6178
*/
6179
static int
6180
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6181
int i, j;
6182
unsigned int *hashs1;
6183
unsigned int *hashs2;
6184
xmlChar **values1;
6185
xmlChar **values2;
6186
int ret = 0;
6187
xmlNodeSetPtr ns1;
6188
xmlNodeSetPtr ns2;
6189
6190
if ((arg1 == NULL) ||
6191
((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6192
return(0);
6193
if ((arg2 == NULL) ||
6194
((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6195
return(0);
6196
6197
ns1 = arg1->nodesetval;
6198
ns2 = arg2->nodesetval;
6199
6200
if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6201
return(0);
6202
if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6203
return(0);
6204
6205
/*
6206
* for equal, check if there is a node pertaining to both sets
6207
*/
6208
if (neq == 0)
6209
for (i = 0;i < ns1->nodeNr;i++)
6210
for (j = 0;j < ns2->nodeNr;j++)
6211
if (ns1->nodeTab[i] == ns2->nodeTab[j])
6212
return(1);
6213
6214
values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6215
if (values1 == NULL) {
6216
/* TODO: Propagate memory error. */
6217
xmlXPathErrMemory(NULL, "comparing nodesets\n");
6218
return(0);
6219
}
6220
hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6221
if (hashs1 == NULL) {
6222
/* TODO: Propagate memory error. */
6223
xmlXPathErrMemory(NULL, "comparing nodesets\n");
6224
xmlFree(values1);
6225
return(0);
6226
}
6227
memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6228
values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6229
if (values2 == NULL) {
6230
/* TODO: Propagate memory error. */
6231
xmlXPathErrMemory(NULL, "comparing nodesets\n");
6232
xmlFree(hashs1);
6233
xmlFree(values1);
6234
return(0);
6235
}
6236
hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6237
if (hashs2 == NULL) {
6238
/* TODO: Propagate memory error. */
6239
xmlXPathErrMemory(NULL, "comparing nodesets\n");
6240
xmlFree(hashs1);
6241
xmlFree(values1);
6242
xmlFree(values2);
6243
return(0);
6244
}
6245
memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6246
for (i = 0;i < ns1->nodeNr;i++) {
6247
hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6248
for (j = 0;j < ns2->nodeNr;j++) {
6249
if (i == 0)
6250
hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6251
if (hashs1[i] != hashs2[j]) {
6252
if (neq) {
6253
ret = 1;
6254
break;
6255
}
6256
}
6257
else {
6258
if (values1[i] == NULL)
6259
values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6260
if (values2[j] == NULL)
6261
values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6262
ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6263
if (ret)
6264
break;
6265
}
6266
}
6267
if (ret)
6268
break;
6269
}
6270
for (i = 0;i < ns1->nodeNr;i++)
6271
if (values1[i] != NULL)
6272
xmlFree(values1[i]);
6273
for (j = 0;j < ns2->nodeNr;j++)
6274
if (values2[j] != NULL)
6275
xmlFree(values2[j]);
6276
xmlFree(values1);
6277
xmlFree(values2);
6278
xmlFree(hashs1);
6279
xmlFree(hashs2);
6280
return(ret);
6281
}
6282
6283
static int
6284
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6285
xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6286
int ret = 0;
6287
/*
6288
*At this point we are assured neither arg1 nor arg2
6289
*is a nodeset, so we can just pick the appropriate routine.
6290
*/
6291
switch (arg1->type) {
6292
case XPATH_UNDEFINED:
6293
break;
6294
case XPATH_BOOLEAN:
6295
switch (arg2->type) {
6296
case XPATH_UNDEFINED:
6297
break;
6298
case XPATH_BOOLEAN:
6299
ret = (arg1->boolval == arg2->boolval);
6300
break;
6301
case XPATH_NUMBER:
6302
ret = (arg1->boolval ==
6303
xmlXPathCastNumberToBoolean(arg2->floatval));
6304
break;
6305
case XPATH_STRING:
6306
if ((arg2->stringval == NULL) ||
6307
(arg2->stringval[0] == 0)) ret = 0;
6308
else
6309
ret = 1;
6310
ret = (arg1->boolval == ret);
6311
break;
6312
case XPATH_USERS:
6313
#ifdef LIBXML_XPTR_LOCS_ENABLED
6314
case XPATH_POINT:
6315
case XPATH_RANGE:
6316
case XPATH_LOCATIONSET:
6317
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6318
TODO
6319
break;
6320
case XPATH_NODESET:
6321
case XPATH_XSLT_TREE:
6322
break;
6323
}
6324
break;
6325
case XPATH_NUMBER:
6326
switch (arg2->type) {
6327
case XPATH_UNDEFINED:
6328
break;
6329
case XPATH_BOOLEAN:
6330
ret = (arg2->boolval==
6331
xmlXPathCastNumberToBoolean(arg1->floatval));
6332
break;
6333
case XPATH_STRING:
6334
valuePush(ctxt, arg2);
6335
xmlXPathNumberFunction(ctxt, 1);
6336
arg2 = valuePop(ctxt);
6337
if (ctxt->error)
6338
break;
6339
/* Falls through. */
6340
case XPATH_NUMBER:
6341
/* Hand check NaN and Infinity equalities */
6342
if (xmlXPathIsNaN(arg1->floatval) ||
6343
xmlXPathIsNaN(arg2->floatval)) {
6344
ret = 0;
6345
} else if (xmlXPathIsInf(arg1->floatval) == 1) {
6346
if (xmlXPathIsInf(arg2->floatval) == 1)
6347
ret = 1;
6348
else
6349
ret = 0;
6350
} else if (xmlXPathIsInf(arg1->floatval) == -1) {
6351
if (xmlXPathIsInf(arg2->floatval) == -1)
6352
ret = 1;
6353
else
6354
ret = 0;
6355
} else if (xmlXPathIsInf(arg2->floatval) == 1) {
6356
if (xmlXPathIsInf(arg1->floatval) == 1)
6357
ret = 1;
6358
else
6359
ret = 0;
6360
} else if (xmlXPathIsInf(arg2->floatval) == -1) {
6361
if (xmlXPathIsInf(arg1->floatval) == -1)
6362
ret = 1;
6363
else
6364
ret = 0;
6365
} else {
6366
ret = (arg1->floatval == arg2->floatval);
6367
}
6368
break;
6369
case XPATH_USERS:
6370
#ifdef LIBXML_XPTR_LOCS_ENABLED
6371
case XPATH_POINT:
6372
case XPATH_RANGE:
6373
case XPATH_LOCATIONSET:
6374
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6375
TODO
6376
break;
6377
case XPATH_NODESET:
6378
case XPATH_XSLT_TREE:
6379
break;
6380
}
6381
break;
6382
case XPATH_STRING:
6383
switch (arg2->type) {
6384
case XPATH_UNDEFINED:
6385
break;
6386
case XPATH_BOOLEAN:
6387
if ((arg1->stringval == NULL) ||
6388
(arg1->stringval[0] == 0)) ret = 0;
6389
else
6390
ret = 1;
6391
ret = (arg2->boolval == ret);
6392
break;
6393
case XPATH_STRING:
6394
ret = xmlStrEqual(arg1->stringval, arg2->stringval);
6395
break;
6396
case XPATH_NUMBER:
6397
valuePush(ctxt, arg1);
6398
xmlXPathNumberFunction(ctxt, 1);
6399
arg1 = valuePop(ctxt);
6400
if (ctxt->error)
6401
break;
6402
/* Hand check NaN and Infinity equalities */
6403
if (xmlXPathIsNaN(arg1->floatval) ||
6404
xmlXPathIsNaN(arg2->floatval)) {
6405
ret = 0;
6406
} else if (xmlXPathIsInf(arg1->floatval) == 1) {
6407
if (xmlXPathIsInf(arg2->floatval) == 1)
6408
ret = 1;
6409
else
6410
ret = 0;
6411
} else if (xmlXPathIsInf(arg1->floatval) == -1) {
6412
if (xmlXPathIsInf(arg2->floatval) == -1)
6413
ret = 1;
6414
else
6415
ret = 0;
6416
} else if (xmlXPathIsInf(arg2->floatval) == 1) {
6417
if (xmlXPathIsInf(arg1->floatval) == 1)
6418
ret = 1;
6419
else
6420
ret = 0;
6421
} else if (xmlXPathIsInf(arg2->floatval) == -1) {
6422
if (xmlXPathIsInf(arg1->floatval) == -1)
6423
ret = 1;
6424
else
6425
ret = 0;
6426
} else {
6427
ret = (arg1->floatval == arg2->floatval);
6428
}
6429
break;
6430
case XPATH_USERS:
6431
#ifdef LIBXML_XPTR_LOCS_ENABLED
6432
case XPATH_POINT:
6433
case XPATH_RANGE:
6434
case XPATH_LOCATIONSET:
6435
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6436
TODO
6437
break;
6438
case XPATH_NODESET:
6439
case XPATH_XSLT_TREE:
6440
break;
6441
}
6442
break;
6443
case XPATH_USERS:
6444
#ifdef LIBXML_XPTR_LOCS_ENABLED
6445
case XPATH_POINT:
6446
case XPATH_RANGE:
6447
case XPATH_LOCATIONSET:
6448
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6449
TODO
6450
break;
6451
case XPATH_NODESET:
6452
case XPATH_XSLT_TREE:
6453
break;
6454
}
6455
xmlXPathReleaseObject(ctxt->context, arg1);
6456
xmlXPathReleaseObject(ctxt->context, arg2);
6457
return(ret);
6458
}
6459
6460
/**
6461
* xmlXPathEqualValues:
6462
* @ctxt: the XPath Parser context
6463
*
6464
* Implement the equal operation on XPath objects content: @arg1 == @arg2
6465
*
6466
* Returns 0 or 1 depending on the results of the test.
6467
*/
6468
int
6469
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
6470
xmlXPathObjectPtr arg1, arg2, argtmp;
6471
int ret = 0;
6472
6473
if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6474
arg2 = valuePop(ctxt);
6475
arg1 = valuePop(ctxt);
6476
if ((arg1 == NULL) || (arg2 == NULL)) {
6477
if (arg1 != NULL)
6478
xmlXPathReleaseObject(ctxt->context, arg1);
6479
else
6480
xmlXPathReleaseObject(ctxt->context, arg2);
6481
XP_ERROR0(XPATH_INVALID_OPERAND);
6482
}
6483
6484
if (arg1 == arg2) {
6485
xmlXPathFreeObject(arg1);
6486
return(1);
6487
}
6488
6489
/*
6490
*If either argument is a nodeset, it's a 'special case'
6491
*/
6492
if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6493
(arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6494
/*
6495
*Hack it to assure arg1 is the nodeset
6496
*/
6497
if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6498
argtmp = arg2;
6499
arg2 = arg1;
6500
arg1 = argtmp;
6501
}
6502
switch (arg2->type) {
6503
case XPATH_UNDEFINED:
6504
break;
6505
case XPATH_NODESET:
6506
case XPATH_XSLT_TREE:
6507
ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
6508
break;
6509
case XPATH_BOOLEAN:
6510
if ((arg1->nodesetval == NULL) ||
6511
(arg1->nodesetval->nodeNr == 0)) ret = 0;
6512
else
6513
ret = 1;
6514
ret = (ret == arg2->boolval);
6515
break;
6516
case XPATH_NUMBER:
6517
ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
6518
break;
6519
case XPATH_STRING:
6520
ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
6521
break;
6522
case XPATH_USERS:
6523
#ifdef LIBXML_XPTR_LOCS_ENABLED
6524
case XPATH_POINT:
6525
case XPATH_RANGE:
6526
case XPATH_LOCATIONSET:
6527
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6528
TODO
6529
break;
6530
}
6531
xmlXPathReleaseObject(ctxt->context, arg1);
6532
xmlXPathReleaseObject(ctxt->context, arg2);
6533
return(ret);
6534
}
6535
6536
return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6537
}
6538
6539
/**
6540
* xmlXPathNotEqualValues:
6541
* @ctxt: the XPath Parser context
6542
*
6543
* Implement the equal operation on XPath objects content: @arg1 == @arg2
6544
*
6545
* Returns 0 or 1 depending on the results of the test.
6546
*/
6547
int
6548
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
6549
xmlXPathObjectPtr arg1, arg2, argtmp;
6550
int ret = 0;
6551
6552
if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6553
arg2 = valuePop(ctxt);
6554
arg1 = valuePop(ctxt);
6555
if ((arg1 == NULL) || (arg2 == NULL)) {
6556
if (arg1 != NULL)
6557
xmlXPathReleaseObject(ctxt->context, arg1);
6558
else
6559
xmlXPathReleaseObject(ctxt->context, arg2);
6560
XP_ERROR0(XPATH_INVALID_OPERAND);
6561
}
6562
6563
if (arg1 == arg2) {
6564
xmlXPathReleaseObject(ctxt->context, arg1);
6565
return(0);
6566
}
6567
6568
/*
6569
*If either argument is a nodeset, it's a 'special case'
6570
*/
6571
if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6572
(arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6573
/*
6574
*Hack it to assure arg1 is the nodeset
6575
*/
6576
if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
6577
argtmp = arg2;
6578
arg2 = arg1;
6579
arg1 = argtmp;
6580
}
6581
switch (arg2->type) {
6582
case XPATH_UNDEFINED:
6583
break;
6584
case XPATH_NODESET:
6585
case XPATH_XSLT_TREE:
6586
ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
6587
break;
6588
case XPATH_BOOLEAN:
6589
if ((arg1->nodesetval == NULL) ||
6590
(arg1->nodesetval->nodeNr == 0)) ret = 0;
6591
else
6592
ret = 1;
6593
ret = (ret != arg2->boolval);
6594
break;
6595
case XPATH_NUMBER:
6596
ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
6597
break;
6598
case XPATH_STRING:
6599
ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
6600
break;
6601
case XPATH_USERS:
6602
#ifdef LIBXML_XPTR_LOCS_ENABLED
6603
case XPATH_POINT:
6604
case XPATH_RANGE:
6605
case XPATH_LOCATIONSET:
6606
#endif /* LIBXML_XPTR_LOCS_ENABLED */
6607
TODO
6608
break;
6609
}
6610
xmlXPathReleaseObject(ctxt->context, arg1);
6611
xmlXPathReleaseObject(ctxt->context, arg2);
6612
return(ret);
6613
}
6614
6615
return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
6616
}
6617
6618
/**
6619
* xmlXPathCompareValues:
6620
* @ctxt: the XPath Parser context
6621
* @inf: less than (1) or greater than (0)
6622
* @strict: is the comparison strict
6623
*
6624
* Implement the compare operation on XPath objects:
6625
* @arg1 < @arg2 (1, 1, ...
6626
* @arg1 <= @arg2 (1, 0, ...
6627
* @arg1 > @arg2 (0, 1, ...
6628
* @arg1 >= @arg2 (0, 0, ...
6629
*
6630
* When neither object to be compared is a node-set and the operator is
6631
* <=, <, >=, >, then the objects are compared by converted both objects
6632
* to numbers and comparing the numbers according to IEEE 754. The <
6633
* comparison will be true if and only if the first number is less than the
6634
* second number. The <= comparison will be true if and only if the first
6635
* number is less than or equal to the second number. The > comparison
6636
* will be true if and only if the first number is greater than the second
6637
* number. The >= comparison will be true if and only if the first number
6638
* is greater than or equal to the second number.
6639
*
6640
* Returns 1 if the comparison succeeded, 0 if it failed
6641
*/
6642
int
6643
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
6644
int ret = 0, arg1i = 0, arg2i = 0;
6645
xmlXPathObjectPtr arg1, arg2;
6646
6647
if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
6648
arg2 = valuePop(ctxt);
6649
arg1 = valuePop(ctxt);
6650
if ((arg1 == NULL) || (arg2 == NULL)) {
6651
if (arg1 != NULL)
6652
xmlXPathReleaseObject(ctxt->context, arg1);
6653
else
6654
xmlXPathReleaseObject(ctxt->context, arg2);
6655
XP_ERROR0(XPATH_INVALID_OPERAND);
6656
}
6657
6658
if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
6659
(arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6660
/*
6661
* If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
6662
* are not freed from within this routine; they will be freed from the
6663
* called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
6664
*/
6665
if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
6666
((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
6667
ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
6668
} else {
6669
if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
6670
ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
6671
arg1, arg2);
6672
} else {
6673
ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
6674
arg2, arg1);
6675
}
6676
}
6677
return(ret);
6678
}
6679
6680
if (arg1->type != XPATH_NUMBER) {
6681
valuePush(ctxt, arg1);
6682
xmlXPathNumberFunction(ctxt, 1);
6683
arg1 = valuePop(ctxt);
6684
}
6685
if (arg2->type != XPATH_NUMBER) {
6686
valuePush(ctxt, arg2);
6687
xmlXPathNumberFunction(ctxt, 1);
6688
arg2 = valuePop(ctxt);
6689
}
6690
if (ctxt->error)
6691
goto error;
6692
/*
6693
* Add tests for infinity and nan
6694
* => feedback on 3.4 for Inf and NaN
6695
*/
6696
/* Hand check NaN and Infinity comparisons */
6697
if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
6698
ret=0;
6699
} else {
6700
arg1i=xmlXPathIsInf(arg1->floatval);
6701
arg2i=xmlXPathIsInf(arg2->floatval);
6702
if (inf && strict) {
6703
if ((arg1i == -1 && arg2i != -1) ||
6704
(arg2i == 1 && arg1i != 1)) {
6705
ret = 1;
6706
} else if (arg1i == 0 && arg2i == 0) {
6707
ret = (arg1->floatval < arg2->floatval);
6708
} else {
6709
ret = 0;
6710
}
6711
}
6712
else if (inf && !strict) {
6713
if (arg1i == -1 || arg2i == 1) {
6714
ret = 1;
6715
} else if (arg1i == 0 && arg2i == 0) {
6716
ret = (arg1->floatval <= arg2->floatval);
6717
} else {
6718
ret = 0;
6719
}
6720
}
6721
else if (!inf && strict) {
6722
if ((arg1i == 1 && arg2i != 1) ||
6723
(arg2i == -1 && arg1i != -1)) {
6724
ret = 1;
6725
} else if (arg1i == 0 && arg2i == 0) {
6726
ret = (arg1->floatval > arg2->floatval);
6727
} else {
6728
ret = 0;
6729
}
6730
}
6731
else if (!inf && !strict) {
6732
if (arg1i == 1 || arg2i == -1) {
6733
ret = 1;
6734
} else if (arg1i == 0 && arg2i == 0) {
6735
ret = (arg1->floatval >= arg2->floatval);
6736
} else {
6737
ret = 0;
6738
}
6739
}
6740
}
6741
error:
6742
xmlXPathReleaseObject(ctxt->context, arg1);
6743
xmlXPathReleaseObject(ctxt->context, arg2);
6744
return(ret);
6745
}
6746
6747
/**
6748
* xmlXPathValueFlipSign:
6749
* @ctxt: the XPath Parser context
6750
*
6751
* Implement the unary - operation on an XPath object
6752
* The numeric operators convert their operands to numbers as if
6753
* by calling the number function.
6754
*/
6755
void
6756
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
6757
if ((ctxt == NULL) || (ctxt->context == NULL)) return;
6758
CAST_TO_NUMBER;
6759
CHECK_TYPE(XPATH_NUMBER);
6760
ctxt->value->floatval = -ctxt->value->floatval;
6761
}
6762
6763
/**
6764
* xmlXPathAddValues:
6765
* @ctxt: the XPath Parser context
6766
*
6767
* Implement the add operation on XPath objects:
6768
* The numeric operators convert their operands to numbers as if
6769
* by calling the number function.
6770
*/
6771
void
6772
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
6773
xmlXPathObjectPtr arg;
6774
double val;
6775
6776
arg = valuePop(ctxt);
6777
if (arg == NULL)
6778
XP_ERROR(XPATH_INVALID_OPERAND);
6779
val = xmlXPathCastToNumber(arg);
6780
xmlXPathReleaseObject(ctxt->context, arg);
6781
CAST_TO_NUMBER;
6782
CHECK_TYPE(XPATH_NUMBER);
6783
ctxt->value->floatval += val;
6784
}
6785
6786
/**
6787
* xmlXPathSubValues:
6788
* @ctxt: the XPath Parser context
6789
*
6790
* Implement the subtraction operation on XPath objects:
6791
* The numeric operators convert their operands to numbers as if
6792
* by calling the number function.
6793
*/
6794
void
6795
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
6796
xmlXPathObjectPtr arg;
6797
double val;
6798
6799
arg = valuePop(ctxt);
6800
if (arg == NULL)
6801
XP_ERROR(XPATH_INVALID_OPERAND);
6802
val = xmlXPathCastToNumber(arg);
6803
xmlXPathReleaseObject(ctxt->context, arg);
6804
CAST_TO_NUMBER;
6805
CHECK_TYPE(XPATH_NUMBER);
6806
ctxt->value->floatval -= val;
6807
}
6808
6809
/**
6810
* xmlXPathMultValues:
6811
* @ctxt: the XPath Parser context
6812
*
6813
* Implement the multiply operation on XPath objects:
6814
* The numeric operators convert their operands to numbers as if
6815
* by calling the number function.
6816
*/
6817
void
6818
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
6819
xmlXPathObjectPtr arg;
6820
double val;
6821
6822
arg = valuePop(ctxt);
6823
if (arg == NULL)
6824
XP_ERROR(XPATH_INVALID_OPERAND);
6825
val = xmlXPathCastToNumber(arg);
6826
xmlXPathReleaseObject(ctxt->context, arg);
6827
CAST_TO_NUMBER;
6828
CHECK_TYPE(XPATH_NUMBER);
6829
ctxt->value->floatval *= val;
6830
}
6831
6832
/**
6833
* xmlXPathDivValues:
6834
* @ctxt: the XPath Parser context
6835
*
6836
* Implement the div operation on XPath objects @arg1 / @arg2:
6837
* The numeric operators convert their operands to numbers as if
6838
* by calling the number function.
6839
*/
6840
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
6841
void
6842
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
6843
xmlXPathObjectPtr arg;
6844
double val;
6845
6846
arg = valuePop(ctxt);
6847
if (arg == NULL)
6848
XP_ERROR(XPATH_INVALID_OPERAND);
6849
val = xmlXPathCastToNumber(arg);
6850
xmlXPathReleaseObject(ctxt->context, arg);
6851
CAST_TO_NUMBER;
6852
CHECK_TYPE(XPATH_NUMBER);
6853
ctxt->value->floatval /= val;
6854
}
6855
6856
/**
6857
* xmlXPathModValues:
6858
* @ctxt: the XPath Parser context
6859
*
6860
* Implement the mod operation on XPath objects: @arg1 / @arg2
6861
* The numeric operators convert their operands to numbers as if
6862
* by calling the number function.
6863
*/
6864
void
6865
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
6866
xmlXPathObjectPtr arg;
6867
double arg1, arg2;
6868
6869
arg = valuePop(ctxt);
6870
if (arg == NULL)
6871
XP_ERROR(XPATH_INVALID_OPERAND);
6872
arg2 = xmlXPathCastToNumber(arg);
6873
xmlXPathReleaseObject(ctxt->context, arg);
6874
CAST_TO_NUMBER;
6875
CHECK_TYPE(XPATH_NUMBER);
6876
arg1 = ctxt->value->floatval;
6877
if (arg2 == 0)
6878
ctxt->value->floatval = xmlXPathNAN;
6879
else {
6880
ctxt->value->floatval = fmod(arg1, arg2);
6881
}
6882
}
6883
6884
/************************************************************************
6885
* *
6886
* The traversal functions *
6887
* *
6888
************************************************************************/
6889
6890
/*
6891
* A traversal function enumerates nodes along an axis.
6892
* Initially it must be called with NULL, and it indicates
6893
* termination on the axis by returning NULL.
6894
*/
6895
typedef xmlNodePtr (*xmlXPathTraversalFunction)
6896
(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
6897
6898
/*
6899
* xmlXPathTraversalFunctionExt:
6900
* A traversal function enumerates nodes along an axis.
6901
* Initially it must be called with NULL, and it indicates
6902
* termination on the axis by returning NULL.
6903
* The context node of the traversal is specified via @contextNode.
6904
*/
6905
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
6906
(xmlNodePtr cur, xmlNodePtr contextNode);
6907
6908
/*
6909
* xmlXPathNodeSetMergeFunction:
6910
* Used for merging node sets in xmlXPathCollectAndTest().
6911
*/
6912
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
6913
(xmlNodeSetPtr, xmlNodeSetPtr);
6914
6915
6916
/**
6917
* xmlXPathNextSelf:
6918
* @ctxt: the XPath Parser context
6919
* @cur: the current node in the traversal
6920
*
6921
* Traversal function for the "self" direction
6922
* The self axis contains just the context node itself
6923
*
6924
* Returns the next element following that axis
6925
*/
6926
xmlNodePtr
6927
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6928
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6929
if (cur == NULL)
6930
return(ctxt->context->node);
6931
return(NULL);
6932
}
6933
6934
/**
6935
* xmlXPathNextChild:
6936
* @ctxt: the XPath Parser context
6937
* @cur: the current node in the traversal
6938
*
6939
* Traversal function for the "child" direction
6940
* The child axis contains the children of the context node in document order.
6941
*
6942
* Returns the next element following that axis
6943
*/
6944
xmlNodePtr
6945
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6946
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6947
if (cur == NULL) {
6948
if (ctxt->context->node == NULL) return(NULL);
6949
switch (ctxt->context->node->type) {
6950
case XML_ELEMENT_NODE:
6951
case XML_TEXT_NODE:
6952
case XML_CDATA_SECTION_NODE:
6953
case XML_ENTITY_REF_NODE:
6954
case XML_ENTITY_NODE:
6955
case XML_PI_NODE:
6956
case XML_COMMENT_NODE:
6957
case XML_NOTATION_NODE:
6958
case XML_DTD_NODE:
6959
return(ctxt->context->node->children);
6960
case XML_DOCUMENT_NODE:
6961
case XML_DOCUMENT_TYPE_NODE:
6962
case XML_DOCUMENT_FRAG_NODE:
6963
case XML_HTML_DOCUMENT_NODE:
6964
return(((xmlDocPtr) ctxt->context->node)->children);
6965
case XML_ELEMENT_DECL:
6966
case XML_ATTRIBUTE_DECL:
6967
case XML_ENTITY_DECL:
6968
case XML_ATTRIBUTE_NODE:
6969
case XML_NAMESPACE_DECL:
6970
case XML_XINCLUDE_START:
6971
case XML_XINCLUDE_END:
6972
return(NULL);
6973
}
6974
return(NULL);
6975
}
6976
if ((cur->type == XML_DOCUMENT_NODE) ||
6977
(cur->type == XML_HTML_DOCUMENT_NODE))
6978
return(NULL);
6979
return(cur->next);
6980
}
6981
6982
/**
6983
* xmlXPathNextChildElement:
6984
* @ctxt: the XPath Parser context
6985
* @cur: the current node in the traversal
6986
*
6987
* Traversal function for the "child" direction and nodes of type element.
6988
* The child axis contains the children of the context node in document order.
6989
*
6990
* Returns the next element following that axis
6991
*/
6992
static xmlNodePtr
6993
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
6994
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
6995
if (cur == NULL) {
6996
cur = ctxt->context->node;
6997
if (cur == NULL) return(NULL);
6998
/*
6999
* Get the first element child.
7000
*/
7001
switch (cur->type) {
7002
case XML_ELEMENT_NODE:
7003
case XML_DOCUMENT_FRAG_NODE:
7004
case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7005
case XML_ENTITY_NODE:
7006
cur = cur->children;
7007
if (cur != NULL) {
7008
if (cur->type == XML_ELEMENT_NODE)
7009
return(cur);
7010
do {
7011
cur = cur->next;
7012
} while ((cur != NULL) &&
7013
(cur->type != XML_ELEMENT_NODE));
7014
return(cur);
7015
}
7016
return(NULL);
7017
case XML_DOCUMENT_NODE:
7018
case XML_HTML_DOCUMENT_NODE:
7019
return(xmlDocGetRootElement((xmlDocPtr) cur));
7020
default:
7021
return(NULL);
7022
}
7023
return(NULL);
7024
}
7025
/*
7026
* Get the next sibling element node.
7027
*/
7028
switch (cur->type) {
7029
case XML_ELEMENT_NODE:
7030
case XML_TEXT_NODE:
7031
case XML_ENTITY_REF_NODE:
7032
case XML_ENTITY_NODE:
7033
case XML_CDATA_SECTION_NODE:
7034
case XML_PI_NODE:
7035
case XML_COMMENT_NODE:
7036
case XML_XINCLUDE_END:
7037
break;
7038
/* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7039
default:
7040
return(NULL);
7041
}
7042
if (cur->next != NULL) {
7043
if (cur->next->type == XML_ELEMENT_NODE)
7044
return(cur->next);
7045
cur = cur->next;
7046
do {
7047
cur = cur->next;
7048
} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7049
return(cur);
7050
}
7051
return(NULL);
7052
}
7053
7054
#if 0
7055
/**
7056
* xmlXPathNextDescendantOrSelfElemParent:
7057
* @ctxt: the XPath Parser context
7058
* @cur: the current node in the traversal
7059
*
7060
* Traversal function for the "descendant-or-self" axis.
7061
* Additionally it returns only nodes which can be parents of
7062
* element nodes.
7063
*
7064
*
7065
* Returns the next element following that axis
7066
*/
7067
static xmlNodePtr
7068
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7069
xmlNodePtr contextNode)
7070
{
7071
if (cur == NULL) {
7072
if (contextNode == NULL)
7073
return(NULL);
7074
switch (contextNode->type) {
7075
case XML_ELEMENT_NODE:
7076
case XML_XINCLUDE_START:
7077
case XML_DOCUMENT_FRAG_NODE:
7078
case XML_DOCUMENT_NODE:
7079
case XML_HTML_DOCUMENT_NODE:
7080
return(contextNode);
7081
default:
7082
return(NULL);
7083
}
7084
return(NULL);
7085
} else {
7086
xmlNodePtr start = cur;
7087
7088
while (cur != NULL) {
7089
switch (cur->type) {
7090
case XML_ELEMENT_NODE:
7091
/* TODO: OK to have XInclude here? */
7092
case XML_XINCLUDE_START:
7093
case XML_DOCUMENT_FRAG_NODE:
7094
if (cur != start)
7095
return(cur);
7096
if (cur->children != NULL) {
7097
cur = cur->children;
7098
continue;
7099
}
7100
break;
7101
/* Not sure if we need those here. */
7102
case XML_DOCUMENT_NODE:
7103
case XML_HTML_DOCUMENT_NODE:
7104
if (cur != start)
7105
return(cur);
7106
return(xmlDocGetRootElement((xmlDocPtr) cur));
7107
default:
7108
break;
7109
}
7110
7111
next_sibling:
7112
if ((cur == NULL) || (cur == contextNode))
7113
return(NULL);
7114
if (cur->next != NULL) {
7115
cur = cur->next;
7116
} else {
7117
cur = cur->parent;
7118
goto next_sibling;
7119
}
7120
}
7121
}
7122
return(NULL);
7123
}
7124
#endif
7125
7126
/**
7127
* xmlXPathNextDescendant:
7128
* @ctxt: the XPath Parser context
7129
* @cur: the current node in the traversal
7130
*
7131
* Traversal function for the "descendant" direction
7132
* the descendant axis contains the descendants of the context node in document
7133
* order; a descendant is a child or a child of a child and so on.
7134
*
7135
* Returns the next element following that axis
7136
*/
7137
xmlNodePtr
7138
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7139
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7140
if (cur == NULL) {
7141
if (ctxt->context->node == NULL)
7142
return(NULL);
7143
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7144
(ctxt->context->node->type == XML_NAMESPACE_DECL))
7145
return(NULL);
7146
7147
if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7148
return(ctxt->context->doc->children);
7149
return(ctxt->context->node->children);
7150
}
7151
7152
if (cur->type == XML_NAMESPACE_DECL)
7153
return(NULL);
7154
if (cur->children != NULL) {
7155
/*
7156
* Do not descend on entities declarations
7157
*/
7158
if (cur->children->type != XML_ENTITY_DECL) {
7159
cur = cur->children;
7160
/*
7161
* Skip DTDs
7162
*/
7163
if (cur->type != XML_DTD_NODE)
7164
return(cur);
7165
}
7166
}
7167
7168
if (cur == ctxt->context->node) return(NULL);
7169
7170
while (cur->next != NULL) {
7171
cur = cur->next;
7172
if ((cur->type != XML_ENTITY_DECL) &&
7173
(cur->type != XML_DTD_NODE))
7174
return(cur);
7175
}
7176
7177
do {
7178
cur = cur->parent;
7179
if (cur == NULL) break;
7180
if (cur == ctxt->context->node) return(NULL);
7181
if (cur->next != NULL) {
7182
cur = cur->next;
7183
return(cur);
7184
}
7185
} while (cur != NULL);
7186
return(cur);
7187
}
7188
7189
/**
7190
* xmlXPathNextDescendantOrSelf:
7191
* @ctxt: the XPath Parser context
7192
* @cur: the current node in the traversal
7193
*
7194
* Traversal function for the "descendant-or-self" direction
7195
* the descendant-or-self axis contains the context node and the descendants
7196
* of the context node in document order; thus the context node is the first
7197
* node on the axis, and the first child of the context node is the second node
7198
* on the axis
7199
*
7200
* Returns the next element following that axis
7201
*/
7202
xmlNodePtr
7203
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7204
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7205
if (cur == NULL)
7206
return(ctxt->context->node);
7207
7208
if (ctxt->context->node == NULL)
7209
return(NULL);
7210
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7211
(ctxt->context->node->type == XML_NAMESPACE_DECL))
7212
return(NULL);
7213
7214
return(xmlXPathNextDescendant(ctxt, cur));
7215
}
7216
7217
/**
7218
* xmlXPathNextParent:
7219
* @ctxt: the XPath Parser context
7220
* @cur: the current node in the traversal
7221
*
7222
* Traversal function for the "parent" direction
7223
* The parent axis contains the parent of the context node, if there is one.
7224
*
7225
* Returns the next element following that axis
7226
*/
7227
xmlNodePtr
7228
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7229
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7230
/*
7231
* the parent of an attribute or namespace node is the element
7232
* to which the attribute or namespace node is attached
7233
* Namespace handling !!!
7234
*/
7235
if (cur == NULL) {
7236
if (ctxt->context->node == NULL) return(NULL);
7237
switch (ctxt->context->node->type) {
7238
case XML_ELEMENT_NODE:
7239
case XML_TEXT_NODE:
7240
case XML_CDATA_SECTION_NODE:
7241
case XML_ENTITY_REF_NODE:
7242
case XML_ENTITY_NODE:
7243
case XML_PI_NODE:
7244
case XML_COMMENT_NODE:
7245
case XML_NOTATION_NODE:
7246
case XML_DTD_NODE:
7247
case XML_ELEMENT_DECL:
7248
case XML_ATTRIBUTE_DECL:
7249
case XML_XINCLUDE_START:
7250
case XML_XINCLUDE_END:
7251
case XML_ENTITY_DECL:
7252
if (ctxt->context->node->parent == NULL)
7253
return((xmlNodePtr) ctxt->context->doc);
7254
if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7255
((ctxt->context->node->parent->name[0] == ' ') ||
7256
(xmlStrEqual(ctxt->context->node->parent->name,
7257
BAD_CAST "fake node libxslt"))))
7258
return(NULL);
7259
return(ctxt->context->node->parent);
7260
case XML_ATTRIBUTE_NODE: {
7261
xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
7262
7263
return(att->parent);
7264
}
7265
case XML_DOCUMENT_NODE:
7266
case XML_DOCUMENT_TYPE_NODE:
7267
case XML_DOCUMENT_FRAG_NODE:
7268
case XML_HTML_DOCUMENT_NODE:
7269
return(NULL);
7270
case XML_NAMESPACE_DECL: {
7271
xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7272
7273
if ((ns->next != NULL) &&
7274
(ns->next->type != XML_NAMESPACE_DECL))
7275
return((xmlNodePtr) ns->next);
7276
return(NULL);
7277
}
7278
}
7279
}
7280
return(NULL);
7281
}
7282
7283
/**
7284
* xmlXPathNextAncestor:
7285
* @ctxt: the XPath Parser context
7286
* @cur: the current node in the traversal
7287
*
7288
* Traversal function for the "ancestor" direction
7289
* the ancestor axis contains the ancestors of the context node; the ancestors
7290
* of the context node consist of the parent of context node and the parent's
7291
* parent and so on; the nodes are ordered in reverse document order; thus the
7292
* parent is the first node on the axis, and the parent's parent is the second
7293
* node on the axis
7294
*
7295
* Returns the next element following that axis
7296
*/
7297
xmlNodePtr
7298
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7299
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7300
/*
7301
* the parent of an attribute or namespace node is the element
7302
* to which the attribute or namespace node is attached
7303
* !!!!!!!!!!!!!
7304
*/
7305
if (cur == NULL) {
7306
if (ctxt->context->node == NULL) return(NULL);
7307
switch (ctxt->context->node->type) {
7308
case XML_ELEMENT_NODE:
7309
case XML_TEXT_NODE:
7310
case XML_CDATA_SECTION_NODE:
7311
case XML_ENTITY_REF_NODE:
7312
case XML_ENTITY_NODE:
7313
case XML_PI_NODE:
7314
case XML_COMMENT_NODE:
7315
case XML_DTD_NODE:
7316
case XML_ELEMENT_DECL:
7317
case XML_ATTRIBUTE_DECL:
7318
case XML_ENTITY_DECL:
7319
case XML_NOTATION_NODE:
7320
case XML_XINCLUDE_START:
7321
case XML_XINCLUDE_END:
7322
if (ctxt->context->node->parent == NULL)
7323
return((xmlNodePtr) ctxt->context->doc);
7324
if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
7325
((ctxt->context->node->parent->name[0] == ' ') ||
7326
(xmlStrEqual(ctxt->context->node->parent->name,
7327
BAD_CAST "fake node libxslt"))))
7328
return(NULL);
7329
return(ctxt->context->node->parent);
7330
case XML_ATTRIBUTE_NODE: {
7331
xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
7332
7333
return(tmp->parent);
7334
}
7335
case XML_DOCUMENT_NODE:
7336
case XML_DOCUMENT_TYPE_NODE:
7337
case XML_DOCUMENT_FRAG_NODE:
7338
case XML_HTML_DOCUMENT_NODE:
7339
return(NULL);
7340
case XML_NAMESPACE_DECL: {
7341
xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
7342
7343
if ((ns->next != NULL) &&
7344
(ns->next->type != XML_NAMESPACE_DECL))
7345
return((xmlNodePtr) ns->next);
7346
/* Bad, how did that namespace end up here ? */
7347
return(NULL);
7348
}
7349
}
7350
return(NULL);
7351
}
7352
if (cur == ctxt->context->doc->children)
7353
return((xmlNodePtr) ctxt->context->doc);
7354
if (cur == (xmlNodePtr) ctxt->context->doc)
7355
return(NULL);
7356
switch (cur->type) {
7357
case XML_ELEMENT_NODE:
7358
case XML_TEXT_NODE:
7359
case XML_CDATA_SECTION_NODE:
7360
case XML_ENTITY_REF_NODE:
7361
case XML_ENTITY_NODE:
7362
case XML_PI_NODE:
7363
case XML_COMMENT_NODE:
7364
case XML_NOTATION_NODE:
7365
case XML_DTD_NODE:
7366
case XML_ELEMENT_DECL:
7367
case XML_ATTRIBUTE_DECL:
7368
case XML_ENTITY_DECL:
7369
case XML_XINCLUDE_START:
7370
case XML_XINCLUDE_END:
7371
if (cur->parent == NULL)
7372
return(NULL);
7373
if ((cur->parent->type == XML_ELEMENT_NODE) &&
7374
((cur->parent->name[0] == ' ') ||
7375
(xmlStrEqual(cur->parent->name,
7376
BAD_CAST "fake node libxslt"))))
7377
return(NULL);
7378
return(cur->parent);
7379
case XML_ATTRIBUTE_NODE: {
7380
xmlAttrPtr att = (xmlAttrPtr) cur;
7381
7382
return(att->parent);
7383
}
7384
case XML_NAMESPACE_DECL: {
7385
xmlNsPtr ns = (xmlNsPtr) cur;
7386
7387
if ((ns->next != NULL) &&
7388
(ns->next->type != XML_NAMESPACE_DECL))
7389
return((xmlNodePtr) ns->next);
7390
/* Bad, how did that namespace end up here ? */
7391
return(NULL);
7392
}
7393
case XML_DOCUMENT_NODE:
7394
case XML_DOCUMENT_TYPE_NODE:
7395
case XML_DOCUMENT_FRAG_NODE:
7396
case XML_HTML_DOCUMENT_NODE:
7397
return(NULL);
7398
}
7399
return(NULL);
7400
}
7401
7402
/**
7403
* xmlXPathNextAncestorOrSelf:
7404
* @ctxt: the XPath Parser context
7405
* @cur: the current node in the traversal
7406
*
7407
* Traversal function for the "ancestor-or-self" direction
7408
* he ancestor-or-self axis contains the context node and ancestors of
7409
* the context node in reverse document order; thus the context node is
7410
* the first node on the axis, and the context node's parent the second;
7411
* parent here is defined the same as with the parent axis.
7412
*
7413
* Returns the next element following that axis
7414
*/
7415
xmlNodePtr
7416
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7417
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7418
if (cur == NULL)
7419
return(ctxt->context->node);
7420
return(xmlXPathNextAncestor(ctxt, cur));
7421
}
7422
7423
/**
7424
* xmlXPathNextFollowingSibling:
7425
* @ctxt: the XPath Parser context
7426
* @cur: the current node in the traversal
7427
*
7428
* Traversal function for the "following-sibling" direction
7429
* The following-sibling axis contains the following siblings of the context
7430
* node in document order.
7431
*
7432
* Returns the next element following that axis
7433
*/
7434
xmlNodePtr
7435
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7436
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7437
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7438
(ctxt->context->node->type == XML_NAMESPACE_DECL))
7439
return(NULL);
7440
if (cur == (xmlNodePtr) ctxt->context->doc)
7441
return(NULL);
7442
if (cur == NULL)
7443
return(ctxt->context->node->next);
7444
return(cur->next);
7445
}
7446
7447
/**
7448
* xmlXPathNextPrecedingSibling:
7449
* @ctxt: the XPath Parser context
7450
* @cur: the current node in the traversal
7451
*
7452
* Traversal function for the "preceding-sibling" direction
7453
* The preceding-sibling axis contains the preceding siblings of the context
7454
* node in reverse document order; the first preceding sibling is first on the
7455
* axis; the sibling preceding that node is the second on the axis and so on.
7456
*
7457
* Returns the next element following that axis
7458
*/
7459
xmlNodePtr
7460
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7461
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7462
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7463
(ctxt->context->node->type == XML_NAMESPACE_DECL))
7464
return(NULL);
7465
if (cur == (xmlNodePtr) ctxt->context->doc)
7466
return(NULL);
7467
if (cur == NULL)
7468
return(ctxt->context->node->prev);
7469
if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
7470
cur = cur->prev;
7471
if (cur == NULL)
7472
return(ctxt->context->node->prev);
7473
}
7474
return(cur->prev);
7475
}
7476
7477
/**
7478
* xmlXPathNextFollowing:
7479
* @ctxt: the XPath Parser context
7480
* @cur: the current node in the traversal
7481
*
7482
* Traversal function for the "following" direction
7483
* The following axis contains all nodes in the same document as the context
7484
* node that are after the context node in document order, excluding any
7485
* descendants and excluding attribute nodes and namespace nodes; the nodes
7486
* are ordered in document order
7487
*
7488
* Returns the next element following that axis
7489
*/
7490
xmlNodePtr
7491
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7492
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7493
if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
7494
(cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
7495
return(cur->children);
7496
7497
if (cur == NULL) {
7498
cur = ctxt->context->node;
7499
if (cur->type == XML_ATTRIBUTE_NODE) {
7500
cur = cur->parent;
7501
} else if (cur->type == XML_NAMESPACE_DECL) {
7502
xmlNsPtr ns = (xmlNsPtr) cur;
7503
7504
if ((ns->next == NULL) ||
7505
(ns->next->type == XML_NAMESPACE_DECL))
7506
return (NULL);
7507
cur = (xmlNodePtr) ns->next;
7508
}
7509
}
7510
if (cur == NULL) return(NULL) ; /* ERROR */
7511
if (cur->next != NULL) return(cur->next) ;
7512
do {
7513
cur = cur->parent;
7514
if (cur == NULL) break;
7515
if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
7516
if (cur->next != NULL) return(cur->next);
7517
} while (cur != NULL);
7518
return(cur);
7519
}
7520
7521
/*
7522
* xmlXPathIsAncestor:
7523
* @ancestor: the ancestor node
7524
* @node: the current node
7525
*
7526
* Check that @ancestor is a @node's ancestor
7527
*
7528
* returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
7529
*/
7530
static int
7531
xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
7532
if ((ancestor == NULL) || (node == NULL)) return(0);
7533
if (node->type == XML_NAMESPACE_DECL)
7534
return(0);
7535
if (ancestor->type == XML_NAMESPACE_DECL)
7536
return(0);
7537
/* nodes need to be in the same document */
7538
if (ancestor->doc != node->doc) return(0);
7539
/* avoid searching if ancestor or node is the root node */
7540
if (ancestor == (xmlNodePtr) node->doc) return(1);
7541
if (node == (xmlNodePtr) ancestor->doc) return(0);
7542
while (node->parent != NULL) {
7543
if (node->parent == ancestor)
7544
return(1);
7545
node = node->parent;
7546
}
7547
return(0);
7548
}
7549
7550
/**
7551
* xmlXPathNextPreceding:
7552
* @ctxt: the XPath Parser context
7553
* @cur: the current node in the traversal
7554
*
7555
* Traversal function for the "preceding" direction
7556
* the preceding axis contains all nodes in the same document as the context
7557
* node that are before the context node in document order, excluding any
7558
* ancestors and excluding attribute nodes and namespace nodes; the nodes are
7559
* ordered in reverse document order
7560
*
7561
* Returns the next element following that axis
7562
*/
7563
xmlNodePtr
7564
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
7565
{
7566
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7567
if (cur == NULL) {
7568
cur = ctxt->context->node;
7569
if (cur->type == XML_ATTRIBUTE_NODE) {
7570
cur = cur->parent;
7571
} else if (cur->type == XML_NAMESPACE_DECL) {
7572
xmlNsPtr ns = (xmlNsPtr) cur;
7573
7574
if ((ns->next == NULL) ||
7575
(ns->next->type == XML_NAMESPACE_DECL))
7576
return (NULL);
7577
cur = (xmlNodePtr) ns->next;
7578
}
7579
}
7580
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
7581
return (NULL);
7582
if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7583
cur = cur->prev;
7584
do {
7585
if (cur->prev != NULL) {
7586
for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
7587
return (cur);
7588
}
7589
7590
cur = cur->parent;
7591
if (cur == NULL)
7592
return (NULL);
7593
if (cur == ctxt->context->doc->children)
7594
return (NULL);
7595
} while (xmlXPathIsAncestor(cur, ctxt->context->node));
7596
return (cur);
7597
}
7598
7599
/**
7600
* xmlXPathNextPrecedingInternal:
7601
* @ctxt: the XPath Parser context
7602
* @cur: the current node in the traversal
7603
*
7604
* Traversal function for the "preceding" direction
7605
* the preceding axis contains all nodes in the same document as the context
7606
* node that are before the context node in document order, excluding any
7607
* ancestors and excluding attribute nodes and namespace nodes; the nodes are
7608
* ordered in reverse document order
7609
* This is a faster implementation but internal only since it requires a
7610
* state kept in the parser context: ctxt->ancestor.
7611
*
7612
* Returns the next element following that axis
7613
*/
7614
static xmlNodePtr
7615
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
7616
xmlNodePtr cur)
7617
{
7618
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7619
if (cur == NULL) {
7620
cur = ctxt->context->node;
7621
if (cur == NULL)
7622
return (NULL);
7623
if (cur->type == XML_ATTRIBUTE_NODE) {
7624
cur = cur->parent;
7625
} else if (cur->type == XML_NAMESPACE_DECL) {
7626
xmlNsPtr ns = (xmlNsPtr) cur;
7627
7628
if ((ns->next == NULL) ||
7629
(ns->next->type == XML_NAMESPACE_DECL))
7630
return (NULL);
7631
cur = (xmlNodePtr) ns->next;
7632
}
7633
ctxt->ancestor = cur->parent;
7634
}
7635
if (cur->type == XML_NAMESPACE_DECL)
7636
return(NULL);
7637
if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
7638
cur = cur->prev;
7639
while (cur->prev == NULL) {
7640
cur = cur->parent;
7641
if (cur == NULL)
7642
return (NULL);
7643
if (cur == ctxt->context->doc->children)
7644
return (NULL);
7645
if (cur != ctxt->ancestor)
7646
return (cur);
7647
ctxt->ancestor = cur->parent;
7648
}
7649
cur = cur->prev;
7650
while (cur->last != NULL)
7651
cur = cur->last;
7652
return (cur);
7653
}
7654
7655
/**
7656
* xmlXPathNextNamespace:
7657
* @ctxt: the XPath Parser context
7658
* @cur: the current attribute in the traversal
7659
*
7660
* Traversal function for the "namespace" direction
7661
* the namespace axis contains the namespace nodes of the context node;
7662
* the order of nodes on this axis is implementation-defined; the axis will
7663
* be empty unless the context node is an element
7664
*
7665
* We keep the XML namespace node at the end of the list.
7666
*
7667
* Returns the next element following that axis
7668
*/
7669
xmlNodePtr
7670
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7671
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7672
if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
7673
if (cur == NULL) {
7674
if (ctxt->context->tmpNsList != NULL)
7675
xmlFree(ctxt->context->tmpNsList);
7676
ctxt->context->tmpNsList =
7677
xmlGetNsList(ctxt->context->doc, ctxt->context->node);
7678
ctxt->context->tmpNsNr = 0;
7679
if (ctxt->context->tmpNsList != NULL) {
7680
while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
7681
ctxt->context->tmpNsNr++;
7682
}
7683
}
7684
return((xmlNodePtr) xmlXPathXMLNamespace);
7685
}
7686
if (ctxt->context->tmpNsNr > 0) {
7687
return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
7688
} else {
7689
if (ctxt->context->tmpNsList != NULL)
7690
xmlFree(ctxt->context->tmpNsList);
7691
ctxt->context->tmpNsList = NULL;
7692
return(NULL);
7693
}
7694
}
7695
7696
/**
7697
* xmlXPathNextAttribute:
7698
* @ctxt: the XPath Parser context
7699
* @cur: the current attribute in the traversal
7700
*
7701
* Traversal function for the "attribute" direction
7702
* TODO: support DTD inherited default attributes
7703
*
7704
* Returns the next element following that axis
7705
*/
7706
xmlNodePtr
7707
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7708
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7709
if (ctxt->context->node == NULL)
7710
return(NULL);
7711
if (ctxt->context->node->type != XML_ELEMENT_NODE)
7712
return(NULL);
7713
if (cur == NULL) {
7714
if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7715
return(NULL);
7716
return((xmlNodePtr)ctxt->context->node->properties);
7717
}
7718
return((xmlNodePtr)cur->next);
7719
}
7720
7721
/************************************************************************
7722
* *
7723
* NodeTest Functions *
7724
* *
7725
************************************************************************/
7726
7727
#define IS_FUNCTION 200
7728
7729
7730
/************************************************************************
7731
* *
7732
* Implicit tree core function library *
7733
* *
7734
************************************************************************/
7735
7736
/**
7737
* xmlXPathRoot:
7738
* @ctxt: the XPath Parser context
7739
*
7740
* Initialize the context to the root of the document
7741
*/
7742
void
7743
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
7744
if ((ctxt == NULL) || (ctxt->context == NULL))
7745
return;
7746
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7747
(xmlNodePtr) ctxt->context->doc));
7748
}
7749
7750
/************************************************************************
7751
* *
7752
* The explicit core function library *
7753
*http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
7754
* *
7755
************************************************************************/
7756
7757
7758
/**
7759
* xmlXPathLastFunction:
7760
* @ctxt: the XPath Parser context
7761
* @nargs: the number of arguments
7762
*
7763
* Implement the last() XPath function
7764
* number last()
7765
* The last function returns the number of nodes in the context node list.
7766
*/
7767
void
7768
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7769
CHECK_ARITY(0);
7770
if (ctxt->context->contextSize >= 0) {
7771
valuePush(ctxt,
7772
xmlXPathCacheNewFloat(ctxt->context,
7773
(double) ctxt->context->contextSize));
7774
} else {
7775
XP_ERROR(XPATH_INVALID_CTXT_SIZE);
7776
}
7777
}
7778
7779
/**
7780
* xmlXPathPositionFunction:
7781
* @ctxt: the XPath Parser context
7782
* @nargs: the number of arguments
7783
*
7784
* Implement the position() XPath function
7785
* number position()
7786
* The position function returns the position of the context node in the
7787
* context node list. The first position is 1, and so the last position
7788
* will be equal to last().
7789
*/
7790
void
7791
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7792
CHECK_ARITY(0);
7793
if (ctxt->context->proximityPosition >= 0) {
7794
valuePush(ctxt,
7795
xmlXPathCacheNewFloat(ctxt->context,
7796
(double) ctxt->context->proximityPosition));
7797
} else {
7798
XP_ERROR(XPATH_INVALID_CTXT_POSITION);
7799
}
7800
}
7801
7802
/**
7803
* xmlXPathCountFunction:
7804
* @ctxt: the XPath Parser context
7805
* @nargs: the number of arguments
7806
*
7807
* Implement the count() XPath function
7808
* number count(node-set)
7809
*/
7810
void
7811
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7812
xmlXPathObjectPtr cur;
7813
7814
CHECK_ARITY(1);
7815
if ((ctxt->value == NULL) ||
7816
((ctxt->value->type != XPATH_NODESET) &&
7817
(ctxt->value->type != XPATH_XSLT_TREE)))
7818
XP_ERROR(XPATH_INVALID_TYPE);
7819
cur = valuePop(ctxt);
7820
7821
if ((cur == NULL) || (cur->nodesetval == NULL))
7822
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
7823
else
7824
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
7825
(double) cur->nodesetval->nodeNr));
7826
xmlXPathReleaseObject(ctxt->context, cur);
7827
}
7828
7829
/**
7830
* xmlXPathGetElementsByIds:
7831
* @doc: the document
7832
* @ids: a whitespace separated list of IDs
7833
*
7834
* Selects elements by their unique ID.
7835
*
7836
* Returns a node-set of selected elements.
7837
*/
7838
static xmlNodeSetPtr
7839
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
7840
xmlNodeSetPtr ret;
7841
const xmlChar *cur = ids;
7842
xmlChar *ID;
7843
xmlAttrPtr attr;
7844
xmlNodePtr elem = NULL;
7845
7846
if (ids == NULL) return(NULL);
7847
7848
ret = xmlXPathNodeSetCreate(NULL);
7849
if (ret == NULL)
7850
return(ret);
7851
7852
while (IS_BLANK_CH(*cur)) cur++;
7853
while (*cur != 0) {
7854
while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
7855
cur++;
7856
7857
ID = xmlStrndup(ids, cur - ids);
7858
if (ID != NULL) {
7859
/*
7860
* We used to check the fact that the value passed
7861
* was an NCName, but this generated much troubles for
7862
* me and Aleksey Sanin, people blatantly violated that
7863
* constraint, like Visa3D spec.
7864
* if (xmlValidateNCName(ID, 1) == 0)
7865
*/
7866
attr = xmlGetID(doc, ID);
7867
if (attr != NULL) {
7868
if (attr->type == XML_ATTRIBUTE_NODE)
7869
elem = attr->parent;
7870
else if (attr->type == XML_ELEMENT_NODE)
7871
elem = (xmlNodePtr) attr;
7872
else
7873
elem = NULL;
7874
/* TODO: Check memory error. */
7875
if (elem != NULL)
7876
xmlXPathNodeSetAdd(ret, elem);
7877
}
7878
xmlFree(ID);
7879
}
7880
7881
while (IS_BLANK_CH(*cur)) cur++;
7882
ids = cur;
7883
}
7884
return(ret);
7885
}
7886
7887
/**
7888
* xmlXPathIdFunction:
7889
* @ctxt: the XPath Parser context
7890
* @nargs: the number of arguments
7891
*
7892
* Implement the id() XPath function
7893
* node-set id(object)
7894
* The id function selects elements by their unique ID
7895
* (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
7896
* then the result is the union of the result of applying id to the
7897
* string value of each of the nodes in the argument node-set. When the
7898
* argument to id is of any other type, the argument is converted to a
7899
* string as if by a call to the string function; the string is split
7900
* into a whitespace-separated list of tokens (whitespace is any sequence
7901
* of characters matching the production S); the result is a node-set
7902
* containing the elements in the same document as the context node that
7903
* have a unique ID equal to any of the tokens in the list.
7904
*/
7905
void
7906
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7907
xmlChar *tokens;
7908
xmlNodeSetPtr ret;
7909
xmlXPathObjectPtr obj;
7910
7911
CHECK_ARITY(1);
7912
obj = valuePop(ctxt);
7913
if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
7914
if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
7915
xmlNodeSetPtr ns;
7916
int i;
7917
7918
/* TODO: Check memory error. */
7919
ret = xmlXPathNodeSetCreate(NULL);
7920
7921
if (obj->nodesetval != NULL) {
7922
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
7923
tokens =
7924
xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
7925
ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
7926
/* TODO: Check memory error. */
7927
ret = xmlXPathNodeSetMerge(ret, ns);
7928
xmlXPathFreeNodeSet(ns);
7929
if (tokens != NULL)
7930
xmlFree(tokens);
7931
}
7932
}
7933
xmlXPathReleaseObject(ctxt->context, obj);
7934
valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
7935
return;
7936
}
7937
obj = xmlXPathCacheConvertString(ctxt->context, obj);
7938
if (obj == NULL) return;
7939
ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
7940
valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
7941
xmlXPathReleaseObject(ctxt->context, obj);
7942
return;
7943
}
7944
7945
/**
7946
* xmlXPathLocalNameFunction:
7947
* @ctxt: the XPath Parser context
7948
* @nargs: the number of arguments
7949
*
7950
* Implement the local-name() XPath function
7951
* string local-name(node-set?)
7952
* The local-name function returns a string containing the local part
7953
* of the name of the node in the argument node-set that is first in
7954
* document order. If the node-set is empty or the first node has no
7955
* name, an empty string is returned. If the argument is omitted it
7956
* defaults to the context node.
7957
*/
7958
void
7959
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7960
xmlXPathObjectPtr cur;
7961
7962
if (ctxt == NULL) return;
7963
7964
if (nargs == 0) {
7965
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
7966
ctxt->context->node));
7967
nargs = 1;
7968
}
7969
7970
CHECK_ARITY(1);
7971
if ((ctxt->value == NULL) ||
7972
((ctxt->value->type != XPATH_NODESET) &&
7973
(ctxt->value->type != XPATH_XSLT_TREE)))
7974
XP_ERROR(XPATH_INVALID_TYPE);
7975
cur = valuePop(ctxt);
7976
7977
if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
7978
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7979
} else {
7980
int i = 0; /* Should be first in document order !!!!! */
7981
switch (cur->nodesetval->nodeTab[i]->type) {
7982
case XML_ELEMENT_NODE:
7983
case XML_ATTRIBUTE_NODE:
7984
case XML_PI_NODE:
7985
if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
7986
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7987
else
7988
valuePush(ctxt,
7989
xmlXPathCacheNewString(ctxt->context,
7990
cur->nodesetval->nodeTab[i]->name));
7991
break;
7992
case XML_NAMESPACE_DECL:
7993
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
7994
((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
7995
break;
7996
default:
7997
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
7998
}
7999
}
8000
xmlXPathReleaseObject(ctxt->context, cur);
8001
}
8002
8003
/**
8004
* xmlXPathNamespaceURIFunction:
8005
* @ctxt: the XPath Parser context
8006
* @nargs: the number of arguments
8007
*
8008
* Implement the namespace-uri() XPath function
8009
* string namespace-uri(node-set?)
8010
* The namespace-uri function returns a string containing the
8011
* namespace URI of the expanded name of the node in the argument
8012
* node-set that is first in document order. If the node-set is empty,
8013
* the first node has no name, or the expanded name has no namespace
8014
* URI, an empty string is returned. If the argument is omitted it
8015
* defaults to the context node.
8016
*/
8017
void
8018
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8019
xmlXPathObjectPtr cur;
8020
8021
if (ctxt == NULL) return;
8022
8023
if (nargs == 0) {
8024
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8025
ctxt->context->node));
8026
nargs = 1;
8027
}
8028
CHECK_ARITY(1);
8029
if ((ctxt->value == NULL) ||
8030
((ctxt->value->type != XPATH_NODESET) &&
8031
(ctxt->value->type != XPATH_XSLT_TREE)))
8032
XP_ERROR(XPATH_INVALID_TYPE);
8033
cur = valuePop(ctxt);
8034
8035
if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8036
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8037
} else {
8038
int i = 0; /* Should be first in document order !!!!! */
8039
switch (cur->nodesetval->nodeTab[i]->type) {
8040
case XML_ELEMENT_NODE:
8041
case XML_ATTRIBUTE_NODE:
8042
if (cur->nodesetval->nodeTab[i]->ns == NULL)
8043
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8044
else
8045
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8046
cur->nodesetval->nodeTab[i]->ns->href));
8047
break;
8048
default:
8049
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8050
}
8051
}
8052
xmlXPathReleaseObject(ctxt->context, cur);
8053
}
8054
8055
/**
8056
* xmlXPathNameFunction:
8057
* @ctxt: the XPath Parser context
8058
* @nargs: the number of arguments
8059
*
8060
* Implement the name() XPath function
8061
* string name(node-set?)
8062
* The name function returns a string containing a QName representing
8063
* the name of the node in the argument node-set that is first in document
8064
* order. The QName must represent the name with respect to the namespace
8065
* declarations in effect on the node whose name is being represented.
8066
* Typically, this will be the form in which the name occurred in the XML
8067
* source. This need not be the case if there are namespace declarations
8068
* in effect on the node that associate multiple prefixes with the same
8069
* namespace. However, an implementation may include information about
8070
* the original prefix in its representation of nodes; in this case, an
8071
* implementation can ensure that the returned string is always the same
8072
* as the QName used in the XML source. If the argument it omitted it
8073
* defaults to the context node.
8074
* Libxml keep the original prefix so the "real qualified name" used is
8075
* returned.
8076
*/
8077
static void
8078
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8079
{
8080
xmlXPathObjectPtr cur;
8081
8082
if (nargs == 0) {
8083
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8084
ctxt->context->node));
8085
nargs = 1;
8086
}
8087
8088
CHECK_ARITY(1);
8089
if ((ctxt->value == NULL) ||
8090
((ctxt->value->type != XPATH_NODESET) &&
8091
(ctxt->value->type != XPATH_XSLT_TREE)))
8092
XP_ERROR(XPATH_INVALID_TYPE);
8093
cur = valuePop(ctxt);
8094
8095
if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8096
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8097
} else {
8098
int i = 0; /* Should be first in document order !!!!! */
8099
8100
switch (cur->nodesetval->nodeTab[i]->type) {
8101
case XML_ELEMENT_NODE:
8102
case XML_ATTRIBUTE_NODE:
8103
if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8104
valuePush(ctxt,
8105
xmlXPathCacheNewCString(ctxt->context, ""));
8106
else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8107
(cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8108
valuePush(ctxt,
8109
xmlXPathCacheNewString(ctxt->context,
8110
cur->nodesetval->nodeTab[i]->name));
8111
} else {
8112
xmlChar *fullname;
8113
8114
fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8115
cur->nodesetval->nodeTab[i]->ns->prefix,
8116
NULL, 0);
8117
if (fullname == cur->nodesetval->nodeTab[i]->name)
8118
fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8119
if (fullname == NULL)
8120
xmlXPathPErrMemory(ctxt, NULL);
8121
valuePush(ctxt, xmlXPathCacheWrapString(
8122
ctxt->context, fullname));
8123
}
8124
break;
8125
default:
8126
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8127
cur->nodesetval->nodeTab[i]));
8128
xmlXPathLocalNameFunction(ctxt, 1);
8129
}
8130
}
8131
xmlXPathReleaseObject(ctxt->context, cur);
8132
}
8133
8134
8135
/**
8136
* xmlXPathStringFunction:
8137
* @ctxt: the XPath Parser context
8138
* @nargs: the number of arguments
8139
*
8140
* Implement the string() XPath function
8141
* string string(object?)
8142
* The string function converts an object to a string as follows:
8143
* - A node-set is converted to a string by returning the value of
8144
* the node in the node-set that is first in document order.
8145
* If the node-set is empty, an empty string is returned.
8146
* - A number is converted to a string as follows
8147
* + NaN is converted to the string NaN
8148
* + positive zero is converted to the string 0
8149
* + negative zero is converted to the string 0
8150
* + positive infinity is converted to the string Infinity
8151
* + negative infinity is converted to the string -Infinity
8152
* + if the number is an integer, the number is represented in
8153
* decimal form as a Number with no decimal point and no leading
8154
* zeros, preceded by a minus sign (-) if the number is negative
8155
* + otherwise, the number is represented in decimal form as a
8156
* Number including a decimal point with at least one digit
8157
* before the decimal point and at least one digit after the
8158
* decimal point, preceded by a minus sign (-) if the number
8159
* is negative; there must be no leading zeros before the decimal
8160
* point apart possibly from the one required digit immediately
8161
* before the decimal point; beyond the one required digit
8162
* after the decimal point there must be as many, but only as
8163
* many, more digits as are needed to uniquely distinguish the
8164
* number from all other IEEE 754 numeric values.
8165
* - The boolean false value is converted to the string false.
8166
* The boolean true value is converted to the string true.
8167
*
8168
* If the argument is omitted, it defaults to a node-set with the
8169
* context node as its only member.
8170
*/
8171
void
8172
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8173
xmlXPathObjectPtr cur;
8174
8175
if (ctxt == NULL) return;
8176
if (nargs == 0) {
8177
valuePush(ctxt,
8178
xmlXPathCacheWrapString(ctxt->context,
8179
xmlXPathCastNodeToString(ctxt->context->node)));
8180
return;
8181
}
8182
8183
CHECK_ARITY(1);
8184
cur = valuePop(ctxt);
8185
if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8186
valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8187
}
8188
8189
/**
8190
* xmlXPathStringLengthFunction:
8191
* @ctxt: the XPath Parser context
8192
* @nargs: the number of arguments
8193
*
8194
* Implement the string-length() XPath function
8195
* number string-length(string?)
8196
* The string-length returns the number of characters in the string
8197
* (see [3.6 Strings]). If the argument is omitted, it defaults to
8198
* the context node converted to a string, in other words the value
8199
* of the context node.
8200
*/
8201
void
8202
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8203
xmlXPathObjectPtr cur;
8204
8205
if (nargs == 0) {
8206
if ((ctxt == NULL) || (ctxt->context == NULL))
8207
return;
8208
if (ctxt->context->node == NULL) {
8209
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
8210
} else {
8211
xmlChar *content;
8212
8213
content = xmlXPathCastNodeToString(ctxt->context->node);
8214
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8215
xmlUTF8Strlen(content)));
8216
xmlFree(content);
8217
}
8218
return;
8219
}
8220
CHECK_ARITY(1);
8221
CAST_TO_STRING;
8222
CHECK_TYPE(XPATH_STRING);
8223
cur = valuePop(ctxt);
8224
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8225
xmlUTF8Strlen(cur->stringval)));
8226
xmlXPathReleaseObject(ctxt->context, cur);
8227
}
8228
8229
/**
8230
* xmlXPathConcatFunction:
8231
* @ctxt: the XPath Parser context
8232
* @nargs: the number of arguments
8233
*
8234
* Implement the concat() XPath function
8235
* string concat(string, string, string*)
8236
* The concat function returns the concatenation of its arguments.
8237
*/
8238
void
8239
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8240
xmlXPathObjectPtr cur, newobj;
8241
xmlChar *tmp;
8242
8243
if (ctxt == NULL) return;
8244
if (nargs < 2) {
8245
CHECK_ARITY(2);
8246
}
8247
8248
CAST_TO_STRING;
8249
cur = valuePop(ctxt);
8250
if ((cur == NULL) || (cur->type != XPATH_STRING)) {
8251
xmlXPathReleaseObject(ctxt->context, cur);
8252
return;
8253
}
8254
nargs--;
8255
8256
while (nargs > 0) {
8257
CAST_TO_STRING;
8258
newobj = valuePop(ctxt);
8259
if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
8260
xmlXPathReleaseObject(ctxt->context, newobj);
8261
xmlXPathReleaseObject(ctxt->context, cur);
8262
XP_ERROR(XPATH_INVALID_TYPE);
8263
}
8264
tmp = xmlStrcat(newobj->stringval, cur->stringval);
8265
newobj->stringval = cur->stringval;
8266
cur->stringval = tmp;
8267
xmlXPathReleaseObject(ctxt->context, newobj);
8268
nargs--;
8269
}
8270
valuePush(ctxt, cur);
8271
}
8272
8273
/**
8274
* xmlXPathContainsFunction:
8275
* @ctxt: the XPath Parser context
8276
* @nargs: the number of arguments
8277
*
8278
* Implement the contains() XPath function
8279
* boolean contains(string, string)
8280
* The contains function returns true if the first argument string
8281
* contains the second argument string, and otherwise returns false.
8282
*/
8283
void
8284
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8285
xmlXPathObjectPtr hay, needle;
8286
8287
CHECK_ARITY(2);
8288
CAST_TO_STRING;
8289
CHECK_TYPE(XPATH_STRING);
8290
needle = valuePop(ctxt);
8291
CAST_TO_STRING;
8292
hay = valuePop(ctxt);
8293
8294
if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8295
xmlXPathReleaseObject(ctxt->context, hay);
8296
xmlXPathReleaseObject(ctxt->context, needle);
8297
XP_ERROR(XPATH_INVALID_TYPE);
8298
}
8299
if (xmlStrstr(hay->stringval, needle->stringval))
8300
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8301
else
8302
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8303
xmlXPathReleaseObject(ctxt->context, hay);
8304
xmlXPathReleaseObject(ctxt->context, needle);
8305
}
8306
8307
/**
8308
* xmlXPathStartsWithFunction:
8309
* @ctxt: the XPath Parser context
8310
* @nargs: the number of arguments
8311
*
8312
* Implement the starts-with() XPath function
8313
* boolean starts-with(string, string)
8314
* The starts-with function returns true if the first argument string
8315
* starts with the second argument string, and otherwise returns false.
8316
*/
8317
void
8318
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8319
xmlXPathObjectPtr hay, needle;
8320
int n;
8321
8322
CHECK_ARITY(2);
8323
CAST_TO_STRING;
8324
CHECK_TYPE(XPATH_STRING);
8325
needle = valuePop(ctxt);
8326
CAST_TO_STRING;
8327
hay = valuePop(ctxt);
8328
8329
if ((hay == NULL) || (hay->type != XPATH_STRING)) {
8330
xmlXPathReleaseObject(ctxt->context, hay);
8331
xmlXPathReleaseObject(ctxt->context, needle);
8332
XP_ERROR(XPATH_INVALID_TYPE);
8333
}
8334
n = xmlStrlen(needle->stringval);
8335
if (xmlStrncmp(hay->stringval, needle->stringval, n))
8336
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8337
else
8338
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8339
xmlXPathReleaseObject(ctxt->context, hay);
8340
xmlXPathReleaseObject(ctxt->context, needle);
8341
}
8342
8343
/**
8344
* xmlXPathSubstringFunction:
8345
* @ctxt: the XPath Parser context
8346
* @nargs: the number of arguments
8347
*
8348
* Implement the substring() XPath function
8349
* string substring(string, number, number?)
8350
* The substring function returns the substring of the first argument
8351
* starting at the position specified in the second argument with
8352
* length specified in the third argument. For example,
8353
* substring("12345",2,3) returns "234". If the third argument is not
8354
* specified, it returns the substring starting at the position specified
8355
* in the second argument and continuing to the end of the string. For
8356
* example, substring("12345",2) returns "2345". More precisely, each
8357
* character in the string (see [3.6 Strings]) is considered to have a
8358
* numeric position: the position of the first character is 1, the position
8359
* of the second character is 2 and so on. The returned substring contains
8360
* those characters for which the position of the character is greater than
8361
* or equal to the second argument and, if the third argument is specified,
8362
* less than the sum of the second and third arguments; the comparisons
8363
* and addition used for the above follow the standard IEEE 754 rules. Thus:
8364
* - substring("12345", 1.5, 2.6) returns "234"
8365
* - substring("12345", 0, 3) returns "12"
8366
* - substring("12345", 0 div 0, 3) returns ""
8367
* - substring("12345", 1, 0 div 0) returns ""
8368
* - substring("12345", -42, 1 div 0) returns "12345"
8369
* - substring("12345", -1 div 0, 1 div 0) returns ""
8370
*/
8371
void
8372
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8373
xmlXPathObjectPtr str, start, len;
8374
double le=0, in;
8375
int i = 1, j = INT_MAX;
8376
8377
if (nargs < 2) {
8378
CHECK_ARITY(2);
8379
}
8380
if (nargs > 3) {
8381
CHECK_ARITY(3);
8382
}
8383
/*
8384
* take care of possible last (position) argument
8385
*/
8386
if (nargs == 3) {
8387
CAST_TO_NUMBER;
8388
CHECK_TYPE(XPATH_NUMBER);
8389
len = valuePop(ctxt);
8390
le = len->floatval;
8391
xmlXPathReleaseObject(ctxt->context, len);
8392
}
8393
8394
CAST_TO_NUMBER;
8395
CHECK_TYPE(XPATH_NUMBER);
8396
start = valuePop(ctxt);
8397
in = start->floatval;
8398
xmlXPathReleaseObject(ctxt->context, start);
8399
CAST_TO_STRING;
8400
CHECK_TYPE(XPATH_STRING);
8401
str = valuePop(ctxt);
8402
8403
if (!(in < INT_MAX)) { /* Logical NOT to handle NaNs */
8404
i = INT_MAX;
8405
} else if (in >= 1.0) {
8406
i = (int)in;
8407
if (in - floor(in) >= 0.5)
8408
i += 1;
8409
}
8410
8411
if (nargs == 3) {
8412
double rin, rle, end;
8413
8414
rin = floor(in);
8415
if (in - rin >= 0.5)
8416
rin += 1.0;
8417
8418
rle = floor(le);
8419
if (le - rle >= 0.5)
8420
rle += 1.0;
8421
8422
end = rin + rle;
8423
if (!(end >= 1.0)) { /* Logical NOT to handle NaNs */
8424
j = 1;
8425
} else if (end < INT_MAX) {
8426
j = (int)end;
8427
}
8428
}
8429
8430
if (i < j) {
8431
xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
8432
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
8433
xmlFree(ret);
8434
} else {
8435
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8436
}
8437
8438
xmlXPathReleaseObject(ctxt->context, str);
8439
}
8440
8441
/**
8442
* xmlXPathSubstringBeforeFunction:
8443
* @ctxt: the XPath Parser context
8444
* @nargs: the number of arguments
8445
*
8446
* Implement the substring-before() XPath function
8447
* string substring-before(string, string)
8448
* The substring-before function returns the substring of the first
8449
* argument string that precedes the first occurrence of the second
8450
* argument string in the first argument string, or the empty string
8451
* if the first argument string does not contain the second argument
8452
* string. For example, substring-before("1999/04/01","/") returns 1999.
8453
*/
8454
void
8455
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8456
xmlXPathObjectPtr str;
8457
xmlXPathObjectPtr find;
8458
xmlBufPtr target;
8459
const xmlChar *point;
8460
int offset;
8461
8462
CHECK_ARITY(2);
8463
CAST_TO_STRING;
8464
find = valuePop(ctxt);
8465
CAST_TO_STRING;
8466
str = valuePop(ctxt);
8467
8468
target = xmlBufCreate();
8469
if (target) {
8470
point = xmlStrstr(str->stringval, find->stringval);
8471
if (point) {
8472
offset = point - str->stringval;
8473
xmlBufAdd(target, str->stringval, offset);
8474
}
8475
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8476
xmlBufContent(target)));
8477
xmlBufFree(target);
8478
}
8479
xmlXPathReleaseObject(ctxt->context, str);
8480
xmlXPathReleaseObject(ctxt->context, find);
8481
}
8482
8483
/**
8484
* xmlXPathSubstringAfterFunction:
8485
* @ctxt: the XPath Parser context
8486
* @nargs: the number of arguments
8487
*
8488
* Implement the substring-after() XPath function
8489
* string substring-after(string, string)
8490
* The substring-after function returns the substring of the first
8491
* argument string that follows the first occurrence of the second
8492
* argument string in the first argument string, or the empty stringi
8493
* if the first argument string does not contain the second argument
8494
* string. For example, substring-after("1999/04/01","/") returns 04/01,
8495
* and substring-after("1999/04/01","19") returns 99/04/01.
8496
*/
8497
void
8498
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8499
xmlXPathObjectPtr str;
8500
xmlXPathObjectPtr find;
8501
xmlBufPtr target;
8502
const xmlChar *point;
8503
int offset;
8504
8505
CHECK_ARITY(2);
8506
CAST_TO_STRING;
8507
find = valuePop(ctxt);
8508
CAST_TO_STRING;
8509
str = valuePop(ctxt);
8510
8511
target = xmlBufCreate();
8512
if (target) {
8513
point = xmlStrstr(str->stringval, find->stringval);
8514
if (point) {
8515
offset = point - str->stringval + xmlStrlen(find->stringval);
8516
xmlBufAdd(target, &str->stringval[offset],
8517
xmlStrlen(str->stringval) - offset);
8518
}
8519
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8520
xmlBufContent(target)));
8521
xmlBufFree(target);
8522
}
8523
xmlXPathReleaseObject(ctxt->context, str);
8524
xmlXPathReleaseObject(ctxt->context, find);
8525
}
8526
8527
/**
8528
* xmlXPathNormalizeFunction:
8529
* @ctxt: the XPath Parser context
8530
* @nargs: the number of arguments
8531
*
8532
* Implement the normalize-space() XPath function
8533
* string normalize-space(string?)
8534
* The normalize-space function returns the argument string with white
8535
* space normalized by stripping leading and trailing whitespace
8536
* and replacing sequences of whitespace characters by a single
8537
* space. Whitespace characters are the same allowed by the S production
8538
* in XML. If the argument is omitted, it defaults to the context
8539
* node converted to a string, in other words the value of the context node.
8540
*/
8541
void
8542
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8543
xmlChar *source, *target;
8544
int blank;
8545
8546
if (ctxt == NULL) return;
8547
if (nargs == 0) {
8548
/* Use current context node */
8549
valuePush(ctxt,
8550
xmlXPathCacheWrapString(ctxt->context,
8551
xmlXPathCastNodeToString(ctxt->context->node)));
8552
nargs = 1;
8553
}
8554
8555
CHECK_ARITY(1);
8556
CAST_TO_STRING;
8557
CHECK_TYPE(XPATH_STRING);
8558
source = ctxt->value->stringval;
8559
if (source == NULL)
8560
return;
8561
target = source;
8562
8563
/* Skip leading whitespaces */
8564
while (IS_BLANK_CH(*source))
8565
source++;
8566
8567
/* Collapse intermediate whitespaces, and skip trailing whitespaces */
8568
blank = 0;
8569
while (*source) {
8570
if (IS_BLANK_CH(*source)) {
8571
blank = 1;
8572
} else {
8573
if (blank) {
8574
*target++ = 0x20;
8575
blank = 0;
8576
}
8577
*target++ = *source;
8578
}
8579
source++;
8580
}
8581
*target = 0;
8582
}
8583
8584
/**
8585
* xmlXPathTranslateFunction:
8586
* @ctxt: the XPath Parser context
8587
* @nargs: the number of arguments
8588
*
8589
* Implement the translate() XPath function
8590
* string translate(string, string, string)
8591
* The translate function returns the first argument string with
8592
* occurrences of characters in the second argument string replaced
8593
* by the character at the corresponding position in the third argument
8594
* string. For example, translate("bar","abc","ABC") returns the string
8595
* BAr. If there is a character in the second argument string with no
8596
* character at a corresponding position in the third argument string
8597
* (because the second argument string is longer than the third argument
8598
* string), then occurrences of that character in the first argument
8599
* string are removed. For example, translate("--aaa--","abc-","ABC")
8600
* returns "AAA". If a character occurs more than once in second
8601
* argument string, then the first occurrence determines the replacement
8602
* character. If the third argument string is longer than the second
8603
* argument string, then excess characters are ignored.
8604
*/
8605
void
8606
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8607
xmlXPathObjectPtr str;
8608
xmlXPathObjectPtr from;
8609
xmlXPathObjectPtr to;
8610
xmlBufPtr target;
8611
int offset, max;
8612
int ch;
8613
const xmlChar *point;
8614
xmlChar *cptr;
8615
8616
CHECK_ARITY(3);
8617
8618
CAST_TO_STRING;
8619
to = valuePop(ctxt);
8620
CAST_TO_STRING;
8621
from = valuePop(ctxt);
8622
CAST_TO_STRING;
8623
str = valuePop(ctxt);
8624
8625
target = xmlBufCreate();
8626
if (target) {
8627
max = xmlUTF8Strlen(to->stringval);
8628
for (cptr = str->stringval; (ch=*cptr); ) {
8629
offset = xmlUTF8Strloc(from->stringval, cptr);
8630
if (offset >= 0) {
8631
if (offset < max) {
8632
point = xmlUTF8Strpos(to->stringval, offset);
8633
if (point)
8634
xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
8635
}
8636
} else
8637
xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
8638
8639
/* Step to next character in input */
8640
cptr++;
8641
if ( ch & 0x80 ) {
8642
/* if not simple ascii, verify proper format */
8643
if ( (ch & 0xc0) != 0xc0 ) {
8644
xmlGenericError(xmlGenericErrorContext,
8645
"xmlXPathTranslateFunction: Invalid UTF8 string\n");
8646
/* not asserting an XPath error is probably better */
8647
break;
8648
}
8649
/* then skip over remaining bytes for this char */
8650
while ( (ch <<= 1) & 0x80 )
8651
if ( (*cptr++ & 0xc0) != 0x80 ) {
8652
xmlGenericError(xmlGenericErrorContext,
8653
"xmlXPathTranslateFunction: Invalid UTF8 string\n");
8654
/* not asserting an XPath error is probably better */
8655
break;
8656
}
8657
if (ch & 0x80) /* must have had error encountered */
8658
break;
8659
}
8660
}
8661
}
8662
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8663
xmlBufContent(target)));
8664
xmlBufFree(target);
8665
xmlXPathReleaseObject(ctxt->context, str);
8666
xmlXPathReleaseObject(ctxt->context, from);
8667
xmlXPathReleaseObject(ctxt->context, to);
8668
}
8669
8670
/**
8671
* xmlXPathBooleanFunction:
8672
* @ctxt: the XPath Parser context
8673
* @nargs: the number of arguments
8674
*
8675
* Implement the boolean() XPath function
8676
* boolean boolean(object)
8677
* The boolean function converts its argument to a boolean as follows:
8678
* - a number is true if and only if it is neither positive or
8679
* negative zero nor NaN
8680
* - a node-set is true if and only if it is non-empty
8681
* - a string is true if and only if its length is non-zero
8682
*/
8683
void
8684
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8685
xmlXPathObjectPtr cur;
8686
8687
CHECK_ARITY(1);
8688
cur = valuePop(ctxt);
8689
if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8690
cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
8691
valuePush(ctxt, cur);
8692
}
8693
8694
/**
8695
* xmlXPathNotFunction:
8696
* @ctxt: the XPath Parser context
8697
* @nargs: the number of arguments
8698
*
8699
* Implement the not() XPath function
8700
* boolean not(boolean)
8701
* The not function returns true if its argument is false,
8702
* and false otherwise.
8703
*/
8704
void
8705
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8706
CHECK_ARITY(1);
8707
CAST_TO_BOOLEAN;
8708
CHECK_TYPE(XPATH_BOOLEAN);
8709
ctxt->value->boolval = ! ctxt->value->boolval;
8710
}
8711
8712
/**
8713
* xmlXPathTrueFunction:
8714
* @ctxt: the XPath Parser context
8715
* @nargs: the number of arguments
8716
*
8717
* Implement the true() XPath function
8718
* boolean true()
8719
*/
8720
void
8721
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8722
CHECK_ARITY(0);
8723
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
8724
}
8725
8726
/**
8727
* xmlXPathFalseFunction:
8728
* @ctxt: the XPath Parser context
8729
* @nargs: the number of arguments
8730
*
8731
* Implement the false() XPath function
8732
* boolean false()
8733
*/
8734
void
8735
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8736
CHECK_ARITY(0);
8737
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
8738
}
8739
8740
/**
8741
* xmlXPathLangFunction:
8742
* @ctxt: the XPath Parser context
8743
* @nargs: the number of arguments
8744
*
8745
* Implement the lang() XPath function
8746
* boolean lang(string)
8747
* The lang function returns true or false depending on whether the
8748
* language of the context node as specified by xml:lang attributes
8749
* is the same as or is a sublanguage of the language specified by
8750
* the argument string. The language of the context node is determined
8751
* by the value of the xml:lang attribute on the context node, or, if
8752
* the context node has no xml:lang attribute, by the value of the
8753
* xml:lang attribute on the nearest ancestor of the context node that
8754
* has an xml:lang attribute. If there is no such attribute, then lang
8755
* returns false. If there is such an attribute, then lang returns
8756
* true if the attribute value is equal to the argument ignoring case,
8757
* or if there is some suffix starting with - such that the attribute
8758
* value is equal to the argument ignoring that suffix of the attribute
8759
* value and ignoring case.
8760
*/
8761
void
8762
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8763
xmlXPathObjectPtr val = NULL;
8764
const xmlChar *theLang = NULL;
8765
const xmlChar *lang;
8766
int ret = 0;
8767
int i;
8768
8769
CHECK_ARITY(1);
8770
CAST_TO_STRING;
8771
CHECK_TYPE(XPATH_STRING);
8772
val = valuePop(ctxt);
8773
lang = val->stringval;
8774
theLang = xmlNodeGetLang(ctxt->context->node);
8775
if ((theLang != NULL) && (lang != NULL)) {
8776
for (i = 0;lang[i] != 0;i++)
8777
if (toupper(lang[i]) != toupper(theLang[i]))
8778
goto not_equal;
8779
if ((theLang[i] == 0) || (theLang[i] == '-'))
8780
ret = 1;
8781
}
8782
not_equal:
8783
if (theLang != NULL)
8784
xmlFree((void *)theLang);
8785
8786
xmlXPathReleaseObject(ctxt->context, val);
8787
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
8788
}
8789
8790
/**
8791
* xmlXPathNumberFunction:
8792
* @ctxt: the XPath Parser context
8793
* @nargs: the number of arguments
8794
*
8795
* Implement the number() XPath function
8796
* number number(object?)
8797
*/
8798
void
8799
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8800
xmlXPathObjectPtr cur;
8801
double res;
8802
8803
if (ctxt == NULL) return;
8804
if (nargs == 0) {
8805
if (ctxt->context->node == NULL) {
8806
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
8807
} else {
8808
xmlChar* content = xmlNodeGetContent(ctxt->context->node);
8809
8810
res = xmlXPathStringEvalNumber(content);
8811
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
8812
xmlFree(content);
8813
}
8814
return;
8815
}
8816
8817
CHECK_ARITY(1);
8818
cur = valuePop(ctxt);
8819
valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
8820
}
8821
8822
/**
8823
* xmlXPathSumFunction:
8824
* @ctxt: the XPath Parser context
8825
* @nargs: the number of arguments
8826
*
8827
* Implement the sum() XPath function
8828
* number sum(node-set)
8829
* The sum function returns the sum of the values of the nodes in
8830
* the argument node-set.
8831
*/
8832
void
8833
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8834
xmlXPathObjectPtr cur;
8835
int i;
8836
double res = 0.0;
8837
8838
CHECK_ARITY(1);
8839
if ((ctxt->value == NULL) ||
8840
((ctxt->value->type != XPATH_NODESET) &&
8841
(ctxt->value->type != XPATH_XSLT_TREE)))
8842
XP_ERROR(XPATH_INVALID_TYPE);
8843
cur = valuePop(ctxt);
8844
8845
if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
8846
for (i = 0; i < cur->nodesetval->nodeNr; i++) {
8847
res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
8848
}
8849
}
8850
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
8851
xmlXPathReleaseObject(ctxt->context, cur);
8852
}
8853
8854
/**
8855
* xmlXPathFloorFunction:
8856
* @ctxt: the XPath Parser context
8857
* @nargs: the number of arguments
8858
*
8859
* Implement the floor() XPath function
8860
* number floor(number)
8861
* The floor function returns the largest (closest to positive infinity)
8862
* number that is not greater than the argument and that is an integer.
8863
*/
8864
void
8865
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8866
CHECK_ARITY(1);
8867
CAST_TO_NUMBER;
8868
CHECK_TYPE(XPATH_NUMBER);
8869
8870
ctxt->value->floatval = floor(ctxt->value->floatval);
8871
}
8872
8873
/**
8874
* xmlXPathCeilingFunction:
8875
* @ctxt: the XPath Parser context
8876
* @nargs: the number of arguments
8877
*
8878
* Implement the ceiling() XPath function
8879
* number ceiling(number)
8880
* The ceiling function returns the smallest (closest to negative infinity)
8881
* number that is not less than the argument and that is an integer.
8882
*/
8883
void
8884
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8885
CHECK_ARITY(1);
8886
CAST_TO_NUMBER;
8887
CHECK_TYPE(XPATH_NUMBER);
8888
8889
#ifdef _AIX
8890
/* Work around buggy ceil() function on AIX */
8891
ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
8892
#else
8893
ctxt->value->floatval = ceil(ctxt->value->floatval);
8894
#endif
8895
}
8896
8897
/**
8898
* xmlXPathRoundFunction:
8899
* @ctxt: the XPath Parser context
8900
* @nargs: the number of arguments
8901
*
8902
* Implement the round() XPath function
8903
* number round(number)
8904
* The round function returns the number that is closest to the
8905
* argument and that is an integer. If there are two such numbers,
8906
* then the one that is closest to positive infinity is returned.
8907
*/
8908
void
8909
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8910
double f;
8911
8912
CHECK_ARITY(1);
8913
CAST_TO_NUMBER;
8914
CHECK_TYPE(XPATH_NUMBER);
8915
8916
f = ctxt->value->floatval;
8917
8918
if ((f >= -0.5) && (f < 0.5)) {
8919
/* Handles negative zero. */
8920
ctxt->value->floatval *= 0.0;
8921
}
8922
else {
8923
double rounded = floor(f);
8924
if (f - rounded >= 0.5)
8925
rounded += 1.0;
8926
ctxt->value->floatval = rounded;
8927
}
8928
}
8929
8930
/************************************************************************
8931
* *
8932
* The Parser *
8933
* *
8934
************************************************************************/
8935
8936
/*
8937
* a few forward declarations since we use a recursive call based
8938
* implementation.
8939
*/
8940
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
8941
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
8942
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
8943
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
8944
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
8945
int qualified);
8946
8947
/**
8948
* xmlXPathCurrentChar:
8949
* @ctxt: the XPath parser context
8950
* @cur: pointer to the beginning of the char
8951
* @len: pointer to the length of the char read
8952
*
8953
* The current char value, if using UTF-8 this may actually span multiple
8954
* bytes in the input buffer.
8955
*
8956
* Returns the current char value and its length
8957
*/
8958
8959
static int
8960
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
8961
unsigned char c;
8962
unsigned int val;
8963
const xmlChar *cur;
8964
8965
if (ctxt == NULL)
8966
return(0);
8967
cur = ctxt->cur;
8968
8969
/*
8970
* We are supposed to handle UTF8, check it's valid
8971
* From rfc2044: encoding of the Unicode values on UTF-8:
8972
*
8973
* UCS-4 range (hex.) UTF-8 octet sequence (binary)
8974
* 0000 0000-0000 007F 0xxxxxxx
8975
* 0000 0080-0000 07FF 110xxxxx 10xxxxxx
8976
* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
8977
*
8978
* Check for the 0x110000 limit too
8979
*/
8980
c = *cur;
8981
if (c & 0x80) {
8982
if ((cur[1] & 0xc0) != 0x80)
8983
goto encoding_error;
8984
if ((c & 0xe0) == 0xe0) {
8985
8986
if ((cur[2] & 0xc0) != 0x80)
8987
goto encoding_error;
8988
if ((c & 0xf0) == 0xf0) {
8989
if (((c & 0xf8) != 0xf0) ||
8990
((cur[3] & 0xc0) != 0x80))
8991
goto encoding_error;
8992
/* 4-byte code */
8993
*len = 4;
8994
val = (cur[0] & 0x7) << 18;
8995
val |= (cur[1] & 0x3f) << 12;
8996
val |= (cur[2] & 0x3f) << 6;
8997
val |= cur[3] & 0x3f;
8998
} else {
8999
/* 3-byte code */
9000
*len = 3;
9001
val = (cur[0] & 0xf) << 12;
9002
val |= (cur[1] & 0x3f) << 6;
9003
val |= cur[2] & 0x3f;
9004
}
9005
} else {
9006
/* 2-byte code */
9007
*len = 2;
9008
val = (cur[0] & 0x1f) << 6;
9009
val |= cur[1] & 0x3f;
9010
}
9011
if (!IS_CHAR(val)) {
9012
XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9013
}
9014
return(val);
9015
} else {
9016
/* 1-byte code */
9017
*len = 1;
9018
return(*cur);
9019
}
9020
encoding_error:
9021
/*
9022
* If we detect an UTF8 error that probably means that the
9023
* input encoding didn't get properly advertised in the
9024
* declaration header. Report the error and switch the encoding
9025
* to ISO-Latin-1 (if you don't like this policy, just declare the
9026
* encoding !)
9027
*/
9028
*len = 0;
9029
XP_ERROR0(XPATH_ENCODING_ERROR);
9030
}
9031
9032
/**
9033
* xmlXPathParseNCName:
9034
* @ctxt: the XPath Parser context
9035
*
9036
* parse an XML namespace non qualified name.
9037
*
9038
* [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9039
*
9040
* [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9041
* CombiningChar | Extender
9042
*
9043
* Returns the namespace name or NULL
9044
*/
9045
9046
xmlChar *
9047
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9048
const xmlChar *in;
9049
xmlChar *ret;
9050
int count = 0;
9051
9052
if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9053
/*
9054
* Accelerator for simple ASCII names
9055
*/
9056
in = ctxt->cur;
9057
if (((*in >= 0x61) && (*in <= 0x7A)) ||
9058
((*in >= 0x41) && (*in <= 0x5A)) ||
9059
(*in == '_')) {
9060
in++;
9061
while (((*in >= 0x61) && (*in <= 0x7A)) ||
9062
((*in >= 0x41) && (*in <= 0x5A)) ||
9063
((*in >= 0x30) && (*in <= 0x39)) ||
9064
(*in == '_') || (*in == '.') ||
9065
(*in == '-'))
9066
in++;
9067
if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9068
(*in == '[') || (*in == ']') || (*in == ':') ||
9069
(*in == '@') || (*in == '*')) {
9070
count = in - ctxt->cur;
9071
if (count == 0)
9072
return(NULL);
9073
ret = xmlStrndup(ctxt->cur, count);
9074
ctxt->cur = in;
9075
return(ret);
9076
}
9077
}
9078
return(xmlXPathParseNameComplex(ctxt, 0));
9079
}
9080
9081
9082
/**
9083
* xmlXPathParseQName:
9084
* @ctxt: the XPath Parser context
9085
* @prefix: a xmlChar **
9086
*
9087
* parse an XML qualified name
9088
*
9089
* [NS 5] QName ::= (Prefix ':')? LocalPart
9090
*
9091
* [NS 6] Prefix ::= NCName
9092
*
9093
* [NS 7] LocalPart ::= NCName
9094
*
9095
* Returns the function returns the local part, and prefix is updated
9096
* to get the Prefix if any.
9097
*/
9098
9099
static xmlChar *
9100
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9101
xmlChar *ret = NULL;
9102
9103
*prefix = NULL;
9104
ret = xmlXPathParseNCName(ctxt);
9105
if (ret && CUR == ':') {
9106
*prefix = ret;
9107
NEXT;
9108
ret = xmlXPathParseNCName(ctxt);
9109
}
9110
return(ret);
9111
}
9112
9113
/**
9114
* xmlXPathParseName:
9115
* @ctxt: the XPath Parser context
9116
*
9117
* parse an XML name
9118
*
9119
* [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9120
* CombiningChar | Extender
9121
*
9122
* [5] Name ::= (Letter | '_' | ':') (NameChar)*
9123
*
9124
* Returns the namespace name or NULL
9125
*/
9126
9127
xmlChar *
9128
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9129
const xmlChar *in;
9130
xmlChar *ret;
9131
size_t count = 0;
9132
9133
if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9134
/*
9135
* Accelerator for simple ASCII names
9136
*/
9137
in = ctxt->cur;
9138
if (((*in >= 0x61) && (*in <= 0x7A)) ||
9139
((*in >= 0x41) && (*in <= 0x5A)) ||
9140
(*in == '_') || (*in == ':')) {
9141
in++;
9142
while (((*in >= 0x61) && (*in <= 0x7A)) ||
9143
((*in >= 0x41) && (*in <= 0x5A)) ||
9144
((*in >= 0x30) && (*in <= 0x39)) ||
9145
(*in == '_') || (*in == '-') ||
9146
(*in == ':') || (*in == '.'))
9147
in++;
9148
if ((*in > 0) && (*in < 0x80)) {
9149
count = in - ctxt->cur;
9150
if (count > XML_MAX_NAME_LENGTH) {
9151
ctxt->cur = in;
9152
XP_ERRORNULL(XPATH_EXPR_ERROR);
9153
}
9154
ret = xmlStrndup(ctxt->cur, count);
9155
ctxt->cur = in;
9156
return(ret);
9157
}
9158
}
9159
return(xmlXPathParseNameComplex(ctxt, 1));
9160
}
9161
9162
static xmlChar *
9163
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
9164
xmlChar buf[XML_MAX_NAMELEN + 5];
9165
int len = 0, l;
9166
int c;
9167
9168
/*
9169
* Handler for more complex cases
9170
*/
9171
c = CUR_CHAR(l);
9172
if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9173
(c == '[') || (c == ']') || (c == '@') || /* accelerators */
9174
(c == '*') || /* accelerators */
9175
(!IS_LETTER(c) && (c != '_') &&
9176
((!qualified) || (c != ':')))) {
9177
return(NULL);
9178
}
9179
9180
while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9181
((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9182
(c == '.') || (c == '-') ||
9183
(c == '_') || ((qualified) && (c == ':')) ||
9184
(IS_COMBINING(c)) ||
9185
(IS_EXTENDER(c)))) {
9186
COPY_BUF(l,buf,len,c);
9187
NEXTL(l);
9188
c = CUR_CHAR(l);
9189
if (len >= XML_MAX_NAMELEN) {
9190
/*
9191
* Okay someone managed to make a huge name, so he's ready to pay
9192
* for the processing speed.
9193
*/
9194
xmlChar *buffer;
9195
int max = len * 2;
9196
9197
if (len > XML_MAX_NAME_LENGTH) {
9198
XP_ERRORNULL(XPATH_EXPR_ERROR);
9199
}
9200
buffer = (xmlChar *) xmlMallocAtomic(max);
9201
if (buffer == NULL) {
9202
XP_ERRORNULL(XPATH_MEMORY_ERROR);
9203
}
9204
memcpy(buffer, buf, len);
9205
while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
9206
(c == '.') || (c == '-') ||
9207
(c == '_') || ((qualified) && (c == ':')) ||
9208
(IS_COMBINING(c)) ||
9209
(IS_EXTENDER(c))) {
9210
if (len + 10 > max) {
9211
xmlChar *tmp;
9212
if (max > XML_MAX_NAME_LENGTH) {
9213
xmlFree(buffer);
9214
XP_ERRORNULL(XPATH_EXPR_ERROR);
9215
}
9216
max *= 2;
9217
tmp = (xmlChar *) xmlRealloc(buffer, max);
9218
if (tmp == NULL) {
9219
xmlFree(buffer);
9220
XP_ERRORNULL(XPATH_MEMORY_ERROR);
9221
}
9222
buffer = tmp;
9223
}
9224
COPY_BUF(l,buffer,len,c);
9225
NEXTL(l);
9226
c = CUR_CHAR(l);
9227
}
9228
buffer[len] = 0;
9229
return(buffer);
9230
}
9231
}
9232
if (len == 0)
9233
return(NULL);
9234
return(xmlStrndup(buf, len));
9235
}
9236
9237
#define MAX_FRAC 20
9238
9239
/**
9240
* xmlXPathStringEvalNumber:
9241
* @str: A string to scan
9242
*
9243
* [30a] Float ::= Number ('e' Digits?)?
9244
*
9245
* [30] Number ::= Digits ('.' Digits?)?
9246
* | '.' Digits
9247
* [31] Digits ::= [0-9]+
9248
*
9249
* Compile a Number in the string
9250
* In complement of the Number expression, this function also handles
9251
* negative values : '-' Number.
9252
*
9253
* Returns the double value.
9254
*/
9255
double
9256
xmlXPathStringEvalNumber(const xmlChar *str) {
9257
const xmlChar *cur = str;
9258
double ret;
9259
int ok = 0;
9260
int isneg = 0;
9261
int exponent = 0;
9262
int is_exponent_negative = 0;
9263
#ifdef __GNUC__
9264
unsigned long tmp = 0;
9265
double temp;
9266
#endif
9267
if (cur == NULL) return(0);
9268
while (IS_BLANK_CH(*cur)) cur++;
9269
if (*cur == '-') {
9270
isneg = 1;
9271
cur++;
9272
}
9273
if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
9274
return(xmlXPathNAN);
9275
}
9276
9277
#ifdef __GNUC__
9278
/*
9279
* tmp/temp is a workaround against a gcc compiler bug
9280
* http://veillard.com/gcc.bug
9281
*/
9282
ret = 0;
9283
while ((*cur >= '0') && (*cur <= '9')) {
9284
ret = ret * 10;
9285
tmp = (*cur - '0');
9286
ok = 1;
9287
cur++;
9288
temp = (double) tmp;
9289
ret = ret + temp;
9290
}
9291
#else
9292
ret = 0;
9293
while ((*cur >= '0') && (*cur <= '9')) {
9294
ret = ret * 10 + (*cur - '0');
9295
ok = 1;
9296
cur++;
9297
}
9298
#endif
9299
9300
if (*cur == '.') {
9301
int v, frac = 0, max;
9302
double fraction = 0;
9303
9304
cur++;
9305
if (((*cur < '0') || (*cur > '9')) && (!ok)) {
9306
return(xmlXPathNAN);
9307
}
9308
while (*cur == '0') {
9309
frac = frac + 1;
9310
cur++;
9311
}
9312
max = frac + MAX_FRAC;
9313
while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
9314
v = (*cur - '0');
9315
fraction = fraction * 10 + v;
9316
frac = frac + 1;
9317
cur++;
9318
}
9319
fraction /= pow(10.0, frac);
9320
ret = ret + fraction;
9321
while ((*cur >= '0') && (*cur <= '9'))
9322
cur++;
9323
}
9324
if ((*cur == 'e') || (*cur == 'E')) {
9325
cur++;
9326
if (*cur == '-') {
9327
is_exponent_negative = 1;
9328
cur++;
9329
} else if (*cur == '+') {
9330
cur++;
9331
}
9332
while ((*cur >= '0') && (*cur <= '9')) {
9333
if (exponent < 1000000)
9334
exponent = exponent * 10 + (*cur - '0');
9335
cur++;
9336
}
9337
}
9338
while (IS_BLANK_CH(*cur)) cur++;
9339
if (*cur != 0) return(xmlXPathNAN);
9340
if (isneg) ret = -ret;
9341
if (is_exponent_negative) exponent = -exponent;
9342
ret *= pow(10.0, (double)exponent);
9343
return(ret);
9344
}
9345
9346
/**
9347
* xmlXPathCompNumber:
9348
* @ctxt: the XPath Parser context
9349
*
9350
* [30] Number ::= Digits ('.' Digits?)?
9351
* | '.' Digits
9352
* [31] Digits ::= [0-9]+
9353
*
9354
* Compile a Number, then push it on the stack
9355
*
9356
*/
9357
static void
9358
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
9359
{
9360
double ret = 0.0;
9361
int ok = 0;
9362
int exponent = 0;
9363
int is_exponent_negative = 0;
9364
xmlXPathObjectPtr num;
9365
#ifdef __GNUC__
9366
unsigned long tmp = 0;
9367
double temp;
9368
#endif
9369
9370
CHECK_ERROR;
9371
if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
9372
XP_ERROR(XPATH_NUMBER_ERROR);
9373
}
9374
#ifdef __GNUC__
9375
/*
9376
* tmp/temp is a workaround against a gcc compiler bug
9377
* http://veillard.com/gcc.bug
9378
*/
9379
ret = 0;
9380
while ((CUR >= '0') && (CUR <= '9')) {
9381
ret = ret * 10;
9382
tmp = (CUR - '0');
9383
ok = 1;
9384
NEXT;
9385
temp = (double) tmp;
9386
ret = ret + temp;
9387
}
9388
#else
9389
ret = 0;
9390
while ((CUR >= '0') && (CUR <= '9')) {
9391
ret = ret * 10 + (CUR - '0');
9392
ok = 1;
9393
NEXT;
9394
}
9395
#endif
9396
if (CUR == '.') {
9397
int v, frac = 0, max;
9398
double fraction = 0;
9399
9400
NEXT;
9401
if (((CUR < '0') || (CUR > '9')) && (!ok)) {
9402
XP_ERROR(XPATH_NUMBER_ERROR);
9403
}
9404
while (CUR == '0') {
9405
frac = frac + 1;
9406
NEXT;
9407
}
9408
max = frac + MAX_FRAC;
9409
while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
9410
v = (CUR - '0');
9411
fraction = fraction * 10 + v;
9412
frac = frac + 1;
9413
NEXT;
9414
}
9415
fraction /= pow(10.0, frac);
9416
ret = ret + fraction;
9417
while ((CUR >= '0') && (CUR <= '9'))
9418
NEXT;
9419
}
9420
if ((CUR == 'e') || (CUR == 'E')) {
9421
NEXT;
9422
if (CUR == '-') {
9423
is_exponent_negative = 1;
9424
NEXT;
9425
} else if (CUR == '+') {
9426
NEXT;
9427
}
9428
while ((CUR >= '0') && (CUR <= '9')) {
9429
if (exponent < 1000000)
9430
exponent = exponent * 10 + (CUR - '0');
9431
NEXT;
9432
}
9433
if (is_exponent_negative)
9434
exponent = -exponent;
9435
ret *= pow(10.0, (double) exponent);
9436
}
9437
num = xmlXPathCacheNewFloat(ctxt->context, ret);
9438
if (num == NULL) {
9439
ctxt->error = XPATH_MEMORY_ERROR;
9440
} else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
9441
NULL) == -1) {
9442
xmlXPathReleaseObject(ctxt->context, num);
9443
}
9444
}
9445
9446
/**
9447
* xmlXPathParseLiteral:
9448
* @ctxt: the XPath Parser context
9449
*
9450
* Parse a Literal
9451
*
9452
* [29] Literal ::= '"' [^"]* '"'
9453
* | "'" [^']* "'"
9454
*
9455
* Returns the value found or NULL in case of error
9456
*/
9457
static xmlChar *
9458
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
9459
const xmlChar *q;
9460
xmlChar *ret = NULL;
9461
9462
if (CUR == '"') {
9463
NEXT;
9464
q = CUR_PTR;
9465
while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9466
NEXT;
9467
if (!IS_CHAR_CH(CUR)) {
9468
XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9469
} else {
9470
ret = xmlStrndup(q, CUR_PTR - q);
9471
NEXT;
9472
}
9473
} else if (CUR == '\'') {
9474
NEXT;
9475
q = CUR_PTR;
9476
while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9477
NEXT;
9478
if (!IS_CHAR_CH(CUR)) {
9479
XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
9480
} else {
9481
ret = xmlStrndup(q, CUR_PTR - q);
9482
NEXT;
9483
}
9484
} else {
9485
XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
9486
}
9487
return(ret);
9488
}
9489
9490
/**
9491
* xmlXPathCompLiteral:
9492
* @ctxt: the XPath Parser context
9493
*
9494
* Parse a Literal and push it on the stack.
9495
*
9496
* [29] Literal ::= '"' [^"]* '"'
9497
* | "'" [^']* "'"
9498
*
9499
* TODO: xmlXPathCompLiteral memory allocation could be improved.
9500
*/
9501
static void
9502
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
9503
const xmlChar *q;
9504
xmlChar *ret = NULL;
9505
xmlXPathObjectPtr lit;
9506
9507
if (CUR == '"') {
9508
NEXT;
9509
q = CUR_PTR;
9510
while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
9511
NEXT;
9512
if (!IS_CHAR_CH(CUR)) {
9513
XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9514
} else {
9515
ret = xmlStrndup(q, CUR_PTR - q);
9516
NEXT;
9517
}
9518
} else if (CUR == '\'') {
9519
NEXT;
9520
q = CUR_PTR;
9521
while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
9522
NEXT;
9523
if (!IS_CHAR_CH(CUR)) {
9524
XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
9525
} else {
9526
ret = xmlStrndup(q, CUR_PTR - q);
9527
NEXT;
9528
}
9529
} else {
9530
XP_ERROR(XPATH_START_LITERAL_ERROR);
9531
}
9532
if (ret == NULL) {
9533
xmlXPathPErrMemory(ctxt, NULL);
9534
return;
9535
}
9536
lit = xmlXPathCacheNewString(ctxt->context, ret);
9537
if (lit == NULL) {
9538
ctxt->error = XPATH_MEMORY_ERROR;
9539
} else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
9540
NULL) == -1) {
9541
xmlXPathReleaseObject(ctxt->context, lit);
9542
}
9543
xmlFree(ret);
9544
}
9545
9546
/**
9547
* xmlXPathCompVariableReference:
9548
* @ctxt: the XPath Parser context
9549
*
9550
* Parse a VariableReference, evaluate it and push it on the stack.
9551
*
9552
* The variable bindings consist of a mapping from variable names
9553
* to variable values. The value of a variable is an object, which can be
9554
* of any of the types that are possible for the value of an expression,
9555
* and may also be of additional types not specified here.
9556
*
9557
* Early evaluation is possible since:
9558
* The variable bindings [...] used to evaluate a subexpression are
9559
* always the same as those used to evaluate the containing expression.
9560
*
9561
* [36] VariableReference ::= '$' QName
9562
*/
9563
static void
9564
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
9565
xmlChar *name;
9566
xmlChar *prefix;
9567
9568
SKIP_BLANKS;
9569
if (CUR != '$') {
9570
XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9571
}
9572
NEXT;
9573
name = xmlXPathParseQName(ctxt, &prefix);
9574
if (name == NULL) {
9575
xmlFree(prefix);
9576
XP_ERROR(XPATH_VARIABLE_REF_ERROR);
9577
}
9578
ctxt->comp->last = -1;
9579
if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
9580
xmlFree(prefix);
9581
xmlFree(name);
9582
}
9583
SKIP_BLANKS;
9584
if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
9585
XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
9586
}
9587
}
9588
9589
/**
9590
* xmlXPathIsNodeType:
9591
* @name: a name string
9592
*
9593
* Is the name given a NodeType one.
9594
*
9595
* [38] NodeType ::= 'comment'
9596
* | 'text'
9597
* | 'processing-instruction'
9598
* | 'node'
9599
*
9600
* Returns 1 if true 0 otherwise
9601
*/
9602
int
9603
xmlXPathIsNodeType(const xmlChar *name) {
9604
if (name == NULL)
9605
return(0);
9606
9607
if (xmlStrEqual(name, BAD_CAST "node"))
9608
return(1);
9609
if (xmlStrEqual(name, BAD_CAST "text"))
9610
return(1);
9611
if (xmlStrEqual(name, BAD_CAST "comment"))
9612
return(1);
9613
if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
9614
return(1);
9615
return(0);
9616
}
9617
9618
/**
9619
* xmlXPathCompFunctionCall:
9620
* @ctxt: the XPath Parser context
9621
*
9622
* [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
9623
* [17] Argument ::= Expr
9624
*
9625
* Compile a function call, the evaluation of all arguments are
9626
* pushed on the stack
9627
*/
9628
static void
9629
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
9630
xmlChar *name;
9631
xmlChar *prefix;
9632
int nbargs = 0;
9633
int sort = 1;
9634
9635
name = xmlXPathParseQName(ctxt, &prefix);
9636
if (name == NULL) {
9637
xmlFree(prefix);
9638
XP_ERROR(XPATH_EXPR_ERROR);
9639
}
9640
SKIP_BLANKS;
9641
9642
if (CUR != '(') {
9643
xmlFree(name);
9644
xmlFree(prefix);
9645
XP_ERROR(XPATH_EXPR_ERROR);
9646
}
9647
NEXT;
9648
SKIP_BLANKS;
9649
9650
/*
9651
* Optimization for count(): we don't need the node-set to be sorted.
9652
*/
9653
if ((prefix == NULL) && (name[0] == 'c') &&
9654
xmlStrEqual(name, BAD_CAST "count"))
9655
{
9656
sort = 0;
9657
}
9658
ctxt->comp->last = -1;
9659
if (CUR != ')') {
9660
while (CUR != 0) {
9661
int op1 = ctxt->comp->last;
9662
ctxt->comp->last = -1;
9663
xmlXPathCompileExpr(ctxt, sort);
9664
if (ctxt->error != XPATH_EXPRESSION_OK) {
9665
xmlFree(name);
9666
xmlFree(prefix);
9667
return;
9668
}
9669
PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
9670
nbargs++;
9671
if (CUR == ')') break;
9672
if (CUR != ',') {
9673
xmlFree(name);
9674
xmlFree(prefix);
9675
XP_ERROR(XPATH_EXPR_ERROR);
9676
}
9677
NEXT;
9678
SKIP_BLANKS;
9679
}
9680
}
9681
if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
9682
xmlFree(prefix);
9683
xmlFree(name);
9684
}
9685
NEXT;
9686
SKIP_BLANKS;
9687
}
9688
9689
/**
9690
* xmlXPathCompPrimaryExpr:
9691
* @ctxt: the XPath Parser context
9692
*
9693
* [15] PrimaryExpr ::= VariableReference
9694
* | '(' Expr ')'
9695
* | Literal
9696
* | Number
9697
* | FunctionCall
9698
*
9699
* Compile a primary expression.
9700
*/
9701
static void
9702
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
9703
SKIP_BLANKS;
9704
if (CUR == '$') xmlXPathCompVariableReference(ctxt);
9705
else if (CUR == '(') {
9706
NEXT;
9707
SKIP_BLANKS;
9708
xmlXPathCompileExpr(ctxt, 1);
9709
CHECK_ERROR;
9710
if (CUR != ')') {
9711
XP_ERROR(XPATH_EXPR_ERROR);
9712
}
9713
NEXT;
9714
SKIP_BLANKS;
9715
} else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9716
xmlXPathCompNumber(ctxt);
9717
} else if ((CUR == '\'') || (CUR == '"')) {
9718
xmlXPathCompLiteral(ctxt);
9719
} else {
9720
xmlXPathCompFunctionCall(ctxt);
9721
}
9722
SKIP_BLANKS;
9723
}
9724
9725
/**
9726
* xmlXPathCompFilterExpr:
9727
* @ctxt: the XPath Parser context
9728
*
9729
* [20] FilterExpr ::= PrimaryExpr
9730
* | FilterExpr Predicate
9731
*
9732
* Compile a filter expression.
9733
* Square brackets are used to filter expressions in the same way that
9734
* they are used in location paths. It is an error if the expression to
9735
* be filtered does not evaluate to a node-set. The context node list
9736
* used for evaluating the expression in square brackets is the node-set
9737
* to be filtered listed in document order.
9738
*/
9739
9740
static void
9741
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
9742
xmlXPathCompPrimaryExpr(ctxt);
9743
CHECK_ERROR;
9744
SKIP_BLANKS;
9745
9746
while (CUR == '[') {
9747
xmlXPathCompPredicate(ctxt, 1);
9748
SKIP_BLANKS;
9749
}
9750
9751
9752
}
9753
9754
/**
9755
* xmlXPathScanName:
9756
* @ctxt: the XPath Parser context
9757
*
9758
* Trickery: parse an XML name but without consuming the input flow
9759
* Needed to avoid insanity in the parser state.
9760
*
9761
* [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9762
* CombiningChar | Extender
9763
*
9764
* [5] Name ::= (Letter | '_' | ':') (NameChar)*
9765
*
9766
* [6] Names ::= Name (S Name)*
9767
*
9768
* Returns the Name parsed or NULL
9769
*/
9770
9771
static xmlChar *
9772
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
9773
int l;
9774
int c;
9775
const xmlChar *cur;
9776
xmlChar *ret;
9777
9778
cur = ctxt->cur;
9779
9780
c = CUR_CHAR(l);
9781
if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
9782
(!IS_LETTER(c) && (c != '_') &&
9783
(c != ':'))) {
9784
return(NULL);
9785
}
9786
9787
while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
9788
((IS_LETTER(c)) || (IS_DIGIT(c)) ||
9789
(c == '.') || (c == '-') ||
9790
(c == '_') || (c == ':') ||
9791
(IS_COMBINING(c)) ||
9792
(IS_EXTENDER(c)))) {
9793
NEXTL(l);
9794
c = CUR_CHAR(l);
9795
}
9796
ret = xmlStrndup(cur, ctxt->cur - cur);
9797
ctxt->cur = cur;
9798
return(ret);
9799
}
9800
9801
/**
9802
* xmlXPathCompPathExpr:
9803
* @ctxt: the XPath Parser context
9804
*
9805
* [19] PathExpr ::= LocationPath
9806
* | FilterExpr
9807
* | FilterExpr '/' RelativeLocationPath
9808
* | FilterExpr '//' RelativeLocationPath
9809
*
9810
* Compile a path expression.
9811
* The / operator and // operators combine an arbitrary expression
9812
* and a relative location path. It is an error if the expression
9813
* does not evaluate to a node-set.
9814
* The / operator does composition in the same way as when / is
9815
* used in a location path. As in location paths, // is short for
9816
* /descendant-or-self::node()/.
9817
*/
9818
9819
static void
9820
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
9821
int lc = 1; /* Should we branch to LocationPath ? */
9822
xmlChar *name = NULL; /* we may have to preparse a name to find out */
9823
9824
SKIP_BLANKS;
9825
if ((CUR == '$') || (CUR == '(') ||
9826
(IS_ASCII_DIGIT(CUR)) ||
9827
(CUR == '\'') || (CUR == '"') ||
9828
(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
9829
lc = 0;
9830
} else if (CUR == '*') {
9831
/* relative or absolute location path */
9832
lc = 1;
9833
} else if (CUR == '/') {
9834
/* relative or absolute location path */
9835
lc = 1;
9836
} else if (CUR == '@') {
9837
/* relative abbreviated attribute location path */
9838
lc = 1;
9839
} else if (CUR == '.') {
9840
/* relative abbreviated attribute location path */
9841
lc = 1;
9842
} else {
9843
/*
9844
* Problem is finding if we have a name here whether it's:
9845
* - a nodetype
9846
* - a function call in which case it's followed by '('
9847
* - an axis in which case it's followed by ':'
9848
* - a element name
9849
* We do an a priori analysis here rather than having to
9850
* maintain parsed token content through the recursive function
9851
* calls. This looks uglier but makes the code easier to
9852
* read/write/debug.
9853
*/
9854
SKIP_BLANKS;
9855
name = xmlXPathScanName(ctxt);
9856
if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
9857
lc = 1;
9858
xmlFree(name);
9859
} else if (name != NULL) {
9860
int len =xmlStrlen(name);
9861
9862
9863
while (NXT(len) != 0) {
9864
if (NXT(len) == '/') {
9865
/* element name */
9866
lc = 1;
9867
break;
9868
} else if (IS_BLANK_CH(NXT(len))) {
9869
/* ignore blanks */
9870
;
9871
} else if (NXT(len) == ':') {
9872
lc = 1;
9873
break;
9874
} else if ((NXT(len) == '(')) {
9875
/* Node Type or Function */
9876
if (xmlXPathIsNodeType(name)) {
9877
lc = 1;
9878
#ifdef LIBXML_XPTR_LOCS_ENABLED
9879
} else if (ctxt->xptr &&
9880
xmlStrEqual(name, BAD_CAST "range-to")) {
9881
lc = 1;
9882
#endif
9883
} else {
9884
lc = 0;
9885
}
9886
break;
9887
} else if ((NXT(len) == '[')) {
9888
/* element name */
9889
lc = 1;
9890
break;
9891
} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
9892
(NXT(len) == '=')) {
9893
lc = 1;
9894
break;
9895
} else {
9896
lc = 1;
9897
break;
9898
}
9899
len++;
9900
}
9901
if (NXT(len) == 0) {
9902
/* element name */
9903
lc = 1;
9904
}
9905
xmlFree(name);
9906
} else {
9907
/* make sure all cases are covered explicitly */
9908
XP_ERROR(XPATH_EXPR_ERROR);
9909
}
9910
}
9911
9912
if (lc) {
9913
if (CUR == '/') {
9914
PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
9915
} else {
9916
PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9917
}
9918
xmlXPathCompLocationPath(ctxt);
9919
} else {
9920
xmlXPathCompFilterExpr(ctxt);
9921
CHECK_ERROR;
9922
if ((CUR == '/') && (NXT(1) == '/')) {
9923
SKIP(2);
9924
SKIP_BLANKS;
9925
9926
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
9927
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
9928
9929
xmlXPathCompRelativeLocationPath(ctxt);
9930
} else if (CUR == '/') {
9931
xmlXPathCompRelativeLocationPath(ctxt);
9932
}
9933
}
9934
SKIP_BLANKS;
9935
}
9936
9937
/**
9938
* xmlXPathCompUnionExpr:
9939
* @ctxt: the XPath Parser context
9940
*
9941
* [18] UnionExpr ::= PathExpr
9942
* | UnionExpr '|' PathExpr
9943
*
9944
* Compile an union expression.
9945
*/
9946
9947
static void
9948
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
9949
xmlXPathCompPathExpr(ctxt);
9950
CHECK_ERROR;
9951
SKIP_BLANKS;
9952
while (CUR == '|') {
9953
int op1 = ctxt->comp->last;
9954
PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
9955
9956
NEXT;
9957
SKIP_BLANKS;
9958
xmlXPathCompPathExpr(ctxt);
9959
9960
PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
9961
9962
SKIP_BLANKS;
9963
}
9964
}
9965
9966
/**
9967
* xmlXPathCompUnaryExpr:
9968
* @ctxt: the XPath Parser context
9969
*
9970
* [27] UnaryExpr ::= UnionExpr
9971
* | '-' UnaryExpr
9972
*
9973
* Compile an unary expression.
9974
*/
9975
9976
static void
9977
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
9978
int minus = 0;
9979
int found = 0;
9980
9981
SKIP_BLANKS;
9982
while (CUR == '-') {
9983
minus = 1 - minus;
9984
found = 1;
9985
NEXT;
9986
SKIP_BLANKS;
9987
}
9988
9989
xmlXPathCompUnionExpr(ctxt);
9990
CHECK_ERROR;
9991
if (found) {
9992
if (minus)
9993
PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
9994
else
9995
PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
9996
}
9997
}
9998
9999
/**
10000
* xmlXPathCompMultiplicativeExpr:
10001
* @ctxt: the XPath Parser context
10002
*
10003
* [26] MultiplicativeExpr ::= UnaryExpr
10004
* | MultiplicativeExpr MultiplyOperator UnaryExpr
10005
* | MultiplicativeExpr 'div' UnaryExpr
10006
* | MultiplicativeExpr 'mod' UnaryExpr
10007
* [34] MultiplyOperator ::= '*'
10008
*
10009
* Compile an Additive expression.
10010
*/
10011
10012
static void
10013
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10014
xmlXPathCompUnaryExpr(ctxt);
10015
CHECK_ERROR;
10016
SKIP_BLANKS;
10017
while ((CUR == '*') ||
10018
((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10019
((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10020
int op = -1;
10021
int op1 = ctxt->comp->last;
10022
10023
if (CUR == '*') {
10024
op = 0;
10025
NEXT;
10026
} else if (CUR == 'd') {
10027
op = 1;
10028
SKIP(3);
10029
} else if (CUR == 'm') {
10030
op = 2;
10031
SKIP(3);
10032
}
10033
SKIP_BLANKS;
10034
xmlXPathCompUnaryExpr(ctxt);
10035
CHECK_ERROR;
10036
PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10037
SKIP_BLANKS;
10038
}
10039
}
10040
10041
/**
10042
* xmlXPathCompAdditiveExpr:
10043
* @ctxt: the XPath Parser context
10044
*
10045
* [25] AdditiveExpr ::= MultiplicativeExpr
10046
* | AdditiveExpr '+' MultiplicativeExpr
10047
* | AdditiveExpr '-' MultiplicativeExpr
10048
*
10049
* Compile an Additive expression.
10050
*/
10051
10052
static void
10053
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10054
10055
xmlXPathCompMultiplicativeExpr(ctxt);
10056
CHECK_ERROR;
10057
SKIP_BLANKS;
10058
while ((CUR == '+') || (CUR == '-')) {
10059
int plus;
10060
int op1 = ctxt->comp->last;
10061
10062
if (CUR == '+') plus = 1;
10063
else plus = 0;
10064
NEXT;
10065
SKIP_BLANKS;
10066
xmlXPathCompMultiplicativeExpr(ctxt);
10067
CHECK_ERROR;
10068
PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10069
SKIP_BLANKS;
10070
}
10071
}
10072
10073
/**
10074
* xmlXPathCompRelationalExpr:
10075
* @ctxt: the XPath Parser context
10076
*
10077
* [24] RelationalExpr ::= AdditiveExpr
10078
* | RelationalExpr '<' AdditiveExpr
10079
* | RelationalExpr '>' AdditiveExpr
10080
* | RelationalExpr '<=' AdditiveExpr
10081
* | RelationalExpr '>=' AdditiveExpr
10082
*
10083
* A <= B > C is allowed ? Answer from James, yes with
10084
* (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10085
* which is basically what got implemented.
10086
*
10087
* Compile a Relational expression, then push the result
10088
* on the stack
10089
*/
10090
10091
static void
10092
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10093
xmlXPathCompAdditiveExpr(ctxt);
10094
CHECK_ERROR;
10095
SKIP_BLANKS;
10096
while ((CUR == '<') || (CUR == '>')) {
10097
int inf, strict;
10098
int op1 = ctxt->comp->last;
10099
10100
if (CUR == '<') inf = 1;
10101
else inf = 0;
10102
if (NXT(1) == '=') strict = 0;
10103
else strict = 1;
10104
NEXT;
10105
if (!strict) NEXT;
10106
SKIP_BLANKS;
10107
xmlXPathCompAdditiveExpr(ctxt);
10108
CHECK_ERROR;
10109
PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10110
SKIP_BLANKS;
10111
}
10112
}
10113
10114
/**
10115
* xmlXPathCompEqualityExpr:
10116
* @ctxt: the XPath Parser context
10117
*
10118
* [23] EqualityExpr ::= RelationalExpr
10119
* | EqualityExpr '=' RelationalExpr
10120
* | EqualityExpr '!=' RelationalExpr
10121
*
10122
* A != B != C is allowed ? Answer from James, yes with
10123
* (RelationalExpr = RelationalExpr) = RelationalExpr
10124
* (RelationalExpr != RelationalExpr) != RelationalExpr
10125
* which is basically what got implemented.
10126
*
10127
* Compile an Equality expression.
10128
*
10129
*/
10130
static void
10131
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10132
xmlXPathCompRelationalExpr(ctxt);
10133
CHECK_ERROR;
10134
SKIP_BLANKS;
10135
while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10136
int eq;
10137
int op1 = ctxt->comp->last;
10138
10139
if (CUR == '=') eq = 1;
10140
else eq = 0;
10141
NEXT;
10142
if (!eq) NEXT;
10143
SKIP_BLANKS;
10144
xmlXPathCompRelationalExpr(ctxt);
10145
CHECK_ERROR;
10146
PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
10147
SKIP_BLANKS;
10148
}
10149
}
10150
10151
/**
10152
* xmlXPathCompAndExpr:
10153
* @ctxt: the XPath Parser context
10154
*
10155
* [22] AndExpr ::= EqualityExpr
10156
* | AndExpr 'and' EqualityExpr
10157
*
10158
* Compile an AND expression.
10159
*
10160
*/
10161
static void
10162
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
10163
xmlXPathCompEqualityExpr(ctxt);
10164
CHECK_ERROR;
10165
SKIP_BLANKS;
10166
while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
10167
int op1 = ctxt->comp->last;
10168
SKIP(3);
10169
SKIP_BLANKS;
10170
xmlXPathCompEqualityExpr(ctxt);
10171
CHECK_ERROR;
10172
PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
10173
SKIP_BLANKS;
10174
}
10175
}
10176
10177
/**
10178
* xmlXPathCompileExpr:
10179
* @ctxt: the XPath Parser context
10180
*
10181
* [14] Expr ::= OrExpr
10182
* [21] OrExpr ::= AndExpr
10183
* | OrExpr 'or' AndExpr
10184
*
10185
* Parse and compile an expression
10186
*/
10187
static void
10188
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
10189
xmlXPathContextPtr xpctxt = ctxt->context;
10190
10191
if (xpctxt != NULL) {
10192
if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
10193
XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
10194
/*
10195
* Parsing a single '(' pushes about 10 functions on the call stack
10196
* before recursing!
10197
*/
10198
xpctxt->depth += 10;
10199
}
10200
10201
xmlXPathCompAndExpr(ctxt);
10202
CHECK_ERROR;
10203
SKIP_BLANKS;
10204
while ((CUR == 'o') && (NXT(1) == 'r')) {
10205
int op1 = ctxt->comp->last;
10206
SKIP(2);
10207
SKIP_BLANKS;
10208
xmlXPathCompAndExpr(ctxt);
10209
CHECK_ERROR;
10210
PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
10211
SKIP_BLANKS;
10212
}
10213
if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
10214
/* more ops could be optimized too */
10215
/*
10216
* This is the main place to eliminate sorting for
10217
* operations which don't require a sorted node-set.
10218
* E.g. count().
10219
*/
10220
PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
10221
}
10222
10223
if (xpctxt != NULL)
10224
xpctxt->depth -= 10;
10225
}
10226
10227
/**
10228
* xmlXPathCompPredicate:
10229
* @ctxt: the XPath Parser context
10230
* @filter: act as a filter
10231
*
10232
* [8] Predicate ::= '[' PredicateExpr ']'
10233
* [9] PredicateExpr ::= Expr
10234
*
10235
* Compile a predicate expression
10236
*/
10237
static void
10238
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
10239
int op1 = ctxt->comp->last;
10240
10241
SKIP_BLANKS;
10242
if (CUR != '[') {
10243
XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10244
}
10245
NEXT;
10246
SKIP_BLANKS;
10247
10248
ctxt->comp->last = -1;
10249
/*
10250
* This call to xmlXPathCompileExpr() will deactivate sorting
10251
* of the predicate result.
10252
* TODO: Sorting is still activated for filters, since I'm not
10253
* sure if needed. Normally sorting should not be needed, since
10254
* a filter can only diminish the number of items in a sequence,
10255
* but won't change its order; so if the initial sequence is sorted,
10256
* subsequent sorting is not needed.
10257
*/
10258
if (! filter)
10259
xmlXPathCompileExpr(ctxt, 0);
10260
else
10261
xmlXPathCompileExpr(ctxt, 1);
10262
CHECK_ERROR;
10263
10264
if (CUR != ']') {
10265
XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
10266
}
10267
10268
if (filter)
10269
PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
10270
else
10271
PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
10272
10273
NEXT;
10274
SKIP_BLANKS;
10275
}
10276
10277
/**
10278
* xmlXPathCompNodeTest:
10279
* @ctxt: the XPath Parser context
10280
* @test: pointer to a xmlXPathTestVal
10281
* @type: pointer to a xmlXPathTypeVal
10282
* @prefix: placeholder for a possible name prefix
10283
*
10284
* [7] NodeTest ::= NameTest
10285
* | NodeType '(' ')'
10286
* | 'processing-instruction' '(' Literal ')'
10287
*
10288
* [37] NameTest ::= '*'
10289
* | NCName ':' '*'
10290
* | QName
10291
* [38] NodeType ::= 'comment'
10292
* | 'text'
10293
* | 'processing-instruction'
10294
* | 'node'
10295
*
10296
* Returns the name found and updates @test, @type and @prefix appropriately
10297
*/
10298
static xmlChar *
10299
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
10300
xmlXPathTypeVal *type, xmlChar **prefix,
10301
xmlChar *name) {
10302
int blanks;
10303
10304
if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
10305
STRANGE;
10306
return(NULL);
10307
}
10308
*type = (xmlXPathTypeVal) 0;
10309
*test = (xmlXPathTestVal) 0;
10310
*prefix = NULL;
10311
SKIP_BLANKS;
10312
10313
if ((name == NULL) && (CUR == '*')) {
10314
/*
10315
* All elements
10316
*/
10317
NEXT;
10318
*test = NODE_TEST_ALL;
10319
return(NULL);
10320
}
10321
10322
if (name == NULL)
10323
name = xmlXPathParseNCName(ctxt);
10324
if (name == NULL) {
10325
XP_ERRORNULL(XPATH_EXPR_ERROR);
10326
}
10327
10328
blanks = IS_BLANK_CH(CUR);
10329
SKIP_BLANKS;
10330
if (CUR == '(') {
10331
NEXT;
10332
/*
10333
* NodeType or PI search
10334
*/
10335
if (xmlStrEqual(name, BAD_CAST "comment"))
10336
*type = NODE_TYPE_COMMENT;
10337
else if (xmlStrEqual(name, BAD_CAST "node"))
10338
*type = NODE_TYPE_NODE;
10339
else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10340
*type = NODE_TYPE_PI;
10341
else if (xmlStrEqual(name, BAD_CAST "text"))
10342
*type = NODE_TYPE_TEXT;
10343
else {
10344
if (name != NULL)
10345
xmlFree(name);
10346
XP_ERRORNULL(XPATH_EXPR_ERROR);
10347
}
10348
10349
*test = NODE_TEST_TYPE;
10350
10351
SKIP_BLANKS;
10352
if (*type == NODE_TYPE_PI) {
10353
/*
10354
* Specific case: search a PI by name.
10355
*/
10356
if (name != NULL)
10357
xmlFree(name);
10358
name = NULL;
10359
if (CUR != ')') {
10360
name = xmlXPathParseLiteral(ctxt);
10361
if (name == NULL) {
10362
XP_ERRORNULL(XPATH_EXPR_ERROR);
10363
}
10364
*test = NODE_TEST_PI;
10365
SKIP_BLANKS;
10366
}
10367
}
10368
if (CUR != ')') {
10369
if (name != NULL)
10370
xmlFree(name);
10371
XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
10372
}
10373
NEXT;
10374
return(name);
10375
}
10376
*test = NODE_TEST_NAME;
10377
if ((!blanks) && (CUR == ':')) {
10378
NEXT;
10379
10380
/*
10381
* Since currently the parser context don't have a
10382
* namespace list associated:
10383
* The namespace name for this prefix can be computed
10384
* only at evaluation time. The compilation is done
10385
* outside of any context.
10386
*/
10387
#if 0
10388
*prefix = xmlXPathNsLookup(ctxt->context, name);
10389
if (name != NULL)
10390
xmlFree(name);
10391
if (*prefix == NULL) {
10392
XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
10393
}
10394
#else
10395
*prefix = name;
10396
#endif
10397
10398
if (CUR == '*') {
10399
/*
10400
* All elements
10401
*/
10402
NEXT;
10403
*test = NODE_TEST_ALL;
10404
return(NULL);
10405
}
10406
10407
name = xmlXPathParseNCName(ctxt);
10408
if (name == NULL) {
10409
XP_ERRORNULL(XPATH_EXPR_ERROR);
10410
}
10411
}
10412
return(name);
10413
}
10414
10415
/**
10416
* xmlXPathIsAxisName:
10417
* @name: a preparsed name token
10418
*
10419
* [6] AxisName ::= 'ancestor'
10420
* | 'ancestor-or-self'
10421
* | 'attribute'
10422
* | 'child'
10423
* | 'descendant'
10424
* | 'descendant-or-self'
10425
* | 'following'
10426
* | 'following-sibling'
10427
* | 'namespace'
10428
* | 'parent'
10429
* | 'preceding'
10430
* | 'preceding-sibling'
10431
* | 'self'
10432
*
10433
* Returns the axis or 0
10434
*/
10435
static xmlXPathAxisVal
10436
xmlXPathIsAxisName(const xmlChar *name) {
10437
xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
10438
switch (name[0]) {
10439
case 'a':
10440
if (xmlStrEqual(name, BAD_CAST "ancestor"))
10441
ret = AXIS_ANCESTOR;
10442
if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
10443
ret = AXIS_ANCESTOR_OR_SELF;
10444
if (xmlStrEqual(name, BAD_CAST "attribute"))
10445
ret = AXIS_ATTRIBUTE;
10446
break;
10447
case 'c':
10448
if (xmlStrEqual(name, BAD_CAST "child"))
10449
ret = AXIS_CHILD;
10450
break;
10451
case 'd':
10452
if (xmlStrEqual(name, BAD_CAST "descendant"))
10453
ret = AXIS_DESCENDANT;
10454
if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
10455
ret = AXIS_DESCENDANT_OR_SELF;
10456
break;
10457
case 'f':
10458
if (xmlStrEqual(name, BAD_CAST "following"))
10459
ret = AXIS_FOLLOWING;
10460
if (xmlStrEqual(name, BAD_CAST "following-sibling"))
10461
ret = AXIS_FOLLOWING_SIBLING;
10462
break;
10463
case 'n':
10464
if (xmlStrEqual(name, BAD_CAST "namespace"))
10465
ret = AXIS_NAMESPACE;
10466
break;
10467
case 'p':
10468
if (xmlStrEqual(name, BAD_CAST "parent"))
10469
ret = AXIS_PARENT;
10470
if (xmlStrEqual(name, BAD_CAST "preceding"))
10471
ret = AXIS_PRECEDING;
10472
if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
10473
ret = AXIS_PRECEDING_SIBLING;
10474
break;
10475
case 's':
10476
if (xmlStrEqual(name, BAD_CAST "self"))
10477
ret = AXIS_SELF;
10478
break;
10479
}
10480
return(ret);
10481
}
10482
10483
/**
10484
* xmlXPathCompStep:
10485
* @ctxt: the XPath Parser context
10486
*
10487
* [4] Step ::= AxisSpecifier NodeTest Predicate*
10488
* | AbbreviatedStep
10489
*
10490
* [12] AbbreviatedStep ::= '.' | '..'
10491
*
10492
* [5] AxisSpecifier ::= AxisName '::'
10493
* | AbbreviatedAxisSpecifier
10494
*
10495
* [13] AbbreviatedAxisSpecifier ::= '@'?
10496
*
10497
* Modified for XPtr range support as:
10498
*
10499
* [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
10500
* | AbbreviatedStep
10501
* | 'range-to' '(' Expr ')' Predicate*
10502
*
10503
* Compile one step in a Location Path
10504
* A location step of . is short for self::node(). This is
10505
* particularly useful in conjunction with //. For example, the
10506
* location path .//para is short for
10507
* self::node()/descendant-or-self::node()/child::para
10508
* and so will select all para descendant elements of the context
10509
* node.
10510
* Similarly, a location step of .. is short for parent::node().
10511
* For example, ../title is short for parent::node()/child::title
10512
* and so will select the title children of the parent of the context
10513
* node.
10514
*/
10515
static void
10516
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
10517
#ifdef LIBXML_XPTR_LOCS_ENABLED
10518
int rangeto = 0;
10519
int op2 = -1;
10520
#endif
10521
10522
SKIP_BLANKS;
10523
if ((CUR == '.') && (NXT(1) == '.')) {
10524
SKIP(2);
10525
SKIP_BLANKS;
10526
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
10527
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10528
} else if (CUR == '.') {
10529
NEXT;
10530
SKIP_BLANKS;
10531
} else {
10532
xmlChar *name = NULL;
10533
xmlChar *prefix = NULL;
10534
xmlXPathTestVal test = (xmlXPathTestVal) 0;
10535
xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
10536
xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
10537
int op1;
10538
10539
/*
10540
* The modification needed for XPointer change to the production
10541
*/
10542
#ifdef LIBXML_XPTR_LOCS_ENABLED
10543
if (ctxt->xptr) {
10544
name = xmlXPathParseNCName(ctxt);
10545
if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
10546
op2 = ctxt->comp->last;
10547
xmlFree(name);
10548
SKIP_BLANKS;
10549
if (CUR != '(') {
10550
XP_ERROR(XPATH_EXPR_ERROR);
10551
}
10552
NEXT;
10553
SKIP_BLANKS;
10554
10555
xmlXPathCompileExpr(ctxt, 1);
10556
/* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
10557
CHECK_ERROR;
10558
10559
SKIP_BLANKS;
10560
if (CUR != ')') {
10561
XP_ERROR(XPATH_EXPR_ERROR);
10562
}
10563
NEXT;
10564
rangeto = 1;
10565
goto eval_predicates;
10566
}
10567
}
10568
#endif
10569
if (CUR == '*') {
10570
axis = AXIS_CHILD;
10571
} else {
10572
if (name == NULL)
10573
name = xmlXPathParseNCName(ctxt);
10574
if (name != NULL) {
10575
axis = xmlXPathIsAxisName(name);
10576
if (axis != 0) {
10577
SKIP_BLANKS;
10578
if ((CUR == ':') && (NXT(1) == ':')) {
10579
SKIP(2);
10580
xmlFree(name);
10581
name = NULL;
10582
} else {
10583
/* an element name can conflict with an axis one :-\ */
10584
axis = AXIS_CHILD;
10585
}
10586
} else {
10587
axis = AXIS_CHILD;
10588
}
10589
} else if (CUR == '@') {
10590
NEXT;
10591
axis = AXIS_ATTRIBUTE;
10592
} else {
10593
axis = AXIS_CHILD;
10594
}
10595
}
10596
10597
if (ctxt->error != XPATH_EXPRESSION_OK) {
10598
xmlFree(name);
10599
return;
10600
}
10601
10602
name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
10603
if (test == 0)
10604
return;
10605
10606
if ((prefix != NULL) && (ctxt->context != NULL) &&
10607
(ctxt->context->flags & XML_XPATH_CHECKNS)) {
10608
if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
10609
xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
10610
}
10611
}
10612
10613
#ifdef LIBXML_XPTR_LOCS_ENABLED
10614
eval_predicates:
10615
#endif
10616
op1 = ctxt->comp->last;
10617
ctxt->comp->last = -1;
10618
10619
SKIP_BLANKS;
10620
while (CUR == '[') {
10621
xmlXPathCompPredicate(ctxt, 0);
10622
}
10623
10624
#ifdef LIBXML_XPTR_LOCS_ENABLED
10625
if (rangeto) {
10626
PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
10627
} else
10628
#endif
10629
if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
10630
test, type, (void *)prefix, (void *)name) == -1) {
10631
xmlFree(prefix);
10632
xmlFree(name);
10633
}
10634
}
10635
}
10636
10637
/**
10638
* xmlXPathCompRelativeLocationPath:
10639
* @ctxt: the XPath Parser context
10640
*
10641
* [3] RelativeLocationPath ::= Step
10642
* | RelativeLocationPath '/' Step
10643
* | AbbreviatedRelativeLocationPath
10644
* [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
10645
*
10646
* Compile a relative location path.
10647
*/
10648
static void
10649
xmlXPathCompRelativeLocationPath
10650
(xmlXPathParserContextPtr ctxt) {
10651
SKIP_BLANKS;
10652
if ((CUR == '/') && (NXT(1) == '/')) {
10653
SKIP(2);
10654
SKIP_BLANKS;
10655
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10656
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10657
} else if (CUR == '/') {
10658
NEXT;
10659
SKIP_BLANKS;
10660
}
10661
xmlXPathCompStep(ctxt);
10662
CHECK_ERROR;
10663
SKIP_BLANKS;
10664
while (CUR == '/') {
10665
if ((CUR == '/') && (NXT(1) == '/')) {
10666
SKIP(2);
10667
SKIP_BLANKS;
10668
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10669
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10670
xmlXPathCompStep(ctxt);
10671
} else if (CUR == '/') {
10672
NEXT;
10673
SKIP_BLANKS;
10674
xmlXPathCompStep(ctxt);
10675
}
10676
SKIP_BLANKS;
10677
}
10678
}
10679
10680
/**
10681
* xmlXPathCompLocationPath:
10682
* @ctxt: the XPath Parser context
10683
*
10684
* [1] LocationPath ::= RelativeLocationPath
10685
* | AbsoluteLocationPath
10686
* [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
10687
* | AbbreviatedAbsoluteLocationPath
10688
* [10] AbbreviatedAbsoluteLocationPath ::=
10689
* '//' RelativeLocationPath
10690
*
10691
* Compile a location path
10692
*
10693
* // is short for /descendant-or-self::node()/. For example,
10694
* //para is short for /descendant-or-self::node()/child::para and
10695
* so will select any para element in the document (even a para element
10696
* that is a document element will be selected by //para since the
10697
* document element node is a child of the root node); div//para is
10698
* short for div/descendant-or-self::node()/child::para and so will
10699
* select all para descendants of div children.
10700
*/
10701
static void
10702
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
10703
SKIP_BLANKS;
10704
if (CUR != '/') {
10705
xmlXPathCompRelativeLocationPath(ctxt);
10706
} else {
10707
while (CUR == '/') {
10708
if ((CUR == '/') && (NXT(1) == '/')) {
10709
SKIP(2);
10710
SKIP_BLANKS;
10711
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10712
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10713
xmlXPathCompRelativeLocationPath(ctxt);
10714
} else if (CUR == '/') {
10715
NEXT;
10716
SKIP_BLANKS;
10717
if ((CUR != 0) &&
10718
((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
10719
(CUR == '_') || (CUR == '.') ||
10720
(CUR == '@') || (CUR == '*')))
10721
xmlXPathCompRelativeLocationPath(ctxt);
10722
}
10723
CHECK_ERROR;
10724
}
10725
}
10726
}
10727
10728
/************************************************************************
10729
* *
10730
* XPath precompiled expression evaluation *
10731
* *
10732
************************************************************************/
10733
10734
static int
10735
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
10736
10737
/**
10738
* xmlXPathNodeSetFilter:
10739
* @ctxt: the XPath Parser context
10740
* @set: the node set to filter
10741
* @filterOpIndex: the index of the predicate/filter op
10742
* @minPos: minimum position in the filtered set (1-based)
10743
* @maxPos: maximum position in the filtered set (1-based)
10744
* @hasNsNodes: true if the node set may contain namespace nodes
10745
*
10746
* Filter a node set, keeping only nodes for which the predicate expression
10747
* matches. Afterwards, keep only nodes between minPos and maxPos in the
10748
* filtered result.
10749
*/
10750
static void
10751
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
10752
xmlNodeSetPtr set,
10753
int filterOpIndex,
10754
int minPos, int maxPos,
10755
int hasNsNodes)
10756
{
10757
xmlXPathContextPtr xpctxt;
10758
xmlNodePtr oldnode;
10759
xmlDocPtr olddoc;
10760
xmlXPathStepOpPtr filterOp;
10761
int oldcs, oldpp;
10762
int i, j, pos;
10763
10764
if ((set == NULL) || (set->nodeNr == 0))
10765
return;
10766
10767
/*
10768
* Check if the node set contains a sufficient number of nodes for
10769
* the requested range.
10770
*/
10771
if (set->nodeNr < minPos) {
10772
xmlXPathNodeSetClear(set, hasNsNodes);
10773
return;
10774
}
10775
10776
xpctxt = ctxt->context;
10777
oldnode = xpctxt->node;
10778
olddoc = xpctxt->doc;
10779
oldcs = xpctxt->contextSize;
10780
oldpp = xpctxt->proximityPosition;
10781
filterOp = &ctxt->comp->steps[filterOpIndex];
10782
10783
xpctxt->contextSize = set->nodeNr;
10784
10785
for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
10786
xmlNodePtr node = set->nodeTab[i];
10787
int res;
10788
10789
xpctxt->node = node;
10790
xpctxt->proximityPosition = i + 1;
10791
10792
/*
10793
* Also set the xpath document in case things like
10794
* key() are evaluated in the predicate.
10795
*
10796
* TODO: Get real doc for namespace nodes.
10797
*/
10798
if ((node->type != XML_NAMESPACE_DECL) &&
10799
(node->doc != NULL))
10800
xpctxt->doc = node->doc;
10801
10802
res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10803
10804
if (ctxt->error != XPATH_EXPRESSION_OK)
10805
break;
10806
if (res < 0) {
10807
/* Shouldn't happen */
10808
xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10809
break;
10810
}
10811
10812
if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10813
if (i != j) {
10814
set->nodeTab[j] = node;
10815
set->nodeTab[i] = NULL;
10816
}
10817
10818
j += 1;
10819
} else {
10820
/* Remove the entry from the initial node set. */
10821
set->nodeTab[i] = NULL;
10822
if (node->type == XML_NAMESPACE_DECL)
10823
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10824
}
10825
10826
if (res != 0) {
10827
if (pos == maxPos) {
10828
i += 1;
10829
break;
10830
}
10831
10832
pos += 1;
10833
}
10834
}
10835
10836
/* Free remaining nodes. */
10837
if (hasNsNodes) {
10838
for (; i < set->nodeNr; i++) {
10839
xmlNodePtr node = set->nodeTab[i];
10840
if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
10841
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
10842
}
10843
}
10844
10845
set->nodeNr = j;
10846
10847
/* If too many elements were removed, shrink table to preserve memory. */
10848
if ((set->nodeMax > XML_NODESET_DEFAULT) &&
10849
(set->nodeNr < set->nodeMax / 2)) {
10850
xmlNodePtr *tmp;
10851
int nodeMax = set->nodeNr;
10852
10853
if (nodeMax < XML_NODESET_DEFAULT)
10854
nodeMax = XML_NODESET_DEFAULT;
10855
tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
10856
nodeMax * sizeof(xmlNodePtr));
10857
if (tmp == NULL) {
10858
xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
10859
} else {
10860
set->nodeTab = tmp;
10861
set->nodeMax = nodeMax;
10862
}
10863
}
10864
10865
xpctxt->node = oldnode;
10866
xpctxt->doc = olddoc;
10867
xpctxt->contextSize = oldcs;
10868
xpctxt->proximityPosition = oldpp;
10869
}
10870
10871
#ifdef LIBXML_XPTR_LOCS_ENABLED
10872
/**
10873
* xmlXPathLocationSetFilter:
10874
* @ctxt: the XPath Parser context
10875
* @locset: the location set to filter
10876
* @filterOpIndex: the index of the predicate/filter op
10877
* @minPos: minimum position in the filtered set (1-based)
10878
* @maxPos: maximum position in the filtered set (1-based)
10879
*
10880
* Filter a location set, keeping only nodes for which the predicate
10881
* expression matches. Afterwards, keep only nodes between minPos and maxPos
10882
* in the filtered result.
10883
*/
10884
static void
10885
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
10886
xmlLocationSetPtr locset,
10887
int filterOpIndex,
10888
int minPos, int maxPos)
10889
{
10890
xmlXPathContextPtr xpctxt;
10891
xmlNodePtr oldnode;
10892
xmlDocPtr olddoc;
10893
xmlXPathStepOpPtr filterOp;
10894
int oldcs, oldpp;
10895
int i, j, pos;
10896
10897
if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
10898
return;
10899
10900
xpctxt = ctxt->context;
10901
oldnode = xpctxt->node;
10902
olddoc = xpctxt->doc;
10903
oldcs = xpctxt->contextSize;
10904
oldpp = xpctxt->proximityPosition;
10905
filterOp = &ctxt->comp->steps[filterOpIndex];
10906
10907
xpctxt->contextSize = locset->locNr;
10908
10909
for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
10910
xmlNodePtr contextNode = locset->locTab[i]->user;
10911
int res;
10912
10913
xpctxt->node = contextNode;
10914
xpctxt->proximityPosition = i + 1;
10915
10916
/*
10917
* Also set the xpath document in case things like
10918
* key() are evaluated in the predicate.
10919
*
10920
* TODO: Get real doc for namespace nodes.
10921
*/
10922
if ((contextNode->type != XML_NAMESPACE_DECL) &&
10923
(contextNode->doc != NULL))
10924
xpctxt->doc = contextNode->doc;
10925
10926
res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
10927
10928
if (ctxt->error != XPATH_EXPRESSION_OK)
10929
break;
10930
if (res < 0) {
10931
/* Shouldn't happen */
10932
xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
10933
break;
10934
}
10935
10936
if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
10937
if (i != j) {
10938
locset->locTab[j] = locset->locTab[i];
10939
locset->locTab[i] = NULL;
10940
}
10941
10942
j += 1;
10943
} else {
10944
/* Remove the entry from the initial location set. */
10945
xmlXPathFreeObject(locset->locTab[i]);
10946
locset->locTab[i] = NULL;
10947
}
10948
10949
if (res != 0) {
10950
if (pos == maxPos) {
10951
i += 1;
10952
break;
10953
}
10954
10955
pos += 1;
10956
}
10957
}
10958
10959
/* Free remaining nodes. */
10960
for (; i < locset->locNr; i++)
10961
xmlXPathFreeObject(locset->locTab[i]);
10962
10963
locset->locNr = j;
10964
10965
/* If too many elements were removed, shrink table to preserve memory. */
10966
if ((locset->locMax > XML_NODESET_DEFAULT) &&
10967
(locset->locNr < locset->locMax / 2)) {
10968
xmlXPathObjectPtr *tmp;
10969
int locMax = locset->locNr;
10970
10971
if (locMax < XML_NODESET_DEFAULT)
10972
locMax = XML_NODESET_DEFAULT;
10973
tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
10974
locMax * sizeof(xmlXPathObjectPtr));
10975
if (tmp == NULL) {
10976
xmlXPathPErrMemory(ctxt, "shrinking locset\n");
10977
} else {
10978
locset->locTab = tmp;
10979
locset->locMax = locMax;
10980
}
10981
}
10982
10983
xpctxt->node = oldnode;
10984
xpctxt->doc = olddoc;
10985
xpctxt->contextSize = oldcs;
10986
xpctxt->proximityPosition = oldpp;
10987
}
10988
#endif /* LIBXML_XPTR_LOCS_ENABLED */
10989
10990
/**
10991
* xmlXPathCompOpEvalPredicate:
10992
* @ctxt: the XPath Parser context
10993
* @op: the predicate op
10994
* @set: the node set to filter
10995
* @minPos: minimum position in the filtered set (1-based)
10996
* @maxPos: maximum position in the filtered set (1-based)
10997
* @hasNsNodes: true if the node set may contain namespace nodes
10998
*
10999
* Filter a node set, keeping only nodes for which the sequence of predicate
11000
* expressions matches. Afterwards, keep only nodes between minPos and maxPos
11001
* in the filtered result.
11002
*/
11003
static void
11004
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11005
xmlXPathStepOpPtr op,
11006
xmlNodeSetPtr set,
11007
int minPos, int maxPos,
11008
int hasNsNodes)
11009
{
11010
if (op->ch1 != -1) {
11011
xmlXPathCompExprPtr comp = ctxt->comp;
11012
/*
11013
* Process inner predicates first.
11014
*/
11015
if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11016
xmlGenericError(xmlGenericErrorContext,
11017
"xmlXPathCompOpEvalPredicate: Expected a predicate\n");
11018
XP_ERROR(XPATH_INVALID_OPERAND);
11019
}
11020
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11021
XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
11022
ctxt->context->depth += 1;
11023
xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
11024
1, set->nodeNr, hasNsNodes);
11025
ctxt->context->depth -= 1;
11026
CHECK_ERROR;
11027
}
11028
11029
if (op->ch2 != -1)
11030
xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
11031
}
11032
11033
static int
11034
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
11035
xmlXPathStepOpPtr op,
11036
int *maxPos)
11037
{
11038
11039
xmlXPathStepOpPtr exprOp;
11040
11041
/*
11042
* BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
11043
*/
11044
11045
/*
11046
* If not -1, then ch1 will point to:
11047
* 1) For predicates (XPATH_OP_PREDICATE):
11048
* - an inner predicate operator
11049
* 2) For filters (XPATH_OP_FILTER):
11050
* - an inner filter operator OR
11051
* - an expression selecting the node set.
11052
* E.g. "key('a', 'b')" or "(//foo | //bar)".
11053
*/
11054
if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
11055
return(0);
11056
11057
if (op->ch2 != -1) {
11058
exprOp = &ctxt->comp->steps[op->ch2];
11059
} else
11060
return(0);
11061
11062
if ((exprOp != NULL) &&
11063
(exprOp->op == XPATH_OP_VALUE) &&
11064
(exprOp->value4 != NULL) &&
11065
(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
11066
{
11067
double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
11068
11069
/*
11070
* We have a "[n]" predicate here.
11071
* TODO: Unfortunately this simplistic test here is not
11072
* able to detect a position() predicate in compound
11073
* expressions like "[@attr = 'a" and position() = 1],
11074
* and even not the usage of position() in
11075
* "[position() = 1]"; thus - obviously - a position-range,
11076
* like it "[position() < 5]", is also not detected.
11077
* Maybe we could rewrite the AST to ease the optimization.
11078
*/
11079
11080
if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
11081
*maxPos = (int) floatval;
11082
if (floatval == (double) *maxPos)
11083
return(1);
11084
}
11085
}
11086
return(0);
11087
}
11088
11089
static int
11090
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
11091
xmlXPathStepOpPtr op,
11092
xmlNodePtr * first, xmlNodePtr * last,
11093
int toBool)
11094
{
11095
11096
#define XP_TEST_HIT \
11097
if (hasAxisRange != 0) { \
11098
if (++pos == maxPos) { \
11099
if (addNode(seq, cur) < 0) \
11100
ctxt->error = XPATH_MEMORY_ERROR; \
11101
goto axis_range_end; } \
11102
} else { \
11103
if (addNode(seq, cur) < 0) \
11104
ctxt->error = XPATH_MEMORY_ERROR; \
11105
if (breakOnFirstHit) goto first_hit; }
11106
11107
#define XP_TEST_HIT_NS \
11108
if (hasAxisRange != 0) { \
11109
if (++pos == maxPos) { \
11110
hasNsNodes = 1; \
11111
if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11112
ctxt->error = XPATH_MEMORY_ERROR; \
11113
goto axis_range_end; } \
11114
} else { \
11115
hasNsNodes = 1; \
11116
if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
11117
ctxt->error = XPATH_MEMORY_ERROR; \
11118
if (breakOnFirstHit) goto first_hit; }
11119
11120
xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
11121
xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
11122
xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
11123
const xmlChar *prefix = op->value4;
11124
const xmlChar *name = op->value5;
11125
const xmlChar *URI = NULL;
11126
11127
int total = 0, hasNsNodes = 0;
11128
/* The popped object holding the context nodes */
11129
xmlXPathObjectPtr obj;
11130
/* The set of context nodes for the node tests */
11131
xmlNodeSetPtr contextSeq;
11132
int contextIdx;
11133
xmlNodePtr contextNode;
11134
/* The final resulting node set wrt to all context nodes */
11135
xmlNodeSetPtr outSeq;
11136
/*
11137
* The temporary resulting node set wrt 1 context node.
11138
* Used to feed predicate evaluation.
11139
*/
11140
xmlNodeSetPtr seq;
11141
xmlNodePtr cur;
11142
/* First predicate operator */
11143
xmlXPathStepOpPtr predOp;
11144
int maxPos; /* The requested position() (when a "[n]" predicate) */
11145
int hasPredicateRange, hasAxisRange, pos;
11146
int breakOnFirstHit;
11147
11148
xmlXPathTraversalFunction next = NULL;
11149
int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
11150
xmlXPathNodeSetMergeFunction mergeAndClear;
11151
xmlNodePtr oldContextNode;
11152
xmlXPathContextPtr xpctxt = ctxt->context;
11153
11154
11155
CHECK_TYPE0(XPATH_NODESET);
11156
obj = valuePop(ctxt);
11157
/*
11158
* Setup namespaces.
11159
*/
11160
if (prefix != NULL) {
11161
URI = xmlXPathNsLookup(xpctxt, prefix);
11162
if (URI == NULL) {
11163
xmlXPathReleaseObject(xpctxt, obj);
11164
XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11165
}
11166
}
11167
/*
11168
* Setup axis.
11169
*
11170
* MAYBE FUTURE TODO: merging optimizations:
11171
* - If the nodes to be traversed wrt to the initial nodes and
11172
* the current axis cannot overlap, then we could avoid searching
11173
* for duplicates during the merge.
11174
* But the question is how/when to evaluate if they cannot overlap.
11175
* Example: if we know that for two initial nodes, the one is
11176
* not in the ancestor-or-self axis of the other, then we could safely
11177
* avoid a duplicate-aware merge, if the axis to be traversed is e.g.
11178
* the descendant-or-self axis.
11179
*/
11180
mergeAndClear = xmlXPathNodeSetMergeAndClear;
11181
switch (axis) {
11182
case AXIS_ANCESTOR:
11183
first = NULL;
11184
next = xmlXPathNextAncestor;
11185
break;
11186
case AXIS_ANCESTOR_OR_SELF:
11187
first = NULL;
11188
next = xmlXPathNextAncestorOrSelf;
11189
break;
11190
case AXIS_ATTRIBUTE:
11191
first = NULL;
11192
last = NULL;
11193
next = xmlXPathNextAttribute;
11194
mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11195
break;
11196
case AXIS_CHILD:
11197
last = NULL;
11198
if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
11199
(type == NODE_TYPE_NODE))
11200
{
11201
/*
11202
* Optimization if an element node type is 'element'.
11203
*/
11204
next = xmlXPathNextChildElement;
11205
} else
11206
next = xmlXPathNextChild;
11207
mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11208
break;
11209
case AXIS_DESCENDANT:
11210
last = NULL;
11211
next = xmlXPathNextDescendant;
11212
break;
11213
case AXIS_DESCENDANT_OR_SELF:
11214
last = NULL;
11215
next = xmlXPathNextDescendantOrSelf;
11216
break;
11217
case AXIS_FOLLOWING:
11218
last = NULL;
11219
next = xmlXPathNextFollowing;
11220
break;
11221
case AXIS_FOLLOWING_SIBLING:
11222
last = NULL;
11223
next = xmlXPathNextFollowingSibling;
11224
break;
11225
case AXIS_NAMESPACE:
11226
first = NULL;
11227
last = NULL;
11228
next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
11229
mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11230
break;
11231
case AXIS_PARENT:
11232
first = NULL;
11233
next = xmlXPathNextParent;
11234
break;
11235
case AXIS_PRECEDING:
11236
first = NULL;
11237
next = xmlXPathNextPrecedingInternal;
11238
break;
11239
case AXIS_PRECEDING_SIBLING:
11240
first = NULL;
11241
next = xmlXPathNextPrecedingSibling;
11242
break;
11243
case AXIS_SELF:
11244
first = NULL;
11245
last = NULL;
11246
next = xmlXPathNextSelf;
11247
mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
11248
break;
11249
}
11250
11251
if (next == NULL) {
11252
xmlXPathReleaseObject(xpctxt, obj);
11253
return(0);
11254
}
11255
contextSeq = obj->nodesetval;
11256
if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
11257
xmlXPathReleaseObject(xpctxt, obj);
11258
valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
11259
return(0);
11260
}
11261
/*
11262
* Predicate optimization ---------------------------------------------
11263
* If this step has a last predicate, which contains a position(),
11264
* then we'll optimize (although not exactly "position()", but only
11265
* the short-hand form, i.e., "[n]".
11266
*
11267
* Example - expression "/foo[parent::bar][1]":
11268
*
11269
* COLLECT 'child' 'name' 'node' foo -- op (we are here)
11270
* ROOT -- op->ch1
11271
* PREDICATE -- op->ch2 (predOp)
11272
* PREDICATE -- predOp->ch1 = [parent::bar]
11273
* SORT
11274
* COLLECT 'parent' 'name' 'node' bar
11275
* NODE
11276
* ELEM Object is a number : 1 -- predOp->ch2 = [1]
11277
*
11278
*/
11279
maxPos = 0;
11280
predOp = NULL;
11281
hasPredicateRange = 0;
11282
hasAxisRange = 0;
11283
if (op->ch2 != -1) {
11284
/*
11285
* There's at least one predicate. 16 == XPATH_OP_PREDICATE
11286
*/
11287
predOp = &ctxt->comp->steps[op->ch2];
11288
if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
11289
if (predOp->ch1 != -1) {
11290
/*
11291
* Use the next inner predicate operator.
11292
*/
11293
predOp = &ctxt->comp->steps[predOp->ch1];
11294
hasPredicateRange = 1;
11295
} else {
11296
/*
11297
* There's no other predicate than the [n] predicate.
11298
*/
11299
predOp = NULL;
11300
hasAxisRange = 1;
11301
}
11302
}
11303
}
11304
breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
11305
/*
11306
* Axis traversal -----------------------------------------------------
11307
*/
11308
/*
11309
* 2.3 Node Tests
11310
* - For the attribute axis, the principal node type is attribute.
11311
* - For the namespace axis, the principal node type is namespace.
11312
* - For other axes, the principal node type is element.
11313
*
11314
* A node test * is true for any node of the
11315
* principal node type. For example, child::* will
11316
* select all element children of the context node
11317
*/
11318
oldContextNode = xpctxt->node;
11319
addNode = xmlXPathNodeSetAddUnique;
11320
outSeq = NULL;
11321
seq = NULL;
11322
contextNode = NULL;
11323
contextIdx = 0;
11324
11325
11326
while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
11327
(ctxt->error == XPATH_EXPRESSION_OK)) {
11328
xpctxt->node = contextSeq->nodeTab[contextIdx++];
11329
11330
if (seq == NULL) {
11331
seq = xmlXPathNodeSetCreate(NULL);
11332
if (seq == NULL) {
11333
/* TODO: Propagate memory error. */
11334
total = 0;
11335
goto error;
11336
}
11337
}
11338
/*
11339
* Traverse the axis and test the nodes.
11340
*/
11341
pos = 0;
11342
cur = NULL;
11343
hasNsNodes = 0;
11344
do {
11345
if (OP_LIMIT_EXCEEDED(ctxt, 1))
11346
goto error;
11347
11348
cur = next(ctxt, cur);
11349
if (cur == NULL)
11350
break;
11351
11352
/*
11353
* QUESTION TODO: What does the "first" and "last" stuff do?
11354
*/
11355
if ((first != NULL) && (*first != NULL)) {
11356
if (*first == cur)
11357
break;
11358
if (((total % 256) == 0) &&
11359
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11360
(xmlXPathCmpNodesExt(*first, cur) >= 0))
11361
#else
11362
(xmlXPathCmpNodes(*first, cur) >= 0))
11363
#endif
11364
{
11365
break;
11366
}
11367
}
11368
if ((last != NULL) && (*last != NULL)) {
11369
if (*last == cur)
11370
break;
11371
if (((total % 256) == 0) &&
11372
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
11373
(xmlXPathCmpNodesExt(cur, *last) >= 0))
11374
#else
11375
(xmlXPathCmpNodes(cur, *last) >= 0))
11376
#endif
11377
{
11378
break;
11379
}
11380
}
11381
11382
total++;
11383
11384
switch (test) {
11385
case NODE_TEST_NONE:
11386
total = 0;
11387
STRANGE
11388
goto error;
11389
case NODE_TEST_TYPE:
11390
if (type == NODE_TYPE_NODE) {
11391
switch (cur->type) {
11392
case XML_DOCUMENT_NODE:
11393
case XML_HTML_DOCUMENT_NODE:
11394
case XML_ELEMENT_NODE:
11395
case XML_ATTRIBUTE_NODE:
11396
case XML_PI_NODE:
11397
case XML_COMMENT_NODE:
11398
case XML_CDATA_SECTION_NODE:
11399
case XML_TEXT_NODE:
11400
XP_TEST_HIT
11401
break;
11402
case XML_NAMESPACE_DECL: {
11403
if (axis == AXIS_NAMESPACE) {
11404
XP_TEST_HIT_NS
11405
} else {
11406
hasNsNodes = 1;
11407
XP_TEST_HIT
11408
}
11409
break;
11410
}
11411
default:
11412
break;
11413
}
11414
} else if (cur->type == (xmlElementType) type) {
11415
if (cur->type == XML_NAMESPACE_DECL)
11416
XP_TEST_HIT_NS
11417
else
11418
XP_TEST_HIT
11419
} else if ((type == NODE_TYPE_TEXT) &&
11420
(cur->type == XML_CDATA_SECTION_NODE))
11421
{
11422
XP_TEST_HIT
11423
}
11424
break;
11425
case NODE_TEST_PI:
11426
if ((cur->type == XML_PI_NODE) &&
11427
((name == NULL) || xmlStrEqual(name, cur->name)))
11428
{
11429
XP_TEST_HIT
11430
}
11431
break;
11432
case NODE_TEST_ALL:
11433
if (axis == AXIS_ATTRIBUTE) {
11434
if (cur->type == XML_ATTRIBUTE_NODE)
11435
{
11436
if (prefix == NULL)
11437
{
11438
XP_TEST_HIT
11439
} else if ((cur->ns != NULL) &&
11440
(xmlStrEqual(URI, cur->ns->href)))
11441
{
11442
XP_TEST_HIT
11443
}
11444
}
11445
} else if (axis == AXIS_NAMESPACE) {
11446
if (cur->type == XML_NAMESPACE_DECL)
11447
{
11448
XP_TEST_HIT_NS
11449
}
11450
} else {
11451
if (cur->type == XML_ELEMENT_NODE) {
11452
if (prefix == NULL)
11453
{
11454
XP_TEST_HIT
11455
11456
} else if ((cur->ns != NULL) &&
11457
(xmlStrEqual(URI, cur->ns->href)))
11458
{
11459
XP_TEST_HIT
11460
}
11461
}
11462
}
11463
break;
11464
case NODE_TEST_NS:{
11465
TODO;
11466
break;
11467
}
11468
case NODE_TEST_NAME:
11469
if (axis == AXIS_ATTRIBUTE) {
11470
if (cur->type != XML_ATTRIBUTE_NODE)
11471
break;
11472
} else if (axis == AXIS_NAMESPACE) {
11473
if (cur->type != XML_NAMESPACE_DECL)
11474
break;
11475
} else {
11476
if (cur->type != XML_ELEMENT_NODE)
11477
break;
11478
}
11479
switch (cur->type) {
11480
case XML_ELEMENT_NODE:
11481
if (xmlStrEqual(name, cur->name)) {
11482
if (prefix == NULL) {
11483
if (cur->ns == NULL)
11484
{
11485
XP_TEST_HIT
11486
}
11487
} else {
11488
if ((cur->ns != NULL) &&
11489
(xmlStrEqual(URI, cur->ns->href)))
11490
{
11491
XP_TEST_HIT
11492
}
11493
}
11494
}
11495
break;
11496
case XML_ATTRIBUTE_NODE:{
11497
xmlAttrPtr attr = (xmlAttrPtr) cur;
11498
11499
if (xmlStrEqual(name, attr->name)) {
11500
if (prefix == NULL) {
11501
if ((attr->ns == NULL) ||
11502
(attr->ns->prefix == NULL))
11503
{
11504
XP_TEST_HIT
11505
}
11506
} else {
11507
if ((attr->ns != NULL) &&
11508
(xmlStrEqual(URI,
11509
attr->ns->href)))
11510
{
11511
XP_TEST_HIT
11512
}
11513
}
11514
}
11515
break;
11516
}
11517
case XML_NAMESPACE_DECL:
11518
if (cur->type == XML_NAMESPACE_DECL) {
11519
xmlNsPtr ns = (xmlNsPtr) cur;
11520
11521
if ((ns->prefix != NULL) && (name != NULL)
11522
&& (xmlStrEqual(ns->prefix, name)))
11523
{
11524
XP_TEST_HIT_NS
11525
}
11526
}
11527
break;
11528
default:
11529
break;
11530
}
11531
break;
11532
} /* switch(test) */
11533
} while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
11534
11535
goto apply_predicates;
11536
11537
axis_range_end: /* ----------------------------------------------------- */
11538
/*
11539
* We have a "/foo[n]", and position() = n was reached.
11540
* Note that we can have as well "/foo/::parent::foo[1]", so
11541
* a duplicate-aware merge is still needed.
11542
* Merge with the result.
11543
*/
11544
if (outSeq == NULL) {
11545
outSeq = seq;
11546
seq = NULL;
11547
} else
11548
/* TODO: Check memory error. */
11549
outSeq = mergeAndClear(outSeq, seq);
11550
/*
11551
* Break if only a true/false result was requested.
11552
*/
11553
if (toBool)
11554
break;
11555
continue;
11556
11557
first_hit: /* ---------------------------------------------------------- */
11558
/*
11559
* Break if only a true/false result was requested and
11560
* no predicates existed and a node test succeeded.
11561
*/
11562
if (outSeq == NULL) {
11563
outSeq = seq;
11564
seq = NULL;
11565
} else
11566
/* TODO: Check memory error. */
11567
outSeq = mergeAndClear(outSeq, seq);
11568
break;
11569
11570
apply_predicates: /* --------------------------------------------------- */
11571
if (ctxt->error != XPATH_EXPRESSION_OK)
11572
goto error;
11573
11574
/*
11575
* Apply predicates.
11576
*/
11577
if ((predOp != NULL) && (seq->nodeNr > 0)) {
11578
/*
11579
* E.g. when we have a "/foo[some expression][n]".
11580
*/
11581
/*
11582
* QUESTION TODO: The old predicate evaluation took into
11583
* account location-sets.
11584
* (E.g. ctxt->value->type == XPATH_LOCATIONSET)
11585
* Do we expect such a set here?
11586
* All what I learned now from the evaluation semantics
11587
* does not indicate that a location-set will be processed
11588
* here, so this looks OK.
11589
*/
11590
/*
11591
* Iterate over all predicates, starting with the outermost
11592
* predicate.
11593
* TODO: Problem: we cannot execute the inner predicates first
11594
* since we cannot go back *up* the operator tree!
11595
* Options we have:
11596
* 1) Use of recursive functions (like is it currently done
11597
* via xmlXPathCompOpEval())
11598
* 2) Add a predicate evaluation information stack to the
11599
* context struct
11600
* 3) Change the way the operators are linked; we need a
11601
* "parent" field on xmlXPathStepOp
11602
*
11603
* For the moment, I'll try to solve this with a recursive
11604
* function: xmlXPathCompOpEvalPredicate().
11605
*/
11606
if (hasPredicateRange != 0)
11607
xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
11608
hasNsNodes);
11609
else
11610
xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
11611
hasNsNodes);
11612
11613
if (ctxt->error != XPATH_EXPRESSION_OK) {
11614
total = 0;
11615
goto error;
11616
}
11617
}
11618
11619
if (seq->nodeNr > 0) {
11620
/*
11621
* Add to result set.
11622
*/
11623
if (outSeq == NULL) {
11624
outSeq = seq;
11625
seq = NULL;
11626
} else {
11627
/* TODO: Check memory error. */
11628
outSeq = mergeAndClear(outSeq, seq);
11629
}
11630
11631
if (toBool)
11632
break;
11633
}
11634
}
11635
11636
error:
11637
if ((obj->boolval) && (obj->user != NULL)) {
11638
/*
11639
* QUESTION TODO: What does this do and why?
11640
* TODO: Do we have to do this also for the "error"
11641
* cleanup further down?
11642
*/
11643
ctxt->value->boolval = 1;
11644
ctxt->value->user = obj->user;
11645
obj->user = NULL;
11646
obj->boolval = 0;
11647
}
11648
xmlXPathReleaseObject(xpctxt, obj);
11649
11650
/*
11651
* Ensure we return at least an empty set.
11652
*/
11653
if (outSeq == NULL) {
11654
if ((seq != NULL) && (seq->nodeNr == 0))
11655
outSeq = seq;
11656
else
11657
/* TODO: Check memory error. */
11658
outSeq = xmlXPathNodeSetCreate(NULL);
11659
}
11660
if ((seq != NULL) && (seq != outSeq)) {
11661
xmlXPathFreeNodeSet(seq);
11662
}
11663
/*
11664
* Hand over the result. Better to push the set also in
11665
* case of errors.
11666
*/
11667
valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
11668
/*
11669
* Reset the context node.
11670
*/
11671
xpctxt->node = oldContextNode;
11672
/*
11673
* When traversing the namespace axis in "toBool" mode, it's
11674
* possible that tmpNsList wasn't freed.
11675
*/
11676
if (xpctxt->tmpNsList != NULL) {
11677
xmlFree(xpctxt->tmpNsList);
11678
xpctxt->tmpNsList = NULL;
11679
}
11680
11681
return(total);
11682
}
11683
11684
static int
11685
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11686
xmlXPathStepOpPtr op, xmlNodePtr * first);
11687
11688
/**
11689
* xmlXPathCompOpEvalFirst:
11690
* @ctxt: the XPath parser context with the compiled expression
11691
* @op: an XPath compiled operation
11692
* @first: the first elem found so far
11693
*
11694
* Evaluate the Precompiled XPath operation searching only the first
11695
* element in document order
11696
*
11697
* Returns the number of examined objects.
11698
*/
11699
static int
11700
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
11701
xmlXPathStepOpPtr op, xmlNodePtr * first)
11702
{
11703
int total = 0, cur;
11704
xmlXPathCompExprPtr comp;
11705
xmlXPathObjectPtr arg1, arg2;
11706
11707
CHECK_ERROR0;
11708
if (OP_LIMIT_EXCEEDED(ctxt, 1))
11709
return(0);
11710
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11711
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11712
ctxt->context->depth += 1;
11713
comp = ctxt->comp;
11714
switch (op->op) {
11715
case XPATH_OP_END:
11716
break;
11717
case XPATH_OP_UNION:
11718
total =
11719
xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11720
first);
11721
CHECK_ERROR0;
11722
if ((ctxt->value != NULL)
11723
&& (ctxt->value->type == XPATH_NODESET)
11724
&& (ctxt->value->nodesetval != NULL)
11725
&& (ctxt->value->nodesetval->nodeNr >= 1)) {
11726
/*
11727
* limit tree traversing to first node in the result
11728
*/
11729
/*
11730
* OPTIMIZE TODO: This implicitly sorts
11731
* the result, even if not needed. E.g. if the argument
11732
* of the count() function, no sorting is needed.
11733
* OPTIMIZE TODO: How do we know if the node-list wasn't
11734
* already sorted?
11735
*/
11736
if (ctxt->value->nodesetval->nodeNr > 1)
11737
xmlXPathNodeSetSort(ctxt->value->nodesetval);
11738
*first = ctxt->value->nodesetval->nodeTab[0];
11739
}
11740
cur =
11741
xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
11742
first);
11743
CHECK_ERROR0;
11744
11745
arg2 = valuePop(ctxt);
11746
arg1 = valuePop(ctxt);
11747
if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11748
(arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11749
xmlXPathReleaseObject(ctxt->context, arg1);
11750
xmlXPathReleaseObject(ctxt->context, arg2);
11751
XP_ERROR0(XPATH_INVALID_TYPE);
11752
}
11753
if ((ctxt->context->opLimit != 0) &&
11754
(((arg1->nodesetval != NULL) &&
11755
(xmlXPathCheckOpLimit(ctxt,
11756
arg1->nodesetval->nodeNr) < 0)) ||
11757
((arg2->nodesetval != NULL) &&
11758
(xmlXPathCheckOpLimit(ctxt,
11759
arg2->nodesetval->nodeNr) < 0)))) {
11760
xmlXPathReleaseObject(ctxt->context, arg1);
11761
xmlXPathReleaseObject(ctxt->context, arg2);
11762
break;
11763
}
11764
11765
/* TODO: Check memory error. */
11766
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11767
arg2->nodesetval);
11768
valuePush(ctxt, arg1);
11769
xmlXPathReleaseObject(ctxt->context, arg2);
11770
/* optimizer */
11771
if (total > cur)
11772
xmlXPathCompSwap(op);
11773
total += cur;
11774
break;
11775
case XPATH_OP_ROOT:
11776
xmlXPathRoot(ctxt);
11777
break;
11778
case XPATH_OP_NODE:
11779
if (op->ch1 != -1)
11780
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11781
CHECK_ERROR0;
11782
if (op->ch2 != -1)
11783
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11784
CHECK_ERROR0;
11785
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11786
ctxt->context->node));
11787
break;
11788
case XPATH_OP_COLLECT:{
11789
if (op->ch1 == -1)
11790
break;
11791
11792
total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11793
CHECK_ERROR0;
11794
11795
total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
11796
break;
11797
}
11798
case XPATH_OP_VALUE:
11799
valuePush(ctxt,
11800
xmlXPathCacheObjectCopy(ctxt->context,
11801
(xmlXPathObjectPtr) op->value4));
11802
break;
11803
case XPATH_OP_SORT:
11804
if (op->ch1 != -1)
11805
total +=
11806
xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
11807
first);
11808
CHECK_ERROR0;
11809
if ((ctxt->value != NULL)
11810
&& (ctxt->value->type == XPATH_NODESET)
11811
&& (ctxt->value->nodesetval != NULL)
11812
&& (ctxt->value->nodesetval->nodeNr > 1))
11813
xmlXPathNodeSetSort(ctxt->value->nodesetval);
11814
break;
11815
#ifdef XP_OPTIMIZED_FILTER_FIRST
11816
case XPATH_OP_FILTER:
11817
total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
11818
break;
11819
#endif
11820
default:
11821
total += xmlXPathCompOpEval(ctxt, op);
11822
break;
11823
}
11824
11825
ctxt->context->depth -= 1;
11826
return(total);
11827
}
11828
11829
/**
11830
* xmlXPathCompOpEvalLast:
11831
* @ctxt: the XPath parser context with the compiled expression
11832
* @op: an XPath compiled operation
11833
* @last: the last elem found so far
11834
*
11835
* Evaluate the Precompiled XPath operation searching only the last
11836
* element in document order
11837
*
11838
* Returns the number of nodes traversed
11839
*/
11840
static int
11841
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
11842
xmlNodePtr * last)
11843
{
11844
int total = 0, cur;
11845
xmlXPathCompExprPtr comp;
11846
xmlXPathObjectPtr arg1, arg2;
11847
11848
CHECK_ERROR0;
11849
if (OP_LIMIT_EXCEEDED(ctxt, 1))
11850
return(0);
11851
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
11852
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
11853
ctxt->context->depth += 1;
11854
comp = ctxt->comp;
11855
switch (op->op) {
11856
case XPATH_OP_END:
11857
break;
11858
case XPATH_OP_UNION:
11859
total =
11860
xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
11861
CHECK_ERROR0;
11862
if ((ctxt->value != NULL)
11863
&& (ctxt->value->type == XPATH_NODESET)
11864
&& (ctxt->value->nodesetval != NULL)
11865
&& (ctxt->value->nodesetval->nodeNr >= 1)) {
11866
/*
11867
* limit tree traversing to first node in the result
11868
*/
11869
if (ctxt->value->nodesetval->nodeNr > 1)
11870
xmlXPathNodeSetSort(ctxt->value->nodesetval);
11871
*last =
11872
ctxt->value->nodesetval->nodeTab[ctxt->value->
11873
nodesetval->nodeNr -
11874
1];
11875
}
11876
cur =
11877
xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
11878
CHECK_ERROR0;
11879
if ((ctxt->value != NULL)
11880
&& (ctxt->value->type == XPATH_NODESET)
11881
&& (ctxt->value->nodesetval != NULL)
11882
&& (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
11883
}
11884
11885
arg2 = valuePop(ctxt);
11886
arg1 = valuePop(ctxt);
11887
if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
11888
(arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
11889
xmlXPathReleaseObject(ctxt->context, arg1);
11890
xmlXPathReleaseObject(ctxt->context, arg2);
11891
XP_ERROR0(XPATH_INVALID_TYPE);
11892
}
11893
if ((ctxt->context->opLimit != 0) &&
11894
(((arg1->nodesetval != NULL) &&
11895
(xmlXPathCheckOpLimit(ctxt,
11896
arg1->nodesetval->nodeNr) < 0)) ||
11897
((arg2->nodesetval != NULL) &&
11898
(xmlXPathCheckOpLimit(ctxt,
11899
arg2->nodesetval->nodeNr) < 0)))) {
11900
xmlXPathReleaseObject(ctxt->context, arg1);
11901
xmlXPathReleaseObject(ctxt->context, arg2);
11902
break;
11903
}
11904
11905
/* TODO: Check memory error. */
11906
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
11907
arg2->nodesetval);
11908
valuePush(ctxt, arg1);
11909
xmlXPathReleaseObject(ctxt->context, arg2);
11910
/* optimizer */
11911
if (total > cur)
11912
xmlXPathCompSwap(op);
11913
total += cur;
11914
break;
11915
case XPATH_OP_ROOT:
11916
xmlXPathRoot(ctxt);
11917
break;
11918
case XPATH_OP_NODE:
11919
if (op->ch1 != -1)
11920
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11921
CHECK_ERROR0;
11922
if (op->ch2 != -1)
11923
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
11924
CHECK_ERROR0;
11925
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
11926
ctxt->context->node));
11927
break;
11928
case XPATH_OP_COLLECT:{
11929
if (op->ch1 == -1)
11930
break;
11931
11932
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
11933
CHECK_ERROR0;
11934
11935
total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
11936
break;
11937
}
11938
case XPATH_OP_VALUE:
11939
valuePush(ctxt,
11940
xmlXPathCacheObjectCopy(ctxt->context,
11941
(xmlXPathObjectPtr) op->value4));
11942
break;
11943
case XPATH_OP_SORT:
11944
if (op->ch1 != -1)
11945
total +=
11946
xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
11947
last);
11948
CHECK_ERROR0;
11949
if ((ctxt->value != NULL)
11950
&& (ctxt->value->type == XPATH_NODESET)
11951
&& (ctxt->value->nodesetval != NULL)
11952
&& (ctxt->value->nodesetval->nodeNr > 1))
11953
xmlXPathNodeSetSort(ctxt->value->nodesetval);
11954
break;
11955
default:
11956
total += xmlXPathCompOpEval(ctxt, op);
11957
break;
11958
}
11959
11960
ctxt->context->depth -= 1;
11961
return (total);
11962
}
11963
11964
#ifdef XP_OPTIMIZED_FILTER_FIRST
11965
static int
11966
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
11967
xmlXPathStepOpPtr op, xmlNodePtr * first)
11968
{
11969
int total = 0;
11970
xmlXPathCompExprPtr comp;
11971
xmlXPathObjectPtr obj;
11972
xmlNodeSetPtr set;
11973
11974
CHECK_ERROR0;
11975
comp = ctxt->comp;
11976
/*
11977
* Optimization for ()[last()] selection i.e. the last elem
11978
*/
11979
if ((op->ch1 != -1) && (op->ch2 != -1) &&
11980
(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
11981
(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
11982
int f = comp->steps[op->ch2].ch1;
11983
11984
if ((f != -1) &&
11985
(comp->steps[f].op == XPATH_OP_FUNCTION) &&
11986
(comp->steps[f].value5 == NULL) &&
11987
(comp->steps[f].value == 0) &&
11988
(comp->steps[f].value4 != NULL) &&
11989
(xmlStrEqual
11990
(comp->steps[f].value4, BAD_CAST "last"))) {
11991
xmlNodePtr last = NULL;
11992
11993
total +=
11994
xmlXPathCompOpEvalLast(ctxt,
11995
&comp->steps[op->ch1],
11996
&last);
11997
CHECK_ERROR0;
11998
/*
11999
* The nodeset should be in document order,
12000
* Keep only the last value
12001
*/
12002
if ((ctxt->value != NULL) &&
12003
(ctxt->value->type == XPATH_NODESET) &&
12004
(ctxt->value->nodesetval != NULL) &&
12005
(ctxt->value->nodesetval->nodeTab != NULL) &&
12006
(ctxt->value->nodesetval->nodeNr > 1)) {
12007
xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12008
*first = *(ctxt->value->nodesetval->nodeTab);
12009
}
12010
return (total);
12011
}
12012
}
12013
12014
if (op->ch1 != -1)
12015
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12016
CHECK_ERROR0;
12017
if (op->ch2 == -1)
12018
return (total);
12019
if (ctxt->value == NULL)
12020
return (total);
12021
12022
#ifdef LIBXML_XPTR_LOCS_ENABLED
12023
/*
12024
* Hum are we filtering the result of an XPointer expression
12025
*/
12026
if (ctxt->value->type == XPATH_LOCATIONSET) {
12027
xmlLocationSetPtr locset = ctxt->value->user;
12028
12029
if (locset != NULL) {
12030
xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
12031
if (locset->locNr > 0)
12032
*first = (xmlNodePtr) locset->locTab[0]->user;
12033
}
12034
12035
return (total);
12036
}
12037
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12038
12039
/*
12040
* In case of errors, xmlXPathNodeSetFilter can pop additional nodes from
12041
* the stack. We have to temporarily remove the nodeset object from the
12042
* stack to avoid freeing it prematurely.
12043
*/
12044
CHECK_TYPE0(XPATH_NODESET);
12045
obj = valuePop(ctxt);
12046
set = obj->nodesetval;
12047
if (set != NULL) {
12048
xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
12049
if (set->nodeNr > 0)
12050
*first = set->nodeTab[0];
12051
}
12052
valuePush(ctxt, obj);
12053
12054
return (total);
12055
}
12056
#endif /* XP_OPTIMIZED_FILTER_FIRST */
12057
12058
/**
12059
* xmlXPathCompOpEval:
12060
* @ctxt: the XPath parser context with the compiled expression
12061
* @op: an XPath compiled operation
12062
*
12063
* Evaluate the Precompiled XPath operation
12064
* Returns the number of nodes traversed
12065
*/
12066
static int
12067
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
12068
{
12069
int total = 0;
12070
int equal, ret;
12071
xmlXPathCompExprPtr comp;
12072
xmlXPathObjectPtr arg1, arg2;
12073
12074
CHECK_ERROR0;
12075
if (OP_LIMIT_EXCEEDED(ctxt, 1))
12076
return(0);
12077
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
12078
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
12079
ctxt->context->depth += 1;
12080
comp = ctxt->comp;
12081
switch (op->op) {
12082
case XPATH_OP_END:
12083
break;
12084
case XPATH_OP_AND:
12085
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12086
CHECK_ERROR0;
12087
xmlXPathBooleanFunction(ctxt, 1);
12088
if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
12089
break;
12090
arg2 = valuePop(ctxt);
12091
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12092
if (ctxt->error) {
12093
xmlXPathFreeObject(arg2);
12094
break;
12095
}
12096
xmlXPathBooleanFunction(ctxt, 1);
12097
if (ctxt->value != NULL)
12098
ctxt->value->boolval &= arg2->boolval;
12099
xmlXPathReleaseObject(ctxt->context, arg2);
12100
break;
12101
case XPATH_OP_OR:
12102
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12103
CHECK_ERROR0;
12104
xmlXPathBooleanFunction(ctxt, 1);
12105
if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
12106
break;
12107
arg2 = valuePop(ctxt);
12108
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12109
if (ctxt->error) {
12110
xmlXPathFreeObject(arg2);
12111
break;
12112
}
12113
xmlXPathBooleanFunction(ctxt, 1);
12114
if (ctxt->value != NULL)
12115
ctxt->value->boolval |= arg2->boolval;
12116
xmlXPathReleaseObject(ctxt->context, arg2);
12117
break;
12118
case XPATH_OP_EQUAL:
12119
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12120
CHECK_ERROR0;
12121
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12122
CHECK_ERROR0;
12123
if (op->value)
12124
equal = xmlXPathEqualValues(ctxt);
12125
else
12126
equal = xmlXPathNotEqualValues(ctxt);
12127
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
12128
break;
12129
case XPATH_OP_CMP:
12130
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12131
CHECK_ERROR0;
12132
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12133
CHECK_ERROR0;
12134
ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
12135
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
12136
break;
12137
case XPATH_OP_PLUS:
12138
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12139
CHECK_ERROR0;
12140
if (op->ch2 != -1) {
12141
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12142
}
12143
CHECK_ERROR0;
12144
if (op->value == 0)
12145
xmlXPathSubValues(ctxt);
12146
else if (op->value == 1)
12147
xmlXPathAddValues(ctxt);
12148
else if (op->value == 2)
12149
xmlXPathValueFlipSign(ctxt);
12150
else if (op->value == 3) {
12151
CAST_TO_NUMBER;
12152
CHECK_TYPE0(XPATH_NUMBER);
12153
}
12154
break;
12155
case XPATH_OP_MULT:
12156
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12157
CHECK_ERROR0;
12158
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12159
CHECK_ERROR0;
12160
if (op->value == 0)
12161
xmlXPathMultValues(ctxt);
12162
else if (op->value == 1)
12163
xmlXPathDivValues(ctxt);
12164
else if (op->value == 2)
12165
xmlXPathModValues(ctxt);
12166
break;
12167
case XPATH_OP_UNION:
12168
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12169
CHECK_ERROR0;
12170
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12171
CHECK_ERROR0;
12172
12173
arg2 = valuePop(ctxt);
12174
arg1 = valuePop(ctxt);
12175
if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12176
(arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12177
xmlXPathReleaseObject(ctxt->context, arg1);
12178
xmlXPathReleaseObject(ctxt->context, arg2);
12179
XP_ERROR0(XPATH_INVALID_TYPE);
12180
}
12181
if ((ctxt->context->opLimit != 0) &&
12182
(((arg1->nodesetval != NULL) &&
12183
(xmlXPathCheckOpLimit(ctxt,
12184
arg1->nodesetval->nodeNr) < 0)) ||
12185
((arg2->nodesetval != NULL) &&
12186
(xmlXPathCheckOpLimit(ctxt,
12187
arg2->nodesetval->nodeNr) < 0)))) {
12188
xmlXPathReleaseObject(ctxt->context, arg1);
12189
xmlXPathReleaseObject(ctxt->context, arg2);
12190
break;
12191
}
12192
12193
if ((arg1->nodesetval == NULL) ||
12194
((arg2->nodesetval != NULL) &&
12195
(arg2->nodesetval->nodeNr != 0)))
12196
{
12197
/* TODO: Check memory error. */
12198
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12199
arg2->nodesetval);
12200
}
12201
12202
valuePush(ctxt, arg1);
12203
xmlXPathReleaseObject(ctxt->context, arg2);
12204
break;
12205
case XPATH_OP_ROOT:
12206
xmlXPathRoot(ctxt);
12207
break;
12208
case XPATH_OP_NODE:
12209
if (op->ch1 != -1)
12210
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12211
CHECK_ERROR0;
12212
if (op->ch2 != -1)
12213
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12214
CHECK_ERROR0;
12215
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12216
ctxt->context->node));
12217
break;
12218
case XPATH_OP_COLLECT:{
12219
if (op->ch1 == -1)
12220
break;
12221
12222
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12223
CHECK_ERROR0;
12224
12225
total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
12226
break;
12227
}
12228
case XPATH_OP_VALUE:
12229
valuePush(ctxt,
12230
xmlXPathCacheObjectCopy(ctxt->context,
12231
(xmlXPathObjectPtr) op->value4));
12232
break;
12233
case XPATH_OP_VARIABLE:{
12234
xmlXPathObjectPtr val;
12235
12236
if (op->ch1 != -1)
12237
total +=
12238
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12239
if (op->value5 == NULL) {
12240
val = xmlXPathVariableLookup(ctxt->context, op->value4);
12241
if (val == NULL)
12242
XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
12243
valuePush(ctxt, val);
12244
} else {
12245
const xmlChar *URI;
12246
12247
URI = xmlXPathNsLookup(ctxt->context, op->value5);
12248
if (URI == NULL) {
12249
xmlGenericError(xmlGenericErrorContext,
12250
"xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
12251
(char *) op->value4, (char *)op->value5);
12252
ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
12253
break;
12254
}
12255
val = xmlXPathVariableLookupNS(ctxt->context,
12256
op->value4, URI);
12257
if (val == NULL)
12258
XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
12259
valuePush(ctxt, val);
12260
}
12261
break;
12262
}
12263
case XPATH_OP_FUNCTION:{
12264
xmlXPathFunction func;
12265
const xmlChar *oldFunc, *oldFuncURI;
12266
int i;
12267
int frame;
12268
12269
frame = ctxt->valueNr;
12270
if (op->ch1 != -1) {
12271
total +=
12272
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12273
if (ctxt->error != XPATH_EXPRESSION_OK)
12274
break;
12275
}
12276
if (ctxt->valueNr < frame + op->value) {
12277
xmlGenericError(xmlGenericErrorContext,
12278
"xmlXPathCompOpEval: parameter error\n");
12279
ctxt->error = XPATH_INVALID_OPERAND;
12280
break;
12281
}
12282
for (i = 0; i < op->value; i++) {
12283
if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
12284
xmlGenericError(xmlGenericErrorContext,
12285
"xmlXPathCompOpEval: parameter error\n");
12286
ctxt->error = XPATH_INVALID_OPERAND;
12287
break;
12288
}
12289
}
12290
if (op->cache != NULL)
12291
func = op->cache;
12292
else {
12293
const xmlChar *URI = NULL;
12294
12295
if (op->value5 == NULL)
12296
func =
12297
xmlXPathFunctionLookup(ctxt->context,
12298
op->value4);
12299
else {
12300
URI = xmlXPathNsLookup(ctxt->context, op->value5);
12301
if (URI == NULL) {
12302
xmlGenericError(xmlGenericErrorContext,
12303
"xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
12304
(char *)op->value4, (char *)op->value5);
12305
ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
12306
break;
12307
}
12308
func = xmlXPathFunctionLookupNS(ctxt->context,
12309
op->value4, URI);
12310
}
12311
if (func == NULL) {
12312
xmlGenericError(xmlGenericErrorContext,
12313
"xmlXPathCompOpEval: function %s not found\n",
12314
(char *)op->value4);
12315
XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
12316
}
12317
op->cache = func;
12318
op->cacheURI = (void *) URI;
12319
}
12320
oldFunc = ctxt->context->function;
12321
oldFuncURI = ctxt->context->functionURI;
12322
ctxt->context->function = op->value4;
12323
ctxt->context->functionURI = op->cacheURI;
12324
func(ctxt, op->value);
12325
ctxt->context->function = oldFunc;
12326
ctxt->context->functionURI = oldFuncURI;
12327
if ((ctxt->error == XPATH_EXPRESSION_OK) &&
12328
(ctxt->valueNr != frame + 1))
12329
XP_ERROR0(XPATH_STACK_ERROR);
12330
break;
12331
}
12332
case XPATH_OP_ARG:
12333
if (op->ch1 != -1) {
12334
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12335
CHECK_ERROR0;
12336
}
12337
if (op->ch2 != -1) {
12338
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12339
CHECK_ERROR0;
12340
}
12341
break;
12342
case XPATH_OP_PREDICATE:
12343
case XPATH_OP_FILTER:{
12344
xmlXPathObjectPtr obj;
12345
xmlNodeSetPtr set;
12346
12347
/*
12348
* Optimization for ()[1] selection i.e. the first elem
12349
*/
12350
if ((op->ch1 != -1) && (op->ch2 != -1) &&
12351
#ifdef XP_OPTIMIZED_FILTER_FIRST
12352
/*
12353
* FILTER TODO: Can we assume that the inner processing
12354
* will result in an ordered list if we have an
12355
* XPATH_OP_FILTER?
12356
* What about an additional field or flag on
12357
* xmlXPathObject like @sorted ? This way we wouldn't need
12358
* to assume anything, so it would be more robust and
12359
* easier to optimize.
12360
*/
12361
((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
12362
(comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
12363
#else
12364
(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12365
#endif
12366
(comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
12367
xmlXPathObjectPtr val;
12368
12369
val = comp->steps[op->ch2].value4;
12370
if ((val != NULL) && (val->type == XPATH_NUMBER) &&
12371
(val->floatval == 1.0)) {
12372
xmlNodePtr first = NULL;
12373
12374
total +=
12375
xmlXPathCompOpEvalFirst(ctxt,
12376
&comp->steps[op->ch1],
12377
&first);
12378
CHECK_ERROR0;
12379
/*
12380
* The nodeset should be in document order,
12381
* Keep only the first value
12382
*/
12383
if ((ctxt->value != NULL) &&
12384
(ctxt->value->type == XPATH_NODESET) &&
12385
(ctxt->value->nodesetval != NULL) &&
12386
(ctxt->value->nodesetval->nodeNr > 1))
12387
xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
12388
1, 1);
12389
break;
12390
}
12391
}
12392
/*
12393
* Optimization for ()[last()] selection i.e. the last elem
12394
*/
12395
if ((op->ch1 != -1) && (op->ch2 != -1) &&
12396
(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
12397
(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
12398
int f = comp->steps[op->ch2].ch1;
12399
12400
if ((f != -1) &&
12401
(comp->steps[f].op == XPATH_OP_FUNCTION) &&
12402
(comp->steps[f].value5 == NULL) &&
12403
(comp->steps[f].value == 0) &&
12404
(comp->steps[f].value4 != NULL) &&
12405
(xmlStrEqual
12406
(comp->steps[f].value4, BAD_CAST "last"))) {
12407
xmlNodePtr last = NULL;
12408
12409
total +=
12410
xmlXPathCompOpEvalLast(ctxt,
12411
&comp->steps[op->ch1],
12412
&last);
12413
CHECK_ERROR0;
12414
/*
12415
* The nodeset should be in document order,
12416
* Keep only the last value
12417
*/
12418
if ((ctxt->value != NULL) &&
12419
(ctxt->value->type == XPATH_NODESET) &&
12420
(ctxt->value->nodesetval != NULL) &&
12421
(ctxt->value->nodesetval->nodeTab != NULL) &&
12422
(ctxt->value->nodesetval->nodeNr > 1))
12423
xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
12424
break;
12425
}
12426
}
12427
/*
12428
* Process inner predicates first.
12429
* Example "index[parent::book][1]":
12430
* ...
12431
* PREDICATE <-- we are here "[1]"
12432
* PREDICATE <-- process "[parent::book]" first
12433
* SORT
12434
* COLLECT 'parent' 'name' 'node' book
12435
* NODE
12436
* ELEM Object is a number : 1
12437
*/
12438
if (op->ch1 != -1)
12439
total +=
12440
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12441
CHECK_ERROR0;
12442
if (op->ch2 == -1)
12443
break;
12444
if (ctxt->value == NULL)
12445
break;
12446
12447
#ifdef LIBXML_XPTR_LOCS_ENABLED
12448
/*
12449
* Hum are we filtering the result of an XPointer expression
12450
*/
12451
if (ctxt->value->type == XPATH_LOCATIONSET) {
12452
xmlLocationSetPtr locset = ctxt->value->user;
12453
xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
12454
1, locset->locNr);
12455
break;
12456
}
12457
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12458
12459
/*
12460
* In case of errors, xmlXPathNodeSetFilter can pop additional
12461
* nodes from the stack. We have to temporarily remove the
12462
* nodeset object from the stack to avoid freeing it
12463
* prematurely.
12464
*/
12465
CHECK_TYPE0(XPATH_NODESET);
12466
obj = valuePop(ctxt);
12467
set = obj->nodesetval;
12468
if (set != NULL)
12469
xmlXPathNodeSetFilter(ctxt, set, op->ch2,
12470
1, set->nodeNr, 1);
12471
valuePush(ctxt, obj);
12472
break;
12473
}
12474
case XPATH_OP_SORT:
12475
if (op->ch1 != -1)
12476
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12477
CHECK_ERROR0;
12478
if ((ctxt->value != NULL) &&
12479
(ctxt->value->type == XPATH_NODESET) &&
12480
(ctxt->value->nodesetval != NULL) &&
12481
(ctxt->value->nodesetval->nodeNr > 1))
12482
{
12483
xmlXPathNodeSetSort(ctxt->value->nodesetval);
12484
}
12485
break;
12486
#ifdef LIBXML_XPTR_LOCS_ENABLED
12487
case XPATH_OP_RANGETO:{
12488
xmlXPathObjectPtr range;
12489
xmlXPathObjectPtr res, obj;
12490
xmlXPathObjectPtr tmp;
12491
xmlLocationSetPtr newlocset = NULL;
12492
xmlLocationSetPtr oldlocset;
12493
xmlNodeSetPtr oldset;
12494
xmlNodePtr oldnode = ctxt->context->node;
12495
int oldcs = ctxt->context->contextSize;
12496
int oldpp = ctxt->context->proximityPosition;
12497
int i, j;
12498
12499
if (op->ch1 != -1) {
12500
total +=
12501
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12502
CHECK_ERROR0;
12503
}
12504
if (ctxt->value == NULL) {
12505
XP_ERROR0(XPATH_INVALID_OPERAND);
12506
}
12507
if (op->ch2 == -1)
12508
break;
12509
12510
if (ctxt->value->type == XPATH_LOCATIONSET) {
12511
/*
12512
* Extract the old locset, and then evaluate the result of the
12513
* expression for all the element in the locset. use it to grow
12514
* up a new locset.
12515
*/
12516
CHECK_TYPE0(XPATH_LOCATIONSET);
12517
12518
if ((ctxt->value->user == NULL) ||
12519
(((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
12520
break;
12521
12522
obj = valuePop(ctxt);
12523
oldlocset = obj->user;
12524
12525
newlocset = xmlXPtrLocationSetCreate(NULL);
12526
12527
for (i = 0; i < oldlocset->locNr; i++) {
12528
/*
12529
* Run the evaluation with a node list made of a
12530
* single item in the nodelocset.
12531
*/
12532
ctxt->context->node = oldlocset->locTab[i]->user;
12533
ctxt->context->contextSize = oldlocset->locNr;
12534
ctxt->context->proximityPosition = i + 1;
12535
tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12536
ctxt->context->node);
12537
valuePush(ctxt, tmp);
12538
12539
if (op->ch2 != -1)
12540
total +=
12541
xmlXPathCompOpEval(ctxt,
12542
&comp->steps[op->ch2]);
12543
if (ctxt->error != XPATH_EXPRESSION_OK) {
12544
xmlXPtrFreeLocationSet(newlocset);
12545
goto rangeto_error;
12546
}
12547
12548
res = valuePop(ctxt);
12549
if (res->type == XPATH_LOCATIONSET) {
12550
xmlLocationSetPtr rloc =
12551
(xmlLocationSetPtr)res->user;
12552
for (j=0; j<rloc->locNr; j++) {
12553
range = xmlXPtrNewRange(
12554
oldlocset->locTab[i]->user,
12555
oldlocset->locTab[i]->index,
12556
rloc->locTab[j]->user2,
12557
rloc->locTab[j]->index2);
12558
if (range != NULL) {
12559
xmlXPtrLocationSetAdd(newlocset, range);
12560
}
12561
}
12562
} else {
12563
range = xmlXPtrNewRangeNodeObject(
12564
(xmlNodePtr)oldlocset->locTab[i]->user, res);
12565
if (range != NULL) {
12566
xmlXPtrLocationSetAdd(newlocset,range);
12567
}
12568
}
12569
12570
/*
12571
* Cleanup
12572
*/
12573
if (res != NULL) {
12574
xmlXPathReleaseObject(ctxt->context, res);
12575
}
12576
if (ctxt->value == tmp) {
12577
res = valuePop(ctxt);
12578
xmlXPathReleaseObject(ctxt->context, res);
12579
}
12580
}
12581
} else { /* Not a location set */
12582
CHECK_TYPE0(XPATH_NODESET);
12583
obj = valuePop(ctxt);
12584
oldset = obj->nodesetval;
12585
12586
newlocset = xmlXPtrLocationSetCreate(NULL);
12587
12588
if (oldset != NULL) {
12589
for (i = 0; i < oldset->nodeNr; i++) {
12590
/*
12591
* Run the evaluation with a node list made of a single item
12592
* in the nodeset.
12593
*/
12594
ctxt->context->node = oldset->nodeTab[i];
12595
/*
12596
* OPTIMIZE TODO: Avoid recreation for every iteration.
12597
*/
12598
tmp = xmlXPathCacheNewNodeSet(ctxt->context,
12599
ctxt->context->node);
12600
valuePush(ctxt, tmp);
12601
12602
if (op->ch2 != -1)
12603
total +=
12604
xmlXPathCompOpEval(ctxt,
12605
&comp->steps[op->ch2]);
12606
if (ctxt->error != XPATH_EXPRESSION_OK) {
12607
xmlXPtrFreeLocationSet(newlocset);
12608
goto rangeto_error;
12609
}
12610
12611
res = valuePop(ctxt);
12612
range =
12613
xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
12614
res);
12615
if (range != NULL) {
12616
xmlXPtrLocationSetAdd(newlocset, range);
12617
}
12618
12619
/*
12620
* Cleanup
12621
*/
12622
if (res != NULL) {
12623
xmlXPathReleaseObject(ctxt->context, res);
12624
}
12625
if (ctxt->value == tmp) {
12626
res = valuePop(ctxt);
12627
xmlXPathReleaseObject(ctxt->context, res);
12628
}
12629
}
12630
}
12631
}
12632
12633
/*
12634
* The result is used as the new evaluation set.
12635
*/
12636
valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
12637
rangeto_error:
12638
xmlXPathReleaseObject(ctxt->context, obj);
12639
ctxt->context->node = oldnode;
12640
ctxt->context->contextSize = oldcs;
12641
ctxt->context->proximityPosition = oldpp;
12642
break;
12643
}
12644
#endif /* LIBXML_XPTR_LOCS_ENABLED */
12645
default:
12646
xmlGenericError(xmlGenericErrorContext,
12647
"XPath: unknown precompiled operation %d\n", op->op);
12648
ctxt->error = XPATH_INVALID_OPERAND;
12649
break;
12650
}
12651
12652
ctxt->context->depth -= 1;
12653
return (total);
12654
}
12655
12656
/**
12657
* xmlXPathCompOpEvalToBoolean:
12658
* @ctxt: the XPath parser context
12659
*
12660
* Evaluates if the expression evaluates to true.
12661
*
12662
* Returns 1 if true, 0 if false and -1 on API or internal errors.
12663
*/
12664
static int
12665
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
12666
xmlXPathStepOpPtr op,
12667
int isPredicate)
12668
{
12669
xmlXPathObjectPtr resObj = NULL;
12670
12671
start:
12672
if (OP_LIMIT_EXCEEDED(ctxt, 1))
12673
return(0);
12674
/* comp = ctxt->comp; */
12675
switch (op->op) {
12676
case XPATH_OP_END:
12677
return (0);
12678
case XPATH_OP_VALUE:
12679
resObj = (xmlXPathObjectPtr) op->value4;
12680
if (isPredicate)
12681
return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
12682
return(xmlXPathCastToBoolean(resObj));
12683
case XPATH_OP_SORT:
12684
/*
12685
* We don't need sorting for boolean results. Skip this one.
12686
*/
12687
if (op->ch1 != -1) {
12688
op = &ctxt->comp->steps[op->ch1];
12689
goto start;
12690
}
12691
return(0);
12692
case XPATH_OP_COLLECT:
12693
if (op->ch1 == -1)
12694
return(0);
12695
12696
xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
12697
if (ctxt->error != XPATH_EXPRESSION_OK)
12698
return(-1);
12699
12700
xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
12701
if (ctxt->error != XPATH_EXPRESSION_OK)
12702
return(-1);
12703
12704
resObj = valuePop(ctxt);
12705
if (resObj == NULL)
12706
return(-1);
12707
break;
12708
default:
12709
/*
12710
* Fallback to call xmlXPathCompOpEval().
12711
*/
12712
xmlXPathCompOpEval(ctxt, op);
12713
if (ctxt->error != XPATH_EXPRESSION_OK)
12714
return(-1);
12715
12716
resObj = valuePop(ctxt);
12717
if (resObj == NULL)
12718
return(-1);
12719
break;
12720
}
12721
12722
if (resObj) {
12723
int res;
12724
12725
if (resObj->type == XPATH_BOOLEAN) {
12726
res = resObj->boolval;
12727
} else if (isPredicate) {
12728
/*
12729
* For predicates a result of type "number" is handled
12730
* differently:
12731
* SPEC XPath 1.0:
12732
* "If the result is a number, the result will be converted
12733
* to true if the number is equal to the context position
12734
* and will be converted to false otherwise;"
12735
*/
12736
res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
12737
} else {
12738
res = xmlXPathCastToBoolean(resObj);
12739
}
12740
xmlXPathReleaseObject(ctxt->context, resObj);
12741
return(res);
12742
}
12743
12744
return(0);
12745
}
12746
12747
#ifdef XPATH_STREAMING
12748
/**
12749
* xmlXPathRunStreamEval:
12750
* @ctxt: the XPath parser context with the compiled expression
12751
*
12752
* Evaluate the Precompiled Streamable XPath expression in the given context.
12753
*/
12754
static int
12755
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
12756
xmlXPathObjectPtr *resultSeq, int toBool)
12757
{
12758
int max_depth, min_depth;
12759
int from_root;
12760
int ret, depth;
12761
int eval_all_nodes;
12762
xmlNodePtr cur = NULL, limit = NULL;
12763
xmlStreamCtxtPtr patstream = NULL;
12764
12765
if ((ctxt == NULL) || (comp == NULL))
12766
return(-1);
12767
max_depth = xmlPatternMaxDepth(comp);
12768
if (max_depth == -1)
12769
return(-1);
12770
if (max_depth == -2)
12771
max_depth = 10000;
12772
min_depth = xmlPatternMinDepth(comp);
12773
if (min_depth == -1)
12774
return(-1);
12775
from_root = xmlPatternFromRoot(comp);
12776
if (from_root < 0)
12777
return(-1);
12778
#if 0
12779
printf("stream eval: depth %d from root %d\n", max_depth, from_root);
12780
#endif
12781
12782
if (! toBool) {
12783
if (resultSeq == NULL)
12784
return(-1);
12785
*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
12786
if (*resultSeq == NULL)
12787
return(-1);
12788
}
12789
12790
/*
12791
* handle the special cases of "/" amd "." being matched
12792
*/
12793
if (min_depth == 0) {
12794
if (from_root) {
12795
/* Select "/" */
12796
if (toBool)
12797
return(1);
12798
/* TODO: Check memory error. */
12799
xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
12800
(xmlNodePtr) ctxt->doc);
12801
} else {
12802
/* Select "self::node()" */
12803
if (toBool)
12804
return(1);
12805
/* TODO: Check memory error. */
12806
xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
12807
}
12808
}
12809
if (max_depth == 0) {
12810
return(0);
12811
}
12812
12813
if (from_root) {
12814
cur = (xmlNodePtr)ctxt->doc;
12815
} else if (ctxt->node != NULL) {
12816
switch (ctxt->node->type) {
12817
case XML_ELEMENT_NODE:
12818
case XML_DOCUMENT_NODE:
12819
case XML_DOCUMENT_FRAG_NODE:
12820
case XML_HTML_DOCUMENT_NODE:
12821
cur = ctxt->node;
12822
break;
12823
case XML_ATTRIBUTE_NODE:
12824
case XML_TEXT_NODE:
12825
case XML_CDATA_SECTION_NODE:
12826
case XML_ENTITY_REF_NODE:
12827
case XML_ENTITY_NODE:
12828
case XML_PI_NODE:
12829
case XML_COMMENT_NODE:
12830
case XML_NOTATION_NODE:
12831
case XML_DTD_NODE:
12832
case XML_DOCUMENT_TYPE_NODE:
12833
case XML_ELEMENT_DECL:
12834
case XML_ATTRIBUTE_DECL:
12835
case XML_ENTITY_DECL:
12836
case XML_NAMESPACE_DECL:
12837
case XML_XINCLUDE_START:
12838
case XML_XINCLUDE_END:
12839
break;
12840
}
12841
limit = cur;
12842
}
12843
if (cur == NULL) {
12844
return(0);
12845
}
12846
12847
patstream = xmlPatternGetStreamCtxt(comp);
12848
if (patstream == NULL) {
12849
/*
12850
* QUESTION TODO: Is this an error?
12851
*/
12852
return(0);
12853
}
12854
12855
eval_all_nodes = xmlStreamWantsAnyNode(patstream);
12856
12857
if (from_root) {
12858
ret = xmlStreamPush(patstream, NULL, NULL);
12859
if (ret < 0) {
12860
} else if (ret == 1) {
12861
if (toBool)
12862
goto return_1;
12863
/* TODO: Check memory error. */
12864
xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
12865
}
12866
}
12867
depth = 0;
12868
goto scan_children;
12869
next_node:
12870
do {
12871
if (ctxt->opLimit != 0) {
12872
if (ctxt->opCount >= ctxt->opLimit) {
12873
xmlGenericError(xmlGenericErrorContext,
12874
"XPath operation limit exceeded\n");
12875
xmlFreeStreamCtxt(patstream);
12876
return(-1);
12877
}
12878
ctxt->opCount++;
12879
}
12880
12881
switch (cur->type) {
12882
case XML_ELEMENT_NODE:
12883
case XML_TEXT_NODE:
12884
case XML_CDATA_SECTION_NODE:
12885
case XML_COMMENT_NODE:
12886
case XML_PI_NODE:
12887
if (cur->type == XML_ELEMENT_NODE) {
12888
ret = xmlStreamPush(patstream, cur->name,
12889
(cur->ns ? cur->ns->href : NULL));
12890
} else if (eval_all_nodes)
12891
ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
12892
else
12893
break;
12894
12895
if (ret < 0) {
12896
/* NOP. */
12897
} else if (ret == 1) {
12898
if (toBool)
12899
goto return_1;
12900
if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
12901
< 0) {
12902
ctxt->lastError.domain = XML_FROM_XPATH;
12903
ctxt->lastError.code = XML_ERR_NO_MEMORY;
12904
}
12905
}
12906
if ((cur->children == NULL) || (depth >= max_depth)) {
12907
ret = xmlStreamPop(patstream);
12908
while (cur->next != NULL) {
12909
cur = cur->next;
12910
if ((cur->type != XML_ENTITY_DECL) &&
12911
(cur->type != XML_DTD_NODE))
12912
goto next_node;
12913
}
12914
}
12915
default:
12916
break;
12917
}
12918
12919
scan_children:
12920
if (cur->type == XML_NAMESPACE_DECL) break;
12921
if ((cur->children != NULL) && (depth < max_depth)) {
12922
/*
12923
* Do not descend on entities declarations
12924
*/
12925
if (cur->children->type != XML_ENTITY_DECL) {
12926
cur = cur->children;
12927
depth++;
12928
/*
12929
* Skip DTDs
12930
*/
12931
if (cur->type != XML_DTD_NODE)
12932
continue;
12933
}
12934
}
12935
12936
if (cur == limit)
12937
break;
12938
12939
while (cur->next != NULL) {
12940
cur = cur->next;
12941
if ((cur->type != XML_ENTITY_DECL) &&
12942
(cur->type != XML_DTD_NODE))
12943
goto next_node;
12944
}
12945
12946
do {
12947
cur = cur->parent;
12948
depth--;
12949
if ((cur == NULL) || (cur == limit) ||
12950
(cur->type == XML_DOCUMENT_NODE))
12951
goto done;
12952
if (cur->type == XML_ELEMENT_NODE) {
12953
ret = xmlStreamPop(patstream);
12954
} else if ((eval_all_nodes) &&
12955
((cur->type == XML_TEXT_NODE) ||
12956
(cur->type == XML_CDATA_SECTION_NODE) ||
12957
(cur->type == XML_COMMENT_NODE) ||
12958
(cur->type == XML_PI_NODE)))
12959
{
12960
ret = xmlStreamPop(patstream);
12961
}
12962
if (cur->next != NULL) {
12963
cur = cur->next;
12964
break;
12965
}
12966
} while (cur != NULL);
12967
12968
} while ((cur != NULL) && (depth >= 0));
12969
12970
done:
12971
12972
if (patstream)
12973
xmlFreeStreamCtxt(patstream);
12974
return(0);
12975
12976
return_1:
12977
if (patstream)
12978
xmlFreeStreamCtxt(patstream);
12979
return(1);
12980
}
12981
#endif /* XPATH_STREAMING */
12982
12983
/**
12984
* xmlXPathRunEval:
12985
* @ctxt: the XPath parser context with the compiled expression
12986
* @toBool: evaluate to a boolean result
12987
*
12988
* Evaluate the Precompiled XPath expression in the given context.
12989
*/
12990
static int
12991
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
12992
{
12993
xmlXPathCompExprPtr comp;
12994
int oldDepth;
12995
12996
if ((ctxt == NULL) || (ctxt->comp == NULL))
12997
return(-1);
12998
12999
if (ctxt->valueTab == NULL) {
13000
/* Allocate the value stack */
13001
ctxt->valueTab = (xmlXPathObjectPtr *)
13002
xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
13003
if (ctxt->valueTab == NULL) {
13004
xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
13005
return(-1);
13006
}
13007
ctxt->valueNr = 0;
13008
ctxt->valueMax = 10;
13009
ctxt->value = NULL;
13010
}
13011
#ifdef XPATH_STREAMING
13012
if (ctxt->comp->stream) {
13013
int res;
13014
13015
if (toBool) {
13016
/*
13017
* Evaluation to boolean result.
13018
*/
13019
res = xmlXPathRunStreamEval(ctxt->context,
13020
ctxt->comp->stream, NULL, 1);
13021
if (res != -1)
13022
return(res);
13023
} else {
13024
xmlXPathObjectPtr resObj = NULL;
13025
13026
/*
13027
* Evaluation to a sequence.
13028
*/
13029
res = xmlXPathRunStreamEval(ctxt->context,
13030
ctxt->comp->stream, &resObj, 0);
13031
13032
if ((res != -1) && (resObj != NULL)) {
13033
valuePush(ctxt, resObj);
13034
return(0);
13035
}
13036
if (resObj != NULL)
13037
xmlXPathReleaseObject(ctxt->context, resObj);
13038
}
13039
/*
13040
* QUESTION TODO: This falls back to normal XPath evaluation
13041
* if res == -1. Is this intended?
13042
*/
13043
}
13044
#endif
13045
comp = ctxt->comp;
13046
if (comp->last < 0) {
13047
xmlGenericError(xmlGenericErrorContext,
13048
"xmlXPathRunEval: last is less than zero\n");
13049
return(-1);
13050
}
13051
oldDepth = ctxt->context->depth;
13052
if (toBool)
13053
return(xmlXPathCompOpEvalToBoolean(ctxt,
13054
&comp->steps[comp->last], 0));
13055
else
13056
xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
13057
ctxt->context->depth = oldDepth;
13058
13059
return(0);
13060
}
13061
13062
/************************************************************************
13063
* *
13064
* Public interfaces *
13065
* *
13066
************************************************************************/
13067
13068
/**
13069
* xmlXPathEvalPredicate:
13070
* @ctxt: the XPath context
13071
* @res: the Predicate Expression evaluation result
13072
*
13073
* Evaluate a predicate result for the current node.
13074
* A PredicateExpr is evaluated by evaluating the Expr and converting
13075
* the result to a boolean. If the result is a number, the result will
13076
* be converted to true if the number is equal to the position of the
13077
* context node in the context node list (as returned by the position
13078
* function) and will be converted to false otherwise; if the result
13079
* is not a number, then the result will be converted as if by a call
13080
* to the boolean function.
13081
*
13082
* Returns 1 if predicate is true, 0 otherwise
13083
*/
13084
int
13085
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
13086
if ((ctxt == NULL) || (res == NULL)) return(0);
13087
switch (res->type) {
13088
case XPATH_BOOLEAN:
13089
return(res->boolval);
13090
case XPATH_NUMBER:
13091
return(res->floatval == ctxt->proximityPosition);
13092
case XPATH_NODESET:
13093
case XPATH_XSLT_TREE:
13094
if (res->nodesetval == NULL)
13095
return(0);
13096
return(res->nodesetval->nodeNr != 0);
13097
case XPATH_STRING:
13098
return((res->stringval != NULL) &&
13099
(xmlStrlen(res->stringval) != 0));
13100
default:
13101
STRANGE
13102
}
13103
return(0);
13104
}
13105
13106
/**
13107
* xmlXPathEvaluatePredicateResult:
13108
* @ctxt: the XPath Parser context
13109
* @res: the Predicate Expression evaluation result
13110
*
13111
* Evaluate a predicate result for the current node.
13112
* A PredicateExpr is evaluated by evaluating the Expr and converting
13113
* the result to a boolean. If the result is a number, the result will
13114
* be converted to true if the number is equal to the position of the
13115
* context node in the context node list (as returned by the position
13116
* function) and will be converted to false otherwise; if the result
13117
* is not a number, then the result will be converted as if by a call
13118
* to the boolean function.
13119
*
13120
* Returns 1 if predicate is true, 0 otherwise
13121
*/
13122
int
13123
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
13124
xmlXPathObjectPtr res) {
13125
if ((ctxt == NULL) || (res == NULL)) return(0);
13126
switch (res->type) {
13127
case XPATH_BOOLEAN:
13128
return(res->boolval);
13129
case XPATH_NUMBER:
13130
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
13131
return((res->floatval == ctxt->context->proximityPosition) &&
13132
(!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
13133
#else
13134
return(res->floatval == ctxt->context->proximityPosition);
13135
#endif
13136
case XPATH_NODESET:
13137
case XPATH_XSLT_TREE:
13138
if (res->nodesetval == NULL)
13139
return(0);
13140
return(res->nodesetval->nodeNr != 0);
13141
case XPATH_STRING:
13142
return((res->stringval != NULL) && (res->stringval[0] != 0));
13143
#ifdef LIBXML_XPTR_LOCS_ENABLED
13144
case XPATH_LOCATIONSET:{
13145
xmlLocationSetPtr ptr = res->user;
13146
if (ptr == NULL)
13147
return(0);
13148
return (ptr->locNr != 0);
13149
}
13150
#endif
13151
default:
13152
STRANGE
13153
}
13154
return(0);
13155
}
13156
13157
#ifdef XPATH_STREAMING
13158
/**
13159
* xmlXPathTryStreamCompile:
13160
* @ctxt: an XPath context
13161
* @str: the XPath expression
13162
*
13163
* Try to compile the XPath expression as a streamable subset.
13164
*
13165
* Returns the compiled expression or NULL if failed to compile.
13166
*/
13167
static xmlXPathCompExprPtr
13168
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13169
/*
13170
* Optimization: use streaming patterns when the XPath expression can
13171
* be compiled to a stream lookup
13172
*/
13173
xmlPatternPtr stream;
13174
xmlXPathCompExprPtr comp;
13175
xmlDictPtr dict = NULL;
13176
const xmlChar **namespaces = NULL;
13177
xmlNsPtr ns;
13178
int i, j;
13179
13180
if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
13181
(!xmlStrchr(str, '@'))) {
13182
const xmlChar *tmp;
13183
13184
/*
13185
* We don't try to handle expressions using the verbose axis
13186
* specifiers ("::"), just the simplified form at this point.
13187
* Additionally, if there is no list of namespaces available and
13188
* there's a ":" in the expression, indicating a prefixed QName,
13189
* then we won't try to compile either. xmlPatterncompile() needs
13190
* to have a list of namespaces at compilation time in order to
13191
* compile prefixed name tests.
13192
*/
13193
tmp = xmlStrchr(str, ':');
13194
if ((tmp != NULL) &&
13195
((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
13196
return(NULL);
13197
13198
if (ctxt != NULL) {
13199
dict = ctxt->dict;
13200
if (ctxt->nsNr > 0) {
13201
namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
13202
if (namespaces == NULL) {
13203
xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
13204
return(NULL);
13205
}
13206
for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
13207
ns = ctxt->namespaces[j];
13208
namespaces[i++] = ns->href;
13209
namespaces[i++] = ns->prefix;
13210
}
13211
namespaces[i++] = NULL;
13212
namespaces[i] = NULL;
13213
}
13214
}
13215
13216
stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
13217
if (namespaces != NULL) {
13218
xmlFree((xmlChar **)namespaces);
13219
}
13220
if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
13221
comp = xmlXPathNewCompExpr();
13222
if (comp == NULL) {
13223
xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
13224
xmlFreePattern(stream);
13225
return(NULL);
13226
}
13227
comp->stream = stream;
13228
comp->dict = dict;
13229
if (comp->dict)
13230
xmlDictReference(comp->dict);
13231
return(comp);
13232
}
13233
xmlFreePattern(stream);
13234
}
13235
return(NULL);
13236
}
13237
#endif /* XPATH_STREAMING */
13238
13239
static void
13240
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
13241
xmlXPathStepOpPtr op)
13242
{
13243
xmlXPathCompExprPtr comp = pctxt->comp;
13244
xmlXPathContextPtr ctxt;
13245
13246
/*
13247
* Try to rewrite "descendant-or-self::node()/foo" to an optimized
13248
* internal representation.
13249
*/
13250
13251
if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
13252
(op->ch1 != -1) &&
13253
(op->ch2 == -1 /* no predicate */))
13254
{
13255
xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
13256
13257
if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
13258
((xmlXPathAxisVal) prevop->value ==
13259
AXIS_DESCENDANT_OR_SELF) &&
13260
(prevop->ch2 == -1) &&
13261
((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
13262
((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
13263
{
13264
/*
13265
* This is a "descendant-or-self::node()" without predicates.
13266
* Try to eliminate it.
13267
*/
13268
13269
switch ((xmlXPathAxisVal) op->value) {
13270
case AXIS_CHILD:
13271
case AXIS_DESCENDANT:
13272
/*
13273
* Convert "descendant-or-self::node()/child::" or
13274
* "descendant-or-self::node()/descendant::" to
13275
* "descendant::"
13276
*/
13277
op->ch1 = prevop->ch1;
13278
op->value = AXIS_DESCENDANT;
13279
break;
13280
case AXIS_SELF:
13281
case AXIS_DESCENDANT_OR_SELF:
13282
/*
13283
* Convert "descendant-or-self::node()/self::" or
13284
* "descendant-or-self::node()/descendant-or-self::" to
13285
* to "descendant-or-self::"
13286
*/
13287
op->ch1 = prevop->ch1;
13288
op->value = AXIS_DESCENDANT_OR_SELF;
13289
break;
13290
default:
13291
break;
13292
}
13293
}
13294
}
13295
13296
/* OP_VALUE has invalid ch1. */
13297
if (op->op == XPATH_OP_VALUE)
13298
return;
13299
13300
/* Recurse */
13301
ctxt = pctxt->context;
13302
if (ctxt != NULL) {
13303
if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
13304
return;
13305
ctxt->depth += 1;
13306
}
13307
if (op->ch1 != -1)
13308
xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
13309
if (op->ch2 != -1)
13310
xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
13311
if (ctxt != NULL)
13312
ctxt->depth -= 1;
13313
}
13314
13315
/**
13316
* xmlXPathCtxtCompile:
13317
* @ctxt: an XPath context
13318
* @str: the XPath expression
13319
*
13320
* Compile an XPath expression
13321
*
13322
* Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13323
* the caller has to free the object.
13324
*/
13325
xmlXPathCompExprPtr
13326
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
13327
xmlXPathParserContextPtr pctxt;
13328
xmlXPathCompExprPtr comp;
13329
int oldDepth = 0;
13330
13331
#ifdef XPATH_STREAMING
13332
comp = xmlXPathTryStreamCompile(ctxt, str);
13333
if (comp != NULL)
13334
return(comp);
13335
#endif
13336
13337
xmlInitParser();
13338
13339
pctxt = xmlXPathNewParserContext(str, ctxt);
13340
if (pctxt == NULL)
13341
return NULL;
13342
if (ctxt != NULL)
13343
oldDepth = ctxt->depth;
13344
xmlXPathCompileExpr(pctxt, 1);
13345
if (ctxt != NULL)
13346
ctxt->depth = oldDepth;
13347
13348
if( pctxt->error != XPATH_EXPRESSION_OK )
13349
{
13350
xmlXPathFreeParserContext(pctxt);
13351
return(NULL);
13352
}
13353
13354
if (*pctxt->cur != 0) {
13355
/*
13356
* aleksey: in some cases this line prints *second* error message
13357
* (see bug #78858) and probably this should be fixed.
13358
* However, we are not sure that all error messages are printed
13359
* out in other places. It's not critical so we leave it as-is for now
13360
*/
13361
xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
13362
comp = NULL;
13363
} else {
13364
comp = pctxt->comp;
13365
if ((comp->nbStep > 1) && (comp->last >= 0)) {
13366
if (ctxt != NULL)
13367
oldDepth = ctxt->depth;
13368
xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
13369
if (ctxt != NULL)
13370
ctxt->depth = oldDepth;
13371
}
13372
pctxt->comp = NULL;
13373
}
13374
xmlXPathFreeParserContext(pctxt);
13375
13376
if (comp != NULL) {
13377
comp->expr = xmlStrdup(str);
13378
}
13379
return(comp);
13380
}
13381
13382
/**
13383
* xmlXPathCompile:
13384
* @str: the XPath expression
13385
*
13386
* Compile an XPath expression
13387
*
13388
* Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
13389
* the caller has to free the object.
13390
*/
13391
xmlXPathCompExprPtr
13392
xmlXPathCompile(const xmlChar *str) {
13393
return(xmlXPathCtxtCompile(NULL, str));
13394
}
13395
13396
/**
13397
* xmlXPathCompiledEvalInternal:
13398
* @comp: the compiled XPath expression
13399
* @ctxt: the XPath context
13400
* @resObj: the resulting XPath object or NULL
13401
* @toBool: 1 if only a boolean result is requested
13402
*
13403
* Evaluate the Precompiled XPath expression in the given context.
13404
* The caller has to free @resObj.
13405
*
13406
* Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13407
* the caller has to free the object.
13408
*/
13409
static int
13410
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
13411
xmlXPathContextPtr ctxt,
13412
xmlXPathObjectPtr *resObjPtr,
13413
int toBool)
13414
{
13415
xmlXPathParserContextPtr pctxt;
13416
xmlXPathObjectPtr resObj;
13417
#ifndef LIBXML_THREAD_ENABLED
13418
static int reentance = 0;
13419
#endif
13420
int res;
13421
13422
CHECK_CTXT_NEG(ctxt)
13423
13424
if (comp == NULL)
13425
return(-1);
13426
xmlInitParser();
13427
13428
#ifndef LIBXML_THREAD_ENABLED
13429
reentance++;
13430
if (reentance > 1)
13431
xmlXPathDisableOptimizer = 1;
13432
#endif
13433
13434
pctxt = xmlXPathCompParserContext(comp, ctxt);
13435
if (pctxt == NULL)
13436
return(-1);
13437
res = xmlXPathRunEval(pctxt, toBool);
13438
13439
if (pctxt->error != XPATH_EXPRESSION_OK) {
13440
resObj = NULL;
13441
} else {
13442
resObj = valuePop(pctxt);
13443
if (resObj == NULL) {
13444
if (!toBool)
13445
xmlGenericError(xmlGenericErrorContext,
13446
"xmlXPathCompiledEval: No result on the stack.\n");
13447
} else if (pctxt->valueNr > 0) {
13448
xmlGenericError(xmlGenericErrorContext,
13449
"xmlXPathCompiledEval: %d object(s) left on the stack.\n",
13450
pctxt->valueNr);
13451
}
13452
}
13453
13454
if (resObjPtr)
13455
*resObjPtr = resObj;
13456
else
13457
xmlXPathReleaseObject(ctxt, resObj);
13458
13459
pctxt->comp = NULL;
13460
xmlXPathFreeParserContext(pctxt);
13461
#ifndef LIBXML_THREAD_ENABLED
13462
reentance--;
13463
#endif
13464
13465
return(res);
13466
}
13467
13468
/**
13469
* xmlXPathCompiledEval:
13470
* @comp: the compiled XPath expression
13471
* @ctx: the XPath context
13472
*
13473
* Evaluate the Precompiled XPath expression in the given context.
13474
*
13475
* Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13476
* the caller has to free the object.
13477
*/
13478
xmlXPathObjectPtr
13479
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
13480
{
13481
xmlXPathObjectPtr res = NULL;
13482
13483
xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
13484
return(res);
13485
}
13486
13487
/**
13488
* xmlXPathCompiledEvalToBoolean:
13489
* @comp: the compiled XPath expression
13490
* @ctxt: the XPath context
13491
*
13492
* Applies the XPath boolean() function on the result of the given
13493
* compiled expression.
13494
*
13495
* Returns 1 if the expression evaluated to true, 0 if to false and
13496
* -1 in API and internal errors.
13497
*/
13498
int
13499
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
13500
xmlXPathContextPtr ctxt)
13501
{
13502
return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
13503
}
13504
13505
/**
13506
* xmlXPathEvalExpr:
13507
* @ctxt: the XPath Parser context
13508
*
13509
* Parse and evaluate an XPath expression in the given context,
13510
* then push the result on the context stack
13511
*/
13512
void
13513
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
13514
#ifdef XPATH_STREAMING
13515
xmlXPathCompExprPtr comp;
13516
#endif
13517
int oldDepth = 0;
13518
13519
if (ctxt == NULL) return;
13520
13521
#ifdef XPATH_STREAMING
13522
comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
13523
if (comp != NULL) {
13524
if (ctxt->comp != NULL)
13525
xmlXPathFreeCompExpr(ctxt->comp);
13526
ctxt->comp = comp;
13527
} else
13528
#endif
13529
{
13530
if (ctxt->context != NULL)
13531
oldDepth = ctxt->context->depth;
13532
xmlXPathCompileExpr(ctxt, 1);
13533
if (ctxt->context != NULL)
13534
ctxt->context->depth = oldDepth;
13535
CHECK_ERROR;
13536
13537
/* Check for trailing characters. */
13538
if (*ctxt->cur != 0)
13539
XP_ERROR(XPATH_EXPR_ERROR);
13540
13541
if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
13542
if (ctxt->context != NULL)
13543
oldDepth = ctxt->context->depth;
13544
xmlXPathOptimizeExpression(ctxt,
13545
&ctxt->comp->steps[ctxt->comp->last]);
13546
if (ctxt->context != NULL)
13547
ctxt->context->depth = oldDepth;
13548
}
13549
}
13550
13551
xmlXPathRunEval(ctxt, 0);
13552
}
13553
13554
/**
13555
* xmlXPathEval:
13556
* @str: the XPath expression
13557
* @ctx: the XPath context
13558
*
13559
* Evaluate the XPath Location Path in the given context.
13560
*
13561
* Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13562
* the caller has to free the object.
13563
*/
13564
xmlXPathObjectPtr
13565
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
13566
xmlXPathParserContextPtr ctxt;
13567
xmlXPathObjectPtr res;
13568
13569
CHECK_CTXT(ctx)
13570
13571
xmlInitParser();
13572
13573
ctxt = xmlXPathNewParserContext(str, ctx);
13574
if (ctxt == NULL)
13575
return NULL;
13576
xmlXPathEvalExpr(ctxt);
13577
13578
if (ctxt->error != XPATH_EXPRESSION_OK) {
13579
res = NULL;
13580
} else {
13581
res = valuePop(ctxt);
13582
if (res == NULL) {
13583
xmlGenericError(xmlGenericErrorContext,
13584
"xmlXPathCompiledEval: No result on the stack.\n");
13585
} else if (ctxt->valueNr > 0) {
13586
xmlGenericError(xmlGenericErrorContext,
13587
"xmlXPathCompiledEval: %d object(s) left on the stack.\n",
13588
ctxt->valueNr);
13589
}
13590
}
13591
13592
xmlXPathFreeParserContext(ctxt);
13593
return(res);
13594
}
13595
13596
/**
13597
* xmlXPathSetContextNode:
13598
* @node: the node to to use as the context node
13599
* @ctx: the XPath context
13600
*
13601
* Sets 'node' as the context node. The node must be in the same
13602
* document as that associated with the context.
13603
*
13604
* Returns -1 in case of error or 0 if successful
13605
*/
13606
int
13607
xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
13608
if ((node == NULL) || (ctx == NULL))
13609
return(-1);
13610
13611
if (node->doc == ctx->doc) {
13612
ctx->node = node;
13613
return(0);
13614
}
13615
return(-1);
13616
}
13617
13618
/**
13619
* xmlXPathNodeEval:
13620
* @node: the node to to use as the context node
13621
* @str: the XPath expression
13622
* @ctx: the XPath context
13623
*
13624
* Evaluate the XPath Location Path in the given context. The node 'node'
13625
* is set as the context node. The context node is not restored.
13626
*
13627
* Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13628
* the caller has to free the object.
13629
*/
13630
xmlXPathObjectPtr
13631
xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
13632
if (str == NULL)
13633
return(NULL);
13634
if (xmlXPathSetContextNode(node, ctx) < 0)
13635
return(NULL);
13636
return(xmlXPathEval(str, ctx));
13637
}
13638
13639
/**
13640
* xmlXPathEvalExpression:
13641
* @str: the XPath expression
13642
* @ctxt: the XPath context
13643
*
13644
* Alias for xmlXPathEval().
13645
*
13646
* Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
13647
* the caller has to free the object.
13648
*/
13649
xmlXPathObjectPtr
13650
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
13651
return(xmlXPathEval(str, ctxt));
13652
}
13653
13654
/************************************************************************
13655
* *
13656
* Extra functions not pertaining to the XPath spec *
13657
* *
13658
************************************************************************/
13659
/**
13660
* xmlXPathEscapeUriFunction:
13661
* @ctxt: the XPath Parser context
13662
* @nargs: the number of arguments
13663
*
13664
* Implement the escape-uri() XPath function
13665
* string escape-uri(string $str, bool $escape-reserved)
13666
*
13667
* This function applies the URI escaping rules defined in section 2 of [RFC
13668
* 2396] to the string supplied as $uri-part, which typically represents all
13669
* or part of a URI. The effect of the function is to replace any special
13670
* character in the string by an escape sequence of the form %xx%yy...,
13671
* where xxyy... is the hexadecimal representation of the octets used to
13672
* represent the character in UTF-8.
13673
*
13674
* The set of characters that are escaped depends on the setting of the
13675
* boolean argument $escape-reserved.
13676
*
13677
* If $escape-reserved is true, all characters are escaped other than lower
13678
* case letters a-z, upper case letters A-Z, digits 0-9, and the characters
13679
* referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
13680
* | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
13681
* if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
13682
* A-F).
13683
*
13684
* If $escape-reserved is false, the behavior differs in that characters
13685
* referred to in [RFC 2396] as reserved characters are not escaped. These
13686
* characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
13687
*
13688
* [RFC 2396] does not define whether escaped URIs should use lower case or
13689
* upper case for hexadecimal digits. To ensure that escaped URIs can be
13690
* compared using string comparison functions, this function must always use
13691
* the upper-case letters A-F.
13692
*
13693
* Generally, $escape-reserved should be set to true when escaping a string
13694
* that is to form a single part of a URI, and to false when escaping an
13695
* entire URI or URI reference.
13696
*
13697
* In the case of non-ascii characters, the string is encoded according to
13698
* utf-8 and then converted according to RFC 2396.
13699
*
13700
* Examples
13701
* xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
13702
* returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
13703
* xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
13704
* returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
13705
*
13706
*/
13707
static void
13708
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
13709
xmlXPathObjectPtr str;
13710
int escape_reserved;
13711
xmlBufPtr target;
13712
xmlChar *cptr;
13713
xmlChar escape[4];
13714
13715
CHECK_ARITY(2);
13716
13717
escape_reserved = xmlXPathPopBoolean(ctxt);
13718
13719
CAST_TO_STRING;
13720
str = valuePop(ctxt);
13721
13722
target = xmlBufCreate();
13723
13724
escape[0] = '%';
13725
escape[3] = 0;
13726
13727
if (target) {
13728
for (cptr = str->stringval; *cptr; cptr++) {
13729
if ((*cptr >= 'A' && *cptr <= 'Z') ||
13730
(*cptr >= 'a' && *cptr <= 'z') ||
13731
(*cptr >= '0' && *cptr <= '9') ||
13732
*cptr == '-' || *cptr == '_' || *cptr == '.' ||
13733
*cptr == '!' || *cptr == '~' || *cptr == '*' ||
13734
*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
13735
(*cptr == '%' &&
13736
((cptr[1] >= 'A' && cptr[1] <= 'F') ||
13737
(cptr[1] >= 'a' && cptr[1] <= 'f') ||
13738
(cptr[1] >= '0' && cptr[1] <= '9')) &&
13739
((cptr[2] >= 'A' && cptr[2] <= 'F') ||
13740
(cptr[2] >= 'a' && cptr[2] <= 'f') ||
13741
(cptr[2] >= '0' && cptr[2] <= '9'))) ||
13742
(!escape_reserved &&
13743
(*cptr == ';' || *cptr == '/' || *cptr == '?' ||
13744
*cptr == ':' || *cptr == '@' || *cptr == '&' ||
13745
*cptr == '=' || *cptr == '+' || *cptr == '$' ||
13746
*cptr == ','))) {
13747
xmlBufAdd(target, cptr, 1);
13748
} else {
13749
if ((*cptr >> 4) < 10)
13750
escape[1] = '0' + (*cptr >> 4);
13751
else
13752
escape[1] = 'A' - 10 + (*cptr >> 4);
13753
if ((*cptr & 0xF) < 10)
13754
escape[2] = '0' + (*cptr & 0xF);
13755
else
13756
escape[2] = 'A' - 10 + (*cptr & 0xF);
13757
13758
xmlBufAdd(target, &escape[0], 3);
13759
}
13760
}
13761
}
13762
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
13763
xmlBufContent(target)));
13764
xmlBufFree(target);
13765
xmlXPathReleaseObject(ctxt->context, str);
13766
}
13767
13768
/**
13769
* xmlXPathRegisterAllFunctions:
13770
* @ctxt: the XPath context
13771
*
13772
* Registers all default XPath functions in this context
13773
*/
13774
void
13775
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
13776
{
13777
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
13778
xmlXPathBooleanFunction);
13779
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
13780
xmlXPathCeilingFunction);
13781
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
13782
xmlXPathCountFunction);
13783
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
13784
xmlXPathConcatFunction);
13785
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
13786
xmlXPathContainsFunction);
13787
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
13788
xmlXPathIdFunction);
13789
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
13790
xmlXPathFalseFunction);
13791
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
13792
xmlXPathFloorFunction);
13793
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
13794
xmlXPathLastFunction);
13795
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
13796
xmlXPathLangFunction);
13797
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
13798
xmlXPathLocalNameFunction);
13799
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
13800
xmlXPathNotFunction);
13801
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
13802
xmlXPathNameFunction);
13803
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
13804
xmlXPathNamespaceURIFunction);
13805
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
13806
xmlXPathNormalizeFunction);
13807
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
13808
xmlXPathNumberFunction);
13809
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
13810
xmlXPathPositionFunction);
13811
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
13812
xmlXPathRoundFunction);
13813
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
13814
xmlXPathStringFunction);
13815
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
13816
xmlXPathStringLengthFunction);
13817
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
13818
xmlXPathStartsWithFunction);
13819
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
13820
xmlXPathSubstringFunction);
13821
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
13822
xmlXPathSubstringBeforeFunction);
13823
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
13824
xmlXPathSubstringAfterFunction);
13825
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
13826
xmlXPathSumFunction);
13827
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
13828
xmlXPathTrueFunction);
13829
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
13830
xmlXPathTranslateFunction);
13831
13832
xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
13833
(const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
13834
xmlXPathEscapeUriFunction);
13835
}
13836
13837
#endif /* LIBXML_XPATH_ENABLED */
13838
13839