ab75d585aa0148e7c4535699f03bb5344ae014f7
[idzebra-moved-to-github.git] / util / xpath.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 1994-2010 Index Data
3
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <ctype.h>
25 #include <yaz/nmem.h>
26 #include <zebra_xpath.h>
27
28 static char *get_xp_part (char **strs, NMEM mem, int *literal)
29 {
30     char *cp = *strs;
31     char *str = 0;
32     char *res = 0;
33
34     *literal = 0;
35     while (*cp == ' ')
36         cp++;
37     str = cp;
38     if (strchr("()", *cp))
39         cp++;
40     else if (strchr("><=", *cp))
41     {
42         while (strchr("><=", *cp))
43             cp++;
44     }
45     else if (*cp == '"' || *cp == '\'')
46     {
47         int sep = *cp;
48         str++;
49         cp++;
50         while (*cp && *cp != sep)
51             cp++;
52         res = nmem_malloc(mem, cp - str + 1);
53         if ((cp - str))
54             memcpy (res, str, (cp-str));
55         res[cp-str] = '\0';
56         if (*cp)
57             cp++;
58         *literal = 1;
59     }
60     else
61     {
62         while (*cp && !strchr("><=()]\" ", *cp))
63             cp++;
64     }
65     if (!res)
66     {
67         res = nmem_malloc(mem, cp - str + 1);
68         if ((cp - str))
69             memcpy (res, str, (cp-str));
70         res[cp-str] = '\0';
71     }
72     *strs = cp;
73     return res;
74 }
75
76 static struct xpath_predicate *get_xpath_boolean(char **pr, NMEM mem,
77                                                  char **look, int *literal);
78
79 static struct xpath_predicate *get_xpath_relation(char **pr, NMEM mem,
80                                                   char **look, int *literal)
81 {
82     struct xpath_predicate *res = 0;
83     if (!*literal && !strcmp(*look, "("))
84     {
85         *look = get_xp_part(pr, mem, literal);
86         res = get_xpath_boolean(pr, mem, look, literal);
87         if (!strcmp(*look, ")"))
88             *look = get_xp_part(pr, mem, literal);
89         else
90             res = 0; /* error */
91     }
92     else
93     {
94         res=nmem_malloc(mem, sizeof(struct xpath_predicate));
95         res->which = XPATH_PREDICATE_RELATION;
96         res->u.relation.name = *look;
97
98         *look = get_xp_part(pr, mem, literal);
99         if (*look && !*literal && strchr("><=", **look))
100         {
101             res->u.relation.op = *look;
102
103             *look = get_xp_part(pr, mem, literal);
104             if (!*look)
105                 return 0;  /* error */
106             res->u.relation.value = *look;
107             *look = get_xp_part(pr, mem, literal);
108         }
109         else
110         {
111             res->u.relation.op = "";
112             res->u.relation.value = "";
113         }
114     }
115     return res;
116 }
117
118 static struct xpath_predicate *get_xpath_boolean(char **pr, NMEM mem,
119                                                  char **look, int *literal)
120 {
121     struct xpath_predicate *left = 0;
122     
123     left = get_xpath_relation(pr, mem, look, literal);
124     if (!left)
125         return 0;
126     
127     while (*look && !*literal &&
128            (!strcmp(*look, "and") || !strcmp(*look, "or") || 
129             !strcmp(*look, "not")))
130     {
131         struct xpath_predicate *res, *right;
132
133         res = nmem_malloc(mem, sizeof(struct xpath_predicate));
134         res->which = XPATH_PREDICATE_BOOLEAN;
135         res->u.boolean.op = *look;
136         res->u.boolean.left = left;
137
138         *look = get_xp_part(pr, mem, literal); /* skip the boolean name */
139         right = get_xpath_relation(pr, mem, look, literal);
140
141         res->u.boolean.right = right;
142
143         left = res;
144     }
145     return left;
146 }
147
148 static struct xpath_predicate *get_xpath_predicate(char *predicate, NMEM mem)
149 {
150     int literal;
151     char **pr = &predicate;
152     char *look = get_xp_part(pr, mem, &literal);
153
154     if (!look)
155         return 0;
156     return get_xpath_boolean(pr, mem, &look, &literal);
157 }
158
159 int zebra_parse_xpath_str(const char *xpath_string,
160                           struct xpath_location_step *xpath, int max, NMEM mem)
161 {
162     const char *cp;
163     char *a;
164     
165     int no = 0;
166     
167     if (!xpath_string || *xpath_string != '/')
168         return -1;
169     cp = xpath_string;
170     
171     while (*cp && no < max)
172     {
173         int i = 0;
174         while (*cp && !strchr("/[",*cp))
175         {
176             i++;
177             cp++;
178         }
179         xpath[no].predicate = 0;
180         xpath[no].part = nmem_malloc (mem, i+1);
181         if (i)
182             memcpy (xpath[no].part,  cp - i, i);
183         xpath[no].part[i] = 0;
184
185         if (*cp == '[')
186         {
187             cp++;
188             while (*cp == ' ')
189                 cp++;
190
191             a = (char *)cp;
192             xpath[no].predicate = get_xpath_predicate(a, mem);
193             while(*cp && *cp != ']') {
194               cp++;
195             }
196             if (*cp == ']')
197                 cp++;
198         } /* end of ] predicate */
199         no++;
200         if (*cp != '/')
201             break;
202         cp++;
203     }
204
205 /* for debugging .. */
206 #if 0
207     dump_xp_steps(xpath, no);
208 #endif
209
210     return no;
211 }
212
213 void dump_xp_predicate (struct xpath_predicate *p)
214 {
215     if (p) {
216         if (p->which == XPATH_PREDICATE_RELATION &&
217             p->u.relation.name[0]) {
218             fprintf (stderr, "%s,%s,%s", 
219                      p->u.relation.name,
220                      p->u.relation.op,
221                      p->u.relation.value);
222         } else {
223             fprintf (stderr, "(");
224             dump_xp_predicate(p->u.boolean.left);
225             fprintf (stderr, ") %s (", p->u.boolean.op);
226             dump_xp_predicate(p->u.boolean.right);
227             fprintf (stderr, ")");
228         }
229     }
230 }
231
232 void dump_xp_steps (struct xpath_location_step *xpath, int no)
233 {
234     int i;
235     for (i=0; i<no; i++) {
236         fprintf (stderr, "Step %d: %s   ",i,xpath[i].part);
237         dump_xp_predicate(xpath[i].predicate);
238         fprintf (stderr, "\n");
239     }
240 }
241
242 /*
243  * Local variables:
244  * c-basic-offset: 4
245  * c-file-style: "Stroustrup"
246  * indent-tabs-mode: nil
247  * End:
248  * vim: shiftwidth=4 tabstop=8 expandtab
249  */
250