SRW record retrieval works for ZOOM
[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.3 2003-02-17 14:35:42 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 #if 0
55     for (attr = ptr->properties; attr; attr = attr->next)
56         if (!strcmp(attr->name, "type") &&
57             attr->children && attr->children->type == XML_TEXT_NODE)
58         {
59             const char *t = strchr(attr->children->content, ':');
60             if (t)
61                 t = t + 1;
62             else
63                 t = attr->children->content;
64             if (!strcmp(t, "string"))
65                 break;
66         }
67     if (!attr)
68         return 0;
69 #endif
70     ptr = ptr->children;
71     if (!ptr || ptr->type != XML_TEXT_NODE)
72         return 0;
73     *val = odr_strdup(o, ptr->content);
74     if (len)
75         *len = strlen(ptr->content);
76     return 1;
77 }
78
79
80 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
81                             char **val)
82 {
83     return match_xsd_string_n(ptr, elem, o, val, 0);
84 }
85                      
86 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
87 {
88     struct _xmlAttr *attr;
89     if (!match_element(ptr, elem))
90         return 0;
91 #if 0
92     for (attr = ptr->properties; attr; attr = attr->next)
93         if (!strcmp(attr->name, "type") &&
94             attr->children && attr->children->type == XML_TEXT_NODE)
95         {
96             const char *t = strchr(attr->children->content, ':');
97             if (t)
98                 t = t + 1;
99             else
100                 t = attr->children->content;
101             if (!strcmp(t, "integer"))
102                 break;
103         }
104     if (!attr)
105         return 0;
106 #endif
107     ptr = ptr->children;
108     if (!ptr || ptr->type != XML_TEXT_NODE)
109         return 0;
110     *val = odr_intdup(o, atoi(ptr->content));
111     return 1;
112 }
113
114 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
115                            int *num, void *client_data, const char *ns)
116 {
117     if (o->direction == ODR_DECODE)
118     {
119         int i;
120         xmlNodePtr ptr;
121         *num = 0;
122         for (ptr = pptr->children; ptr; ptr = ptr->next)
123         {
124             if (ptr->type == XML_ELEMENT_NODE &&
125                 !strcmp(ptr->name, "record"))
126                 (*num)++;
127         }
128         if (!*num)
129             return 1;
130         *recs = odr_malloc(o, *num * sizeof(**recs));
131         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
132         {
133             if (ptr->type == XML_ELEMENT_NODE &&
134                 !strcmp(ptr->name, "record"))
135             {
136                 xmlNodePtr rptr;
137                 (*recs)[i].recordSchema = 0;
138                 (*recs)[i].recordData_buf = 0;
139                 (*recs)[i].recordData_len = 0;
140                 (*recs)[i].recordPosition = 0;
141                 for (rptr = ptr->children; rptr; rptr = rptr->next)
142                 {
143                     if (match_xsd_string(rptr, "recordSchema", o, 
144                                          &(*recs)[i].recordSchema))
145                         ;
146                     else if (match_xsd_string_n(rptr, "recordData", o, 
147                                                 &(*recs)[i].recordData_buf,
148                                                 &(*recs)[i].recordData_len))
149                         ;
150                     else if (match_xsd_integer(rptr, "recordPosition", o, 
151                                                &(*recs)[i].recordPosition))
152                         ;
153                 }
154             }
155         }
156     }
157     else if (o->direction == ODR_ENCODE)
158     {
159         int i;
160         for (i = 0; i < *num; i++)
161         {
162             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
163             add_xsd_string(rptr, "recordSchema", (*recs)[i].recordSchema);
164             add_xsd_string_n(rptr, "recordData", (*recs)[i].recordData_buf,
165                              (*recs)[i].recordData_len);
166             add_xsd_integer(rptr, "recordPosition", (*recs)[i].recordPosition);
167         }
168     }
169     return 0;
170 }
171
172 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
173                                int *num, void *client_data, const char *ns)
174 {
175     if (o->direction == ODR_DECODE)
176     {
177         int i;
178         xmlNodePtr ptr;
179         *num = 0;
180         for (ptr = pptr->children; ptr; ptr = ptr->next)
181         {
182             if (ptr->type == XML_ELEMENT_NODE &&
183                 !strcmp(ptr->name, "diagnostic"))
184                 (*num)++;
185         }
186         if (!*num)
187             return 1;
188         *recs = odr_malloc(o, *num * sizeof(**recs));
189         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
190         {
191             if (ptr->type == XML_ELEMENT_NODE &&
192                 !strcmp(ptr->name, "diagnostic"))
193             {
194                 xmlNodePtr rptr;
195                 (*recs)[i].code = 0;
196                 (*recs)[i].details = 0;
197                 for (rptr = ptr->children; rptr; rptr = rptr->next)
198                 {
199                     if (match_xsd_integer(rptr, "code", o, 
200                                                &(*recs)[i].code))
201                         ;
202                     else if (match_xsd_string(rptr, "details", o, 
203                                               &(*recs)[i].details))
204                         ;
205                 }
206                 i++;
207             }
208         }
209     }
210     else if (o->direction == ODR_ENCODE)
211     {
212         int i;
213         for (i = 0; i < *num; i++)
214         {
215             xmlNodePtr rptr = xmlNewChild(pptr, 0, "diagnostic", 0);
216             add_xsd_integer(rptr, "code", (*recs)[i].code);
217             add_xsd_string(rptr, "details", (*recs)[i].details);
218         }
219     }
220     return 0;
221 }
222
223
224 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_searchRetrieve **handler_data,
225                   void *client_data, const char *ns)
226 {
227     xmlNodePtr pptr = vptr;
228     if (o->direction == ODR_DECODE)
229     {
230         xmlNodePtr method = pptr->children;
231
232         while (method && method->type == XML_TEXT_NODE)
233             method = method->next;
234         
235         if (method->type != XML_ELEMENT_NODE)
236             return -1;
237         if (method && !strcmp(method->name, "searchRetrieveRequest"))
238         {
239             Z_SRW_searchRetrieve **p = handler_data;
240             xmlNodePtr ptr = method->children;
241             Z_SRW_searchRetrieveRequest *req;
242
243             *p = odr_malloc(o, sizeof(**p));
244             (*p)->which = Z_SRW_searchRetrieve_request;
245             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
246             req->query = 0;
247             req->xQuery = 0;
248             req->sortKeys = 0;
249             req->xSortKeys = 0;
250             req->startRecord = 0;
251             req->maximumRecords = 0;
252             req->recordSchema = 0;
253             req->recordPacking = 0;
254             req->database = 0;
255
256             for (; ptr; ptr = ptr->next)
257             {
258                 if (match_xsd_string(ptr, "query", o, 
259                                      &req->query))
260                     ;
261                 else if (match_xsd_string(ptr, "pQuery", o, 
262                                      &req->pQuery))
263                     ;
264                 else if (match_xsd_string(ptr, "sortKeys", o, 
265                                           &req->sortKeys))
266                     ;
267                 else if (match_xsd_string(ptr, "recordSchema", o, 
268                                           &req->recordSchema))
269                     ;
270                 else if (match_xsd_string(ptr, "recordPacking", o,
271                                           &req->recordPacking))
272                     ;
273                 else if (match_xsd_integer(ptr, "startRecord", o,
274                                            &req->startRecord))
275                     ;
276                 else if (match_xsd_integer(ptr, "maximumRecords", o,
277                                            &req->maximumRecords))
278                     ;
279                 else if (match_xsd_string(ptr, "database", o,
280                                            &req->database))
281                     ;
282                 /* missing is xQuery, xSortKeys .. */
283             }
284         }
285         else if (method && !strcmp(method->name, "searchRetrieveResponse"))
286         {
287             Z_SRW_searchRetrieve **p = handler_data;
288             xmlNodePtr ptr = method->children;
289             Z_SRW_searchRetrieveResponse *res;
290
291             *p = odr_malloc(o, sizeof(**p));
292             (*p)->which = Z_SRW_searchRetrieve_response;
293             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
294
295             res->numberOfRecords = 0;
296             res->resultSetId = 0;
297             res->resultSetIdleTime = 0;
298             res->records = 0;
299             res->num_records = 0;
300             res->diagnostics = 0;
301             res->num_diagnostics = 0;
302             res->nextRecordPosition = 0;
303
304             for (; ptr; ptr = ptr->next)
305             {
306                 if (match_xsd_integer(ptr, "numberOfRecords", o, 
307                                       &res->numberOfRecords))
308                     ;
309                 else if (match_xsd_string(ptr, "resultSetId", o, 
310                                           &res->resultSetId))
311                     ;
312                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
313                                            &res->resultSetIdleTime))
314                     ;
315                 else if (match_element(ptr, "records"))
316                     yaz_srw_records(o, ptr, &res->records,
317                                     &res->num_records, client_data,
318                                     ns);
319                 else if (match_element(ptr, "diagnostics"))
320                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
321                                         &res->num_diagnostics,
322                                         client_data, ns);
323                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
324                                            &res->nextRecordPosition))
325                     ;
326             }
327
328         }
329         else
330             return -1;
331
332     }
333     else if (o->direction == ODR_ENCODE)
334     {
335         Z_SRW_searchRetrieve **p = handler_data;
336         if ((*p)->which == Z_SRW_searchRetrieve_request)
337         {
338             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
339             xmlNsPtr ns_srw = xmlNewNs(pptr, ns, "zs");
340             xmlNodePtr ptr = xmlNewChild(pptr, ns_srw,
341                                          "searchRetrieveRequest", 0);
342
343             add_xsd_string(ptr, "query", req->query);
344             add_xsd_string(ptr, "pQuery", req->pQuery);
345             add_xsd_string(ptr, "sortKeys", req->sortKeys);
346             add_xsd_integer(ptr, "startRecord", req->startRecord);
347             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
348             add_xsd_string(ptr, "recordSchema", req->recordSchema);
349             add_xsd_string(ptr, "recordPacking", req->recordPacking);
350             add_xsd_string(ptr, "database", req->database);
351         }
352         else if ((*p)->which == Z_SRW_searchRetrieve_response)
353         {
354             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
355             xmlNsPtr ns_srw = xmlNewNs(pptr, ns, "zs");
356             xmlNodePtr ptr = xmlNewChild(pptr, ns_srw,
357                                          "searchRetrieveResponse", 0);
358
359             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
360             add_xsd_string(ptr, "resultSetId", res->resultSetId);
361             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
362             if (res->num_records)
363             {
364                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
365                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
366                                 client_data, ns);
367             }
368             if (res->num_diagnostics)
369             {
370                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
371                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
372                                     &res->num_diagnostics, client_data, ns);
373             }
374             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
375         }
376         else
377             return -1;
378
379     }
380     return 0;
381 }
382
383 Z_SRW_searchRetrieve *yaz_srw_get(ODR o, int which)
384 {
385     Z_SRW_searchRetrieve *sr = odr_malloc(o, sizeof(*o));
386     sr->which = which;
387     switch(which)
388     {
389     case Z_SRW_searchRetrieve_request:
390         sr->u.request = odr_malloc(o, sizeof(*sr->u.request));
391         sr->u.request->query = 0;
392         sr->u.request->xQuery = 0;
393         sr->u.request->pQuery = 0;
394         sr->u.request->sortKeys = 0;
395         sr->u.request->xSortKeys = 0;
396         sr->u.request->startRecord = 0;
397         sr->u.request->maximumRecords = 0;
398         sr->u.request->recordSchema = 0;
399         sr->u.request->recordPacking = 0;
400         sr->u.request->database = 0;
401         break;
402     case Z_SRW_searchRetrieve_response:
403         sr->u.response = odr_malloc(o, sizeof(*sr->u.response));
404         sr->u.response->numberOfRecords = 0;
405         sr->u.response->resultSetId = 0;
406         sr->u.response->resultSetIdleTime = 0;
407         sr->u.response->records = 0;
408         sr->u.response->num_records = 0;
409         sr->u.response->diagnostics = 0;
410         sr->u.response->num_diagnostics = 0;
411         sr->u.response->nextRecordPosition = 0;
412     }
413     return sr;
414 }
415
416 #endif
417
418
419 const char *yaz_srw_error_str (int code)
420 {
421     return "SRW error";
422 }
423
424 #if 0
425
426 1 Permanent system error
427 2 System temporarily unavailable
428 3 Authentication error
429     /* Diagnostics Relating to CQL */
430 Number Description
431 10 Illegal query
432 11 Unsupported query type (XCQL vs CQL)
433 12 Too many characters in query
434 13 Unbalanced or illegal use of parentheses
435 14 Unbalanced or illegal use of quotes
436 15 Illegal or unsupported index set
437 16 Illegal or unsupported index
438 17 Illegal or unsupported combination of index and index set
439 18 Illegal or unsupported combination of indexes
440 19 Illegal or unsupported relation
441 20 Illegal or unsupported relation modifier
442 21 Illegal or unsupported combination of relation modifers
443 22 Illegal or unsupported combination of relation and index
444 23 Too many characters in term
445 24 Illegal combination of relation and term
446 25 Special characters not quoted in term
447 26 Non special character escaped in term
448 27 Empty term unsupported
449 28 Masking character not supported
450 29 Masked words too short
451 30 Too many masking characters in term
452 31 Anchoring character not supported
453 32 Anchoring character in illegal or unsupported position
454 33 Combination of proximity/adjacency and masking characters not supported
455 34 Combination of proximity/adjacency and anchoring characters not supported
456 35 Terms only exclusion (stop) words
457 36 Term in invalid format for index or relation
458 37 Illegal or unsupported boolean operator
459 38 Too many boolean operators in query
460 39 Proximity not supported
461 40 Illegal or unsupported proximity relation
462 41 Illegal or unsupported proximity distance
463 42 Illegal or unsupported proximity unit
464 43 Illegal or unsupported proximity ordering
465 44 Illegal or unsupported combination of proximity modifiers
466 45 Index set name (prefix) assigned to multiple identifiers
467 /* Diagnostics Relating to Result Sets */
468 Number Description
469 50 Result sets not supported
470 51 Result set does not exist
471 52 Result set temporarily unavailable
472 53 Result sets only supported for retrieval
473 54 Retrieval may only occur from an existing result set
474 55 Combination of result sets with search terms not supported
475 56 Only combination of single result set with search terms supported
476 57 Result set created but no records available
477 58 Result set created with unpredictable partial results available
478 59 Result set created with valid partial results available
479 /* Diagnostics Relating to Records */
480 Number Description
481 60 Too many records retrieved
482 61 First record position out of range
483 62 Negative number of records requested
484 63 System error in retrieving records
485 64 Record temporarily unavailable
486 65 Record does not exist
487 66 Unknown schema for retrieval
488 67 Record not available in this schema
489 68 Not authorised to send record
490 69 Not authorised to send record in this schema
491 70 Record too large to send
492 /* Diagnostics Relating to Sorting */
493 Number Description
494 80 Sort not supported
495 81 Unsupported sort type (sortKeys vs xSortKeys)
496 82 Illegal or unsupported sort sequence
497 83 Too many records
498 84 Too many sort keys
499 85 Duplicate sort keys
500 86 Incompatible record formats
501 87 Unsupported schema for sort
502 88 Unsupported tag path for sort
503 89 Tag path illegal or unsupported for schema
504 90 Illegal or unsupported direction value
505 91 Illegal or unsupported case value
506 92 Illegal or unsupported missing value action
507 /* Diagnostics Relating to Explain */
508 Number Description
509 100 Explain not supported
510 101 Explain request type not supported (SOAP vs GET)
511 102 Explain record temporarily unavailable
512
513 #endif