SRW scan
[yaz-moved-to-github.git] / src / srw.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srw.c,v 1.7 2003-12-29 14:54:33 adam Exp $
6  */
7
8 #include <yaz/srw.h>
9
10 #if HAVE_XML2
11 #include <libxml/parser.h>
12 #include <libxml/tree.h>
13
14 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
15 {
16     if (val)
17     {
18         xmlDocPtr doc = xmlParseMemory(val,len);
19         if (doc)
20         {
21             xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
22             xmlNodePtr t = xmlDocGetRootElement(doc);
23             xmlAddChild(c, xmlCopyNode(t,1));
24             xmlFreeDoc(doc);
25         }
26     }
27 }
28
29 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, char *val,
30                             int len)
31 {
32     if (val)
33     {
34         xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
35         xmlNodePtr t = xmlNewTextLen(val, len);
36         xmlAddChild(c, t);
37         return t;
38     }
39     return 0;
40 }
41
42 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, char *val)
43 {
44     if (val)
45         return xmlNewChild(ptr, 0, elem, val);
46     return 0;
47 }
48
49 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, int *val)
50 {
51     if (val)
52     {
53         char str[30];
54         sprintf(str, "%d", *val);
55         xmlNewChild(ptr, 0, elem, str);
56     }
57 }
58
59 static int match_element(xmlNodePtr ptr, const char *elem)
60 {
61     if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
62         return 1;
63     return 0;
64 }
65
66 #define CHECK_TYPE 0
67
68 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
69                               char **val, int *len)
70 {
71 #if CHECK_TYPE
72     struct _xmlAttr *attr;
73 #endif
74     if (!match_element(ptr, elem))
75         return 0;
76 #if CHECK_TYPE
77     for (attr = ptr->properties; attr; attr = attr->next)
78         if (!strcmp(attr->name, "type") &&
79             attr->children && attr->children->type == XML_TEXT_NODE)
80         {
81             const char *t = strchr(attr->children->content, ':');
82             if (t)
83                 t = t + 1;
84             else
85                 t = attr->children->content;
86             if (!strcmp(t, "string"))
87                 break;
88         }
89     if (!attr)
90         return 0;
91 #endif
92     ptr = ptr->children;
93     if (!ptr || ptr->type != XML_TEXT_NODE)
94         return 0;
95     *val = odr_strdup(o, ptr->content);
96     if (len)
97         *len = strlen(ptr->content);
98     return 1;
99 }
100
101
102 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
103                             char **val)
104 {
105     return match_xsd_string_n(ptr, elem, o, val, 0);
106 }
107
108 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
109                            char **val, int *len)
110 {
111     xmlBufferPtr buf;
112
113     if (!match_element(ptr, elem))
114         return 0;
115     ptr = ptr->children;
116     if (!ptr)
117         return 0;
118     buf = xmlBufferCreate();
119
120     xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
121
122     *val = odr_malloc(o, buf->use+1);
123     memcpy (*val, buf->content, buf->use);
124     (*val)[buf->use] = '\0';
125
126     if (len)
127         *len = buf->use;
128
129     xmlBufferFree(buf);
130
131     return 1;
132 }
133
134                      
135 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
136 {
137 #if CHECK_TYPE
138     struct _xmlAttr *attr;
139 #endif
140     if (!match_element(ptr, elem))
141         return 0;
142 #if CHECK_TYPE
143     for (attr = ptr->properties; attr; attr = attr->next)
144         if (!strcmp(attr->name, "type") &&
145             attr->children && attr->children->type == XML_TEXT_NODE)
146         {
147             const char *t = strchr(attr->children->content, ':');
148             if (t)
149                 t = t + 1;
150             else
151                 t = attr->children->content;
152             if (!strcmp(t, "integer"))
153                 break;
154         }
155     if (!attr)
156         return 0;
157 #endif
158     ptr = ptr->children;
159     if (!ptr || ptr->type != XML_TEXT_NODE)
160         return 0;
161     *val = odr_intdup(o, atoi(ptr->content));
162     return 1;
163 }
164
165 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
166                           void *client_data, const char *ns)
167 {
168     if (o->direction == ODR_DECODE)
169     {
170         int pack = Z_SRW_recordPacking_string;
171         xmlNodePtr ptr;
172         rec->recordSchema = 0;
173         rec->recordData_buf = 0;
174         rec->recordData_len = 0;
175         rec->recordPosition = 0;
176         for (ptr = pptr->children; ptr; ptr = ptr->next)
177         {
178             char *spack = 0;
179             
180             if (match_xsd_string(ptr, "recordSchema", o, 
181                                  &rec->recordSchema))
182                 ;
183             else if (match_xsd_string(ptr, "recordPacking", o, &spack))
184             {
185                 if (pack && !strcmp(spack, "xml"))
186                     pack = Z_SRW_recordPacking_XML;
187                 if (pack && !strcmp(spack, "string"))
188                     pack = Z_SRW_recordPacking_string;
189             }
190             else if (match_xsd_integer(ptr, "recordPosition", o, 
191                                        &rec->recordPosition))
192                 ;
193             else 
194             {
195                 if (pack == Z_SRW_recordPacking_XML)
196                     match_xsd_XML_n(ptr, "recordData", o, 
197                                     &rec->recordData_buf,
198                                     &rec->recordData_len);
199                 if (pack == Z_SRW_recordPacking_string)
200                     match_xsd_string_n(ptr, "recordData", o, 
201                                        &rec->recordData_buf,
202                                        &rec->recordData_len);
203             }
204         }
205         rec->recordPacking = pack;
206     }
207     else if (o->direction == ODR_ENCODE)
208     {
209         xmlNodePtr ptr = pptr;
210         add_xsd_string(ptr, "recordSchema", rec->recordSchema);
211         switch(rec->recordPacking)
212         {
213         case Z_SRW_recordPacking_string:
214             add_xsd_string(ptr, "recordPacking", "string");
215             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
216                              rec->recordData_len);
217             break;
218         case Z_SRW_recordPacking_XML:
219             add_xsd_string(ptr, "recordPacking", "xml");
220             add_XML_n(ptr, "recordData", rec->recordData_buf,
221                       rec->recordData_len);
222             break;
223         }
224         add_xsd_integer(ptr, "recordPosition", rec->recordPosition);
225     }
226 }
227
228 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
229                            int *num, void *client_data, const char *ns)
230 {
231     if (o->direction == ODR_DECODE)
232     {
233         int i;
234         xmlNodePtr ptr;
235         *num = 0;
236         for (ptr = pptr->children; ptr; ptr = ptr->next)
237         {
238             if (ptr->type == XML_ELEMENT_NODE &&
239                 !strcmp(ptr->name, "record"))
240                 (*num)++;
241         }
242         if (!*num)
243             return 1;
244         *recs = odr_malloc(o, *num * sizeof(**recs));
245         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
246         {
247             if (ptr->type == XML_ELEMENT_NODE &&
248                 !strcmp(ptr->name, "record"))
249                 yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
250         }
251     }
252     else if (o->direction == ODR_ENCODE)
253     {
254         int i;
255         for (i = 0; i < *num; i++)
256         {
257             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
258             yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
259         }
260     }
261     return 0;
262 }
263
264 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
265                                int *num, void *client_data, const char *ns)
266 {
267     if (o->direction == ODR_DECODE)
268     {
269         int i;
270         xmlNodePtr ptr;
271         *num = 0;
272         for (ptr = pptr->children; ptr; ptr = ptr->next)
273         {
274             if (ptr->type == XML_ELEMENT_NODE &&
275                 !strcmp(ptr->name, "diagnostic"))
276                 (*num)++;
277         }
278         if (!*num)
279             return 1;
280         *recs = odr_malloc(o, *num * sizeof(**recs));
281         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
282         {
283             if (ptr->type == XML_ELEMENT_NODE &&
284                 !strcmp(ptr->name, "diagnostic"))
285             {
286                 xmlNodePtr rptr;
287                 (*recs)[i].code = 0;
288                 (*recs)[i].details = 0;
289                 for (rptr = ptr->children; rptr; rptr = rptr->next)
290                 {
291                     if (match_xsd_integer(rptr, "code", o, 
292                                                &(*recs)[i].code))
293                         ;
294                     else if (match_xsd_string(rptr, "details", o, 
295                                               &(*recs)[i].details))
296                         ;
297                 }
298                 i++;
299             }
300         }
301     }
302     else if (o->direction == ODR_ENCODE)
303     {
304         int i;
305         xmlNsPtr ns_diag =
306             xmlNewNs(pptr, "http://www.loc.gov/zing/srw/diagnostics/", "diag");
307         for (i = 0; i < *num; i++)
308         {
309             xmlNodePtr rptr = xmlNewChild(pptr, ns_diag, "diagnostic", 0);
310             add_xsd_integer(rptr, "code", (*recs)[i].code);
311             add_xsd_string(rptr, "details", (*recs)[i].details);
312         }
313     }
314     return 0;
315 }
316
317 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
318                         void *client_data, const char *ns)
319 {
320     if (o->direction == ODR_DECODE)
321     {
322         xmlNodePtr ptr;
323         term->value = 0;
324         term->numberOfRecords = 0;
325         term->displayTerm = 0;
326         for (ptr = pptr->children; ptr; ptr = ptr->next)
327         {
328             char *spack = 0;
329             
330             if (match_xsd_string(ptr, "value", o,  &term->value))
331                 ;
332             else if (match_xsd_integer(ptr, "numberOfRecords", o, 
333                                    &term->numberOfRecords))
334                 ;
335             else if (match_xsd_string(ptr, "displayTerm", o, 
336                                       &term->displayTerm))
337                 ;
338         }
339     }
340     else if (o->direction == ODR_ENCODE)
341     {
342         xmlNodePtr ptr = pptr;
343         add_xsd_string(ptr, "value", term->value);
344         add_xsd_integer(ptr, "value", term->numberOfRecords);
345         add_xsd_string(ptr, "displayTerm", term->displayTerm);
346     }
347 }
348
349 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
350                          int *num, void *client_data, const char *ns)
351 {
352     if (o->direction == ODR_DECODE)
353     {
354         int i;
355         xmlNodePtr ptr;
356         *num = 0;
357         for (ptr = pptr->children; ptr; ptr = ptr->next)
358         {
359             if (ptr->type == XML_ELEMENT_NODE &&
360                 !strcmp(ptr->name, "term"))
361                 (*num)++;
362         }
363         if (!*num)
364             return 1;
365         *terms = odr_malloc(o, *num * sizeof(**terms));
366         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
367         {
368             if (ptr->type == XML_ELEMENT_NODE &&
369                 !strcmp(ptr->name, "term"))
370                 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
371         }
372     }
373     else if (o->direction == ODR_ENCODE)
374     {
375         int i;
376         for (i = 0; i < *num; i++)
377         {
378             xmlNodePtr rptr = xmlNewChild(pptr, 0, "term", 0);
379             yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
380         }
381     }
382     return 0;
383 }
384
385 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
386                   void *client_data, const char *ns)
387 {
388     xmlNodePtr pptr = vptr;
389     if (o->direction == ODR_DECODE)
390     {
391         Z_SRW_PDU **p = handler_data;
392         xmlNodePtr method = pptr->children;
393
394         while (method && method->type == XML_TEXT_NODE)
395             method = method->next;
396         
397         if (!method)
398             return -1;
399         if (method->type != XML_ELEMENT_NODE)
400             return -1;
401
402         *p = odr_malloc(o, sizeof(**p));
403         (*p)->srw_version = odr_strdup(o, "1.1");
404         
405         if (!strcmp(method->name, "searchRetrieveRequest"))
406         {
407             xmlNodePtr ptr = method->children;
408             Z_SRW_searchRetrieveRequest *req;
409
410             (*p)->which = Z_SRW_searchRetrieve_request;
411             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
412             req->query_type = Z_SRW_query_type_cql;
413             req->query.cql = 0;
414             req->sort_type = Z_SRW_sort_type_none;
415             req->sort.none = 0;
416             req->startRecord = 0;
417             req->maximumRecords = 0;
418             req->recordSchema = 0;
419             req->recordPacking = 0;
420             req->recordXPath = 0;
421             req->resultSetTTL = 0;
422             req->stylesheet = 0;
423             req->database = 0;
424
425             for (; ptr; ptr = ptr->next)
426             {
427                 if (match_xsd_string(ptr, "query", o, 
428                                      &req->query.cql))
429                     req->query_type = Z_SRW_query_type_cql;
430                 else if (match_xsd_string(ptr, "pQuery", o, 
431                                      &req->query.pqf))
432                     req->query_type = Z_SRW_query_type_pqf;
433                 else if (match_xsd_string(ptr, "xQuery", o, 
434                                      &req->query.xcql))
435                     req->query_type = Z_SRW_query_type_xcql;
436                 else if (match_xsd_string(ptr, "sortKeys", o, 
437                                           &req->sort.sortKeys))
438                     req->sort_type = Z_SRW_sort_type_sort;
439                 else if (match_xsd_string(ptr, "recordSchema", o, 
440                                           &req->recordSchema))
441                     ;
442                 else if (match_xsd_string(ptr, "recordPacking", o,
443                                           &req->recordPacking))
444                     ;
445                 else if (match_xsd_string(ptr, "recordXPath", o,
446                                           &req->recordXPath))
447                     ;
448                 else if (match_xsd_integer(ptr, "startRecord", o,
449                                            &req->startRecord))
450                     ;
451                 else if (match_xsd_integer(ptr, "maximumRecords", o,
452                                            &req->maximumRecords))
453                     ;
454                 else if (match_xsd_string(ptr, "stylesheet", o,
455                                            &req->stylesheet))
456                     ;
457                 else if (match_xsd_string(ptr, "database", o,
458                                            &req->database))
459                     ;
460                 else if (match_xsd_string(ptr, "resultSetTTL", o,
461                                            &req->database))
462                     ;
463                 else if (match_xsd_string(ptr, "version", o,
464                                            &(*p)->srw_version))
465                     ;
466                 /* missing is xQuery, xSortKeys .. */
467             }
468         }
469         else if (!strcmp(method->name, "searchRetrieveResponse"))
470         {
471             xmlNodePtr ptr = method->children;
472             Z_SRW_searchRetrieveResponse *res;
473
474             (*p)->which = Z_SRW_searchRetrieve_response;
475             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
476
477             res->numberOfRecords = 0;
478             res->resultSetId = 0;
479             res->resultSetIdleTime = 0;
480             res->records = 0;
481             res->num_records = 0;
482             res->diagnostics = 0;
483             res->num_diagnostics = 0;
484             res->nextRecordPosition = 0;
485
486             for (; ptr; ptr = ptr->next)
487             {
488                 if (match_xsd_integer(ptr, "numberOfRecords", o, 
489                                       &res->numberOfRecords))
490                     ;
491                 else if (match_xsd_string(ptr, "resultSetId", o, 
492                                           &res->resultSetId))
493                     ;
494                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
495                                            &res->resultSetIdleTime))
496                     ;
497                 else if (match_element(ptr, "records"))
498                     yaz_srw_records(o, ptr, &res->records,
499                                     &res->num_records, client_data,
500                                     ns);
501                 else if (match_element(ptr, "diagnostics"))
502                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
503                                         &res->num_diagnostics,
504                                         client_data, ns);
505                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
506                                            &res->nextRecordPosition))
507                     ;
508                 else if (match_xsd_string(ptr, "version", o,
509                                            &(*p)->srw_version))
510                     ;
511             }
512         }
513         else if (!strcmp(method->name, "explainRequest"))
514         {
515             Z_SRW_explainRequest *req;
516             xmlNodePtr ptr = method->children;
517             
518             (*p)->which = Z_SRW_explain_request;
519             req = (*p)->u.explain_request = odr_malloc(o, sizeof(*req));
520             req->recordPacking = 0;
521             req->database = 0;
522             for (; ptr; ptr = ptr->next)
523             {
524                 if (match_xsd_string(ptr, "database", o,
525                                      &req->database))
526                     ;
527                 else if (match_xsd_string(ptr, "recordPacking", o,
528                                      &req->recordPacking))
529                     ;
530                 else if (match_xsd_string(ptr, "version", o,
531                                            &(*p)->srw_version))
532                     ;
533             }
534         }
535         else if (!strcmp(method->name, "explainResponse"))
536         {
537             Z_SRW_explainResponse *res;
538             xmlNodePtr ptr = method->children;
539
540             (*p)->which = Z_SRW_explain_response;
541             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
542             res->diagnostics = 0;
543             res->num_diagnostics = 0;
544
545             for (; ptr; ptr = ptr->next)
546             {
547                 if (match_element(ptr, "record"))
548                     yaz_srw_record(o, ptr, &res->record, client_data, ns);
549                 else if (match_xsd_string(ptr, "version", o,
550                                           &(*p)->srw_version))
551                     ;
552                 else if (match_element(ptr, "diagnostics"))
553                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
554                                         &res->num_diagnostics,
555                                         client_data, ns);
556                 ;
557             }
558         }
559         else if (!strcmp(method->name, "scanRequest"))
560         {
561             Z_SRW_scanRequest *req;
562             xmlNodePtr ptr = method->children;
563
564             (*p)->which = Z_SRW_scan_request;
565             req = (*p)->u.scan_request = odr_malloc(o, sizeof(*req));
566             req->database = 0;
567             req->scanClause = 0;
568             req->stylesheet = 0;
569             req->responsePosition = 0;
570             req->maximumTerms = 0;
571             
572             for (; ptr; ptr = ptr->next)
573             {
574                 if (match_xsd_string(ptr, "version", o,
575                                      &(*p)->srw_version))
576                     ;
577                 else if (match_xsd_string(ptr, "scanClause", o,
578                                      &req->scanClause))
579                     ;
580                 else if (match_xsd_string(ptr, "database", o,
581                                           &req->database))
582                     ;
583                 else if (match_xsd_string(ptr, "stylesheet", o,
584                                           &req->stylesheet))
585                     ;
586                 else if (match_xsd_integer(ptr, "responsePosition", o,
587                                            &req->responsePosition))
588                     ;
589                 else if (match_xsd_integer(ptr, "maximumTerms", o,
590                                            &req->maximumTerms))
591                     ;
592             }
593         }
594         else if (!strcmp(method->name, "scanResponse"))
595         {
596             Z_SRW_scanResponse *res;
597             xmlNodePtr ptr = method->children;
598
599             (*p)->which = Z_SRW_scan_response;
600             res = (*p)->u.scan_response = odr_malloc(o, sizeof(*res));
601             res->terms = 0;
602             res->num_terms = 0;
603             res->diagnostics = 0;
604             res->num_diagnostics = 0;
605             
606             for (; ptr; ptr = ptr->next)
607             {
608                 if (match_element(ptr, "terms"))
609                     yaz_srw_terms(o, ptr, &res->terms,
610                                   &res->num_terms, client_data,
611                                   ns);
612                 else if (match_element(ptr, "diagnostics"))
613                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
614                                         &res->num_diagnostics,
615                                         client_data, ns);
616                 else if (match_xsd_string(ptr, "version", o,
617                                           &(*p)->srw_version))
618                     ;
619             }
620         }
621         else
622         {
623             *p = 0;
624             return -1;
625         }
626     }
627     else if (o->direction == ODR_ENCODE)
628     {
629         Z_SRW_PDU **p = handler_data;
630         xmlNsPtr ns_srw;
631         
632         if ((*p)->which == Z_SRW_searchRetrieve_request)
633         {
634             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
635             xmlNodePtr ptr = xmlNewChild(pptr, 0,
636                                          "searchRetrieveRequest", 0);
637             ns_srw = xmlNewNs(ptr, ns, "zs");
638             xmlSetNs(ptr, ns_srw);
639
640             if ((*p)->srw_version)
641                 add_xsd_string(ptr, "version", (*p)->srw_version);
642             switch(req->query_type)
643             {
644             case Z_SRW_query_type_cql:
645                 add_xsd_string(ptr, "query", req->query.cql);
646                 break;
647             case Z_SRW_query_type_xcql:
648                 add_xsd_string(ptr, "xQuery", req->query.xcql);
649                 break;
650             case Z_SRW_query_type_pqf:
651                 add_xsd_string(ptr, "pQuery", req->query.pqf);
652                 break;
653             }
654             switch(req->sort_type)
655             {
656             case Z_SRW_sort_type_none:
657                 break;
658             case Z_SRW_sort_type_sort:
659                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
660                 break;
661             case Z_SRW_sort_type_xSort:
662                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
663                 break;
664             }
665             add_xsd_integer(ptr, "startRecord", req->startRecord);
666             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
667             add_xsd_string(ptr, "recordSchema", req->recordSchema);
668             add_xsd_string(ptr, "recordPacking", req->recordPacking);
669             add_xsd_string(ptr, "recordXPath", req->recordXPath);
670             add_xsd_string(ptr, "database", req->database);
671             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
672             add_xsd_string(ptr, "stylesheet", req->stylesheet);
673         }
674         else if ((*p)->which == Z_SRW_searchRetrieve_response)
675         {
676             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
677             xmlNodePtr ptr = xmlNewChild(pptr, 0,
678                                          "searchRetrieveResponse", 0);
679             ns_srw = xmlNewNs(ptr, ns, "zs");
680             xmlSetNs(ptr, ns_srw);
681
682             if ((*p)->srw_version)
683                 add_xsd_string(ptr, "version", (*p)->srw_version);
684             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
685             add_xsd_string(ptr, "resultSetId", res->resultSetId);
686             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
687             if (res->num_records)
688             {
689                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
690                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
691                                 client_data, ns);
692             }
693             if (res->num_diagnostics)
694             {
695                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
696                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
697                                     &res->num_diagnostics, client_data, ns);
698             }
699             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
700         }
701         else if ((*p)->which == Z_SRW_explain_request)
702         {
703             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
704             ns_srw = xmlNewNs(ptr, ns, "zs");
705             xmlSetNs(ptr, ns_srw);
706
707             add_xsd_string(ptr, "version", (*p)->srw_version);
708         }
709         else if ((*p)->which == Z_SRW_explain_response)
710         {
711             Z_SRW_explainResponse *res = (*p)->u.explain_response;
712             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
713             ns_srw = xmlNewNs(ptr, ns, "zs");
714             xmlSetNs(ptr, ns_srw);
715
716             add_xsd_string(ptr, "version", (*p)->srw_version);
717             if (1)
718             {
719                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, "record", 0);
720                 yaz_srw_record(o, ptr1, &res->record, client_data, ns);
721             }
722             if (res->num_diagnostics)
723             {
724                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
725                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
726                                     &res->num_diagnostics, client_data, ns);
727             }
728         }
729         else if ((*p)->which == Z_SRW_scan_request)
730         {
731             Z_SRW_scanRequest *req = (*p)->u.scan_request;
732             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanRequest", 0);
733             ns_srw = xmlNewNs(ptr, ns, "zs");
734             xmlSetNs(ptr, ns_srw);
735
736             add_xsd_string(ptr, "version", (*p)->srw_version);
737             add_xsd_string(ptr, "scanClause", req->scanClause);
738             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
739             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
740             add_xsd_string(ptr, "stylesheet", req->stylesheet);
741         }
742         else if ((*p)->which == Z_SRW_scan_response)
743         {
744             Z_SRW_scanResponse *res = (*p)->u.scan_response;
745             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanResponse", 0);
746             ns_srw = xmlNewNs(ptr, ns, "zs");
747             xmlSetNs(ptr, ns_srw);
748
749             add_xsd_string(ptr, "version", (*p)->srw_version);
750
751             if (res->num_terms)
752             {
753                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "terms", 0);
754                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
755                               client_data, ns);
756             }
757             if (res->num_diagnostics)
758             {
759                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
760                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
761                                     &res->num_diagnostics, client_data, ns);
762             }
763         }
764         else
765             return -1;
766
767     }
768     return 0;
769 }
770
771 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
772 {
773     Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
774
775     sr->srw_version = odr_strdup(o, "1.1");
776     sr->which = which;
777     switch(which)
778     {
779     case Z_SRW_searchRetrieve_request:
780         sr->u.request = (Z_SRW_searchRetrieveRequest *)
781             odr_malloc(o, sizeof(*sr->u.request));
782         sr->u.request->query_type = Z_SRW_query_type_cql;
783         sr->u.request->query.cql = 0;
784         sr->u.request->sort_type = Z_SRW_sort_type_none;
785         sr->u.request->sort.none = 0;
786         sr->u.request->startRecord = 0;
787         sr->u.request->maximumRecords = 0;
788         sr->u.request->recordSchema = 0;
789         sr->u.request->recordPacking = 0;
790         sr->u.request->database = 0;
791         sr->u.request->resultSetTTL = 0;
792         sr->u.request->stylesheet = 0;
793         break;
794     case Z_SRW_searchRetrieve_response:
795         sr->u.response = (Z_SRW_searchRetrieveResponse *)
796             odr_malloc(o, sizeof(*sr->u.response));
797         sr->u.response->numberOfRecords = 0;
798         sr->u.response->resultSetId = 0;
799         sr->u.response->resultSetIdleTime = 0;
800         sr->u.response->records = 0;
801         sr->u.response->num_records = 0;
802         sr->u.response->diagnostics = 0;
803         sr->u.response->num_diagnostics = 0;
804         sr->u.response->nextRecordPosition = 0;
805         break;
806     case Z_SRW_explain_request:
807         sr->u.explain_request = (Z_SRW_explainRequest *)
808             odr_malloc(o, sizeof(*sr->u.explain_request));
809         sr->u.explain_request->recordPacking = 0;
810         sr->u.explain_request->database = 0;
811         break;
812     case Z_SRW_explain_response:
813         sr->u.explain_response = (Z_SRW_explainResponse *)
814             odr_malloc(o, sizeof(*sr->u.explain_response));
815         sr->u.explain_response->record.recordData_buf = 0;
816         sr->u.explain_response->record.recordData_len = 0;
817         sr->u.explain_response->record.recordSchema = 0;
818         sr->u.explain_response->record.recordPosition = 0;
819         sr->u.explain_response->record.recordPacking =
820             Z_SRW_recordPacking_string;
821         sr->u.explain_response->diagnostics = 0;
822         sr->u.explain_response->num_diagnostics = 0;
823     }
824     return sr;
825 }
826
827 #endif
828
829
830 static struct {
831     int code;
832     const char *msg;
833 } yaz_srw_codes [] = {
834 {1, "Permanent system error"}, 
835 {2, "System temporarily unavailable"}, 
836 {3, "Authentication error"}, 
837 /* Diagnostics Relating to CQL */
838 {10, "Illegal query"}, 
839 {11, "Unsupported query type (XCQL vs CQL)"}, 
840 {12, "Too many characters in query"}, 
841 {13, "Unbalanced or illegal use of parentheses"}, 
842 {14, "Unbalanced or illegal use of quotes"}, 
843 {15, "Illegal or unsupported context set"}, 
844 {16, "Illegal or unsupported index"}, 
845 {17, "Illegal or unsupported combination of index and context set"}, 
846 {18, "Illegal or unsupported combination of indexes"}, 
847 {19, "Illegal or unsupported relation"}, 
848 {20, "Illegal or unsupported relation modifier"}, 
849 {21, "Illegal or unsupported combination of relation modifers"}, 
850 {22, "Illegal or unsupported combination of relation and index"}, 
851 {23, "Too many characters in term"}, 
852 {24, "Illegal combination of relation and term"}, 
853 {25, "Special characters not quoted in term"}, 
854 {26, "Non special character escaped in term"}, 
855 {27, "Empty term unsupported"}, 
856 {28, "Masking character not supported"}, 
857 {29, "Masked words too short"}, 
858 {30, "Too many masking characters in term"}, 
859 {31, "Anchoring character not supported"}, 
860 {32, "Anchoring character in illegal or unsupported position"}, 
861 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
862 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
863 {35, "Terms only exclusion (stop) words"}, 
864 {36, "Term in invalid format for index or relation"}, 
865 {37, "Illegal or unsupported boolean operator"}, 
866 {38, "Too many boolean operators in query"}, 
867 {39, "Proximity not supported"}, 
868 {40, "Illegal or unsupported proximity relation"}, 
869 {41, "Illegal or unsupported proximity distance"}, 
870 {42, "Illegal or unsupported proximity unit"}, 
871 {43, "Illegal or unsupported proximity ordering"}, 
872 {44, "Illegal or unsupported combination of proximity modifiers"}, 
873 {45, "context set name (prefix) assigned to multiple identifiers"}, 
874 /* Diagnostics Relating to Result Sets */
875 {50, "Result sets not supported"}, 
876 {51, "Result set does not exist"}, 
877 {52, "Result set temporarily unavailable"}, 
878 {53, "Result sets only supported for retrieval"}, 
879 {54, "Retrieval may only occur from an existing result set"}, 
880 {55, "Combination of result sets with search terms not supported"}, 
881 {56, "Only combination of single result set with search terms supported"}, 
882 {57, "Result set created but no records available"}, 
883 {58, "Result set created with unpredictable partial results available"}, 
884 {59, "Result set created with valid partial results available"}, 
885 /* Diagnostics Relating to Records */
886 {60, "Too many records retrieved"}, 
887 {61, "First record position out of range"}, 
888 {62, "Negative number of records requested"}, 
889 {63, "System error in retrieving records"}, 
890 {64, "Record temporarily unavailable"}, 
891 {65, "Record does not exist"}, 
892 {66, "Unknown schema for retrieval"}, 
893 {67, "Record not available in this schema"}, 
894 {68, "Not authorised to send record"}, 
895 {69, "Not authorised to send record in this schema"}, 
896 {70, "Record too large to send"}, 
897 /* Diagnostics Relating to Sorting */
898 {80, "Sort not supported"}, 
899 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
900 {82, "Illegal or unsupported sort sequence"}, 
901 {83, "Too many records"}, 
902 {84, "Too many sort keys"}, 
903 {85, "Duplicate sort keys"}, 
904 {86, "Incompatible record formats"}, 
905 {87, "Unsupported schema for sort"}, 
906 {88, "Unsupported tag path for sort"}, 
907 {89, "Tag path illegal or unsupported for schema"}, 
908 {90, "Illegal or unsupported direction value"}, 
909 {91, "Illegal or unsupported case value"}, 
910 {92, "Illegal or unsupported missing value action"}, 
911 /* Diagnostics Relating to Explain */
912 {100, "Explain not supported"}, 
913 {101, "Explain request type not supported (SOAP vs GET)"}, 
914 {102, "Explain record temporarily unavailable"},
915 {0, 0}
916 };
917
918 const char *yaz_diag_srw_str (int code)
919 {
920     int i;
921     for (i = 0; yaz_srw_codes[i].code; i++)
922         if (yaz_srw_codes[i].code == code)
923             return yaz_srw_codes[i].msg;
924     return 0;
925 }
926
927
928 /* bib1:srw */
929 static int srw_bib1_map[] = {
930     1, 1,
931     2, 2,
932     3, 11,
933     4, 35,
934     5, 12,
935     6, 38,
936     7, 30,
937     8, 32,
938     9, 29,
939     10, 10,
940     11, 12,
941     11, 23,
942     12, 60,
943     13, 61,
944     13, 62,
945     14, 63,
946     14, 64,
947     14, 65,
948     15, 68,
949     15, 69,
950     16, 70,
951     17, 70,
952     18, 50,
953     19, 55,
954     20, 56, 
955     21, 52,
956     22, 50,
957     23, 1,  /* bad map */
958     24, 63, /* bad map */
959     25, 63, /* bad map */
960     26, 63, /* bad map */
961     27, 51,
962     28, 52,
963     29, 52,
964     30, 51,
965     31, 57,
966     32, 58,
967     33, 59,
968     100, 1, /* bad map */
969     101, 3,
970     102, 3,
971     103, 3,
972     104, 3,
973     105, 3, 
974     106, 66,
975     107, 11,
976     108, 10,
977     108, 13,
978     108, 14,
979     108, 25,
980     108, 26,
981     108, 27,
982     108, 45,
983         
984     109, 1,
985     110, 37,
986     111, 1,
987     112, 58,
988     113, 10,
989     114, 16,
990     115, 16,
991     116, 16,
992     117, 19,
993     118, 22,
994     119, 32,
995     119, 31,
996     120, 28,
997     121, 15,
998     122, 32,
999     123, 22,
1000     123, 17,
1001     123, 18,
1002     124, 24,
1003     125, 36,
1004     126, 36, 
1005     127, 36,
1006     128, 51,
1007     129, 39,
1008     130, 43,
1009     131, 40,
1010     132, 42,
1011     201, 44,
1012     201, 33,
1013     201, 34,
1014     202, 41,
1015     203, 43,
1016     205, 1,  /* bad map */
1017     206, 1,  /* bad map */
1018     207, 89,
1019     208, 1,  /* bad map */
1020     209, 80,
1021     210, 80,
1022     210, 81,
1023     211, 84,
1024     212, 85,
1025     213, 92,
1026     214, 90,
1027     215, 91,
1028     216, 92,
1029     217, 63,
1030     218, 1,  /* bad map */
1031     219, 1,  /* bad map */
1032     220, 1,  /* bad map */
1033     221, 1,  /* bad map */
1034     222, 1,  /* bad map */
1035     223, 1,  /* bad map */
1036     224, 1,  /* bad map */
1037     225, 1,  /* bad map */
1038     226, 1,  /* bad map */
1039     227, 66,
1040     228, 1,  /* bad map */
1041     229, 36,
1042     230, 83,
1043     231, 89,
1044     232, 1,
1045     233, 1, /* bad map */
1046     234, 1, /* bad map */
1047     235, 2,
1048     236, 3, 
1049     237, 82,
1050     238, 67,
1051     239, 66,
1052     240, 1, /* bad map */
1053     241, 1, /* bad map */
1054     242, 70,
1055     243, 1, /* bad map */
1056     244, 66,
1057     245, 10,
1058     246, 10,
1059     247, 10,
1060     1001, 1, /* bad map */
1061     1002, 1, /* bad map */
1062     1003, 1, /* bad map */
1063     1004, 1, /* bad map */
1064     1005, 1, /* bad map */
1065     1006, 1, /* bad map */
1066     1007, 100,
1067     1008, 1, 
1068     1009, 1,
1069     1010, 3,
1070     1011, 3,
1071     1012, 3,
1072     1013, 3,
1073     1014, 3,
1074     1015, 3,
1075     1015, 3,
1076     1016, 3,
1077     1017, 3,
1078     1018, 2,
1079     1019, 2,
1080     1020, 2,
1081     1021, 3,
1082     1022, 3,
1083     1023, 3,
1084     1024, 16,
1085     1025, 3,
1086     1026, 64,
1087     1027, 1,
1088     1028, 65,
1089     1029, 1,
1090     1040, 1,
1091     /* 1041-1065 */
1092     1066, 66,
1093     1066, 67,
1094     0
1095 };
1096
1097 int yaz_diag_bib1_to_srw (int code)
1098 {
1099     const int *p = srw_bib1_map;
1100     while (*p)
1101     {
1102         if (code == p[0])
1103             return p[1];
1104         p += 2;
1105     }
1106     return 1;
1107 }
1108
1109 int yaz_diag_srw_to_bib1(int code)
1110 {
1111     const int *p = srw_bib1_map;
1112     while (*p)
1113     {
1114         if (code == p[1])
1115             return p[0];
1116         p += 2;
1117     }
1118     return 1;
1119 }
1120