43fe1d0b8b6d25ade0941f331238edf316f5649a
[idzebra-moved-to-github.git] / util / xpath.c
1 /* $Id: xpath.c,v 1.2 2003-03-01 20:41:34 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <ctype.h>
28 #include <yaz/nmem.h>
29 #include <zebra_xpath.h>
30
31 char *get_xp_part (char **strs, NMEM mem)
32 {
33     char *str = *strs;
34     char *res = '\0';
35     char *cp = str;
36     char *co;
37     int quoted = 0;
38     
39     /* ugly */
40     char *sep = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\" ";
41     
42     while (*cp == ' ') {cp++; str++;}
43     if (!strchr("><=] ", *cp)) sep = "><=] ";
44     
45     while (*cp && !(strchr(sep,*cp) && !quoted) && (*cp != ']')) {
46         if (*cp =='"') quoted = 1 - quoted;
47         cp++;
48     }  
49     /* removing leading and trailing " */
50     co = cp;
51     if (*str == '"') str++;
52     if (*(cp-1) == '"') cp--;
53     if (str < co) {
54         res = nmem_malloc(mem, cp - str + 1);
55     memcpy (res, str, (cp-str));
56     *(res + (cp-str)) = '\0';
57     *strs = co;
58     }
59     
60     return (res);
61 }
62
63
64 struct xpath_predicate *get_xpath_predicate(char *predicates, NMEM mem) 
65 {
66     char *p1;
67     char *p2;
68     char *p3;
69     char *p4;
70     
71     struct xpath_predicate *r1;
72     struct xpath_predicate *r2;
73     struct xpath_predicate *res = 0;
74     
75     char *pr = predicates;
76     
77     if ((p1 = get_xp_part(&pr, mem))) {
78         if ((p2 = get_xp_part(&pr, mem))) {
79             if (!strcmp (p2, "and") || !strcmp (p2, "or") || !strcmp (p2, "not")) {
80                 r1=nmem_malloc(mem, sizeof(struct xpath_predicate));
81                 r1->which = XPATH_PREDICATE_RELATION;
82                 r1->u.relation.name = p1;
83                 r1->u.relation.op = "";
84                 r1->u.relation.value = "";
85                 
86                 r2 = get_xpath_predicate (pr, mem);
87                 
88                 res = nmem_malloc(mem, sizeof(struct xpath_predicate));
89                 res->which = XPATH_PREDICATE_BOOLEAN;
90                 res->u.boolean.op = p2;
91                 res->u.boolean.left = r1;
92                 res->u.boolean.right = r2;
93                 
94                 return (res);
95             }
96             
97             if (strchr("><=] ", *p2)) {
98                 r1 = nmem_malloc(mem, sizeof(struct xpath_predicate));
99                 
100                 r1->which = XPATH_PREDICATE_RELATION;
101                 r1->u.relation.name = p1;
102                 r1->u.relation.op = p2;
103                 r1->u.relation.value = "";
104
105                 if ((p3 = get_xp_part(&pr, mem))) {
106                     r1->u.relation.value = p3;
107                 } else {
108                     /* error */
109                 }
110             }
111             
112             if ((p4 = get_xp_part(&pr, mem))) {
113                 if (!strcmp (p4, "and") || !strcmp (p4, "or") ||
114                     !strcmp (p4, "not")) 
115                 {
116                     
117                     r2 = get_xpath_predicate (pr, mem);
118                     
119                     res = nmem_malloc(mem, sizeof(struct xpath_predicate));
120                     res->which = XPATH_PREDICATE_BOOLEAN;
121                     res->u.boolean.op = p4;
122                     res->u.boolean.left = r1;
123                     res->u.boolean.right = r2;
124                     return (res);
125                 } else {
126                     /* error */
127                 }
128             } else {
129                 return (r1);
130             }
131             
132         } else {
133             r1 = nmem_malloc(mem, sizeof(struct xpath_predicate));
134             
135             r1->which = XPATH_PREDICATE_RELATION;
136             r1->u.relation.name = p1;
137             r1->u.relation.op = "";
138             r1->u.relation.value = "";
139             
140             return (r1);
141         }
142     }
143     return 0;
144 }
145
146 int parse_xpath_str(const char *xpath_string,
147                     struct xpath_location_step *xpath, NMEM mem)
148 {
149     const char *cp;
150     char *a;
151     
152     int no = 0;
153     
154     if (!xpath_string || *xpath_string != '/')
155         return -1;
156     cp = xpath_string;
157     
158     while (*cp)
159     {
160         int i = 0;
161         while (*cp && !strchr("/[",*cp))
162         {
163             i++;
164             cp++;
165         }
166         xpath[no].predicate = 0;
167         xpath[no].part = nmem_malloc (mem, i+1);
168         memcpy (xpath[no].part,  cp - i, i);
169         xpath[no].part[i] = 0;
170
171         if (*cp == '[')
172         {
173             cp++;
174             while (*cp == ' ')
175                 cp++;
176
177             a = (char *)cp;
178             xpath[no].predicate = get_xpath_predicate(a, mem);
179             while(*cp && *cp != ']') {
180               cp++;
181             }
182             if (*cp == ']')
183                 cp++;
184         } /* end of ] predicate */
185         no++;
186         if (*cp != '/')
187             break;
188         cp++;
189     }
190     return no;
191 }
192
193 void dump_xp_predicate (struct xpath_predicate *p)
194 {
195     if (p) {
196         if (p->which == XPATH_PREDICATE_RELATION &&
197           p->u.relation.name[0]) {
198             fprintf (stderr, "%s,%s,%s", 
199                      p->u.relation.name,
200                      p->u.relation.op,
201                      p->u.relation.value);
202         } else {
203             fprintf (stderr, "(");
204             dump_xp_predicate(p->u.boolean.left);
205             fprintf (stderr, ") %s (", p->u.boolean.op);
206             dump_xp_predicate(p->u.boolean.right);
207             fprintf (stderr, ")");
208         }
209     }
210 }
211
212 void dump_xp_steps (struct xpath_location_step *xpath, int no)
213 {
214     int i;
215     for (i=0; i<no; i++) {
216         fprintf (stderr, "Step %d: %s   ",i,xpath[i].part);
217         dump_xp_predicate(xpath[i].predicate);
218         fprintf (stderr, "\n");
219     }
220 }
221