2.0.9 candidate
[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.11 2004-01-05 09:34:42 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, ptr = pptr->children; ptr; ptr = ptr->next, i++)
283         {
284             if (ptr->type == XML_ELEMENT_NODE &&
285                 !strcmp(ptr->name, "diagnostic"))
286             {
287                 xmlNodePtr rptr;
288                 (*recs)[i].code = 0;
289                 (*recs)[i].details = 0;
290                 for (rptr = ptr->children; rptr; rptr = rptr->next)
291                 {
292                     if (match_xsd_integer(rptr, "code", o, 
293                                                &(*recs)[i].code))
294                         ;
295                     else if (match_xsd_string(rptr, "details", o, 
296                                               &(*recs)[i].details))
297                         ;
298                 }
299                 i++;
300             }
301         }
302     }
303     else if (o->direction == ODR_ENCODE)
304     {
305         int i;
306         xmlNsPtr ns_diag =
307             xmlNewNs(pptr, "http://www.loc.gov/zing/srw/diagnostics/", "diag");
308         for (i = 0; i < *num; i++)
309         {
310             xmlNodePtr rptr = xmlNewChild(pptr, ns_diag, "diagnostic", 0);
311             add_xsd_integer(rptr, "code", (*recs)[i].code);
312             add_xsd_string(rptr, "details", (*recs)[i].details);
313         }
314     }
315     return 0;
316 }
317
318 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
319                         void *client_data, const char *ns)
320 {
321     if (o->direction == ODR_DECODE)
322     {
323         xmlNodePtr ptr;
324         term->value = 0;
325         term->numberOfRecords = 0;
326         term->displayTerm = 0;
327         for (ptr = pptr->children; ptr; ptr = ptr->next)
328         {
329             if (match_xsd_string(ptr, "value", o,  &term->value))
330                 ;
331             else if (match_xsd_integer(ptr, "numberOfRecords", o, 
332                                    &term->numberOfRecords))
333                 ;
334             else if (match_xsd_string(ptr, "displayTerm", o, 
335                                       &term->displayTerm))
336                 ;
337         }
338     }
339     else if (o->direction == ODR_ENCODE)
340     {
341         xmlNodePtr ptr = pptr;
342         add_xsd_string(ptr, "value", term->value);
343         add_xsd_integer(ptr, "value", term->numberOfRecords);
344         add_xsd_string(ptr, "displayTerm", term->displayTerm);
345     }
346     return 0;
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 #endif
772
773