3dd2ea3d28da602af8c6edb6a63b2b011705beea
[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.14 2004-01-06 11:21:04 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, "query", o, 
437                                      &req->query.cql))
438                     req->query_type = Z_SRW_query_type_cql;
439                 else if (match_xsd_string(ptr, "pQuery", o, 
440                                      &req->query.pqf))
441                     req->query_type = Z_SRW_query_type_pqf;
442                 else if (match_xsd_string(ptr, "xQuery", o, 
443                                      &req->query.xcql))
444                     req->query_type = Z_SRW_query_type_xcql;
445                 else if (match_xsd_string(ptr, "sortKeys", o, 
446                                           &req->sort.sortKeys))
447                     req->sort_type = Z_SRW_sort_type_sort;
448                 else if (match_xsd_string(ptr, "recordSchema", o, 
449                                           &req->recordSchema))
450                     ;
451                 else if (match_xsd_string(ptr, "recordPacking", o,
452                                           &req->recordPacking))
453                     ;
454                 else if (match_xsd_string(ptr, "recordXPath", o,
455                                           &req->recordXPath))
456                     ;
457                 else if (match_xsd_integer(ptr, "startRecord", o,
458                                            &req->startRecord))
459                     ;
460                 else if (match_xsd_integer(ptr, "maximumRecords", o,
461                                            &req->maximumRecords))
462                     ;
463                 else if (match_xsd_string(ptr, "stylesheet", o,
464                                            &req->stylesheet))
465                     ;
466                 else if (match_xsd_string(ptr, "database", o,
467                                            &req->database))
468                     ;
469                 else if (match_xsd_string(ptr, "resultSetTTL", o,
470                                            &req->database))
471                     ;
472                 else if (match_xsd_string(ptr, "version", o,
473                                            &(*p)->srw_version))
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_integer(ptr, "numberOfRecords", o, 
498                                       &res->numberOfRecords))
499                     ;
500                 else if (match_xsd_string(ptr, "resultSetId", o, 
501                                           &res->resultSetId))
502                     ;
503                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
504                                            &res->resultSetIdleTime))
505                     ;
506                 else if (match_element(ptr, "records"))
507                     yaz_srw_records(o, ptr, &res->records,
508                                     &res->num_records, client_data,
509                                     ns);
510                 else if (match_element(ptr, "diagnostics"))
511                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
512                                         &res->num_diagnostics,
513                                         client_data, ns);
514                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
515                                            &res->nextRecordPosition))
516                     ;
517                 else if (match_xsd_string(ptr, "version", o,
518                                            &(*p)->srw_version))
519                     ;
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             for (; ptr; ptr = ptr->next)
532             {
533                 if (match_xsd_string(ptr, "database", o,
534                                      &req->database))
535                     ;
536                 else if (match_xsd_string(ptr, "recordPacking", o,
537                                      &req->recordPacking))
538                     ;
539                 else if (match_xsd_string(ptr, "version", o,
540                                            &(*p)->srw_version))
541                     ;
542             }
543         }
544         else if (!strcmp(method->name, "explainResponse"))
545         {
546             Z_SRW_explainResponse *res;
547             xmlNodePtr ptr = method->children;
548
549             (*p)->which = Z_SRW_explain_response;
550             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
551             res->diagnostics = 0;
552             res->num_diagnostics = 0;
553
554             for (; ptr; ptr = ptr->next)
555             {
556                 if (match_element(ptr, "record"))
557                     yaz_srw_record(o, ptr, &res->record, client_data, ns);
558                 else if (match_xsd_string(ptr, "version", o,
559                                           &(*p)->srw_version))
560                     ;
561                 else if (match_element(ptr, "diagnostics"))
562                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
563                                         &res->num_diagnostics,
564                                         client_data, ns);
565                 ;
566             }
567         }
568         else if (!strcmp(method->name, "scanRequest"))
569         {
570             Z_SRW_scanRequest *req;
571             xmlNodePtr ptr = method->children;
572
573             (*p)->which = Z_SRW_scan_request;
574             req = (*p)->u.scan_request = odr_malloc(o, sizeof(*req));
575             req->database = 0;
576             req->scanClause = 0;
577             req->stylesheet = 0;
578             req->responsePosition = 0;
579             req->maximumTerms = 0;
580             
581             for (; ptr; ptr = ptr->next)
582             {
583                 if (match_xsd_string(ptr, "version", o,
584                                      &(*p)->srw_version))
585                     ;
586                 else if (match_xsd_string(ptr, "scanClause", o,
587                                      &req->scanClause))
588                     ;
589                 else if (match_xsd_string(ptr, "database", o,
590                                           &req->database))
591                     ;
592                 else if (match_xsd_string(ptr, "stylesheet", o,
593                                           &req->stylesheet))
594                     ;
595                 else if (match_xsd_integer(ptr, "responsePosition", o,
596                                            &req->responsePosition))
597                     ;
598                 else if (match_xsd_integer(ptr, "maximumTerms", o,
599                                            &req->maximumTerms))
600                     ;
601             }
602         }
603         else if (!strcmp(method->name, "scanResponse"))
604         {
605             Z_SRW_scanResponse *res;
606             xmlNodePtr ptr = method->children;
607
608             (*p)->which = Z_SRW_scan_response;
609             res = (*p)->u.scan_response = odr_malloc(o, sizeof(*res));
610             res->terms = 0;
611             res->num_terms = 0;
612             res->diagnostics = 0;
613             res->num_diagnostics = 0;
614             
615             for (; ptr; ptr = ptr->next)
616             {
617                 if (match_element(ptr, "terms"))
618                     yaz_srw_terms(o, ptr, &res->terms,
619                                   &res->num_terms, client_data,
620                                   ns);
621                 else if (match_element(ptr, "diagnostics"))
622                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
623                                         &res->num_diagnostics,
624                                         client_data, ns);
625                 else if (match_xsd_string(ptr, "version", o,
626                                           &(*p)->srw_version))
627                     ;
628             }
629         }
630         else
631         {
632             *p = 0;
633             return -1;
634         }
635     }
636     else if (o->direction == ODR_ENCODE)
637     {
638         Z_SRW_PDU **p = handler_data;
639         xmlNsPtr ns_srw;
640         
641         if ((*p)->which == Z_SRW_searchRetrieve_request)
642         {
643             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
644             xmlNodePtr ptr = xmlNewChild(pptr, 0,
645                                          "searchRetrieveRequest", 0);
646             ns_srw = xmlNewNs(ptr, ns, "zs");
647             xmlSetNs(ptr, ns_srw);
648
649             if ((*p)->srw_version)
650                 add_xsd_string(ptr, "version", (*p)->srw_version);
651             switch(req->query_type)
652             {
653             case Z_SRW_query_type_cql:
654                 add_xsd_string(ptr, "query", req->query.cql);
655                 break;
656             case Z_SRW_query_type_xcql:
657                 add_xsd_string(ptr, "xQuery", req->query.xcql);
658                 break;
659             case Z_SRW_query_type_pqf:
660                 add_xsd_string(ptr, "pQuery", req->query.pqf);
661                 break;
662             }
663             switch(req->sort_type)
664             {
665             case Z_SRW_sort_type_none:
666                 break;
667             case Z_SRW_sort_type_sort:
668                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
669                 break;
670             case Z_SRW_sort_type_xSort:
671                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
672                 break;
673             }
674             add_xsd_integer(ptr, "startRecord", req->startRecord);
675             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
676             add_xsd_string(ptr, "recordSchema", req->recordSchema);
677             add_xsd_string(ptr, "recordPacking", req->recordPacking);
678             add_xsd_string(ptr, "recordXPath", req->recordXPath);
679             add_xsd_string(ptr, "database", req->database);
680             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
681             add_xsd_string(ptr, "stylesheet", req->stylesheet);
682         }
683         else if ((*p)->which == Z_SRW_searchRetrieve_response)
684         {
685             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
686             xmlNodePtr ptr = xmlNewChild(pptr, 0,
687                                          "searchRetrieveResponse", 0);
688             ns_srw = xmlNewNs(ptr, ns, "zs");
689             xmlSetNs(ptr, ns_srw);
690
691             if ((*p)->srw_version)
692                 add_xsd_string(ptr, "version", (*p)->srw_version);
693             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
694             add_xsd_string(ptr, "resultSetId", res->resultSetId);
695             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
696             if (res->num_records)
697             {
698                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
699                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
700                                 client_data, ns);
701             }
702             if (res->num_diagnostics)
703             {
704                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
705                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
706                                     &res->num_diagnostics, client_data, ns);
707             }
708             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
709         }
710         else if ((*p)->which == Z_SRW_explain_request)
711         {
712             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
713             ns_srw = xmlNewNs(ptr, ns, "zs");
714             xmlSetNs(ptr, ns_srw);
715
716             add_xsd_string(ptr, "version", (*p)->srw_version);
717         }
718         else if ((*p)->which == Z_SRW_explain_response)
719         {
720             Z_SRW_explainResponse *res = (*p)->u.explain_response;
721             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
722             ns_srw = xmlNewNs(ptr, ns, "zs");
723             xmlSetNs(ptr, ns_srw);
724
725             add_xsd_string(ptr, "version", (*p)->srw_version);
726             if (1)
727             {
728                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, "record", 0);
729                 yaz_srw_record(o, ptr1, &res->record, client_data, ns);
730             }
731             if (res->num_diagnostics)
732             {
733                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
734                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
735                                     &res->num_diagnostics, client_data, ns);
736             }
737         }
738         else if ((*p)->which == Z_SRW_scan_request)
739         {
740             Z_SRW_scanRequest *req = (*p)->u.scan_request;
741             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanRequest", 0);
742             ns_srw = xmlNewNs(ptr, ns, "zs");
743             xmlSetNs(ptr, ns_srw);
744
745             add_xsd_string(ptr, "version", (*p)->srw_version);
746             add_xsd_string(ptr, "scanClause", req->scanClause);
747             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
748             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
749             add_xsd_string(ptr, "stylesheet", req->stylesheet);
750         }
751         else if ((*p)->which == Z_SRW_scan_response)
752         {
753             Z_SRW_scanResponse *res = (*p)->u.scan_response;
754             xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanResponse", 0);
755             ns_srw = xmlNewNs(ptr, ns, "zs");
756             xmlSetNs(ptr, ns_srw);
757
758             add_xsd_string(ptr, "version", (*p)->srw_version);
759
760             if (res->num_terms)
761             {
762                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "terms", 0);
763                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
764                               client_data, ns);
765             }
766             if (res->num_diagnostics)
767             {
768                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
769                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
770                                     &res->num_diagnostics, client_data, ns);
771             }
772         }
773         else
774             return -1;
775
776     }
777     return 0;
778 }
779
780 #endif
781
782