SRW diagnostic code now a URI
[yaz-moved-to-github.git] / src / srw.c
1 /*
2  * Copyright (c) 2002-2004, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srw.c,v 1.19 2004-01-27 12:15:12 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, const 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, const 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, const 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     while (ptr && ptr->type != XML_TEXT_NODE && ptr->type != XML_COMMENT_NODE)
117         ptr = ptr->next;
118     if (!ptr)
119         return 0;
120     buf = xmlBufferCreate();
121     
122     xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
123     
124     *val = odr_malloc(o, buf->use+1);
125     memcpy (*val, buf->content, buf->use);
126     (*val)[buf->use] = '\0';
127
128     if (len)
129         *len = buf->use;
130
131     xmlBufferFree(buf);
132
133     return 1;
134 }
135                      
136 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
137 {
138 #if CHECK_TYPE
139     struct _xmlAttr *attr;
140 #endif
141     if (!match_element(ptr, elem))
142         return 0;
143 #if CHECK_TYPE
144     for (attr = ptr->properties; attr; attr = attr->next)
145         if (!strcmp(attr->name, "type") &&
146             attr->children && attr->children->type == XML_TEXT_NODE)
147         {
148             const char *t = strchr(attr->children->content, ':');
149             if (t)
150                 t = t + 1;
151             else
152                 t = attr->children->content;
153             if (!strcmp(t, "integer"))
154                 break;
155         }
156     if (!attr)
157         return 0;
158 #endif
159     ptr = ptr->children;
160     if (!ptr || ptr->type != XML_TEXT_NODE)
161         return 0;
162     *val = odr_intdup(o, atoi(ptr->content));
163     return 1;
164 }
165
166 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
167                           void *client_data, const char *ns)
168 {
169     if (o->direction == ODR_DECODE)
170     {
171         int pack = Z_SRW_recordPacking_string;
172         xmlNodePtr ptr;
173         rec->recordSchema = 0;
174         rec->recordData_buf = 0;
175         rec->recordData_len = 0;
176         rec->recordPosition = 0;
177         for (ptr = pptr->children; ptr; ptr = ptr->next)
178         {
179             char *spack = 0;
180             
181             if (match_xsd_string(ptr, "recordSchema", o, 
182                                  &rec->recordSchema))
183                 ;
184             else if (match_xsd_string(ptr, "recordPacking", o, &spack))
185             {
186                 if (spack && !strcmp(spack, "xml"))
187                     pack = Z_SRW_recordPacking_XML;
188                 if (spack && !strcmp(spack, "string"))
189                     pack = Z_SRW_recordPacking_string;
190             }
191             else if (match_xsd_integer(ptr, "recordPosition", o, 
192                                        &rec->recordPosition))
193                 ;
194             else 
195             {
196                 if (pack == Z_SRW_recordPacking_XML)
197                     match_xsd_XML_n(ptr, "recordData", o, 
198                                     &rec->recordData_buf,
199                                     &rec->recordData_len);
200                 if (pack == Z_SRW_recordPacking_string)
201                     match_xsd_string_n(ptr, "recordData", o, 
202                                        &rec->recordData_buf,
203                                        &rec->recordData_len);
204             }
205         }
206         rec->recordPacking = pack;
207     }
208     else if (o->direction == ODR_ENCODE)
209     {
210         xmlNodePtr ptr = pptr;
211         add_xsd_string(ptr, "recordSchema", rec->recordSchema);
212         switch(rec->recordPacking)
213         {
214         case Z_SRW_recordPacking_string:
215             add_xsd_string(ptr, "recordPacking", "string");
216             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
217                              rec->recordData_len);
218             break;
219         case Z_SRW_recordPacking_XML:
220             add_xsd_string(ptr, "recordPacking", "xml");
221             add_XML_n(ptr, "recordData", rec->recordData_buf,
222                       rec->recordData_len);
223             break;
224         }
225         add_xsd_integer(ptr, "recordPosition", rec->recordPosition);
226     }
227     return 0;
228 }
229
230 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
231                            int *num, void *client_data, const char *ns)
232 {
233     if (o->direction == ODR_DECODE)
234     {
235         int i;
236         xmlNodePtr ptr;
237         *num = 0;
238         for (ptr = pptr->children; ptr; ptr = ptr->next)
239         {
240             if (ptr->type == XML_ELEMENT_NODE &&
241                 !strcmp(ptr->name, "record"))
242                 (*num)++;
243         }
244         if (!*num)
245             return 1;
246         *recs = odr_malloc(o, *num * sizeof(**recs));
247         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
248         {
249             if (ptr->type == XML_ELEMENT_NODE &&
250                 !strcmp(ptr->name, "record"))
251             {
252                 yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
253                 i++;
254             }
255         }
256     }
257     else if (o->direction == ODR_ENCODE)
258     {
259         int i;
260         for (i = 0; i < *num; i++)
261         {
262             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
263             yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
264         }
265     }
266     return 0;
267 }
268
269 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
270                                int *num, void *client_data, const char *ns)
271 {
272     if (o->direction == ODR_DECODE)
273     {
274         int i;
275         xmlNodePtr ptr;
276         *num = 0;
277         for (ptr = pptr->children; ptr; ptr = ptr->next)
278         {
279             if (ptr->type == XML_ELEMENT_NODE &&
280                 !strcmp(ptr->name, "diagnostic"))
281                 (*num)++;
282         }
283         if (!*num)
284             return 1;
285         *recs = odr_malloc(o, *num * sizeof(**recs));
286         for (i = 0; i < *num; i++)
287         {
288             (*recs)[i].code = 0;
289             (*recs)[i].details = 0;
290             (*recs)[i].message = 0;
291         } 
292         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
293         {
294             if (ptr->type == XML_ELEMENT_NODE &&
295                 !strcmp(ptr->name, "diagnostic"))
296             {
297                 xmlNodePtr rptr;
298                 (*recs)[i].code = 0;
299                 (*recs)[i].details = 0;
300                 (*recs)[i].message = 0;
301                 for (rptr = ptr->children; rptr; rptr = rptr->next)
302                 {
303                     if (match_xsd_string(rptr, "code", o, 
304                                          &(*recs)[i].code))
305                         ;
306                     else if (match_xsd_string(rptr, "details", o, 
307                                               &(*recs)[i].details))
308                         ;
309                     else if (match_xsd_string(rptr, "message", o, 
310                                               &(*recs)[i].message))
311                         ;
312                 }
313                 i++;
314             }
315         }
316     }
317     else if (o->direction == ODR_ENCODE)
318     {
319         int i;
320         xmlNsPtr ns_diag =
321             xmlNewNs(pptr, "http://www.loc.gov/zing/srw/diagnostics/", "diag");
322         for (i = 0; i < *num; i++)
323         {
324             const char *std_diag = "info:srw/diagnostic/1/1/";
325             xmlNodePtr rptr = xmlNewChild(pptr, ns_diag, "diagnostic", 0);
326             add_xsd_string(rptr, "code", (*recs)[i].code);
327             if ((*recs)[i].message)
328                 add_xsd_string(rptr, "message", (*recs)[i].message);
329             else if ((*recs)[i].code && 
330                      !strncmp((*recs)[i].code, std_diag, strlen(std_diag)))
331             {
332                 int no = atoi((*recs)[i].code + strlen(std_diag));
333                 const char *message = yaz_diag_srw_str(no);
334                 if (message)
335                     add_xsd_string(rptr, "message", message);
336             }
337             add_xsd_string(rptr, "details", (*recs)[i].details);
338         }
339     }
340     return 0;
341 }
342
343 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
344                         void *client_data, const char *ns)
345 {
346     if (o->direction == ODR_DECODE)
347     {
348         xmlNodePtr ptr;
349         term->value = 0;
350         term->numberOfRecords = 0;
351         term->displayTerm = 0;
352         for (ptr = pptr->children; ptr; ptr = ptr->next)
353         {
354             if (match_xsd_string(ptr, "value", o,  &term->value))
355                 ;
356             else if (match_xsd_integer(ptr, "numberOfRecords", o, 
357                                    &term->numberOfRecords))
358                 ;
359             else if (match_xsd_string(ptr, "displayTerm", o, 
360                                       &term->displayTerm))
361                 ;
362         }
363     }
364     else if (o->direction == ODR_ENCODE)
365     {
366         xmlNodePtr ptr = pptr;
367         add_xsd_string(ptr, "value", term->value);
368         add_xsd_integer(ptr, "value", term->numberOfRecords);
369         add_xsd_string(ptr, "displayTerm", term->displayTerm);
370     }
371     return 0;
372 }
373
374 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
375                          int *num, void *client_data, const char *ns)
376 {
377     if (o->direction == ODR_DECODE)
378     {
379         int i;
380         xmlNodePtr ptr;
381         *num = 0;
382         for (ptr = pptr->children; ptr; ptr = ptr->next)
383         {
384             if (ptr->type == XML_ELEMENT_NODE &&
385                 !strcmp(ptr->name, "term"))
386                 (*num)++;
387         }
388         if (!*num)
389             return 1;
390         *terms = odr_malloc(o, *num * sizeof(**terms));
391         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
392         {
393             if (ptr->type == XML_ELEMENT_NODE &&
394                 !strcmp(ptr->name, "term"))
395                 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
396         }
397     }
398     else if (o->direction == ODR_ENCODE)
399     {
400         int i;
401         for (i = 0; i < *num; i++)
402         {
403             xmlNodePtr rptr = xmlNewChild(pptr, 0, "term", 0);
404             yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
405         }
406     }
407     return 0;
408 }
409
410 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
411                   void *client_data, const char *ns)
412 {
413     xmlNodePtr pptr = vptr;
414     if (o->direction == ODR_DECODE)
415     {
416         Z_SRW_PDU **p = handler_data;
417         xmlNodePtr method = pptr->children;
418
419         while (method && method->type == XML_TEXT_NODE)
420             method = method->next;
421         
422         if (!method)
423             return -1;
424         if (method->type != XML_ELEMENT_NODE)
425             return -1;
426
427         *p = odr_malloc(o, sizeof(**p));
428         (*p)->srw_version = odr_strdup(o, "1.1");
429         
430         if (!strcmp(method->name, "searchRetrieveRequest"))
431         {
432             xmlNodePtr ptr = method->children;
433             Z_SRW_searchRetrieveRequest *req;
434
435             (*p)->which = Z_SRW_searchRetrieve_request;
436             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
437             req->query_type = Z_SRW_query_type_cql;
438             req->query.cql = 0;
439             req->sort_type = Z_SRW_sort_type_none;
440             req->sort.none = 0;
441             req->startRecord = 0;
442             req->maximumRecords = 0;
443             req->recordSchema = 0;
444             req->recordPacking = 0;
445             req->recordXPath = 0;
446             req->resultSetTTL = 0;
447             req->stylesheet = 0;
448             req->database = 0;
449
450             for (; ptr; ptr = ptr->next)
451             {
452                 if (match_xsd_string(ptr, "version", o,
453                                      &(*p)->srw_version))
454                     ;
455                 else if (match_xsd_string(ptr, "query", o, 
456                                      &req->query.cql))
457                     req->query_type = Z_SRW_query_type_cql;
458                 else if (match_xsd_string(ptr, "pQuery", o, 
459                                      &req->query.pqf))
460                     req->query_type = Z_SRW_query_type_pqf;
461                 else if (match_xsd_string(ptr, "xQuery", o, 
462                                      &req->query.xcql))
463                     req->query_type = Z_SRW_query_type_xcql;
464                 else if (match_xsd_integer(ptr, "startRecord", o,
465                                            &req->startRecord))
466                     ;
467                 else if (match_xsd_integer(ptr, "maximumRecords", o,
468                                            &req->maximumRecords))
469                     ;
470                 else if (match_xsd_string(ptr, "recordPacking", o,
471                                           &req->recordPacking))
472                     ;
473                 else if (match_xsd_string(ptr, "recordSchema", o, 
474                                           &req->recordSchema))
475                     ;
476                 else if (match_xsd_string(ptr, "recordXPath", o,
477                                           &req->recordXPath))
478                     ;
479                 else if (match_xsd_string(ptr, "resultSetTTL", o,
480                                            &req->database))
481                     ;
482                 else if (match_xsd_string(ptr, "sortKeys", o, 
483                                           &req->sort.sortKeys))
484                     req->sort_type = Z_SRW_sort_type_sort;
485                 else if (match_xsd_string(ptr, "stylesheet", o,
486                                            &req->stylesheet))
487                     ;
488                 else if (match_xsd_string(ptr, "database", o,
489                                            &req->database))
490                     ;
491                 /* missing is xQuery, xSortKeys .. */
492             }
493         }
494         else if (!strcmp(method->name, "searchRetrieveResponse"))
495         {
496             xmlNodePtr ptr = method->children;
497             Z_SRW_searchRetrieveResponse *res;
498
499             (*p)->which = Z_SRW_searchRetrieve_response;
500             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
501
502             res->numberOfRecords = 0;
503             res->resultSetId = 0;
504             res->resultSetIdleTime = 0;
505             res->records = 0;
506             res->num_records = 0;
507             res->diagnostics = 0;
508             res->num_diagnostics = 0;
509             res->nextRecordPosition = 0;
510
511             for (; ptr; ptr = ptr->next)
512             {
513                 if (match_xsd_string(ptr, "version", o,
514                                      &(*p)->srw_version))
515                     ;
516                 else if (match_xsd_integer(ptr, "numberOfRecords", o, 
517                                       &res->numberOfRecords))
518                     ;
519                 else if (match_xsd_string(ptr, "resultSetId", o, 
520                                           &res->resultSetId))
521                     ;
522                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
523                                            &res->resultSetIdleTime))
524                     ;
525                 else if (match_element(ptr, "records"))
526                     yaz_srw_records(o, ptr, &res->records,
527                                     &res->num_records, client_data,
528                                     ns);
529                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
530                                            &res->nextRecordPosition))
531                     ;
532                 else if (match_element(ptr, "diagnostics"))
533                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
534                                         &res->num_diagnostics,
535                                         client_data, ns);
536             }
537         }
538         else if (!strcmp(method->name, "explainRequest"))
539         {
540             Z_SRW_explainRequest *req;
541             xmlNodePtr ptr = method->children;
542             
543             (*p)->which = Z_SRW_explain_request;
544             req = (*p)->u.explain_request = odr_malloc(o, sizeof(*req));
545             req->recordPacking = 0;
546             req->database = 0;
547             req->stylesheet = 0;
548             for (; ptr; ptr = ptr->next)
549             {
550                 if (match_xsd_string(ptr, "version", o,
551                                            &(*p)->srw_version))
552                     ;
553                 else if (match_xsd_string(ptr, "stylesheet", o,
554                                           &req->stylesheet))
555                     ;
556                 else if (match_xsd_string(ptr, "recordPacking", o,
557                                      &req->recordPacking))
558                     ;
559                 else if (match_xsd_string(ptr, "database", o,
560                                      &req->database))
561                     ;
562             }
563         }
564         else if (!strcmp(method->name, "explainResponse"))
565         {
566             Z_SRW_explainResponse *res;
567             xmlNodePtr ptr = method->children;
568
569             (*p)->which = Z_SRW_explain_response;
570             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
571             res->diagnostics = 0;
572             res->num_diagnostics = 0;
573
574             for (; ptr; ptr = ptr->next)
575             {
576                 if (match_xsd_string(ptr, "version", o,
577                                            &(*p)->srw_version))
578                     ;
579                 else if (match_element(ptr, "record"))
580                     yaz_srw_record(o, ptr, &res->record, client_data, ns);
581                 else if (match_element(ptr, "diagnostics"))
582                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
583                                         &res->num_diagnostics,
584                                         client_data, ns);
585                 ;
586             }
587         }
588         else if (!strcmp(method->name, "scanRequest"))
589         {
590             Z_SRW_scanRequest *req;
591             xmlNodePtr ptr = method->children;
592
593             (*p)->which = Z_SRW_scan_request;
594             req = (*p)->u.scan_request = odr_malloc(o, sizeof(*req));
595             req->database = 0;
596             req->scanClause = 0;
597             req->stylesheet = 0;
598             req->responsePosition = 0;
599             req->maximumTerms = 0;
600             
601             for (; ptr; ptr = ptr->next)
602             {
603                 if (match_xsd_string(ptr, "version", o,
604                                      &(*p)->srw_version))
605                     ;
606                 else if (match_xsd_string(ptr, "scanClause", o,
607                                      &req->scanClause))
608                     ;
609                 else if (match_xsd_integer(ptr, "responsePosition", o,
610                                            &req->responsePosition))
611                     ;
612                 else if (match_xsd_integer(ptr, "maximumTerms", o,
613                                            &req->maximumTerms))
614                     ;
615                 else if (match_xsd_string(ptr, "stylesheet", o,
616                                           &req->stylesheet))
617                     ;
618                 else if (match_xsd_string(ptr, "database", o,
619                                           &req->database))
620                     ;
621             }
622         }
623         else if (!strcmp(method->name, "scanResponse"))
624         {
625             Z_SRW_scanResponse *res;
626             xmlNodePtr ptr = method->children;
627
628             (*p)->which = Z_SRW_scan_response;
629             res = (*p)->u.scan_response = odr_malloc(o, sizeof(*res));
630             res->terms = 0;
631             res->num_terms = 0;
632             res->diagnostics = 0;
633             res->num_diagnostics = 0;
634             
635             for (; ptr; ptr = ptr->next)
636             {
637                 if (match_xsd_string(ptr, "version", o,
638                                      &(*p)->srw_version))
639                     ;
640                 else if (match_element(ptr, "terms"))
641                     yaz_srw_terms(o, ptr, &res->terms,
642                                   &res->num_terms, client_data,
643                                   ns);
644                 else if (match_element(ptr, "diagnostics"))
645                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
646                                         &res->num_diagnostics,
647                                         client_data, ns);
648             }
649         }
650         else
651         {
652             *p = 0;
653             return -1;
654         }
655     }
656     else if (o->direction == ODR_ENCODE)
657     {
658         Z_SRW_PDU **p = handler_data;
659         xmlNsPtr ns_srw;
660         
661         if ((*p)->which == Z_SRW_searchRetrieve_request)
662         {
663             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
664             xmlNodePtr ptr = xmlNewChild(pptr, 0,
665                                          "searchRetrieveRequest", 0);
666             ns_srw = xmlNewNs(ptr, ns, "zs");
667             xmlSetNs(ptr, ns_srw);
668
669             if ((*p)->srw_version)
670                 add_xsd_string(ptr, "version", (*p)->srw_version);
671             switch(req->query_type)
672             {
673             case Z_SRW_query_type_cql:
674                 add_xsd_string(ptr, "query", req->query.cql);
675                 break;
676             case Z_SRW_query_type_xcql:
677                 add_xsd_string(ptr, "xQuery", req->query.xcql);
678                 break;
679             case Z_SRW_query_type_pqf:
680                 add_xsd_string(ptr, "pQuery", req->query.pqf);
681                 break;
682             }
683             add_xsd_integer(ptr, "startRecord", req->startRecord);
684             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
685             add_xsd_string(ptr, "recordPacking", req->recordPacking);
686             add_xsd_string(ptr, "recordSchema", req->recordSchema);
687             add_xsd_string(ptr, "recordXPath", req->recordXPath);
688             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
689             switch(req->sort_type)
690             {
691             case Z_SRW_sort_type_none:
692                 break;
693             case Z_SRW_sort_type_sort:
694                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
695                 break;
696             case Z_SRW_sort_type_xSort:
697                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
698                 break;
699             }
700             add_xsd_string(ptr, "stylesheet", req->stylesheet);
701             add_xsd_string(ptr, "database", req->database);
702         }
703         else if ((*p)->which == Z_SRW_searchRetrieve_response)
704         {
705             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
706             xmlNodePtr ptr = xmlNewChild(pptr, 0,
707                                          "searchRetrieveResponse", 0);
708             ns_srw = xmlNewNs(ptr, ns, "zs");
709             xmlSetNs(ptr, ns_srw);
710
711             if ((*p)->srw_version)
712                 add_xsd_string(ptr, "version", (*p)->srw_version);
713             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
714             add_xsd_string(ptr, "resultSetId", res->resultSetId);
715             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
716             if (res->num_records)
717             {
718                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
719                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
720                                 client_data, ns);
721             }
722             add_xsd_integer(ptr, "nextRecordPosition",
723                             res->nextRecordPosition);
724             if (res->num_diagnostics)
725             {
726                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
727                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
728                                     &res->num_diagnostics, client_data, ns);
729             }
730         }
731         else if ((*p)->which == Z_SRW_explain_request)
732         {
733             Z_SRW_explainRequest *req = (*p)->u.explain_request;
734             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
735             ns_srw = xmlNewNs(ptr, ns, "zs");
736             xmlSetNs(ptr, ns_srw);
737
738             add_xsd_string(ptr, "version", (*p)->srw_version);
739             add_xsd_string(ptr, "recordPacking", req->recordPacking);
740             add_xsd_string(ptr, "stylesheet", req->stylesheet);
741             add_xsd_string(ptr, "database", req->database);
742         }
743         else if ((*p)->which == Z_SRW_explain_response)
744         {
745             Z_SRW_explainResponse *res = (*p)->u.explain_response;
746             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
747             ns_srw = xmlNewNs(ptr, ns, "zs");
748             xmlSetNs(ptr, ns_srw);
749
750             add_xsd_string(ptr, "version", (*p)->srw_version);
751             if (1)
752             {
753                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, "record", 0);
754                 yaz_srw_record(o, ptr1, &res->record, client_data, ns);
755             }
756             if (res->num_diagnostics)
757             {
758                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
759                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
760                                     &res->num_diagnostics, client_data, ns);
761             }
762         }
763         else if ((*p)->which == Z_SRW_scan_request)
764         {
765             Z_SRW_scanRequest *req = (*p)->u.scan_request;
766             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanRequest", 0);
767             ns_srw = xmlNewNs(ptr, ns, "zs");
768             xmlSetNs(ptr, ns_srw);
769
770             add_xsd_string(ptr, "version", (*p)->srw_version);
771             add_xsd_string(ptr, "scanClause", req->scanClause);
772             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
773             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
774             add_xsd_string(ptr, "stylesheet", req->stylesheet);
775             add_xsd_string(ptr, "database", req->database);
776         }
777         else if ((*p)->which == Z_SRW_scan_response)
778         {
779             Z_SRW_scanResponse *res = (*p)->u.scan_response;
780             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanResponse", 0);
781             ns_srw = xmlNewNs(ptr, ns, "zs");
782             xmlSetNs(ptr, ns_srw);
783
784             add_xsd_string(ptr, "version", (*p)->srw_version);
785
786             if (res->num_terms)
787             {
788                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "terms", 0);
789                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
790                               client_data, ns);
791             }
792             if (res->num_diagnostics)
793             {
794                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
795                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
796                                     &res->num_diagnostics, client_data, ns);
797             }
798         }
799         else
800             return -1;
801
802     }
803     return 0;
804 }
805
806 #endif
807
808