Allow empty ODR (NMEM=0) for odr_oiddup and odr_getoidbystr.
[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.13 2004-01-05 14:46:52 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     return 0;
227 }
228
229 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
230                            int *num, void *client_data, const char *ns)
231 {
232     if (o->direction == ODR_DECODE)
233     {
234         int i;
235         xmlNodePtr ptr;
236         *num = 0;
237         for (ptr = pptr->children; ptr; ptr = ptr->next)
238         {
239             if (ptr->type == XML_ELEMENT_NODE &&
240                 !strcmp(ptr->name, "record"))
241                 (*num)++;
242         }
243         if (!*num)
244             return 1;
245         *recs = odr_malloc(o, *num * sizeof(**recs));
246         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
247         {
248             if (ptr->type == XML_ELEMENT_NODE &&
249                 !strcmp(ptr->name, "record"))
250                 yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
251         }
252     }
253     else if (o->direction == ODR_ENCODE)
254     {
255         int i;
256         for (i = 0; i < *num; i++)
257         {
258             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
259             yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
260         }
261     }
262     return 0;
263 }
264
265 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
266                                int *num, void *client_data, const char *ns)
267 {
268     if (o->direction == ODR_DECODE)
269     {
270         int i;
271         xmlNodePtr ptr;
272         *num = 0;
273         for (ptr = pptr->children; ptr; ptr = ptr->next)
274         {
275             if (ptr->type == XML_ELEMENT_NODE &&
276                 !strcmp(ptr->name, "diagnostic"))
277                 (*num)++;
278         }
279         if (!*num)
280             return 1;
281         *recs = odr_malloc(o, *num * sizeof(**recs));
282         for (i = 0; i < *num; i++)
283         {
284             (*recs)[i].code = 0;
285             (*recs)[i].details = 0;
286         } 
287         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
288         {
289             if (ptr->type == XML_ELEMENT_NODE &&
290                 !strcmp(ptr->name, "diagnostic"))
291             {
292                 xmlNodePtr rptr;
293                 (*recs)[i].code = 0;
294                 (*recs)[i].details = 0;
295                 for (rptr = ptr->children; rptr; rptr = rptr->next)
296                 {
297                     if (match_xsd_integer(rptr, "code", o, 
298                                                &(*recs)[i].code))
299                         ;
300                     else if (match_xsd_string(rptr, "details", o, 
301                                               &(*recs)[i].details))
302                         ;
303                 }
304                 i++;
305             }
306         }
307     }
308     else if (o->direction == ODR_ENCODE)
309     {
310         int i;
311         xmlNsPtr ns_diag =
312             xmlNewNs(pptr, "http://www.loc.gov/zing/srw/diagnostics/", "diag");
313         for (i = 0; i < *num; i++)
314         {
315             xmlNodePtr rptr = xmlNewChild(pptr, ns_diag, "diagnostic", 0);
316             add_xsd_integer(rptr, "code", (*recs)[i].code);
317             add_xsd_string(rptr, "details", (*recs)[i].details);
318         }
319     }
320     return 0;
321 }
322
323 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
324                         void *client_data, const char *ns)
325 {
326     if (o->direction == ODR_DECODE)
327     {
328         xmlNodePtr ptr;
329         term->value = 0;
330         term->numberOfRecords = 0;
331         term->displayTerm = 0;
332         for (ptr = pptr->children; ptr; ptr = ptr->next)
333         {
334             if (match_xsd_string(ptr, "value", o,  &term->value))
335                 ;
336             else if (match_xsd_integer(ptr, "numberOfRecords", o, 
337                                    &term->numberOfRecords))
338                 ;
339             else if (match_xsd_string(ptr, "displayTerm", o, 
340                                       &term->displayTerm))
341                 ;
342         }
343     }
344     else if (o->direction == ODR_ENCODE)
345     {
346         xmlNodePtr ptr = pptr;
347         add_xsd_string(ptr, "value", term->value);
348         add_xsd_integer(ptr, "value", term->numberOfRecords);
349         add_xsd_string(ptr, "displayTerm", term->displayTerm);
350     }
351     return 0;
352 }
353
354 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
355                          int *num, void *client_data, const char *ns)
356 {
357     if (o->direction == ODR_DECODE)
358     {
359         int i;
360         xmlNodePtr ptr;
361         *num = 0;
362         for (ptr = pptr->children; ptr; ptr = ptr->next)
363         {
364             if (ptr->type == XML_ELEMENT_NODE &&
365                 !strcmp(ptr->name, "term"))
366                 (*num)++;
367         }
368         if (!*num)
369             return 1;
370         *terms = odr_malloc(o, *num * sizeof(**terms));
371         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
372         {
373             if (ptr->type == XML_ELEMENT_NODE &&
374                 !strcmp(ptr->name, "term"))
375                 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
376         }
377     }
378     else if (o->direction == ODR_ENCODE)
379     {
380         int i;
381         for (i = 0; i < *num; i++)
382         {
383             xmlNodePtr rptr = xmlNewChild(pptr, 0, "term", 0);
384             yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
385         }
386     }
387     return 0;
388 }
389
390 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
391                   void *client_data, const char *ns)
392 {
393     xmlNodePtr pptr = vptr;
394     if (o->direction == ODR_DECODE)
395     {
396         Z_SRW_PDU **p = handler_data;
397         xmlNodePtr method = pptr->children;
398
399         while (method && method->type == XML_TEXT_NODE)
400             method = method->next;
401         
402         if (!method)
403             return -1;
404         if (method->type != XML_ELEMENT_NODE)
405             return -1;
406
407         *p = odr_malloc(o, sizeof(**p));
408         (*p)->srw_version = odr_strdup(o, "1.1");
409         
410         if (!strcmp(method->name, "searchRetrieveRequest"))
411         {
412             xmlNodePtr ptr = method->children;
413             Z_SRW_searchRetrieveRequest *req;
414
415             (*p)->which = Z_SRW_searchRetrieve_request;
416             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
417             req->query_type = Z_SRW_query_type_cql;
418             req->query.cql = 0;
419             req->sort_type = Z_SRW_sort_type_none;
420             req->sort.none = 0;
421             req->startRecord = 0;
422             req->maximumRecords = 0;
423             req->recordSchema = 0;
424             req->recordPacking = 0;
425             req->recordXPath = 0;
426             req->resultSetTTL = 0;
427             req->stylesheet = 0;
428             req->database = 0;
429
430             for (; ptr; ptr = ptr->next)
431             {
432                 if (match_xsd_string(ptr, "query", o, 
433                                      &req->query.cql))
434                     req->query_type = Z_SRW_query_type_cql;
435                 else if (match_xsd_string(ptr, "pQuery", o, 
436                                      &req->query.pqf))
437                     req->query_type = Z_SRW_query_type_pqf;
438                 else if (match_xsd_string(ptr, "xQuery", o, 
439                                      &req->query.xcql))
440                     req->query_type = Z_SRW_query_type_xcql;
441                 else if (match_xsd_string(ptr, "sortKeys", o, 
442                                           &req->sort.sortKeys))
443                     req->sort_type = Z_SRW_sort_type_sort;
444                 else if (match_xsd_string(ptr, "recordSchema", o, 
445                                           &req->recordSchema))
446                     ;
447                 else if (match_xsd_string(ptr, "recordPacking", o,
448                                           &req->recordPacking))
449                     ;
450                 else if (match_xsd_string(ptr, "recordXPath", o,
451                                           &req->recordXPath))
452                     ;
453                 else if (match_xsd_integer(ptr, "startRecord", o,
454                                            &req->startRecord))
455                     ;
456                 else if (match_xsd_integer(ptr, "maximumRecords", o,
457                                            &req->maximumRecords))
458                     ;
459                 else if (match_xsd_string(ptr, "stylesheet", o,
460                                            &req->stylesheet))
461                     ;
462                 else if (match_xsd_string(ptr, "database", o,
463                                            &req->database))
464                     ;
465                 else if (match_xsd_string(ptr, "resultSetTTL", o,
466                                            &req->database))
467                     ;
468                 else if (match_xsd_string(ptr, "version", o,
469                                            &(*p)->srw_version))
470                     ;
471                 /* missing is xQuery, xSortKeys .. */
472             }
473         }
474         else if (!strcmp(method->name, "searchRetrieveResponse"))
475         {
476             xmlNodePtr ptr = method->children;
477             Z_SRW_searchRetrieveResponse *res;
478
479             (*p)->which = Z_SRW_searchRetrieve_response;
480             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
481
482             res->numberOfRecords = 0;
483             res->resultSetId = 0;
484             res->resultSetIdleTime = 0;
485             res->records = 0;
486             res->num_records = 0;
487             res->diagnostics = 0;
488             res->num_diagnostics = 0;
489             res->nextRecordPosition = 0;
490
491             for (; ptr; ptr = ptr->next)
492             {
493                 if (match_xsd_integer(ptr, "numberOfRecords", o, 
494                                       &res->numberOfRecords))
495                     ;
496                 else if (match_xsd_string(ptr, "resultSetId", o, 
497                                           &res->resultSetId))
498                     ;
499                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
500                                            &res->resultSetIdleTime))
501                     ;
502                 else if (match_element(ptr, "records"))
503                     yaz_srw_records(o, ptr, &res->records,
504                                     &res->num_records, client_data,
505                                     ns);
506                 else if (match_element(ptr, "diagnostics"))
507                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
508                                         &res->num_diagnostics,
509                                         client_data, ns);
510                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
511                                            &res->nextRecordPosition))
512                     ;
513                 else if (match_xsd_string(ptr, "version", o,
514                                            &(*p)->srw_version))
515                     ;
516             }
517         }
518         else if (!strcmp(method->name, "explainRequest"))
519         {
520             Z_SRW_explainRequest *req;
521             xmlNodePtr ptr = method->children;
522             
523             (*p)->which = Z_SRW_explain_request;
524             req = (*p)->u.explain_request = odr_malloc(o, sizeof(*req));
525             req->recordPacking = 0;
526             req->database = 0;
527             for (; ptr; ptr = ptr->next)
528             {
529                 if (match_xsd_string(ptr, "database", o,
530                                      &req->database))
531                     ;
532                 else if (match_xsd_string(ptr, "recordPacking", o,
533                                      &req->recordPacking))
534                     ;
535                 else if (match_xsd_string(ptr, "version", o,
536                                            &(*p)->srw_version))
537                     ;
538             }
539         }
540         else if (!strcmp(method->name, "explainResponse"))
541         {
542             Z_SRW_explainResponse *res;
543             xmlNodePtr ptr = method->children;
544
545             (*p)->which = Z_SRW_explain_response;
546             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
547             res->diagnostics = 0;
548             res->num_diagnostics = 0;
549
550             for (; ptr; ptr = ptr->next)
551             {
552                 if (match_element(ptr, "record"))
553                     yaz_srw_record(o, ptr, &res->record, client_data, ns);
554                 else if (match_xsd_string(ptr, "version", o,
555                                           &(*p)->srw_version))
556                     ;
557                 else if (match_element(ptr, "diagnostics"))
558                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
559                                         &res->num_diagnostics,
560                                         client_data, ns);
561                 ;
562             }
563         }
564         else if (!strcmp(method->name, "scanRequest"))
565         {
566             Z_SRW_scanRequest *req;
567             xmlNodePtr ptr = method->children;
568
569             (*p)->which = Z_SRW_scan_request;
570             req = (*p)->u.scan_request = odr_malloc(o, sizeof(*req));
571             req->database = 0;
572             req->scanClause = 0;
573             req->stylesheet = 0;
574             req->responsePosition = 0;
575             req->maximumTerms = 0;
576             
577             for (; ptr; ptr = ptr->next)
578             {
579                 if (match_xsd_string(ptr, "version", o,
580                                      &(*p)->srw_version))
581                     ;
582                 else if (match_xsd_string(ptr, "scanClause", o,
583                                      &req->scanClause))
584                     ;
585                 else if (match_xsd_string(ptr, "database", o,
586                                           &req->database))
587                     ;
588                 else if (match_xsd_string(ptr, "stylesheet", o,
589                                           &req->stylesheet))
590                     ;
591                 else if (match_xsd_integer(ptr, "responsePosition", o,
592                                            &req->responsePosition))
593                     ;
594                 else if (match_xsd_integer(ptr, "maximumTerms", o,
595                                            &req->maximumTerms))
596                     ;
597             }
598         }
599         else if (!strcmp(method->name, "scanResponse"))
600         {
601             Z_SRW_scanResponse *res;
602             xmlNodePtr ptr = method->children;
603
604             (*p)->which = Z_SRW_scan_response;
605             res = (*p)->u.scan_response = odr_malloc(o, sizeof(*res));
606             res->terms = 0;
607             res->num_terms = 0;
608             res->diagnostics = 0;
609             res->num_diagnostics = 0;
610             
611             for (; ptr; ptr = ptr->next)
612             {
613                 if (match_element(ptr, "terms"))
614                     yaz_srw_terms(o, ptr, &res->terms,
615                                   &res->num_terms, client_data,
616                                   ns);
617                 else if (match_element(ptr, "diagnostics"))
618                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
619                                         &res->num_diagnostics,
620                                         client_data, ns);
621                 else if (match_xsd_string(ptr, "version", o,
622                                           &(*p)->srw_version))
623                     ;
624             }
625         }
626         else
627         {
628             *p = 0;
629             return -1;
630         }
631     }
632     else if (o->direction == ODR_ENCODE)
633     {
634         Z_SRW_PDU **p = handler_data;
635         xmlNsPtr ns_srw;
636         
637         if ((*p)->which == Z_SRW_searchRetrieve_request)
638         {
639             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
640             xmlNodePtr ptr = xmlNewChild(pptr, 0,
641                                          "searchRetrieveRequest", 0);
642             ns_srw = xmlNewNs(ptr, ns, "zs");
643             xmlSetNs(ptr, ns_srw);
644
645             if ((*p)->srw_version)
646                 add_xsd_string(ptr, "version", (*p)->srw_version);
647             switch(req->query_type)
648             {
649             case Z_SRW_query_type_cql:
650                 add_xsd_string(ptr, "query", req->query.cql);
651                 break;
652             case Z_SRW_query_type_xcql:
653                 add_xsd_string(ptr, "xQuery", req->query.xcql);
654                 break;
655             case Z_SRW_query_type_pqf:
656                 add_xsd_string(ptr, "pQuery", req->query.pqf);
657                 break;
658             }
659             switch(req->sort_type)
660             {
661             case Z_SRW_sort_type_none:
662                 break;
663             case Z_SRW_sort_type_sort:
664                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
665                 break;
666             case Z_SRW_sort_type_xSort:
667                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
668                 break;
669             }
670             add_xsd_integer(ptr, "startRecord", req->startRecord);
671             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
672             add_xsd_string(ptr, "recordSchema", req->recordSchema);
673             add_xsd_string(ptr, "recordPacking", req->recordPacking);
674             add_xsd_string(ptr, "recordXPath", req->recordXPath);
675             add_xsd_string(ptr, "database", req->database);
676             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
677             add_xsd_string(ptr, "stylesheet", req->stylesheet);
678         }
679         else if ((*p)->which == Z_SRW_searchRetrieve_response)
680         {
681             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
682             xmlNodePtr ptr = xmlNewChild(pptr, 0,
683                                          "searchRetrieveResponse", 0);
684             ns_srw = xmlNewNs(ptr, ns, "zs");
685             xmlSetNs(ptr, ns_srw);
686
687             if ((*p)->srw_version)
688                 add_xsd_string(ptr, "version", (*p)->srw_version);
689             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
690             add_xsd_string(ptr, "resultSetId", res->resultSetId);
691             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
692             if (res->num_records)
693             {
694                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
695                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
696                                 client_data, ns);
697             }
698             if (res->num_diagnostics)
699             {
700                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
701                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
702                                     &res->num_diagnostics, client_data, ns);
703             }
704             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
705         }
706         else if ((*p)->which == Z_SRW_explain_request)
707         {
708             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
709             ns_srw = xmlNewNs(ptr, ns, "zs");
710             xmlSetNs(ptr, ns_srw);
711
712             add_xsd_string(ptr, "version", (*p)->srw_version);
713         }
714         else if ((*p)->which == Z_SRW_explain_response)
715         {
716             Z_SRW_explainResponse *res = (*p)->u.explain_response;
717             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
718             ns_srw = xmlNewNs(ptr, ns, "zs");
719             xmlSetNs(ptr, ns_srw);
720
721             add_xsd_string(ptr, "version", (*p)->srw_version);
722             if (1)
723             {
724                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, "record", 0);
725                 yaz_srw_record(o, ptr1, &res->record, client_data, ns);
726             }
727             if (res->num_diagnostics)
728             {
729                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
730                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
731                                     &res->num_diagnostics, client_data, ns);
732             }
733         }
734         else if ((*p)->which == Z_SRW_scan_request)
735         {
736             Z_SRW_scanRequest *req = (*p)->u.scan_request;
737             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanRequest", 0);
738             ns_srw = xmlNewNs(ptr, ns, "zs");
739             xmlSetNs(ptr, ns_srw);
740
741             add_xsd_string(ptr, "version", (*p)->srw_version);
742             add_xsd_string(ptr, "scanClause", req->scanClause);
743             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
744             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
745             add_xsd_string(ptr, "stylesheet", req->stylesheet);
746         }
747         else if ((*p)->which == Z_SRW_scan_response)
748         {
749             Z_SRW_scanResponse *res = (*p)->u.scan_response;
750             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanResponse", 0);
751             ns_srw = xmlNewNs(ptr, ns, "zs");
752             xmlSetNs(ptr, ns_srw);
753
754             add_xsd_string(ptr, "version", (*p)->srw_version);
755
756             if (res->num_terms)
757             {
758                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "terms", 0);
759                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
760                               client_data, ns);
761             }
762             if (res->num_diagnostics)
763             {
764                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
765                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
766                                     &res->num_diagnostics, client_data, ns);
767             }
768         }
769         else
770             return -1;
771
772     }
773     return 0;
774 }
775
776 #endif
777
778