Make cql_transform_rpn2cql_{stream,wrbuf} thread-safe
[yaz-moved-to-github.git] / src / sru_facet.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file sru_facet.c
7  * \brief Implements SRU 2.0 facets
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdlib.h>
14
15 #include <yaz/srw.h>
16 #include <yaz/wrbuf.h>
17 #if YAZ_HAVE_XML2
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
20 #include <assert.h>
21 #endif
22
23 #include "sru-p.h"
24 #include <yaz/pquery.h>
25 #include <yaz/facet.h>
26
27 static void insert_field(WRBUF w, const char *field, size_t length,
28                          const char *attr)
29 {
30     const char *cp0 = wrbuf_cstr(w);
31     const char *cp = cp0;
32
33     while (1)
34     {
35         const char *cp2 = strstr(cp, "@attr 1=");
36         if (!cp2)
37             break;
38         cp = cp2 + 8;
39         if (!strncmp(cp, field, length) &&
40             (cp[length] == ' ' || cp[length] == ',' || cp[length] == '\0'))
41         {
42             /* found the field */
43
44             cp += length;
45             wrbuf_insert(w, cp - cp0, attr, strlen(attr));
46             wrbuf_insert(w, cp - cp0, " ", 1);
47             return;
48         }
49         while (*cp && *cp != ',')
50             cp++;
51     }
52     if (wrbuf_len(w))
53         wrbuf_puts(w, ",");
54     wrbuf_puts(w, "@attr 1=");
55     wrbuf_write(w, field, length);
56     wrbuf_puts(w, " ");
57     wrbuf_puts(w, attr);
58 }
59
60 void yaz_sru_facet_request(ODR o, Z_FacetList **facetList, const char **limit,
61                            const char **start, const char **sort)
62 {
63     if (o->direction == ODR_ENCODE)
64     {
65         Z_FacetList *fl = *facetList;
66         if (fl)
67         {
68             WRBUF w_limit = wrbuf_alloc();
69             int general_start = -1;
70             int general_sortorder = -1;
71             int general_limit = -1;
72             int i;
73             for (i = 0; i < fl->num; i++)
74             {
75                 struct yaz_facet_attr av;
76                 yaz_facet_attr_init(&av);
77                 av.start = -1;
78                 av.sortorder = -1;
79                 av.limit = -1;
80                 yaz_facet_attr_get_z_attributes(fl->elements[i]->attributes,
81                                                 &av);
82                 if (av.errcode == 0)
83                 {
84                     if (av.limit != -1)
85                     {
86                         if (av.useattr)
87                         {
88                             wrbuf_printf(w_limit, "%d:%s", av.limit,
89                                          av.useattr);
90                             wrbuf_puts(w_limit, ",");
91                         }
92                         else
93                             general_limit = av.limit;
94                     }
95                     if (av.start != -1)
96                         general_start = av.start;
97                     if (av.sortorder != -1)
98                         general_sortorder = av.sortorder;
99                 }
100             }
101             if (general_limit != -1)
102             {
103                 char tmp[32];
104                 sprintf(tmp, "%d,", general_limit);
105                 wrbuf_insert(w_limit, 0, tmp, strlen(tmp));
106             }
107             if (wrbuf_len(w_limit) > 1)
108             {
109                 wrbuf_cut_right(w_limit, 1);
110                 *limit = odr_strdup(o, wrbuf_cstr(w_limit));
111             }
112             if (general_start != -1)
113             {
114                 char tmp[32];
115                 sprintf(tmp, "%d", general_start);
116                 *start = odr_strdup(o, tmp);
117             }
118             if (general_sortorder == 1)
119             {
120                 *sort = odr_strdup(o, "alphanumeric");
121             }
122             wrbuf_destroy(w_limit);
123         }
124     }
125     else if (o->direction == ODR_DECODE)
126     {
127         WRBUF w = wrbuf_alloc();
128         int general_limit = -1;
129
130         if (*limit)
131         {
132             const char *cp = *limit;
133             int nor = 0;
134             int val = 0;
135             while (sscanf(cp, "%d%n", &val, &nor) >= 1 && nor > 0)
136             {
137                 cp += nor;
138                 if (*cp == ':') /* field name follows */
139                 {
140                     char tmp[40];
141                     const char *cp0 = ++cp;
142                     while (*cp && *cp != ',')
143                         cp++;
144                     sprintf(tmp, "@attr 3=%d", val);
145                     insert_field(w, cp0, cp - cp0, tmp);
146
147                     if (*start && strlen(*start) < 20)
148                     {
149                         sprintf(tmp, "@attr 4=%s", *start);
150                         insert_field(w, cp0, cp - cp0, tmp);
151                     }
152                     if (*sort && !strcmp(*sort, "alphanumeric"))
153                         insert_field(w, cp0, cp - cp0, "@attr 2=1");
154                     else
155                         insert_field(w, cp0, cp - cp0, "@attr 2=0");
156                 }
157                 else
158                     general_limit = val;
159
160                 if (*cp != ',')
161                     break;
162                 cp++;
163             }
164         }
165         if (*sort || *start || general_limit != -1)
166         {
167             if (wrbuf_len(w))
168                 wrbuf_puts(w, ",");
169             if (*sort && !strcmp(*sort, "alphanumeric"))
170                 wrbuf_printf(w, " @attr 2=1");
171             else
172                 wrbuf_printf(w, " @attr 2=0");
173             if (general_limit != -1)
174                 wrbuf_printf(w, " @attr 3=%d", general_limit);
175             if (*start)
176             {
177                 wrbuf_printf(w, " @attr 4=%s", *start);
178             }
179         }
180         if (wrbuf_len(w))
181             *facetList = yaz_pqf_parse_facet_list(o, wrbuf_cstr(w));
182         else
183             *facetList = 0;
184         wrbuf_destroy(w);
185     }
186 }
187
188 #if YAZ_HAVE_XML2
189 void yaz_sru_facet_response(ODR o, Z_FacetList **facetList, xmlNodePtr n)
190 {
191     if (o->direction == ODR_ENCODE)
192     {
193         Z_FacetList *fl = *facetList;
194         if (fl)
195         {
196             int i;
197             const char *ns =
198                 "http://docs.oasis-open.org/ns/search-ws/facetedResults";
199             xmlNode *p1 = xmlNewChild(n, 0, BAD_CAST "facetedResults", 0);
200             xmlNsPtr ns_fr = xmlNewNs(p1, BAD_CAST ns, BAD_CAST "fr");
201             for (i = 0; i < fl->num; i++)
202             {
203                 Z_FacetField *ff = fl->elements[i];
204                 xmlNode *p2 = xmlNewChild(p1, ns_fr, BAD_CAST "facet", 0);
205                 int j;
206                 xmlNode *p3;
207                 struct yaz_facet_attr av;
208                 yaz_facet_attr_init(&av);
209                 yaz_facet_attr_get_z_attributes(ff->attributes, &av);
210                 add_xsd_string(p2, "index", av.useattr);
211                 p3 = xmlNewChild(p2, 0, BAD_CAST "terms", 0);
212                 for (j = 0; j < ff->num_terms; j++)
213                 {
214                     Z_FacetTerm *ft = ff->terms[j];
215                     Z_Term *zt = ft->term;
216                     xmlNode *p4 = xmlNewChild(p3, 0, BAD_CAST "term", 0);
217                     if (zt->which == Z_Term_general)
218                         add_xsd_string_n(p4, "actualTerm",
219                                          (char *) zt->u.general->buf,
220                                          zt->u.general->len);
221                     if (ft->count)
222                         add_xsd_integer(p4, "count", ft->count);
223                 }
224             }
225         }
226     }
227     else if (o->direction == ODR_DECODE)
228     {
229         Z_FacetList *fl = (Z_FacetList *) odr_malloc(o, sizeof(*fl));
230         xmlNode *p1;
231
232         fl->num = 0;
233         for (p1 = n->children; p1; p1 = p1->next)
234             if (yaz_match_xsd_element(p1, "facet"))
235                 fl->num++;
236         if (fl->num > 0)
237         {
238             int i = 0;
239             *facetList = fl;
240             fl->elements = (Z_FacetField **)
241                 odr_malloc(o, sizeof(*fl->elements) * fl->num);
242             for (p1 = n->children; p1; p1 = p1->next)
243                 if (yaz_match_xsd_element(p1, "facet"))
244                 {
245                     char *index_name = 0;
246                     xmlNode *p_terms = 0;
247                     xmlNode *p2 = p1->children;
248                     Z_FacetField *ff = (Z_FacetField *)
249                         odr_malloc(o, sizeof(*ff));
250                     fl->elements[i++] = ff;
251                     ff->attributes = 0;
252                     ff->num_terms = 0;
253                     ff->terms = 0;
254                     for (; p2; p2 = p2->next)
255                     {
256                         if (yaz_match_xsd_string(p2, "index", o, &index_name))
257                             ;
258                         else if (yaz_match_xsd_element(p2, "terms"))
259                             p_terms = p2;
260                     }
261                     if (index_name)
262                         ff->attributes =
263                             zget_AttributeList_use_string(o, index_name);
264                     if (p_terms)
265                     {
266                         xmlNode *p;
267                         int i = 0;
268                         for (p = p_terms->children; p; p = p->next)
269                         {
270                             if (yaz_match_xsd_element(p, "term"))
271                                 ff->num_terms++;
272                         }
273                         if (ff->num_terms)
274                             ff->terms = (Z_FacetTerm **)
275                                 odr_malloc(o,
276                                            sizeof(*ff->terms) * ff->num_terms);
277                         for (p = p_terms->children; p; p = p->next)
278                         {
279                             if (yaz_match_xsd_element(p, "term"))
280                             {
281                                 char *cstr = 0;
282                                 Odr_int *count = 0;
283                                 xmlNode *p2 = p->children;
284                                 for (; p2; p2 = p2->next)
285                                 {
286                                     if (yaz_match_xsd_string(p2, "actualTerm", o,
287                                                          &cstr))
288                                         ;
289                                     else if (yaz_match_xsd_integer(p2, "count", o,
290                                                                &count))
291                                         ;
292                                 }
293                                 if (cstr && count)
294                                 {
295                                     ff->terms[i++] =
296                                         facet_term_create_cstr(o, cstr, *count);
297                                 }
298                             }
299                         }
300                         ff->num_terms = i;
301                         if (ff->num_terms == 0)
302                             ff->terms = 0;
303                     }
304                 }
305
306         }
307     }
308 }
309
310 #endif
311
312
313 /*
314  * Local variables:
315  * c-basic-offset: 4
316  * c-file-style: "Stroustrup"
317  * indent-tabs-mode: nil
318  * End:
319  * vim: shiftwidth=4 tabstop=8 expandtab
320  */
321