SOAP, SRW codecs and HTTP transport for YAZ using libxml2.
[yaz-moved-to-github.git] / zutil / srw.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srw.c,v 1.1 2003-02-12 15:06:44 adam Exp $
6  */
7
8 #include <yaz/srw.h>
9
10 static void add_xsd_string_n(xmlNodePtr ptr, const char *elem, char *val,
11                              int len)
12 {
13     if (val)
14     {
15         xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
16         xmlNodePtr t = xmlNewTextLen(val, len);
17         xmlAddChild(c, t);
18     }
19 }
20
21 static void add_xsd_string(xmlNodePtr ptr, const char *elem, char *val)
22 {
23     if (val)
24         xmlNewChild(ptr, 0, elem, val);
25 }
26
27 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, int *val)
28 {
29     if (val)
30     {
31         char str[30];
32         sprintf(str, "%d", *val);
33         xmlNewChild(ptr, 0, elem, str);
34     }
35 }
36
37 static int match_element(xmlNodePtr ptr, const char *elem)
38 {
39     if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
40         return 1;
41     return 0;
42 }
43
44 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
45                               char **val, int *len)
46 {
47     struct _xmlAttr *attr;
48     if (!match_element(ptr, elem))
49         return 0;
50     for (attr = ptr->properties; attr; attr = attr->next)
51         if (!strcmp(attr->name, "type") &&
52             attr->children && attr->children->type == XML_TEXT_NODE)
53         {
54             const char *t = strchr(attr->children->content, ':');
55             if (t)
56                 t = t + 1;
57             else
58                 t = attr->children->content;
59             if (!strcmp(t, "string"))
60                 break;
61         }
62     if (!attr)
63         return 0;
64     ptr = ptr->children;
65     if (!ptr || ptr->type != XML_TEXT_NODE)
66         return 0;
67     *val = odr_strdup(o, ptr->content);
68     if (len)
69         *len = strlen(ptr->content);
70     return 1;
71 }
72
73
74 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
75                             char **val)
76 {
77     return match_xsd_string_n(ptr, elem, o, val, 0);
78 }
79                      
80 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
81 {
82     struct _xmlAttr *attr;
83     if (!match_element(ptr, elem))
84         return 0;
85     for (attr = ptr->properties; attr; attr = attr->next)
86         if (!strcmp(attr->name, "type") &&
87             attr->children && attr->children->type == XML_TEXT_NODE)
88         {
89             const char *t = strchr(attr->children->content, ':');
90             if (t)
91                 t = t + 1;
92             else
93                 t = attr->children->content;
94             if (!strcmp(t, "integer"))
95                 break;
96         }
97     if (!attr)
98         return 0;
99     ptr = ptr->children;
100     if (!ptr || ptr->type != XML_TEXT_NODE)
101         return 0;
102     *val = odr_intdup(o, atoi(ptr->content));
103     return 1;
104 }
105
106 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
107                            int *num, void *client_data, const char *ns)
108 {
109     if (o->direction == ODR_DECODE)
110     {
111         int i;
112         xmlNodePtr ptr;
113         *num = 0;
114         for (ptr = pptr->children; ptr; ptr = ptr->next)
115         {
116             if (ptr->type == XML_ELEMENT_NODE &&
117                 !strcmp(ptr->name, "record"))
118                 (*num)++;
119         }
120         if (!*num)
121             return 1;
122         *recs = odr_malloc(o, *num * sizeof(**recs));
123         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
124         {
125             if (ptr->type == XML_ELEMENT_NODE &&
126                 !strcmp(ptr->name, "record"))
127             {
128                 xmlNodePtr rptr;
129                 (*recs)[i].recordSchema = 0;
130                 (*recs)[i].recordData_buf = 0;
131                 (*recs)[i].recordData_len = 0;
132                 (*recs)[i].recordPosition = 0;
133                 for (rptr = ptr->children; rptr; rptr = rptr->next)
134                 {
135                     if (match_xsd_string(rptr, "recordSchema", o, 
136                                          &(*recs)[i].recordSchema))
137                         ;
138                     else if (match_xsd_string_n(rptr, "recordData", o, 
139                                                 &(*recs)[i].recordData_buf,
140                                                 &(*recs)[i].recordData_len))
141                         ;
142                     else if (match_xsd_integer(rptr, "recordPosition", o, 
143                                                &(*recs)[i].recordPosition))
144                         ;
145                 }
146             }
147         }
148     }
149     else if (o->direction == ODR_ENCODE)
150     {
151         int i;
152         for (i = 0; i < *num; i++)
153         {
154             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
155             add_xsd_string(rptr, "recordSchema", (*recs)[i].recordSchema);
156             add_xsd_string_n(rptr, "recordData", (*recs)[i].recordData_buf,
157                              (*recs)[i].recordData_len);
158             add_xsd_integer(rptr, "recordPosition", (*recs)[i].recordPosition);
159         }
160     }
161     return 0;
162 }
163
164 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
165                                int *num, void *client_data, const char *ns)
166 {
167     if (o->direction == ODR_DECODE)
168     {
169         int i;
170         xmlNodePtr ptr;
171         *num = 0;
172         for (ptr = pptr->children; ptr; ptr = ptr->next)
173         {
174             if (ptr->type == XML_ELEMENT_NODE &&
175                 !strcmp(ptr->name, "diagnostic"))
176                 (*num)++;
177         }
178         if (!*num)
179             return 1;
180         *recs = odr_malloc(o, *num * sizeof(**recs));
181         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
182         {
183             if (ptr->type == XML_ELEMENT_NODE &&
184                 !strcmp(ptr->name, "diagnostic"))
185             {
186                 xmlNodePtr rptr;
187                 (*recs)[i].code = 0;
188                 (*recs)[i].details = 0;
189                 for (rptr = ptr->children; rptr; rptr = rptr->next)
190                 {
191                     if (match_xsd_integer(rptr, "code", o, 
192                                                &(*recs)[i].code))
193                         ;
194                     else if (match_xsd_string(rptr, "details", o, 
195                                               &(*recs)[i].details))
196                         ;
197                 }
198                 i++;
199             }
200         }
201     }
202     else if (o->direction == ODR_ENCODE)
203     {
204         int i;
205         for (i = 0; i < *num; i++)
206         {
207             xmlNodePtr rptr = xmlNewChild(pptr, 0, "diagnostic", 0);
208             add_xsd_integer(rptr, "code", (*recs)[i].code);
209             add_xsd_string(rptr, "details", (*recs)[i].details);
210         }
211     }
212     return 0;
213 }
214
215
216 int yaz_srw_codec(ODR o, xmlNodePtr pptr, Z_SRW_searchRetrieve **handler_data,
217                   void *client_data, const char *ns)
218 {
219     if (o->direction == ODR_DECODE)
220     {
221         xmlNodePtr method = pptr->children;
222
223         while (method && method->type == XML_TEXT_NODE)
224             method = method->next;
225         
226         if (method->type != XML_ELEMENT_NODE)
227             return -1;
228         if (method && !strcmp(method->name, "searchRetrieveRequest"))
229         {
230             Z_SRW_searchRetrieve **p = handler_data;
231             xmlNodePtr ptr = method->children;
232             Z_SRW_searchRetrieveRequest *req;
233
234             *p = odr_malloc(o, sizeof(**p));
235             (*p)->which = Z_SRW_searchRetrieve_request;
236             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
237             req->query = 0;
238             req->xQuery = 0;
239             req->sortKeys = 0;
240             req->xSortKeys = 0;
241             req->startRecord = 0;
242             req->maximumRecords = 0;
243             req->recordSchema = 0;
244             req->recordPacking = 0;
245
246             for (; ptr; ptr = ptr->next)
247             {
248                 if (match_xsd_string(ptr, "query", o, 
249                                      &req->query))
250                     ;
251                 else if (match_xsd_string(ptr, "pQuery", o, 
252                                      &req->pQuery))
253                     ;
254                 else if (match_xsd_string(ptr, "sortKeys", o, 
255                                           &req->sortKeys))
256                     ;
257                 else if (match_xsd_string(ptr, "recordSchema", o, 
258                                           &req->recordSchema))
259                     ;
260                 else if (match_xsd_string(ptr, "recordPacking", o,
261                                           &req->recordPacking))
262                     ;
263                 else if (match_xsd_integer(ptr, "startRecord", o,
264                                            &req->startRecord))
265                     ;
266                 else if (match_xsd_integer(ptr, "maximumRecords", o,
267                                            &req->maximumRecords))
268                     ;
269                 /* missing is xQuery, xSortKeys .. */
270             }
271         }
272         else if (method && !strcmp(method->name, "searchRetrieveResponse"))
273         {
274             Z_SRW_searchRetrieve **p = handler_data;
275             xmlNodePtr ptr = method->children;
276             Z_SRW_searchRetrieveResponse *res;
277
278             *p = odr_malloc(o, sizeof(**p));
279             (*p)->which = Z_SRW_searchRetrieve_response;
280             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
281
282             res->numberOfRecords = 0;
283             res->resultSetId = 0;
284             res->resultSetIdleTime = 0;
285             res->records = 0;
286             res->num_records = 0;
287             res->diagnostics = 0;
288             res->num_diagnostics = 0;
289             res->nextRecordPosition = 0;
290
291             for (; ptr; ptr = ptr->next)
292             {
293                 if (match_xsd_integer(ptr, "numberOfRecords", o, 
294                                       &res->numberOfRecords))
295                     ;
296                 else if (match_xsd_string(ptr, "resultSetId", o, 
297                                           &res->resultSetId))
298                     ;
299                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
300                                            &res->resultSetIdleTime))
301                     ;
302                 else if (match_element(ptr, "records"))
303                     yaz_srw_records(o, ptr, &res->records,
304                                     &res->num_records, client_data,
305                                     ns);
306                 else if (match_element(ptr, "diagnostics"))
307                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
308                                         &res->num_diagnostics,
309                                         client_data, ns);
310                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
311                                            &res->nextRecordPosition))
312                     ;
313             }
314
315         }
316         else
317             return -1;
318
319     }
320     else if (o->direction == ODR_ENCODE)
321     {
322         Z_SRW_searchRetrieve **p = handler_data;
323         if ((*p)->which == Z_SRW_searchRetrieve_request)
324         {
325             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
326             xmlNsPtr ns_srw = xmlNewNs(pptr, ns, "zs");
327             xmlNodePtr ptr = xmlNewChild(pptr, ns_srw,
328                                          "searchRetrieveRequest", 0);
329
330             add_xsd_string(ptr, "query", req->query);
331             add_xsd_string(ptr, "pQuery", req->pQuery);
332             add_xsd_string(ptr, "sortKeys", req->sortKeys);
333             add_xsd_integer(ptr, "startRecord", req->startRecord);
334             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
335             add_xsd_string(ptr, "recordSchema", req->recordSchema);
336             add_xsd_string(ptr, "recordPacking", req->recordPacking);
337         }
338         else if ((*p)->which == Z_SRW_searchRetrieve_response)
339         {
340             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
341             xmlNsPtr ns_srw = xmlNewNs(pptr, ns, "zs");
342             xmlNodePtr ptr = xmlNewChild(pptr, ns_srw,
343                                          "searchRetrieveResponse", 0);
344
345             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
346             add_xsd_string(ptr, "resultSetId", res->resultSetId);
347             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
348             if (res->num_records)
349             {
350                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
351                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
352                                 client_data, ns);
353             }
354             if (res->num_diagnostics)
355             {
356                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
357                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
358                                     &res->num_diagnostics, client_data, ns);
359             }
360             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
361         }
362         else
363             return -1;
364
365     }
366     return 0;
367 }
368
369 Z_SRW_searchRetrieve *yaz_srw_get(ODR o, int which)
370 {
371     Z_SRW_searchRetrieve *sr = odr_malloc(o, sizeof(*o));
372     sr->which = which;
373     switch(which)
374     {
375     case Z_SRW_searchRetrieve_request:
376         sr->u.request = odr_malloc(o, sizeof(*sr->u.request));
377         sr->u.request->query = 0;
378         sr->u.request->xQuery = 0;
379         sr->u.request->sortKeys = 0;
380         sr->u.request->xSortKeys = 0;
381         sr->u.request->startRecord = 0;
382         sr->u.request->maximumRecords = 0;
383         sr->u.request->recordSchema = 0;
384         sr->u.request->recordPacking = 0;
385         break;
386     case Z_SRW_searchRetrieve_response:
387         sr->u.response = odr_malloc(o, sizeof(*sr->u.response));
388         sr->u.response->numberOfRecords = 0;
389         sr->u.response->resultSetId = 0;
390         sr->u.response->resultSetIdleTime = 0;
391         sr->u.response->records = 0;
392         sr->u.response->num_records = 0;
393         sr->u.response->diagnostics = 0;
394         sr->u.response->num_diagnostics = 0;
395         sr->u.response->nextRecordPosition = 0;
396     }
397     return sr;
398 }