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