<libroxml  version="3.0.2" />
contact: tristan.lelong@libroxml.net
roxml_xpath.c
Go to the documentation of this file.
1
11#include <stdlib.h>
12#include <string.h>
13#include "roxml_mem.h"
14#include "roxml_core.h"
15#include "roxml_xpath.h"
16#include "roxml_parser.h"
17
25ROXML_STATIC ROXML_INT int roxml_is_number(char *input)
26{
27 char *end;
28 int is_number = 0;
29
30 /*
31 * we don't need the value per se and some compiler will
32 * complain about an initialized but unused variable if we
33 * get it.
34 */
35 roxml_strtonum(input, &end);
36
37 if ((end == NULL) ||
38 (roxml_is_separator(end[0])) ||
39 (end[0] == '"') ||
40 (end[0] == '\'') ||
41 (end[0] == '\0')) {
42 is_number = 1;
43 }
44
45 return is_number;
46}
47
55ROXML_STATIC ROXML_INT void roxml_free_xcond(xpath_cond_t *xcond)
56{
57 if (xcond->next)
58 roxml_free_xcond(xcond->next);
59 if (xcond->xp)
60 roxml_free_xpath(xcond->xp, xcond->func2);
61 free(xcond);
62}
63
64ROXML_INT void roxml_free_xpath(xpath_node_t *xpath, int nb)
65{
66 int i = 0;
67 for (i = 0; i < nb; i++) {
68 if (xpath[i].next)
69 roxml_free_xpath(xpath[i].next, 1);
70 if (xpath[i].cond)
71 roxml_free_xcond(xpath[i].cond);
72 free(xpath[i].xp_cond);
73 }
74 free(xpath);
75}
76
86ROXML_STATIC ROXML_INT int roxml_in_pool(node_t *root, node_t *n, int req_id)
87{
88 roxml_lock(root);
89 if (n->priv) {
90 xpath_tok_t *tok = (xpath_tok_t *)n->priv;
91 if (tok->id == req_id) {
92 roxml_unlock(root);
93 return 1;
94 } else {
95 while (tok) {
96 if (tok->id == req_id) {
97 roxml_unlock(root);
98 return 1;
99 }
100 tok = tok->next;
101 }
102 }
103 }
104 roxml_unlock(root);
105
106 return 0;
107}
108
118ROXML_STATIC ROXML_INT void roxml_del_from_pool(node_t *root, node_t *n, int req_id)
119{
120 roxml_lock(root);
121 if (n->priv) {
122 xpath_tok_t *prev = (xpath_tok_t *)n->priv;
123 xpath_tok_t *tok = (xpath_tok_t *)n->priv;
124 if (tok->id == req_id) {
125 n->priv = (void *)tok->next;
126 free(tok);
127 } else {
128 while (tok) {
129 if (tok->id == req_id) {
130 prev->next = tok->next;
131 free(tok);
132 break;
133 }
134 prev = tok;
135 tok = tok->next;
136 }
137 }
138 }
139 roxml_unlock(root);
140}
141
152ROXML_STATIC ROXML_INT int roxml_add_to_pool(node_t *root, node_t *n, int req_id)
153{
154 xpath_tok_t *tok;
155 xpath_tok_t *last_tok = NULL;
156
157 if (req_id == 0)
158 return 1;
159
160 roxml_lock(root);
161 tok = (xpath_tok_t *)n->priv;
162
163 while (tok) {
164 if (tok->id == req_id) {
165 roxml_unlock(root);
166 return 0;
167 }
168 last_tok = tok;
169 tok = (xpath_tok_t *)tok->next;
170 }
171 if (last_tok == NULL) {
172 n->priv = calloc(1, sizeof(xpath_tok_t));
173 last_tok = (xpath_tok_t *)n->priv;
174 } else {
175 last_tok->next = calloc(1, sizeof(xpath_tok_t));
176 last_tok = last_tok->next;
177 }
178 last_tok->id = req_id;
179 roxml_unlock(root);
180
181 return 1;
182}
183
194ROXML_STATIC ROXML_INT void roxml_release_id(node_t *root, node_t **pool, int pool_len, int req_id)
195{
196 int i;
197 xpath_tok_table_t *table = (xpath_tok_table_t *)root->priv;
198
199 for (i = 0; i < pool_len; i++)
200 roxml_del_from_pool(root, pool[i], req_id);
201
202 roxml_lock(root);
203 table->ids[req_id] = 0;
204 roxml_unlock(root);
205}
206
214ROXML_STATIC ROXML_INT int roxml_request_id(node_t *root)
215{
216 int i = 0;
217 xpath_tok_table_t *table = (xpath_tok_table_t *)root->priv;
218
219 roxml_lock(root);
220 for (i = ROXML_XPATH_FIRST_ID; i < 255; i++) {
221 if (table->ids[i] == 0) {
222 table->ids[i]++;
223 roxml_unlock(root);
224 return i;
225 }
226 }
227 roxml_unlock(root);
228
229 return -1;
230}
231
242ROXML_STATIC ROXML_INT void roxml_compute_and(node_t *root, node_t **node_set, int *count, int cur_req_id,
243 int prev_req_id)
244{
245 int i = 0;
246 int limit = *count;
247 int pool1 = 0, pool2 = 0;
248
249 for (i = 0; i < limit; i++) {
250 if (pool1 == 0)
251 if (roxml_in_pool(root, node_set[i], cur_req_id))
252 pool1++;
253 if (pool2 == 0)
254 if (roxml_in_pool(root, node_set[i], prev_req_id))
255 pool2++;
256 if (pool1 && pool2)
257 break;
258 }
259
260 if (!pool1 || !pool2) {
261 for (i = 0; i < limit; i++) {
262 roxml_del_from_pool(root, node_set[i], cur_req_id);
263 roxml_del_from_pool(root, node_set[i], prev_req_id);
264 }
265 *count = 0;
266 }
267}
268
280ROXML_STATIC ROXML_INT void roxml_compute_or(node_t *root, node_t **node_set, int *count, int req_id, int glob_id)
281{
282 int i = 0;
283 for (i = 0; i < *count; i++) {
284 if (roxml_in_pool(root, node_set[i], req_id)) {
285 roxml_add_to_pool(root, node_set[i], glob_id);
286 roxml_del_from_pool(root, node_set[i], req_id);
287 }
288 }
289}
290
300ROXML_STATIC ROXML_INT int roxml_parse_xpath(char *path, xpath_node_t **xpath, int context)
301{
302 int ret = 0;
304 roxml_parser_item_t *parser = NULL;
305 ctx.pos = 0;
306 ctx.nbpath = 1;
307 ctx.bracket = 0;
308 ctx.parenthesys = 0;
309 ctx.quoted = 0;
310 ctx.dquoted = 0;
311 ctx.content_quoted = 0;
312 ctx.is_first_node = 1;
313 ctx.wait_first_node = 1;
314 ctx.shorten_cond = 0;
315 ctx.context = context;
316 ctx.first_node = calloc(1, sizeof(xpath_node_t));
317 ctx.new_node = ctx.first_node;
318 ctx.new_cond = NULL;
319 ctx.first_node->rel = ROXML_OPERATOR_OR;
320
321 parser = roxml_append_parser_item(parser, " ", _func_xpath_ignore);
322 parser = roxml_append_parser_item(parser, "\t", _func_xpath_ignore);
323 parser = roxml_append_parser_item(parser, "\n", _func_xpath_ignore);
324 parser = roxml_append_parser_item(parser, "\r", _func_xpath_ignore);
325 parser = roxml_append_parser_item(parser, "\"", _func_xpath_dquote);
326 parser = roxml_append_parser_item(parser, "\'", _func_xpath_quote);
327 parser = roxml_append_parser_item(parser, "/", _func_xpath_new_node);
328 parser = roxml_append_parser_item(parser, "(", _func_xpath_open_parenthesys);
329 parser = roxml_append_parser_item(parser, ")", _func_xpath_close_parenthesys);
330 parser = roxml_append_parser_item(parser, "[", _func_xpath_open_brackets);
331 parser = roxml_append_parser_item(parser, "]", _func_xpath_close_brackets);
332 parser = roxml_append_parser_item(parser, "=", _func_xpath_operator_equal);
333 parser = roxml_append_parser_item(parser, ">", _func_xpath_operator_sup);
334 parser = roxml_append_parser_item(parser, "<", _func_xpath_operator_inf);
335 parser = roxml_append_parser_item(parser, "!", _func_xpath_operator_diff);
336 parser = roxml_append_parser_item(parser, "0", _func_xpath_number);
337 parser = roxml_append_parser_item(parser, "1", _func_xpath_number);
338 parser = roxml_append_parser_item(parser, "2", _func_xpath_number);
339 parser = roxml_append_parser_item(parser, "3", _func_xpath_number);
340 parser = roxml_append_parser_item(parser, "4", _func_xpath_number);
341 parser = roxml_append_parser_item(parser, "5", _func_xpath_number);
342 parser = roxml_append_parser_item(parser, "6", _func_xpath_number);
343 parser = roxml_append_parser_item(parser, "7", _func_xpath_number);
344 parser = roxml_append_parser_item(parser, "8", _func_xpath_number);
345 parser = roxml_append_parser_item(parser, "9", _func_xpath_number);
346 parser = roxml_append_parser_item(parser, "+", _func_xpath_operator_add);
347 parser = roxml_append_parser_item(parser, "-", _func_xpath_operator_subs);
348 parser = roxml_append_parser_item(parser, ROXML_PATH_OR, _func_xpath_path_or);
349 parser = roxml_append_parser_item(parser, ROXML_COND_OR, _func_xpath_condition_or);
350 parser = roxml_append_parser_item(parser, ROXML_COND_AND, _func_xpath_condition_and);
351 parser = roxml_append_parser_item(parser, ROXML_FUNC_POS_STR, _func_xpath_position);
352 parser = roxml_append_parser_item(parser, ROXML_FUNC_FIRST_STR, _func_xpath_first);
353 parser = roxml_append_parser_item(parser, ROXML_FUNC_LAST_STR, _func_xpath_last);
354 parser = roxml_append_parser_item(parser, ROXML_FUNC_NSURI_STR, _func_xpath_nsuri);
355 parser = roxml_append_parser_item(parser, ROXML_FUNC_LNAME_STR, _func_xpath_lname);
356 parser = roxml_append_parser_item(parser, "", _func_xpath_default);
357
358 parser = roxml_parser_prepare(parser);
359 ret = roxml_parse_line(parser, path, 0, &ctx);
360 roxml_parser_free(parser);
361
362 if (ret >= 0) {
363 if (xpath)
364 *xpath = ctx.first_node;
365 return ctx.nbpath;
366 }
367
369 return -1;
370}
371
379ROXML_STATIC ROXML_INT int roxml_get_node_internal_position(node_t *n)
380{
381 int idx = 1;
382 node_t *prnt;
383 node_t *first;
384 if (n == NULL)
385 return 0;
386
387 prnt = n->prnt;
388 if (!prnt)
389 return 1;
390 first = prnt->chld;
391
392 while ((first) && (first != n)) {
393 idx++;
394 first = first->sibl;
395 }
396
397 return idx;
398}
399
409ROXML_STATIC ROXML_INT double roxml_double_oper(double a, double b, int op)
410{
411 if (op == ROXML_OPERATOR_ADD)
412 return (a + b);
413 else if (op == ROXML_OPERATOR_SUB)
414 return (a - b);
415 else if (op == ROXML_OPERATOR_MUL)
416 return (a * b);
417 else if (op == ROXML_OPERATOR_DIV)
418 return (a / b);
419 return 0;
420}
421
431ROXML_STATIC ROXML_INT int roxml_double_cmp(double a, double b, int op)
432{
433 if (op == ROXML_OPERATOR_DIFF)
434 return (a != b);
435 else if (op == ROXML_OPERATOR_EINF)
436 return (a <= b);
437 else if (op == ROXML_OPERATOR_INF)
438 return (a < b);
439 else if (op == ROXML_OPERATOR_ESUP)
440 return (a >= b);
441 else if (op == ROXML_OPERATOR_SUP)
442 return (a > b);
443 else if (op == ROXML_OPERATOR_EQU)
444 return (a == b);
445 return 0;
446}
447
457ROXML_STATIC ROXML_INT int roxml_string_cmp(char *sa, char *sb, int op)
458{
459 int result;
460
461 if (!sa)
462 sa = "";
463 if (!sb)
464 sb = "";
465
466 result = strcmp(sa, sb);
467
468 if (op == ROXML_OPERATOR_DIFF)
469 return (result != 0);
470 else if (op == ROXML_OPERATOR_EINF)
471 return (result <= 0);
472 else if (op == ROXML_OPERATOR_INF)
473 return (result < 0);
474 else if (op == ROXML_OPERATOR_ESUP)
475 return (result >= 0);
476 else if (op == ROXML_OPERATOR_SUP)
477 return (result > 0);
478 else if (op == ROXML_OPERATOR_EQU)
479 return (result == 0);
480 return 0;
481}
482
492ROXML_STATIC ROXML_INT int roxml_validate_predicat(xpath_node_t *xn, xpath_cond_t *condition, node_t *candidat)
493{
494 int valid;
495
496 if (!condition)
497 return 1;
498
499 valid = (condition->rel == ROXML_OPERATOR_AND);
500
501 while (condition) {
502 int status = 0;
503 double iarg2 = 1;
504 double iarg1 = 0;
505 char *sarg1 = NULL;
506 node_t *val = candidat;
507 node_t **node_set;
508
509 if (xn->name[0] == '*')
510 iarg1 = roxml_get_node_internal_position(candidat);
511 else
512 iarg1 = roxml_get_node_position(candidat);
513
514 switch (condition->func) {
515 case ROXML_FUNC_POS:
516 iarg2 = roxml_strtonum(condition->arg2, NULL);
517 status = roxml_double_cmp(iarg1, iarg2, condition->op);
518 break;
519 case ROXML_FUNC_LAST:
520 iarg2 = roxml_get_chld_nb(candidat->prnt);
521 // fall through
522 case ROXML_FUNC_FIRST:
523 if (condition->op > 0)
524 iarg2 = roxml_double_oper(iarg2, roxml_strtonum(condition->arg2, NULL), condition->op);
525 status = roxml_double_cmp(iarg1, iarg2, ROXML_OPERATOR_EQU);
526 break;
527 case ROXML_FUNC_INTCOMP:
528 if (condition->arg1)
529 val = roxml_get_attr(candidat, condition->arg1 + 1, 0);
530 sarg1 = roxml_get_content(val, NULL, 0, &status);
531 iarg1 = roxml_strtonum(sarg1, NULL);
532 iarg2 = roxml_strtonum(condition->arg2, NULL);
533 status = roxml_double_cmp(iarg1, iarg2, condition->op);
534 roxml_release(sarg1);
535 break;
536 case ROXML_FUNC_NSURI:
537 val = roxml_get_ns(candidat);
538 sarg1 = roxml_get_content(val, NULL, 0, &status);
539 status = roxml_string_cmp(sarg1, condition->arg2, condition->op);
540 roxml_release(sarg1);
541 break;
542 case ROXML_FUNC_STRCOMP:
543 if (condition->arg1)
544 val = roxml_get_attr(candidat, condition->arg1 + 1, 0);
545 sarg1 = roxml_get_content(val, NULL, 0, &status);
546 status = roxml_string_cmp(sarg1, condition->arg2, condition->op);
547 roxml_release(sarg1);
548 break;
549 case ROXML_FUNC_LNAME:
550 sarg1 = roxml_get_name(candidat, NULL, 0);
551 status = strcmp(sarg1, condition->arg2) == 0;
552 roxml_release(sarg1);
553 break;
554 case ROXML_FUNC_XPATH:
555 val = roxml_get_root(candidat);
556 node_set = roxml_exec_xpath(val, candidat, condition->xp, condition->func2, &status);
557 roxml_release(node_set);
558 status = ! !status;
559 break;
560 default:
561 break;
562 }
563
564 if (condition->rel == ROXML_OPERATOR_OR)
565 valid = valid || status;
566 else if (condition->rel == ROXML_OPERATOR_AND)
567 valid = valid && status;
568 else
569 valid = status;
570
571 condition = condition->next;
572 }
573
574 return valid;
575}
576
577ROXML_STATIC ROXML_INT void roxml_add_to_set(node_t *root, node_t *candidat, node_t ***ans, int *nb, int *max,
578 int req_id)
579{
580 if (roxml_add_to_pool(root, candidat, req_id)) {
581 if (ans) {
582 if ((*nb) >= (*max)) {
583 int new_max = (*max) * 2;
584 node_t **new_ans = roxml_malloc(sizeof(node_t *), new_max, PTR_NODE_RESULT);
585 memcpy(new_ans, (*ans), *(max) * sizeof(node_t *));
586 roxml_release(*ans);
587 *ans = new_ans;
588 *max = new_max;
589 }
590 (*ans)[*nb] = candidat;
591 }
592 (*nb)++;
593 }
594}
595
596ROXML_STATIC ROXML_INT int roxml_validate_axe_func(node_t *root, node_t **candidat, xpath_node_t *xn)
597{
598 int valid = 0;
599 char *axes = xn->name;
600 int type = (*candidat)->type;
601
602 if ((axes == NULL) || (strcmp("node()", axes) == 0)) {
603 valid = 1;
604 } else if (strcmp("*", axes) == 0) {
605 if (type & (ROXML_ELM_NODE | ROXML_ATTR_NODE))
606 valid = 1;
607 } else if (strcmp("comment()", axes) == 0) {
608 if (type & ROXML_CMT_NODE)
609 valid = 1;
610 } else if (strcmp("processing-instruction()", axes) == 0) {
611 if (type & ROXML_PI_NODE)
612 valid = 1;
613 } else if (strcmp("text()", axes) == 0) {
614 if (type & ROXML_TXT_NODE)
615 valid = 1;
616 } else if (strcmp("", axes) == 0) {
617 if (xn->abs) {
618 *candidat = root;
619 valid = 1;
620 }
621 }
622
623 /* comments and pi can only be reached using their comment()
624 * and processing-instruction() functions */
625 if (!valid)
626 if (type & (ROXML_PI_NODE | ROXML_CMT_NODE))
627 return -1;
628 return valid;
629}
630
631ROXML_STATIC ROXML_INT int roxml_validate_axe_name(node_t *candidat, xpath_node_t *xn)
632{
633 int valid = 0;
634 int ns_len;
635 char *name;
636
637 ROXML_GET_BASE_BUFFER(intern_buff);
638
639 if (candidat->ns) {
640 name = roxml_get_name(candidat->ns, intern_buff, ROXML_BASE_LEN);
641 ns_len = strlen(name);
642 if (ns_len)
643 name[ns_len++] = ':';
644 } else {
645 ns_len = 0;
646 name = intern_buff;
647 }
648
649 roxml_get_name(candidat, name + ns_len, ROXML_BASE_LEN - ns_len);
650 if (name && strcmp(name, xn->name) == 0)
651 valid = 1;
652
653 ROXML_PUT_BASE_BUFFER(intern_buff);
654
655 return valid;
656}
657
671ROXML_STATIC ROXML_INT int roxml_validate_axes(node_t *root, node_t *candidat, node_t ***ans, int *nb, int *max,
672 xpath_node_t *xn, int req_id)
673{
674 int valid = 0;
675 int path_end = 0;
676 xpath_node_t empty;
677
678 if (xn == NULL) {
679 valid = 1;
680 path_end = 1;
681 xn = &empty;
682 memset(xn, 0, sizeof(empty));
683 } else {
684 valid = roxml_validate_axe_func(root, &candidat, xn);
685
686 if (xn->next == NULL)
687 path_end = 1;
688 if ((xn->axes == ROXML_ID_SELF) || (xn->axes == ROXML_ID_PARENT))
689 valid = 1;
690
691 if (valid == 0)
692 valid = roxml_validate_axe_name(candidat, xn);
693 }
694
695 if (valid == 1)
696 valid = roxml_validate_predicat(xn, xn->cond, candidat);
697 if (valid == 1)
698 valid = roxml_validate_predicat(xn, xn->xp_cond, candidat);
699
700 if ((valid == 1) && (path_end))
701 roxml_add_to_set(root, candidat, ans, nb, max, req_id);
702
703 return (valid == 1);
704}
705
720ROXML_STATIC ROXML_INT void roxml_check_node(xpath_node_t *xp, node_t *root, node_t *context, node_t ***ans,
721 int *nb, int *max, int ignore, int req_id)
722{
723 int validate_node = 0;
724
725 if ((req_id == 0) && (*nb > 0))
726 return;
727
728 if (!xp)
729 return;
730
731 // if found a "all document" axes
732 if (ignore == ROXML_DESC_ONLY) {
733 node_t *current = context->chld;
734 while (current) {
735 roxml_check_node(xp, root, current, ans, nb, max, ignore, req_id);
736 current = current->sibl;
737 }
738 }
739
740 switch (xp->axes) {
741 case ROXML_ID_CHILD:{
742 node_t *current = context->chld;
743 while (current) {
744 validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
745 if (validate_node)
746 roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
747 current = current->sibl;
748 }
749 if ((xp->name == NULL) || (strcmp(xp->name, "text()") == 0)
750 || (strcmp(xp->name, "node()") == 0)) {
751 node_t *current = roxml_get_txt(context, 0);
752 while (current) {
753 validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
754 current = current->sibl;
755 }
756 }
757 if ((xp->name == NULL) || (strcmp(xp->name, "node()") == 0)) {
758 node_t *current = context->attr;
759 while (current) {
760 validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
761 current = current->sibl;
762 }
763 }
764 }
765 break;
766 case ROXML_ID_DESC:{
767 roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DESC_ONLY, req_id);
768 }
769 break;
770 case ROXML_ID_DESC_O_SELF:{
771 xp = xp->next;
772 validate_node = roxml_validate_axes(root, context, ans, nb, max, xp, req_id);
773 if (validate_node)
774 roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
775 roxml_check_node(xp, root, context, ans, nb, max, ROXML_DESC_ONLY, req_id);
776 }
777 break;
778 case ROXML_ID_SELF:{
779 validate_node = roxml_validate_axes(root, context, ans, nb, max, xp, req_id);
780 roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
781 }
782 break;
783 case ROXML_ID_PARENT:{
784 if (context->prnt) {
785 validate_node = roxml_validate_axes(root, context->prnt, ans, nb, max, xp, req_id);
786 roxml_check_node(xp->next, root, context->prnt, ans, nb, max, ROXML_DIRECT, req_id);
787 } else {
788 validate_node = 0;
789 }
790 }
791 break;
792 case ROXML_ID_ATTR:{
793 node_t *attribute = context->attr;
794 while (attribute) {
795 validate_node = roxml_validate_axes(root, attribute, ans, nb, max, xp, req_id);
796 if (validate_node)
797 roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
798 attribute = attribute->sibl;
799 }
800 }
801 break;
802 case ROXML_ID_ANC:{
803 node_t *current = context->prnt;
804 while (current) {
805 validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
806 if (validate_node)
807 roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
808 current = current->prnt;
809 }
810 }
811 break;
812 case ROXML_ID_NEXT_SIBL:{
813 node_t *current = context->sibl;
814 while (current) {
815 validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
816 if (validate_node)
817 roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
818 current = current->sibl;
819 }
820 }
821 break;
822 case ROXML_ID_PREV_SIBL:{
823 node_t *current = context->prnt->chld;
824 while (current != context) {
825 validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
826 if (validate_node)
827 roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
828 current = current->sibl;
829 }
830 }
831 break;
832 case ROXML_ID_NEXT:{
833 node_t *current = context;
834 while (current) {
835 node_t *following = current->sibl;
836 while (following) {
837 validate_node = roxml_validate_axes(root, following, ans, nb, max, xp, req_id);
838 if (validate_node) {
839 roxml_check_node(xp->next, root, following, ans, nb, max, ROXML_DIRECT,
840 req_id);
841 } else {
842 xp->axes = ROXML_ID_CHILD;
843 roxml_check_node(xp, root, following, ans, nb, max, ROXML_DESC_ONLY,
844 req_id);
845 xp->axes = ROXML_ID_NEXT;
846 }
847 following = following->sibl;
848 }
849 following = current->prnt->chld;
850 while (following != current)
851 following = following->sibl;
852 current = following->sibl;
853 }
854 }
855 break;
856 case ROXML_ID_PREV:{
857 node_t *current = context;
858 while (current && current->prnt) {
859 node_t *preceding = current->prnt->chld;
860 while (preceding != current) {
861 validate_node = roxml_validate_axes(root, preceding, ans, nb, max, xp, req_id);
862 if (validate_node) {
863 roxml_check_node(xp->next, root, preceding, ans, nb, max, ROXML_DIRECT,
864 req_id);
865 } else {
866 xp->axes = ROXML_ID_CHILD;
867 roxml_check_node(xp, root, preceding, ans, nb, max, ROXML_DESC_ONLY,
868 req_id);
869 xp->axes = ROXML_ID_PREV;
870 }
871 preceding = preceding->sibl;
872 }
873 current = current->prnt;
874 }
875 }
876 break;
877 case ROXML_ID_NS:{
878 validate_node = roxml_validate_axes(root, context->ns, ans, nb, max, xp, req_id);
879 if (validate_node)
880 roxml_check_node(xp->next, root, context, ans, nb, max, ROXML_DIRECT, req_id);
881 }
882 break;
883 case ROXML_ID_ANC_O_SELF:{
884 node_t *current = context;
885 while (current) {
886 validate_node = roxml_validate_axes(root, current, ans, nb, max, xp, req_id);
887 if (validate_node)
888 roxml_check_node(xp->next, root, current, ans, nb, max, ROXML_DIRECT, req_id);
889 current = current->prnt;
890 }
891 }
892 break;
893 }
894
895 return;
896}
897
898ROXML_INT node_t **roxml_exec_xpath(node_t *root, node_t *n, xpath_node_t *xpath, int index, int *count)
899{
900 int path_id;
901 int max_answers = 1;
902 int glob_id = 0;
903 int *req_ids = NULL;
904 node_t **node_set;
905
906 *count = 0;
907 glob_id = roxml_request_id(root);
908 if (glob_id < 0)
909 return NULL;
910 req_ids = calloc(index, sizeof(int));
911 node_set = roxml_malloc(sizeof(node_t *), max_answers, PTR_NODE_RESULT);
912
913 /* process all AND xpath */
914 for (path_id = 0; path_id < index; path_id++) {
915 xpath_node_t *cur_xpath = NULL;
916 xpath_node_t *next_xpath = NULL;
917 cur_xpath = &xpath[path_id];
918
919 if (path_id < index - 1)
920 next_xpath = &xpath[path_id + 1];
921
922 if ((cur_xpath->rel == ROXML_OPERATOR_AND) || ((next_xpath) && (next_xpath->rel == ROXML_OPERATOR_AND))) {
923 int req_id = roxml_request_id(root);
924 node_t *orig = n;
925
926 if (cur_xpath->abs)
927 /* context node is root */
928 orig = root;
929
930 roxml_check_node(cur_xpath, root, orig, &node_set, count, &max_answers, ROXML_DIRECT, req_id);
931
932 if (cur_xpath->rel == ROXML_OPERATOR_AND)
933 roxml_compute_and(root, node_set, count, req_id, req_ids[path_id - 1]);
934 req_ids[path_id] = req_id;
935 }
936 }
937
938 /* process all OR xpath */
939 for (path_id = 0; path_id < index; path_id++) {
940 xpath_node_t *cur_xpath = &xpath[path_id];
941
942 if (cur_xpath->rel == ROXML_OPERATOR_OR) {
943 node_t *orig = n;
944
945 if (req_ids[path_id] == 0) {
946 if (cur_xpath->abs)
947 orig = root;
948
949 /* assign a new request ID */
950 roxml_check_node(cur_xpath, root, orig, &node_set, count, &max_answers, ROXML_DIRECT,
951 glob_id);
952 } else {
953 roxml_compute_or(root, node_set, count, req_ids[path_id + 1], glob_id);
954 roxml_release_id(root, node_set, *count, req_ids[path_id + 1]);
955 }
956 }
957 }
958
959 roxml_release_id(root, node_set, *count, glob_id);
960
961 for (path_id = 0; path_id < index; path_id++)
962 if (req_ids[path_id] != 0)
963 roxml_release_id(root, node_set, *count, req_ids[path_id]);
964 free(req_ids);
965
966 return node_set;
967}
968
969ROXML_API node_t **roxml_xpath(node_t *n, char *path, int *nb_ans)
970{
971 int count = 0;
972 node_t **node_set = NULL;
973 int index = 0;
974 xpath_node_t *xpath = NULL;
975 node_t *root = n;
976 char *full_path_to_find;
977
978 if (n == ROXML_INVALID_DOC) {
979 if (nb_ans)
980 *nb_ans = 0;
981 return NULL;
982 }
983
984 root = roxml_get_root(n);
985
986 full_path_to_find = strdup(path);
987
988 index = roxml_parse_xpath(full_path_to_find, &xpath, 0);
989
990 if (index >= 0) {
991 node_set = roxml_exec_xpath(root, n, xpath, index, &count);
992 roxml_free_xpath(xpath, index);
993
994 if (count == 0) {
995 roxml_release(node_set);
996 node_set = NULL;
997 }
998 }
999 if (nb_ans)
1000 *nb_ans = count;
1001 free(full_path_to_find);
1002
1003 return node_set;
1004}
1005
1015ROXML_STATIC ROXML_INT xpath_node_t *roxml_set_axes(xpath_node_t *node, char *axes, int *offset)
1016{
1017 struct _xpath_axes {
1018 char id;
1019 char *name;
1020 };
1021
1022 struct _xpath_axes xpath_axes[14] = {
1023 {ROXML_ID_PARENT, ROXML_L_PARENT},
1024 {ROXML_ID_PARENT, ROXML_S_PARENT},
1025 {ROXML_ID_SELF, ROXML_L_SELF},
1026 {ROXML_ID_SELF, ROXML_S_SELF},
1027 {ROXML_ID_ATTR, ROXML_L_ATTR},
1028 {ROXML_ID_ATTR, ROXML_S_ATTR},
1029 {ROXML_ID_ANC, ROXML_L_ANC},
1030 {ROXML_ID_ANC_O_SELF, ROXML_L_ANC_O_SELF},
1031 {ROXML_ID_NEXT_SIBL, ROXML_L_NEXT_SIBL},
1032 {ROXML_ID_PREV_SIBL, ROXML_L_PREV_SIBL},
1033 {ROXML_ID_NEXT, ROXML_L_NEXT},
1034 {ROXML_ID_PREV, ROXML_L_PREV},
1035 {ROXML_ID_NS, ROXML_L_NS},
1036 {ROXML_ID_CHILD, ROXML_L_CHILD},
1037 };
1038
1039 xpath_node_t *tmp_node;
1040 if (axes[0] == '/') {
1041 axes[0] = '\0';
1042 *offset += 1;
1043 axes++;
1044 }
1045 if (axes[0] == '/') {
1046 /* ROXML_S_DESC_O_SELF */
1047 node->axes = ROXML_ID_DESC_O_SELF;
1048 node->name = axes + 1;
1049 tmp_node = calloc(1, sizeof(xpath_node_t));
1050 tmp_node->axes = ROXML_ID_CHILD;
1051 node->next = tmp_node;
1052 if (strlen(node->name) > 0) {
1053 tmp_node = calloc(1, sizeof(xpath_node_t));
1054 node->next->next = tmp_node;
1055 node = roxml_set_axes(tmp_node, axes + 1, offset);
1056 }
1057 } else if (strncmp(ROXML_L_DESC_O_SELF, axes, strlen(ROXML_L_DESC_O_SELF)) == 0) {
1058 /* ROXML_L_DESC_O_SELF */
1059 node->axes = ROXML_ID_DESC_O_SELF;
1060 node->name = axes + strlen(ROXML_L_DESC_O_SELF);
1061 *offset += strlen(ROXML_L_DESC_O_SELF);
1062 tmp_node = calloc(1, sizeof(xpath_node_t));
1063 tmp_node->axes = ROXML_ID_CHILD;
1064 node->next = tmp_node;
1065 node = roxml_set_axes(tmp_node, axes + strlen(ROXML_L_DESC_O_SELF), offset);
1066 } else if (strncmp(ROXML_L_DESC, axes, strlen(ROXML_L_DESC)) == 0) {
1067 /* ROXML_L_DESC */
1068 node->axes = ROXML_ID_DESC;
1069 node->name = axes + strlen(ROXML_L_DESC);
1070 *offset += strlen(ROXML_L_DESC);
1071 tmp_node = calloc(1, sizeof(xpath_node_t));
1072 tmp_node->axes = ROXML_ID_CHILD;
1073 node->next = tmp_node;
1074 node = roxml_set_axes(tmp_node, axes + strlen(ROXML_L_DESC), offset);
1075 } else {
1076 int i = 0;
1077
1078 /* ROXML_S_CHILD is default */
1079 node->axes = ROXML_ID_CHILD;
1080 node->name = axes;
1081
1082 for (i = 0; i < 14; i++) {
1083 int len = strlen(xpath_axes[i].name);
1084 if (strncmp(xpath_axes[i].name, axes, len) == 0) {
1085 node->axes = xpath_axes[i].id;
1086 node->name = axes + len;
1087 break;
1088 }
1089 }
1090 }
1091 return node;
1092}
1093
1094ROXML_INT int _func_xpath_ignore(roxml_parser_item_t *parser, char *chunk, void *data)
1095{
1096#ifdef DEBUG_PARSING
1097 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1098#endif /* DEBUG_PARSING */
1099 return 1;
1100}
1101
1102ROXML_INT int _func_xpath_new_node(roxml_parser_item_t *parser, char *chunk, void *data)
1103{
1104 int cur = 0;
1105 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1106#ifdef DEBUG_PARSING
1107 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1108#endif /* DEBUG_PARSING */
1109 if (!ctx->quoted && !ctx->dquoted && !ctx->parenthesys && !ctx->bracket) {
1110 int offset = 0;
1111 xpath_node_t *tmp_node = calloc(1, sizeof(xpath_node_t));
1112 if ((chunk[cur] == '/') && (ctx->is_first_node)) {
1113 free(tmp_node);
1114 ctx->new_node = ctx->first_node;
1115 ctx->first_node->abs = 1;
1116 } else if ((chunk[cur] == '/') && (ctx->wait_first_node)) {
1117 free(tmp_node);
1118 ctx->first_node->abs = 1;
1119 } else if ((ctx->is_first_node) || (ctx->wait_first_node)) {
1120 free(tmp_node);
1121 } else {
1122 if (ctx->new_node)
1123 ctx->new_node->next = tmp_node;
1124 ctx->new_node = tmp_node;
1125 }
1126 ctx->is_first_node = 0;
1127 ctx->wait_first_node = 0;
1128 ctx->new_node = roxml_set_axes(ctx->new_node, chunk + cur, &offset);
1129 cur = offset + 1;
1130 }
1131 ctx->shorten_cond = 0;
1132 return cur;
1133}
1134
1135ROXML_INT int _func_xpath_quote(roxml_parser_item_t *parser, char *chunk, void *data)
1136{
1137 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1138#ifdef DEBUG_PARSING
1139 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1140#endif /* DEBUG_PARSING */
1141 if (!ctx->dquoted) {
1142 if (ctx->quoted && ctx->content_quoted == MODE_COMMENT_QUOTE) {
1144 chunk[0] = '\0';
1145 }
1146 ctx->quoted = (ctx->quoted + 1) % 2;
1147 }
1148 ctx->shorten_cond = 0;
1149 return 1;
1150}
1151
1152ROXML_INT int _func_xpath_dquote(roxml_parser_item_t *parser, char *chunk, void *data)
1153{
1154 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1155#ifdef DEBUG_PARSING
1156 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1157#endif /* DEBUG_PARSING */
1158 if (!ctx->quoted) {
1159 if (ctx->dquoted && ctx->content_quoted == MODE_COMMENT_DQUOTE) {
1161 chunk[0] = '\0';
1162 }
1163 ctx->dquoted = (ctx->dquoted + 1) % 2;
1164 }
1165 ctx->shorten_cond = 0;
1166 return 1;
1167}
1168
1169ROXML_INT int _func_xpath_open_parenthesys(roxml_parser_item_t *parser, char *chunk, void *data)
1170{
1171 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1172#ifdef DEBUG_PARSING
1173 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1174#endif /* DEBUG_PARSING */
1175 if (!ctx->quoted && !ctx->dquoted)
1176 ctx->parenthesys = (ctx->parenthesys + 1) % 2;
1177 ctx->shorten_cond = 0;
1178 return 1;
1179}
1180
1181ROXML_INT int _func_xpath_close_parenthesys(roxml_parser_item_t *parser, char *chunk, void *data)
1182{
1183 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1184#ifdef DEBUG_PARSING
1185 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1186#endif /* DEBUG_PARSING */
1187 if (!ctx->quoted && !ctx->dquoted)
1188 ctx->parenthesys = (ctx->parenthesys + 1) % 2;
1189 ctx->shorten_cond = 0;
1190 return 1;
1191}
1192
1193ROXML_INT int _func_xpath_open_brackets(roxml_parser_item_t *parser, char *chunk, void *data)
1194{
1195 xpath_cond_t *tmp_cond;
1196 int cur = 0;
1197#ifdef DEBUG_PARSING
1198 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1199#endif /* DEBUG_PARSING */
1200 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1201 if (!ctx->quoted && !ctx->dquoted) {
1202 ctx->bracket = (ctx->bracket + 1) % 2;
1203 chunk[0] = '\0';
1204
1205 ctx->shorten_cond = 1;
1206 tmp_cond = calloc(1, sizeof(xpath_cond_t));
1207 ctx->new_node->cond = tmp_cond;
1208 ctx->new_cond = tmp_cond;
1209 ctx->new_cond->arg1 = chunk + cur + 1;
1210 } else {
1211 ctx->shorten_cond = 0;
1212 }
1213 cur++;
1214 return 1;
1215}
1216
1217ROXML_INT int _func_xpath_close_brackets(roxml_parser_item_t *parser, char *chunk, void *data)
1218{
1219 int cur = 0;
1220 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1221#ifdef DEBUG_PARSING
1222 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1223#endif /* DEBUG_PARSING */
1224 if (!ctx->quoted && !ctx->dquoted) {
1225 ctx->bracket = (ctx->bracket + 1) % 2;
1226 chunk[0] = '\0';
1227
1228 if (ctx->new_cond) {
1229 if (ctx->new_cond->func == ROXML_FUNC_XPATH) {
1230 xpath_node_t *xp;
1231 ctx->new_cond->func2 = roxml_parse_xpath(ctx->new_cond->arg1, &xp, 1);
1232 ctx->new_cond->xp = xp;
1233 }
1234 } else {
1235 return -1;
1236 }
1237 }
1238 cur++;
1239 ctx->shorten_cond = 0;
1240 return 1;
1241}
1242
1243ROXML_INT int _func_xpath_condition_or(roxml_parser_item_t *parser, char *chunk, void *data)
1244{
1245 xpath_node_t *tmp_node;
1246 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1247 int cur = 0;
1248 int len = 0;
1249 xpath_cond_t *tmp_cond;
1250#ifdef DEBUG_PARSING
1251 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1252#endif /* DEBUG_PARSING */
1253
1254 len = strlen(ROXML_COND_OR);
1255
1256 if (strncmp(chunk, ROXML_COND_OR, len) == 0) {
1257 if (roxml_is_separator(*(chunk - 1)) && roxml_is_separator(*(chunk + len))) {
1258 if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1259 if (ctx->context != 1) {
1260 return 0;
1261 }
1262 chunk[-1] = '\0';
1263 cur += strlen(ROXML_COND_OR);
1264 tmp_node = calloc(ctx->nbpath + 1, sizeof(xpath_node_t));
1265 memcpy(tmp_node, ctx->first_node, ctx->nbpath * sizeof(xpath_node_t));
1266 free(ctx->first_node);
1267 ctx->first_node = tmp_node;
1268 ctx->wait_first_node = 1;
1269 ctx->new_node = tmp_node + ctx->nbpath;
1270 ctx->new_node->rel = ROXML_OPERATOR_OR;
1271 ctx->nbpath++;
1272 } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1273 if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1274 chunk[-1] = '\0';
1275 cur += strlen(ROXML_COND_OR);
1276 tmp_cond = calloc(1, sizeof(xpath_cond_t));
1277 if (ctx->new_cond) {
1278 ctx->new_cond->next = tmp_cond;
1279 }
1280 ctx->new_cond = tmp_cond;
1281 ctx->new_cond->rel = ROXML_OPERATOR_OR;
1282 ctx->new_cond->arg1 = chunk + cur + 1;
1283 }
1284 }
1285 }
1286 }
1287 if (cur)
1288 ctx->shorten_cond = 0;
1289 return cur;
1290}
1291
1292ROXML_INT int _func_xpath_condition_and(roxml_parser_item_t *parser, char *chunk, void *data)
1293{
1294 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1295 int cur = 0;
1296 int len = 0;
1297 xpath_node_t *tmp_node;
1298 xpath_cond_t *tmp_cond;
1299#ifdef DEBUG_PARSING
1300 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1301#endif /* DEBUG_PARSING */
1302
1303 len = strlen(ROXML_COND_AND);
1304
1305 if (strncmp(chunk, ROXML_COND_AND, len) == 0) {
1306 if (roxml_is_separator(*(chunk - 1)) && roxml_is_separator(*(chunk + len))) {
1307 if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1308 if (ctx->context != 1)
1309 return 0;
1310 chunk[-1] = '\0';
1311 cur += strlen(ROXML_COND_AND);
1312 tmp_node = calloc(ctx->nbpath + 1, sizeof(xpath_node_t));
1313 memcpy(tmp_node, ctx->first_node, ctx->nbpath * sizeof(xpath_node_t));
1314 free(ctx->first_node);
1315 ctx->first_node = tmp_node;
1316 ctx->wait_first_node = 1;
1317 ctx->new_node = tmp_node + ctx->nbpath;
1318 ctx->new_node->rel = ROXML_OPERATOR_AND;
1319 ctx->nbpath++;
1320 } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1321 if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1322 chunk[-1] = '\0';
1323 cur += strlen(ROXML_COND_AND);
1324 tmp_cond = calloc(1, sizeof(xpath_cond_t));
1325 if (ctx->new_cond) {
1326 ctx->new_cond->next = tmp_cond;
1327 }
1328 ctx->new_cond = tmp_cond;
1329 ctx->new_cond->rel = ROXML_OPERATOR_AND;
1330 ctx->new_cond->arg1 = chunk + cur + 1;
1331 }
1332 }
1333 }
1334 }
1335 if (cur)
1336 ctx->shorten_cond = 0;
1337 return cur;
1338}
1339
1340ROXML_INT int _func_xpath_path_or(roxml_parser_item_t *parser, char *chunk, void *data)
1341{
1342 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1343 int cur = 0;
1344 xpath_node_t *tmp_node;
1345#ifdef DEBUG_PARSING
1346 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1347#endif /* DEBUG_PARSING */
1348
1349 if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1350 chunk[-1] = '\0';
1351 cur += strlen(ROXML_PATH_OR);
1352 tmp_node = calloc(ctx->nbpath + 1, sizeof(xpath_node_t));
1353 memcpy(tmp_node, ctx->first_node, ctx->nbpath * sizeof(xpath_node_t));
1354 free(ctx->first_node);
1355 ctx->first_node = tmp_node;
1356 ctx->wait_first_node = 1;
1357 ctx->new_node = tmp_node + ctx->nbpath;
1358 ctx->new_node->rel = ROXML_OPERATOR_OR;
1359 ctx->nbpath++;
1360 }
1361 ctx->shorten_cond = 0;
1362 return cur;
1363}
1364
1365ROXML_INT int _func_xpath_operators(roxml_parser_item_t *parser, char *chunk, void *data, int operator, int operator_bis)
1366{
1367 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1368 int cur = 0;
1369 if (!ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1370 xpath_node_t *xp_root = ctx->new_node;
1371 xpath_cond_t *xp_cond = calloc(1, sizeof(xpath_cond_t));
1372 xp_root->xp_cond = xp_cond;
1373 chunk[cur] = '\0';
1374 xp_cond->op = operator;
1375 if (ROXML_WHITE(chunk[cur - 1]))
1376 chunk[cur - 1] = '\0';
1377 if (chunk[cur + 1] == '=') {
1378 chunk[++cur] = '\0';
1379 xp_cond->op = operator_bis;
1380 }
1381 if (ROXML_WHITE(chunk[cur + 1]))
1382 chunk[++cur] = '\0';
1383
1384 xp_cond->arg2 = chunk + cur + 1;
1385 if (xp_cond->arg2[0] == '"') {
1387 xp_cond->arg2++;
1388 } else if (xp_cond->arg2[0] == '\'') {
1390 xp_cond->arg2++;
1391 }
1392 if (!xp_cond->func) {
1393 xp_cond->func = ROXML_FUNC_INTCOMP;
1394 if (!roxml_is_number(xp_cond->arg2))
1395 xp_cond->func = ROXML_FUNC_STRCOMP;
1396 }
1397 cur++;
1398 } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1399 if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1400 chunk[cur] = '\0';
1401 ctx->new_cond->op = operator;
1402 if (ROXML_WHITE(chunk[cur - 1]))
1403 chunk[cur - 1] = '\0';
1404 if (chunk[cur + 1] == '=') {
1405 chunk[++cur] = '\0';
1406 ctx->new_cond->op = operator_bis;
1407 }
1408 if (ROXML_WHITE(chunk[cur + 1]))
1409 chunk[++cur] = '\0';
1410 ctx->new_cond->arg2 = chunk + cur + 1;
1411 if (ctx->new_cond->arg2[0] == '"') {
1413 ctx->new_cond->arg2++;
1414 } else if (ctx->new_cond->arg2[0] == '\'') {
1416 ctx->new_cond->arg2++;
1417 }
1418 if (ctx->new_cond->func == 0) {
1419 ctx->new_cond->func = ROXML_FUNC_INTCOMP;
1420 if (!roxml_is_number(ctx->new_cond->arg2))
1421 ctx->new_cond->func = ROXML_FUNC_STRCOMP;
1422 }
1423 cur++;
1424 }
1425 }
1426 ctx->shorten_cond = 0;
1427 return cur;
1428}
1429
1430ROXML_INT int _func_xpath_operator_equal(roxml_parser_item_t *parser, char *chunk, void *data)
1431{
1432#ifdef DEBUG_PARSING
1433 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1434#endif /* DEBUG_PARSING */
1435 return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_EQU, ROXML_OPERATOR_EQU);
1436}
1437
1438ROXML_INT int _func_xpath_operator_sup(roxml_parser_item_t *parser, char *chunk, void *data)
1439{
1440#ifdef DEBUG_PARSING
1441 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1442#endif /* DEBUG_PARSING */
1443 return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_SUP, ROXML_OPERATOR_ESUP);
1444}
1445
1446ROXML_INT int _func_xpath_operator_inf(roxml_parser_item_t *parser, char *chunk, void *data)
1447{
1448#ifdef DEBUG_PARSING
1449 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1450#endif /* DEBUG_PARSING */
1451 return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_INF, ROXML_OPERATOR_EINF);
1452}
1453
1454ROXML_INT int _func_xpath_operator_diff(roxml_parser_item_t *parser, char *chunk, void *data)
1455{
1456#ifdef DEBUG_PARSING
1457 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1458#endif /* DEBUG_PARSING */
1459 return _func_xpath_operators(parser, chunk, data, ROXML_OPERATOR_DIFF, ROXML_OPERATOR_DIFF);
1460}
1461
1462ROXML_INT int _func_xpath_number(roxml_parser_item_t *parser, char *chunk, void *data)
1463{
1464#ifdef DEBUG_PARSING
1465 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1466#endif /* DEBUG_PARSING */
1467 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1468 int cur = 0;
1469 if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1470 if ((ctx->new_cond->func != ROXML_FUNC_XPATH) && (ctx->shorten_cond)) {
1471 cur = 1;
1472 ctx->new_cond->func = ROXML_FUNC_POS;
1473 ctx->new_cond->op = ROXML_OPERATOR_EQU;
1474 ctx->new_cond->arg2 = chunk;
1475 while ((chunk[cur + 1] >= '0') && (chunk[cur + 1] <= '9'))
1476 cur++;
1477 }
1478 }
1479 ctx->shorten_cond = 0;
1480 return cur;
1481}
1482
1483ROXML_INT int _func_xpath_funcs(roxml_parser_item_t *parser, char *chunk, void *data, int func, char *name)
1484{
1485#ifdef DEBUG_PARSING
1486 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1487#endif /* DEBUG_PARSING */
1488 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1489 int cur = 0;
1490
1491 if (strncmp(chunk, name, strlen(name)) == 0) {
1492 if (ctx->new_cond->func != func) {
1493 cur += strlen(name);
1494 ctx->new_cond->func = func;
1495 }
1496 }
1497 if (cur)
1498 ctx->shorten_cond = 0;
1499 return cur;
1500}
1501
1502ROXML_INT int _func_xpath_position(roxml_parser_item_t *parser, char *chunk, void *data)
1503{
1504#ifdef DEBUG_PARSING
1505 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1506#endif /* DEBUG_PARSING */
1507 return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_POS, ROXML_FUNC_POS_STR);
1508}
1509
1510ROXML_INT int _func_xpath_first(roxml_parser_item_t *parser, char *chunk, void *data)
1511{
1512#ifdef DEBUG_PARSING
1513 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1514#endif /* DEBUG_PARSING */
1515 return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_FIRST, ROXML_FUNC_FIRST_STR);
1516}
1517
1518ROXML_INT int _func_xpath_last(roxml_parser_item_t *parser, char *chunk, void *data)
1519{
1520#ifdef DEBUG_PARSING
1521 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1522#endif /* DEBUG_PARSING */
1523 return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_LAST, ROXML_FUNC_LAST_STR);
1524}
1525
1526ROXML_INT int _func_xpath_nsuri(roxml_parser_item_t *parser, char *chunk, void *data)
1527{
1528#ifdef DEBUG_PARSING
1529 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1530#endif /* DEBUG_PARSING */
1531 return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_NSURI, ROXML_FUNC_NSURI_STR);
1532}
1533
1534ROXML_INT int _func_xpath_lname(roxml_parser_item_t *parser, char *chunk, void *data)
1535{
1536#ifdef DEBUG_PARSING
1537 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1538#endif /* DEBUG_PARSING */
1539 return _func_xpath_funcs(parser, chunk, data, ROXML_FUNC_LNAME, ROXML_FUNC_LNAME_STR);
1540}
1541
1542ROXML_INT int _func_xpath_operator_add(roxml_parser_item_t *parser, char *chunk, void *data)
1543{
1544#ifdef DEBUG_PARSING
1545 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1546#endif /* DEBUG_PARSING */
1547 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1548 int cur = 0;
1549 if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1550 if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1551 if ((ctx->new_cond->func == ROXML_FUNC_LAST) || (ctx->new_cond->func == ROXML_FUNC_FIRST))
1552 ctx->new_cond->op = ROXML_OPERATOR_ADD;
1553 chunk[cur] = '\0';
1554 if (ROXML_WHITE(chunk[cur + 1]))
1555 chunk[++cur] = '\0';
1556 ctx->new_cond->arg2 = chunk + cur + 1;
1557 }
1558 }
1559 ctx->shorten_cond = 0;
1560 return cur;
1561}
1562
1563ROXML_INT int _func_xpath_operator_subs(roxml_parser_item_t *parser, char *chunk, void *data)
1564{
1565#ifdef DEBUG_PARSING
1566 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1567#endif /* DEBUG_PARSING */
1568 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1569 int cur = 0;
1570 if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1571 if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1572 if ((ctx->new_cond->func == ROXML_FUNC_LAST) || (ctx->new_cond->func == ROXML_FUNC_FIRST))
1573 ctx->new_cond->op = ROXML_OPERATOR_SUB;
1574 chunk[cur] = '\0';
1575 if (ROXML_WHITE(chunk[cur + 1]))
1576 chunk[++cur] = '\0';
1577 ctx->new_cond->arg2 = chunk + cur + 1;
1578 }
1579 }
1580 ctx->shorten_cond = 0;
1581 return cur;
1582}
1583
1584ROXML_INT int _func_xpath_default(roxml_parser_item_t *parser, char *chunk, void *data)
1585{
1586#ifdef DEBUG_PARSING
1587 fprintf(stderr, "calling func %s chunk %c\n", __func__, chunk[0]);
1588#endif /* DEBUG_PARSING */
1589 int cur = 0;
1590 roxml_xpath_ctx_t *ctx = (roxml_xpath_ctx_t *)data;
1591
1592 if ((ctx->is_first_node) || (ctx->wait_first_node)) {
1593 if (!ctx->quoted && !ctx->dquoted && !ctx->parenthesys && !ctx->bracket) {
1594 int offset = 0;
1595 xpath_node_t *tmp_node = calloc(1, sizeof(xpath_node_t));
1596 if ((chunk[cur] == '/') && (ctx->is_first_node)) {
1597 free(tmp_node);
1598 ctx->new_node = ctx->first_node;
1599 ctx->first_node->abs = 1;
1600 } else if ((chunk[cur] == '/') && (ctx->wait_first_node)) {
1601 free(tmp_node);
1602 ctx->first_node->abs = 1;
1603 } else if ((ctx->is_first_node) || (ctx->wait_first_node)) {
1604 free(tmp_node);
1605 } else {
1606 if (ctx->new_node)
1607 ctx->new_node->next = tmp_node;
1608 ctx->new_node = tmp_node;
1609 }
1610 ctx->is_first_node = 0;
1611 ctx->wait_first_node = 0;
1612 ctx->new_node = roxml_set_axes(ctx->new_node, chunk + cur, &offset);
1613 cur += offset;
1614 }
1615 } else if (ctx->bracket && !ctx->quoted && !ctx->dquoted) {
1616 if (ctx->new_cond->func != ROXML_FUNC_XPATH) {
1617 if (ctx->shorten_cond) {
1618 int bracket_lvl = 1;
1619 ctx->new_cond->func = ROXML_FUNC_XPATH;
1620 ctx->new_cond->arg1 = chunk + cur;
1621 while (bracket_lvl > 0) {
1622 if (chunk[cur] == '[')
1623 bracket_lvl++;
1624 else if (chunk[cur] == ']')
1625 bracket_lvl--;
1626 cur++;
1627 }
1628 cur--;
1629 }
1630 }
1631 }
1632 ctx->shorten_cond = 0;
1633 return cur > 0 ? cur : 1;
1634}
ROXML_API node_t * roxml_get_root(node_t *n)
root getter function
Definition roxml_nav.c:55
#define ROXML_CMT_NODE
Definition roxml.h:86
#define ROXML_PI_NODE
Definition roxml.h:94
#define ROXML_INVALID_DOC
Definition roxml.h:235
ROXML_API void roxml_release(void *data)
memory cleanning function
Definition roxml_mem.c:109
#define ROXML_ATTR_NODE
Definition roxml.h:51
#define ROXML_TXT_NODE
Definition roxml.h:78
#define ROXML_ELM_NODE
Definition roxml.h:70
#define ROXML_API
Definition roxml.h:24
ROXML_API int roxml_get_chld_nb(node_t *n)
chlds number getter function
ROXML_API node_t * roxml_get_txt(node_t *n, int nth)
text node getter function
ROXML_API node_t * roxml_get_attr(node_t *n, char *name, int nth)
attribute getter function
ROXML_API int roxml_get_node_position(node_t *n)
node get position function
ROXML_API char * roxml_get_content(node_t *n, char *buffer, int bufsize, int *size)
content getter function
ROXML_API node_t * roxml_get_ns(node_t *n)
namespace getter function
ROXML_API char * roxml_get_name(node_t *n, char *buffer, int size)
name getter function
ROXML_INT int roxml_is_separator(char sep)
separator tester
Definition roxml_core.c:128
XML parsing core module.
#define MODE_COMMENT_DQUOTE
#define MODE_COMMENT_QUOTE
#define ROXML_WHITE(n)
#define ROXML_BASE_LEN
#define MODE_COMMENT_NONE
#define PTR_NODE_RESULT
ROXML_INT void * roxml_malloc(int size, int num, int type)
alloc memory function
Definition roxml_mem.c:124
XML internal memory management module.
ROXML_INT int roxml_parse_line(roxml_parser_item_t *parser, char *line, int len, void *ctx)
line parsing function
ROXML_INT roxml_parser_item_t * roxml_parser_prepare(roxml_parser_item_t *parser)
parser preparation function
ROXML_INT roxml_parser_item_t * roxml_append_parser_item(roxml_parser_item_t *parser, char *key, roxml_parse_func func)
parser item creation function
ROXML_INT void roxml_parser_free(roxml_parser_item_t *parser)
parser table deletion
Parsing engine.
ROXML_STATIC ROXML_INT int roxml_validate_predicat(xpath_node_t *xn, xpath_cond_t *condition, node_t *candidat)
predicat validation function
ROXML_STATIC ROXML_INT void roxml_free_xcond(xpath_cond_t *xcond)
xpath condition free function
Definition roxml_xpath.c:55
ROXML_STATIC ROXML_INT int roxml_double_cmp(double a, double b, int op)
double comparison function
ROXML_STATIC ROXML_INT int roxml_validate_axes(node_t *root, node_t *candidat, node_t ***ans, int *nb, int *max, xpath_node_t *xn, int req_id)
axe validation function
ROXML_API node_t ** roxml_xpath(node_t *n, char *path, int *nb_ans)
exec path function
ROXML_STATIC ROXML_INT xpath_node_t * roxml_set_axes(xpath_node_t *node, char *axes, int *offset)
axes setter function
ROXML_STATIC ROXML_INT int roxml_get_node_internal_position(node_t *n)
node absolute position get
ROXML_INT void roxml_free_xpath(xpath_node_t *xpath, int nb)
xpath free function
Definition roxml_xpath.c:64
ROXML_STATIC ROXML_INT void roxml_compute_and(node_t *root, node_t **node_set, int *count, int cur_req_id, int prev_req_id)
node set and function
ROXML_STATIC ROXML_INT int roxml_string_cmp(char *sa, char *sb, int op)
string comparison function
ROXML_STATIC ROXML_INT int roxml_parse_xpath(char *path, xpath_node_t **xpath, int context)
xpath parsing function
ROXML_STATIC ROXML_INT int roxml_add_to_pool(node_t *root, node_t *n, int req_id)
add a token top node function
ROXML_INT node_t ** roxml_exec_xpath(node_t *root, node_t *n, xpath_node_t *xpath, int index, int *count)
real xpath execution
ROXML_STATIC ROXML_INT void roxml_release_id(node_t *root, node_t **pool, int pool_len, int req_id)
release id function
ROXML_STATIC ROXML_INT int roxml_in_pool(node_t *root, node_t *n, int req_id)
node pool presence tester function
Definition roxml_xpath.c:86
ROXML_STATIC ROXML_INT void roxml_del_from_pool(node_t *root, node_t *n, int req_id)
pool node delete function
ROXML_STATIC ROXML_INT void roxml_compute_or(node_t *root, node_t **node_set, int *count, int req_id, int glob_id)
node set or function
ROXML_STATIC ROXML_INT double roxml_double_oper(double a, double b, int op)
double operation function
ROXML_STATIC ROXML_INT int roxml_is_number(char *input)
number tester
Definition roxml_xpath.c:25
ROXML_STATIC ROXML_INT int roxml_request_id(node_t *root)
id reservation function
ROXML_STATIC ROXML_INT void roxml_check_node(xpath_node_t *xp, node_t *root, node_t *context, node_t ***ans, int *nb, int *max, int ignore, int req_id)
real xpath validation function
xpath execution module
node_t structure
struct node * prnt
struct node * ns
void * priv
struct node * chld
struct node * attr
struct node * sibl
the parser item struct
xpath parsing context
xpath_node_t * first_node
xpath_node_t * new_node
xpath_cond_t * new_cond
xpath cond structure
Definition roxml_types.h:56
struct _xpath_cond * next
Definition roxml_types.h:66
struct _xpath_node * xp
Definition roxml_types.h:65
xpath node structure
Definition roxml_types.h:76
struct _xpath_cond * xp_cond
Definition roxml_types.h:81
struct _xpath_cond * cond
Definition roxml_types.h:82
struct _xpath_node * next
Definition roxml_types.h:83
xpath token structure
struct _xpath_tok * next
unsigned char id
xpath token structure
Definition roxml_types.h:93
unsigned char ids[256]
Definition roxml_types.h:95