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