Initialize facetList
[yaz-moved-to-github.git] / src / srw.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2010 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file srw.c
7  * \brief Implements SRW/SRU package encoding and decoding
8  */
9
10 #include <yaz/srw.h>
11 #if YAZ_HAVE_XML2
12 #include <libxml/parser.h>
13 #include <libxml/tree.h>
14 #include <assert.h>
15
16 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len,
17                       xmlNsPtr ns_ptr)
18 {
19     if (val)
20     {
21         xmlDocPtr doc = xmlParseMemory(val,len);
22         if (doc)
23         {
24             xmlNodePtr c = xmlNewChild(ptr, ns_ptr, BAD_CAST elem, 0);
25             xmlNodePtr t = xmlDocGetRootElement(doc);
26             xmlAddChild(c, xmlCopyNode(t,1));
27             xmlFreeDoc(doc);
28         }
29     }
30 }
31
32 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, const char *val,
33                             int len)
34 {
35     if (val)
36     {
37         xmlNodePtr c = xmlNewChild(ptr, 0, BAD_CAST elem, 0);
38         xmlNodePtr t = xmlNewTextLen(BAD_CAST val, len);
39         xmlAddChild(c, t);
40         return t;
41     }
42     return 0;
43 }
44
45 xmlNodePtr add_xsd_string_ns(xmlNodePtr ptr, const char *elem, const char *val,
46                              xmlNsPtr ns_ptr)
47 {
48     if (val)
49     {
50         xmlNodePtr c = xmlNewChild(ptr, ns_ptr, BAD_CAST elem, 0);
51         xmlNodePtr t = xmlNewText(BAD_CAST val);
52         xmlAddChild(c, t);
53         return t;
54     }
55     return 0;
56 }
57
58 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, const char *val)
59 {
60     return add_xsd_string_ns(ptr, elem, val, 0);
61 }
62
63 static void add_xsd_integer(xmlNodePtr ptr, const char *elem,
64                             const Odr_int *val)
65 {
66     if (val)
67     {
68         char str[40];
69         sprintf(str, ODR_INT_PRINTF, *val);
70         xmlNewTextChild(ptr, 0, BAD_CAST elem, BAD_CAST str);
71     }
72 }
73
74 static int match_element(xmlNodePtr ptr, const char *elem)
75 {
76     if (ptr->type == XML_ELEMENT_NODE && !xmlStrcmp(ptr->name, BAD_CAST elem))
77     {
78         return 1;
79     }
80     return 0;
81 }
82
83 #define CHECK_TYPE 0
84
85 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
86                               char **val, int *len)
87 {
88 #if CHECK_TYPE
89     struct _xmlAttr *attr;
90 #endif
91     if (!match_element(ptr, elem))
92         return 0;
93 #if CHECK_TYPE
94     for (attr = ptr->properties; attr; attr = attr->next)
95         if (!strcmp(attr->name, "type") &&
96             attr->children && attr->children->type == XML_TEXT_NODE)
97         {
98             const char *t = strchr(attr->children->content, ':');
99             if (t)
100                 t = t + 1;
101             else
102                 t = attr->children->content;
103             if (!strcmp(t, "string"))
104                 break;
105         }
106     if (!attr)
107         return 0;
108 #endif
109     ptr = ptr->children;
110     if (!ptr || ptr->type != XML_TEXT_NODE)
111     {
112         *val = "";
113         return 1;
114     }
115     *val = odr_strdup(o, (const char *) ptr->content);
116     if (len)
117         *len = xmlStrlen(ptr->content);
118     return 1;
119 }
120
121
122 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
123                             char **val)
124 {
125     return match_xsd_string_n(ptr, elem, o, val, 0);
126 }
127
128 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
129                            char **val, int *len)
130 {
131     xmlBufferPtr buf;
132
133     if (!match_element(ptr, elem))
134         return 0;
135
136     buf = xmlBufferCreate();
137
138     /* Copy each element nodes at top.
139        In most cases there is only one root node.. At least one server
140        http://www.theeuropeanlibrary.org/sru/sru.pl
141        has multiple root nodes in recordData.
142     */
143     for (ptr = ptr->children; ptr; ptr = ptr->next)
144     {
145         if (ptr->type == XML_ELEMENT_NODE)
146         {
147             /* copy node to get NS right (bug #740). */
148             xmlNode *tmp = xmlCopyNode(ptr, 1);
149             
150             xmlNodeDump(buf, tmp->doc, tmp, 0, 0);
151             
152             xmlFreeNode(tmp);
153         }
154     }
155     
156     *val = (char *) odr_malloc(o, buf->use+1);
157     memcpy (*val, buf->content, buf->use);
158     (*val)[buf->use] = '\0';
159
160     if (len)
161         *len = buf->use;
162
163     xmlBufferFree(buf);
164
165     return 1;
166 }
167                      
168 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o,
169                              Odr_int **val)
170 {
171 #if CHECK_TYPE
172     struct _xmlAttr *attr;
173 #endif
174     if (!match_element(ptr, elem))
175         return 0;
176 #if CHECK_TYPE
177     for (attr = ptr->properties; attr; attr = attr->next)
178         if (!strcmp(attr->name, "type") &&
179             attr->children && attr->children->type == XML_TEXT_NODE)
180         {
181             const char *t = strchr(attr->children->content, ':');
182             if (t)
183                 t = t + 1;
184             else
185                 t = attr->children->content;
186             if (!strcmp(t, "integer"))
187                 break;
188         }
189     if (!attr)
190         return 0;
191 #endif
192     ptr = ptr->children;
193     if (!ptr || ptr->type != XML_TEXT_NODE)
194         return 0;
195     *val = odr_intdup(o, odr_atoi((const char *) ptr->content));
196     return 1;
197 }
198
199 char *yaz_negotiate_sru_version(char *input_ver)
200 {
201     if (!input_ver)
202         input_ver = "1.1";
203
204     if (!strcmp(input_ver, "1.1"))
205         return "1.1";
206     return  "1.2"; /* our latest supported version */
207 }
208
209 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
210                           Z_SRW_extra_record **extra,
211                           void *client_data, const char *ns)
212 {
213     if (o->direction == ODR_DECODE)
214     {
215         Z_SRW_extra_record ex;
216
217         char *spack = 0;
218         int pack = Z_SRW_recordPacking_string;
219         xmlNodePtr ptr;
220         xmlNodePtr data_ptr = 0;
221         rec->recordSchema = 0;
222         rec->recordData_buf = 0;
223         rec->recordData_len = 0;
224         rec->recordPosition = 0;
225         *extra = 0;
226
227         ex.extraRecordData_buf = 0;
228         ex.extraRecordData_len = 0;
229         ex.recordIdentifier = 0;
230
231         for (ptr = pptr->children; ptr; ptr = ptr->next)
232         {
233             
234             if (match_xsd_string(ptr, "recordSchema", o, 
235                                  &rec->recordSchema))
236                 ;
237             else if (match_xsd_string(ptr, "recordPacking", o, &spack))
238             {
239                 if (spack)
240                     pack = yaz_srw_str_to_pack(spack);
241             }
242             else if (match_xsd_integer(ptr, "recordPosition", o, 
243                                        &rec->recordPosition))
244                 ;
245             else if (match_element(ptr, "recordData"))
246             {
247                 /* save position of Data until after the loop
248                    then we will know the packing (hopefully), and
249                    unpacking is done once
250                 */
251                 data_ptr = ptr;
252             }
253             else if (match_xsd_XML_n(ptr, "extraRecordData", o, 
254                                      &ex.extraRecordData_buf,
255                                      &ex.extraRecordData_len) )
256                 ;
257             else if (match_xsd_string(ptr, "recordIdentifier", o, 
258                                       &ex.recordIdentifier))
259                 ;
260
261         }
262         if (data_ptr)
263         {
264             switch(pack)
265             {
266             case Z_SRW_recordPacking_XML:
267                 match_xsd_XML_n(data_ptr, "recordData", o, 
268                                 &rec->recordData_buf, &rec->recordData_len);
269                 break;
270             case Z_SRW_recordPacking_URL:
271                 /* just store it as a string.
272                    leave it to the backend to collect the document */
273                 match_xsd_string_n(data_ptr, "recordData", o, 
274                                    &rec->recordData_buf, &rec->recordData_len);
275                 break;
276             case Z_SRW_recordPacking_string:
277                 match_xsd_string_n(data_ptr, "recordData", o, 
278                                    &rec->recordData_buf, &rec->recordData_len);
279                 break;
280             }
281         }
282         rec->recordPacking = pack;
283         if (ex.extraRecordData_buf || ex.recordIdentifier)
284         {
285             *extra = (Z_SRW_extra_record *)
286                 odr_malloc(o, sizeof(Z_SRW_extra_record));
287             memcpy(*extra, &ex, sizeof(Z_SRW_extra_record));
288         }
289     }
290     else if (o->direction == ODR_ENCODE)
291     {
292         xmlNodePtr ptr = pptr;
293         int pack = rec->recordPacking;
294         const char *spack = yaz_srw_pack_to_str(pack);
295
296         add_xsd_string(ptr, "recordSchema", rec->recordSchema);
297         if (spack)
298             add_xsd_string(ptr, "recordPacking", spack);
299         switch(pack)
300         {
301         case Z_SRW_recordPacking_string:
302             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
303                              rec->recordData_len);
304             break;
305         case Z_SRW_recordPacking_XML:
306             add_XML_n(ptr, "recordData", rec->recordData_buf,
307                       rec->recordData_len, 0);
308             break;
309         case Z_SRW_recordPacking_URL:
310             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
311                              rec->recordData_len);
312             break;
313         }
314         if (rec->recordPosition)
315             add_xsd_integer(ptr, "recordPosition", rec->recordPosition );
316         if (extra && *extra)
317         {
318             if ((*extra)->recordIdentifier)
319                 add_xsd_string(ptr, "recordIdentifier",
320                                (*extra)->recordIdentifier);
321             if ((*extra)->extraRecordData_buf)
322                 add_XML_n(ptr, "extraRecordData",
323                           (*extra)->extraRecordData_buf,
324                           (*extra)->extraRecordData_len, 0);
325         }
326     }
327     return 0;
328 }
329
330 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
331                            Z_SRW_extra_record ***extra,
332                            int *num, void *client_data, const char *ns)
333 {
334     if (o->direction == ODR_DECODE)
335     {
336         int i;
337         xmlNodePtr ptr;
338         *num = 0;
339         for (ptr = pptr->children; ptr; ptr = ptr->next)
340         {
341             if (ptr->type == XML_ELEMENT_NODE &&
342                 !xmlStrcmp(ptr->name, BAD_CAST "record"))
343                 (*num)++;
344         }
345         if (!*num)
346             return 1;
347         *recs = (Z_SRW_record *) odr_malloc(o, *num * sizeof(**recs));
348         *extra = (Z_SRW_extra_record **) odr_malloc(o, *num * sizeof(**extra));
349         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
350         {
351             if (ptr->type == XML_ELEMENT_NODE &&
352                 !xmlStrcmp(ptr->name, BAD_CAST "record"))
353             {
354                 yaz_srw_record(o, ptr, *recs + i, *extra + i, client_data, ns);
355                 i++;
356             }
357         }
358     }
359     else if (o->direction == ODR_ENCODE)
360     {
361         int i;
362         for (i = 0; i < *num; i++)
363         {
364             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "record",
365                                           0);
366             yaz_srw_record(o, rptr, (*recs)+i, (*extra ? *extra + i : 0),
367                            client_data, ns);
368         }
369     }
370     return 0;
371 }
372
373 static int yaz_srw_version(ODR o, xmlNodePtr pptr, Z_SRW_recordVersion *rec,
374                            void *client_data, const char *ns)
375 {
376     if (o->direction == ODR_DECODE)
377     {
378         xmlNodePtr ptr;
379         rec->versionType = 0;
380         rec->versionValue = 0;
381         for (ptr = pptr->children; ptr; ptr = ptr->next)
382         {
383             
384             if (match_xsd_string(ptr, "versionType", o, 
385                                  &rec->versionType))
386                 ;
387             else if (match_xsd_string(ptr, "versionValue", o, 
388                                       &rec->versionValue))
389                 ;
390         }
391     }
392     else if (o->direction == ODR_ENCODE)
393         {
394         xmlNodePtr ptr = pptr;
395         add_xsd_string(ptr, "versionType", rec->versionType);
396         add_xsd_string(ptr, "versionValue", rec->versionValue);
397     }
398     return 0;
399 }
400
401 static int yaz_srw_versions(ODR o, xmlNodePtr pptr, 
402                             Z_SRW_recordVersion **vers,
403                             int *num, void *client_data, const char *ns)
404 {
405     if (o->direction == ODR_DECODE)
406     {
407         int i;
408         xmlNodePtr ptr;
409         *num = 0;
410         for (ptr = pptr->children; ptr; ptr = ptr->next)
411         {
412             if (ptr->type == XML_ELEMENT_NODE &&
413                 !xmlStrcmp(ptr->name, BAD_CAST "recordVersion"))
414                 (*num)++;
415         }
416         if (!*num)
417             return 1;
418         *vers = (Z_SRW_recordVersion *) odr_malloc(o, *num * sizeof(**vers));
419         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
420         {
421             if (ptr->type == XML_ELEMENT_NODE &&
422                 !xmlStrcmp(ptr->name, BAD_CAST "recordVersion"))
423             {
424                 yaz_srw_version(o, ptr, *vers + i, client_data, ns);
425                 i++;
426             }
427         }
428     }
429     else if (o->direction == ODR_ENCODE)
430     {
431         int i;
432         for (i = 0; i < *num; i++)
433             {
434             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "version",
435                                           0);
436             yaz_srw_version(o, rptr, (*vers)+i, client_data, ns);
437         }
438     }
439     return 0;
440 }
441
442
443 static int yaz_srw_decode_diagnostics(ODR o, xmlNodePtr pptr,
444                                       Z_SRW_diagnostic **recs, int *num,
445                                       void *client_data, const char *ns)
446     
447 {
448     int i;
449     xmlNodePtr ptr;
450     *num = 0;
451     for (ptr = pptr; ptr; ptr = ptr->next)
452     {
453             if (ptr->type == XML_ELEMENT_NODE &&
454                 !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
455                 (*num)++;
456     }
457     if (!*num)
458         return 1;
459     *recs = (Z_SRW_diagnostic *) odr_malloc(o, *num * sizeof(**recs));
460     for (i = 0; i < *num; i++)
461         {
462             (*recs)[i].uri = 0;
463             (*recs)[i].details = 0;
464             (*recs)[i].message = 0;
465         } 
466     for (i = 0, ptr = pptr; ptr; ptr = ptr->next)
467     {
468         if (ptr->type == XML_ELEMENT_NODE &&
469             !xmlStrcmp(ptr->name, BAD_CAST "diagnostic"))
470         {
471             xmlNodePtr rptr;
472             (*recs)[i].uri = 0;
473             (*recs)[i].details = 0;
474             (*recs)[i].message = 0;
475             for (rptr = ptr->children; rptr; rptr = rptr->next)
476             {
477                 if (match_xsd_string(rptr, "uri", o, 
478                                      &(*recs)[i].uri))
479                     ;
480                 else if (match_xsd_string(rptr, "details", o, 
481                                           &(*recs)[i].details))
482                     ;
483                 else if (match_xsd_string(rptr, "message", o, 
484                                           &(*recs)[i].message))
485                     ;
486             }
487             i++;
488         }
489     }
490     return 0;
491 }
492
493 int sru_decode_surrogate_diagnostics(const char *buf, size_t len,
494                                      Z_SRW_diagnostic **diag,
495                                      int *num, ODR odr)
496 {
497     int ret = 0;
498     xmlDocPtr doc = xmlParseMemory(buf, len);
499     if (doc)
500     {
501         xmlNodePtr ptr = xmlDocGetRootElement(doc);
502         while (ptr && ptr->type != XML_ELEMENT_NODE)
503             ptr = ptr->next;
504         if (ptr && ptr->ns 
505             && !xmlStrcmp(ptr->ns->href,
506                           BAD_CAST "http://www.loc.gov/zing/srw/diagnostic/"))
507         {
508             ret = yaz_srw_decode_diagnostics(odr, ptr, diag, num, 0, 0);
509         }
510         xmlFreeDoc(doc);
511     }
512     return ret;
513 }
514
515 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
516                                int *num, void *client_data, const char *ns)
517 {
518     if (o->direction == ODR_DECODE)
519     {
520         return yaz_srw_decode_diagnostics(o, pptr->children, recs, num, client_data, ns);
521     }
522     else if (o->direction == ODR_ENCODE)
523     {
524         int i;
525         xmlNsPtr ns_diag =
526             xmlNewNs(pptr, BAD_CAST YAZ_XMLNS_DIAG_v1_1, BAD_CAST "diag" );
527         for (i = 0; i < *num; i++)
528         {
529             const char *std_diag = "info:srw/diagnostic/1/";
530             const char *ucp_diag = "info:srw/diagnostic/12/";
531             xmlNodePtr rptr = xmlNewChild(pptr, ns_diag,
532                                           BAD_CAST "diagnostic", 0);
533             add_xsd_string(rptr, "uri", (*recs)[i].uri);
534             if ((*recs)[i].message)
535                 add_xsd_string(rptr, "message", (*recs)[i].message);
536             else if ((*recs)[i].uri )
537             {
538                 if (!strncmp((*recs)[i].uri, std_diag, strlen(std_diag)))
539                 {
540                     int no = atoi((*recs)[i].uri + strlen(std_diag));
541                     const char *message = yaz_diag_srw_str(no);
542                     if (message)
543                         add_xsd_string(rptr, "message", message);
544                 }
545                 else if (!strncmp((*recs)[i].uri, ucp_diag, strlen(ucp_diag)))
546                 {
547                     int no = atoi((*recs)[i].uri + strlen(ucp_diag));
548                     const char *message = yaz_diag_sru_update_str(no);
549                     if (message)
550                         add_xsd_string(rptr, "message", message);
551                 }
552             }
553             add_xsd_string(rptr, "details", (*recs)[i].details);
554         }
555     }
556     return 0;
557 }
558
559 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
560                         void *client_data, const char *ns)
561 {
562     if (o->direction == ODR_DECODE)
563     {
564         xmlNodePtr ptr;
565         term->value = 0;
566         term->numberOfRecords = 0;
567         term->displayTerm = 0;
568         term->whereInList = 0;
569         for (ptr = pptr->children; ptr; ptr = ptr->next)
570         {
571             if (match_xsd_string(ptr, "value", o,  &term->value))
572                 ;
573             else if (match_xsd_integer(ptr, "numberOfRecords", o, 
574                                    &term->numberOfRecords))
575                 ;
576             else if (match_xsd_string(ptr, "displayTerm", o, 
577                                       &term->displayTerm))
578                 ;
579             else if (match_xsd_string(ptr, "whereInList", o, 
580                                       &term->whereInList))
581                 ;
582         }
583     }
584     else if (o->direction == ODR_ENCODE)
585     {
586         xmlNodePtr ptr = pptr;
587         add_xsd_string(ptr, "value", term->value);
588         add_xsd_integer(ptr, "numberOfRecords", term->numberOfRecords);
589         add_xsd_string(ptr, "displayTerm", term->displayTerm);
590         add_xsd_string(ptr, "whereInList", term->whereInList);
591     }
592     return 0;
593 }
594
595 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
596                          int *num, void *client_data, const char *ns)
597 {
598     if (o->direction == ODR_DECODE)
599     {
600         int i;
601         xmlNodePtr ptr;
602         *num = 0;
603         for (ptr = pptr->children; ptr; ptr = ptr->next)
604         {
605             if (ptr->type == XML_ELEMENT_NODE &&
606                 !xmlStrcmp(ptr->name, BAD_CAST "term"))
607                 (*num)++;
608         }
609         if (!*num)
610             return 1;
611         *terms = (Z_SRW_scanTerm *) odr_malloc(o, *num * sizeof(**terms));
612         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
613         {
614             if (ptr->type == XML_ELEMENT_NODE &&
615                 !xmlStrcmp(ptr->name, BAD_CAST "term"))
616                 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
617         }
618     }
619     else if (o->direction == ODR_ENCODE)
620     {
621         int i;
622         for (i = 0; i < *num; i++)
623         {
624             xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "term", 0);
625             yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
626         }
627     }
628     return 0;
629 }
630
631 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
632                   void *client_data, const char *ns)
633 {
634     xmlNodePtr pptr = (xmlNodePtr) vptr;
635     if (o->direction == ODR_DECODE)
636     {
637         Z_SRW_PDU **p = handler_data;
638         xmlNodePtr method = pptr->children;
639         char *neg_version;
640
641         while (method && method->type == XML_TEXT_NODE)
642             method = method->next;
643         
644         if (!method)
645             return -1;
646         if (method->type != XML_ELEMENT_NODE)
647             return -1;
648
649         *p = yaz_srw_get_core_v_1_1(o);
650         
651         if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveRequest"))
652         {
653             xmlNodePtr ptr = method->children;
654             Z_SRW_searchRetrieveRequest *req;
655
656             (*p)->which = Z_SRW_searchRetrieve_request;
657             req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *)
658                 odr_malloc(o, sizeof(*req));
659             req->query_type = Z_SRW_query_type_cql;
660             req->query.cql = 0;
661             req->sort_type = Z_SRW_sort_type_none;
662             req->sort.none = 0;
663             req->startRecord = 0;
664             req->maximumRecords = 0;
665             req->recordSchema = 0;
666             req->recordPacking = 0;
667             req->recordXPath = 0;
668             req->resultSetTTL = 0;
669             req->stylesheet = 0;
670             req->database = 0;
671
672             for (; ptr; ptr = ptr->next)
673             {
674                 if (match_xsd_string(ptr, "version", o,
675                                      &(*p)->srw_version))
676                     ;
677                 else if (match_xsd_string(ptr, "query", o, 
678                                      &req->query.cql))
679                     req->query_type = Z_SRW_query_type_cql;
680                 else if (match_xsd_string(ptr, "pQuery", o, 
681                                      &req->query.pqf))
682                     req->query_type = Z_SRW_query_type_pqf;
683                 else if (match_xsd_string(ptr, "xQuery", o, 
684                                      &req->query.xcql))
685                     req->query_type = Z_SRW_query_type_xcql;
686                 else if (match_xsd_integer(ptr, "startRecord", o,
687                                            &req->startRecord))
688                     ;
689                 else if (match_xsd_integer(ptr, "maximumRecords", o,
690                                            &req->maximumRecords))
691                     ;
692                 else if (match_xsd_string(ptr, "recordPacking", o,
693                                           &req->recordPacking))
694                     ;
695                 else if (match_xsd_string(ptr, "recordSchema", o, 
696                                           &req->recordSchema))
697                     ;
698                 else if (match_xsd_string(ptr, "recordXPath", o,
699                                           &req->recordXPath))
700                     ;
701                 else if (match_xsd_integer(ptr, "resultSetTTL", o,
702                                            &req->resultSetTTL))
703                     ;
704                 else if (match_xsd_string(ptr, "sortKeys", o, 
705                                           &req->sort.sortKeys))
706                     req->sort_type = Z_SRW_sort_type_sort;
707                 else if (match_xsd_string(ptr, "stylesheet", o,
708                                            &req->stylesheet))
709                     ;
710                 else if (match_xsd_string(ptr, "database", o,
711                                            &req->database))
712                     ;
713             }
714             if (!req->query.cql && !req->query.pqf && !req->query.xcql)
715             {
716                 /* should put proper diagnostic here */
717                 return -1;
718             }
719         }
720         else if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveResponse"))
721         {
722             xmlNodePtr ptr = method->children;
723             Z_SRW_searchRetrieveResponse *res;
724
725             (*p)->which = Z_SRW_searchRetrieve_response;
726             res = (*p)->u.response = (Z_SRW_searchRetrieveResponse *)
727                 odr_malloc(o, sizeof(*res));
728
729             res->numberOfRecords = 0;
730             res->resultSetId = 0;
731             res->resultSetIdleTime = 0;
732             res->records = 0;
733             res->num_records = 0;
734             res->diagnostics = 0;
735             res->num_diagnostics = 0;
736             res->nextRecordPosition = 0;
737             res->facetList = 0;
738
739             for (; ptr; ptr = ptr->next)
740             {
741                 if (match_xsd_string(ptr, "version", o,
742                                      &(*p)->srw_version))
743                     ;
744                 else if (match_xsd_XML_n(ptr, "extraResponseData", o, 
745                                          &(*p)->extraResponseData_buf,
746                                          &(*p)->extraResponseData_len))
747                     ;
748                 else if (match_xsd_integer(ptr, "numberOfRecords", o, 
749                                       &res->numberOfRecords))
750                     ;
751                 else if (match_xsd_string(ptr, "resultSetId", o, 
752                                           &res->resultSetId))
753                     ;
754                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
755                                            &res->resultSetIdleTime))
756                     ;
757                 else if (match_element(ptr, "records"))
758                     yaz_srw_records(o, ptr, &res->records,
759                                     &res->extra_records,
760                                     &res->num_records, client_data, ns);
761                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
762                                            &res->nextRecordPosition))
763                     ;
764                 else if (match_element(ptr, "diagnostics"))
765                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
766                                         &res->num_diagnostics,
767                                         client_data, ns);
768             }
769         }
770         else if (!xmlStrcmp(method->name, BAD_CAST "explainRequest"))
771         {
772             Z_SRW_explainRequest *req;
773             xmlNodePtr ptr = method->children;
774             
775             (*p)->which = Z_SRW_explain_request;
776             req = (*p)->u.explain_request = (Z_SRW_explainRequest *)
777                 odr_malloc(o, sizeof(*req));
778             req->recordPacking = 0;
779             req->database = 0;
780             req->stylesheet = 0;
781             for (; ptr; ptr = ptr->next)
782             {
783                 if (match_xsd_string(ptr, "version", o,
784                                            &(*p)->srw_version))
785                     ;
786                 else if (match_xsd_XML_n(ptr, "extraResponseData", o, 
787                                          &(*p)->extraResponseData_buf,
788                                          &(*p)->extraResponseData_len))
789                     ;
790                 else if (match_xsd_string(ptr, "stylesheet", o,
791                                           &req->stylesheet))
792                     ;
793                 else if (match_xsd_string(ptr, "recordPacking", o,
794                                      &req->recordPacking))
795                     ;
796                 else if (match_xsd_string(ptr, "database", o,
797                                      &req->database))
798                     ;
799             }
800         }
801         else if (!xmlStrcmp(method->name, BAD_CAST "explainResponse"))
802         {
803             Z_SRW_explainResponse *res;
804             xmlNodePtr ptr = method->children;
805
806             (*p)->which = Z_SRW_explain_response;
807             res = (*p)->u.explain_response = (Z_SRW_explainResponse*)
808                 odr_malloc(o, sizeof(*res));
809             res->diagnostics = 0;
810             res->num_diagnostics = 0;
811             res->record.recordSchema = 0;
812             res->record.recordData_buf = 0;
813             res->record.recordData_len = 0;
814             res->record.recordPosition = 0;
815
816             for (; ptr; ptr = ptr->next)
817             {
818                 if (match_xsd_string(ptr, "version", o,
819                                            &(*p)->srw_version))
820                     ;
821                 else if (match_xsd_XML_n(ptr, "extraResponseData", o, 
822                                          &(*p)->extraResponseData_buf,
823                                          &(*p)->extraResponseData_len))
824                     ;
825                 else if (match_element(ptr, "record"))
826                     yaz_srw_record(o, ptr, &res->record, &res->extra_record,
827                                    client_data, ns);
828                 else if (match_element(ptr, "diagnostics"))
829                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
830                                         &res->num_diagnostics,
831                                         client_data, ns);
832                 ;
833             }
834         }
835         else if (!xmlStrcmp(method->name, BAD_CAST "scanRequest"))
836         {
837             Z_SRW_scanRequest *req;
838             xmlNodePtr ptr = method->children;
839
840             (*p)->which = Z_SRW_scan_request;
841             req = (*p)->u.scan_request = (Z_SRW_scanRequest *)
842                 odr_malloc(o, sizeof(*req));
843             req->query_type = Z_SRW_query_type_cql;
844             req->scanClause.cql = 0;
845             req->responsePosition = 0;
846             req->maximumTerms = 0;
847             req->stylesheet = 0;
848             req->database = 0;
849             
850             for (; ptr; ptr = ptr->next)
851             {
852                 if (match_xsd_string(ptr, "version", o,
853                                      &(*p)->srw_version))
854                     ;
855                 else if (match_xsd_XML_n(ptr, "extraResponseData", o, 
856                                          &(*p)->extraResponseData_buf,
857                                          &(*p)->extraResponseData_len))
858                     ;
859                 else if (match_xsd_string(ptr, "scanClause", o,
860                                      &req->scanClause.cql))
861                     ;
862                 else if (match_xsd_string(ptr, "pScanClause", o,
863                                           &req->scanClause.pqf))
864                 {
865                     req->query_type = Z_SRW_query_type_pqf;
866                 }
867                 else if (match_xsd_integer(ptr, "responsePosition", o,
868                                            &req->responsePosition))
869                     ;
870                 else if (match_xsd_integer(ptr, "maximumTerms", o,
871                                            &req->maximumTerms))
872                     ;
873                 else if (match_xsd_string(ptr, "stylesheet", o,
874                                           &req->stylesheet))
875                     ;
876                 else if (match_xsd_string(ptr, "database", o,
877                                           &req->database))
878                     ;
879             }
880         }
881         else if (!xmlStrcmp(method->name, BAD_CAST "scanResponse"))
882         {
883             Z_SRW_scanResponse *res;
884             xmlNodePtr ptr = method->children;
885
886             (*p)->which = Z_SRW_scan_response;
887             res = (*p)->u.scan_response = (Z_SRW_scanResponse *)
888                 odr_malloc(o, sizeof(*res));
889             res->terms = 0;
890             res->num_terms = 0;
891             res->diagnostics = 0;
892             res->num_diagnostics = 0;
893             
894             for (; ptr; ptr = ptr->next)
895             {
896                 if (match_xsd_string(ptr, "version", o,
897                                      &(*p)->srw_version))
898                     ;
899                 else if (match_xsd_XML_n(ptr, "extraResponseData", o, 
900                                          &(*p)->extraResponseData_buf,
901                                          &(*p)->extraResponseData_len))
902                     ;
903                 else if (match_element(ptr, "terms"))
904                     yaz_srw_terms(o, ptr, &res->terms,
905                                   &res->num_terms, client_data,
906                                   ns);
907                 else if (match_element(ptr, "diagnostics"))
908                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
909                                         &res->num_diagnostics,
910                                         client_data, ns);
911             }
912         }
913         else
914         {
915             *p = 0;
916             return -1;
917         }
918         neg_version = yaz_negotiate_sru_version((*p)->srw_version);
919         if (neg_version)
920             (*p)->srw_version = neg_version;
921     }
922     else if (o->direction == ODR_ENCODE)
923     {
924         Z_SRW_PDU **p = handler_data;
925         xmlNsPtr ns_srw;
926         xmlNodePtr ptr = 0;
927         
928         if ((*p)->which == Z_SRW_searchRetrieve_request)
929         {
930             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
931             ptr = xmlNewChild(pptr, 0, BAD_CAST "searchRetrieveRequest", 0);
932             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
933             xmlSetNs(ptr, ns_srw);
934
935             if ((*p)->srw_version)
936                 add_xsd_string(ptr, "version", (*p)->srw_version);
937             switch(req->query_type)
938             {
939             case Z_SRW_query_type_cql:
940                 add_xsd_string(ptr, "query", req->query.cql);
941                 break;
942             case Z_SRW_query_type_xcql:
943                 add_xsd_string(ptr, "xQuery", req->query.xcql);
944                 break;
945             case Z_SRW_query_type_pqf:
946                 add_xsd_string(ptr, "pQuery", req->query.pqf);
947                 break;
948             }
949             add_xsd_integer(ptr, "startRecord", req->startRecord);
950             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
951             add_xsd_string(ptr, "recordPacking", req->recordPacking);
952             add_xsd_string(ptr, "recordSchema", req->recordSchema);
953             add_xsd_string(ptr, "recordXPath", req->recordXPath);
954             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
955             switch(req->sort_type)
956             {
957             case Z_SRW_sort_type_none:
958                 break;
959             case Z_SRW_sort_type_sort:
960                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
961                 break;
962             case Z_SRW_sort_type_xSort:
963                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
964                 break;
965             }
966             add_xsd_string(ptr, "stylesheet", req->stylesheet);
967             add_xsd_string(ptr, "database", req->database);
968         }
969         else if ((*p)->which == Z_SRW_searchRetrieve_response)
970         {
971             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
972             ptr = xmlNewChild(pptr, 0, BAD_CAST "searchRetrieveResponse", 0);
973             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
974             xmlSetNs(ptr, ns_srw);
975
976             if ((*p)->srw_version)
977                 add_xsd_string(ptr, "version", (*p)->srw_version);
978             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
979             add_xsd_string(ptr, "resultSetId", res->resultSetId);
980             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
981             if (res->num_records)
982             {
983                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "records", 0);
984                 yaz_srw_records(o, rptr, &res->records, &res->extra_records,
985                                 &res->num_records,
986                                 client_data, ns);
987             }
988             add_xsd_integer(ptr, "nextRecordPosition",
989                             res->nextRecordPosition);
990             if (res->num_diagnostics)
991             {
992                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
993                                               0);
994                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
995                                     &res->num_diagnostics, client_data, ns);
996             }
997         }
998         else if ((*p)->which == Z_SRW_explain_request)
999         {
1000             Z_SRW_explainRequest *req = (*p)->u.explain_request;
1001             ptr = xmlNewChild(pptr, 0, BAD_CAST "explainRequest", 0);
1002             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1003             xmlSetNs(ptr, ns_srw);
1004
1005             add_xsd_string(ptr, "version", (*p)->srw_version);
1006             add_xsd_string(ptr, "recordPacking", req->recordPacking);
1007             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1008             add_xsd_string(ptr, "database", req->database);
1009         }
1010         else if ((*p)->which == Z_SRW_explain_response)
1011         {
1012             Z_SRW_explainResponse *res = (*p)->u.explain_response;
1013             ptr = xmlNewChild(pptr, 0, BAD_CAST "explainResponse", 0);
1014             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1015             xmlSetNs(ptr, ns_srw);
1016
1017             add_xsd_string(ptr, "version", (*p)->srw_version);
1018             if (1)
1019             {
1020                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1021                 yaz_srw_record(o, ptr1, &res->record, &res->extra_record,
1022                                client_data, ns);
1023             }
1024             if (res->num_diagnostics)
1025             {
1026                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
1027                                               0);
1028                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1029                                     &res->num_diagnostics, client_data, ns);
1030             }
1031         }
1032         else if ((*p)->which == Z_SRW_scan_request)
1033         {
1034             Z_SRW_scanRequest *req = (*p)->u.scan_request;
1035             ptr = xmlNewChild(pptr, 0, BAD_CAST "scanRequest", 0);
1036             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1037             xmlSetNs(ptr, ns_srw);
1038
1039             add_xsd_string(ptr, "version", (*p)->srw_version);
1040             switch(req->query_type)
1041             {
1042             case Z_SRW_query_type_cql:
1043                 add_xsd_string(ptr, "scanClause", req->scanClause.cql);
1044                 break;
1045             case Z_SRW_query_type_pqf:
1046                 add_xsd_string(ptr, "pScanClause", req->scanClause.pqf);
1047                 break;
1048             }
1049             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
1050             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
1051             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1052             add_xsd_string(ptr, "database", req->database);
1053         }
1054         else if ((*p)->which == Z_SRW_scan_response)
1055         {
1056             Z_SRW_scanResponse *res = (*p)->u.scan_response;
1057             ptr = xmlNewChild(pptr, 0, BAD_CAST "scanResponse", 0);
1058             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1059             xmlSetNs(ptr, ns_srw);
1060
1061             add_xsd_string(ptr, "version", (*p)->srw_version);
1062
1063             if (res->num_terms)
1064             {
1065                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "terms", 0);
1066                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
1067                               client_data, ns);
1068             }
1069             if (res->num_diagnostics)
1070             {
1071                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
1072                                               0);
1073                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1074                                     &res->num_diagnostics, client_data, ns);
1075             }
1076         }
1077         else
1078             return -1;
1079         if (ptr && (*p)->extraResponseData_len)
1080             add_XML_n(ptr, "extraResponseData", 
1081                       (*p)->extraResponseData_buf, 
1082                       (*p)->extraResponseData_len, ns_srw);
1083             
1084
1085     }
1086     return 0;
1087 }
1088
1089 int yaz_ucp_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
1090                   void *client_data, const char *ns_ucp_str)
1091 {
1092     xmlNodePtr pptr = (xmlNodePtr) vptr;
1093     const char *ns_srw_str = YAZ_XMLNS_SRU_v1_1;
1094     if (o->direction == ODR_DECODE)
1095     {
1096         Z_SRW_PDU **p = handler_data;
1097         xmlNodePtr method = pptr->children;
1098
1099         while (method && method->type == XML_TEXT_NODE)
1100             method = method->next;
1101         
1102         if (!method)
1103             return -1;
1104         if (method->type != XML_ELEMENT_NODE)
1105             return -1;
1106
1107         *p = yaz_srw_get_core_v_1_1(o);
1108         
1109         if (!xmlStrcmp(method->name, BAD_CAST "updateRequest"))
1110         {
1111             xmlNodePtr ptr = method->children;
1112             Z_SRW_updateRequest *req;
1113             char *oper = 0;
1114
1115             (*p)->which = Z_SRW_update_request;
1116             req = (*p)->u.update_request = (Z_SRW_updateRequest *)
1117                 odr_malloc(o, sizeof(*req));
1118             req->database = 0;
1119             req->operation = 0;
1120             req->recordId = 0;
1121             req->recordVersions = 0;
1122             req->num_recordVersions = 0;
1123             req->record = 0;
1124             req->extra_record = 0;
1125             req->extraRequestData_buf = 0;
1126             req->extraRequestData_len = 0;
1127             req->stylesheet = 0;
1128
1129             for (; ptr; ptr = ptr->next)
1130             {
1131                 if (match_xsd_string(ptr, "version", o,
1132                                      &(*p)->srw_version))
1133                     ;
1134                 else if (match_xsd_string(ptr, "action", o, 
1135                                           &oper)){
1136                     if ( oper ){
1137                         if ( !strcmp(oper, "info:srw/action/1/delete"))
1138                             req->operation = "delete";
1139                         else if (!strcmp(oper,"info:srw/action/1/replace" ))
1140                             req->operation = "replace";
1141                         else if ( !strcmp( oper, "info:srw/action/1/create"))
1142                             req->operation = "insert";
1143                     }
1144                 }
1145                 else if (match_xsd_string(ptr, "recordIdentifier", o,
1146                                           &req->recordId))
1147                     ;
1148                 else if (match_element(ptr, "recordVersions" ) )
1149                     yaz_srw_versions( o, ptr, &req->recordVersions,
1150                                       &req->num_recordVersions, client_data,
1151                                       ns_ucp_str);
1152                 else if (match_element(ptr, "record"))
1153                 {
1154                     req->record = yaz_srw_get_record(o);
1155                     yaz_srw_record(o, ptr, req->record, &req->extra_record,
1156                                    client_data, ns_ucp_str);
1157                 }
1158                 else if (match_xsd_string(ptr, "stylesheet", o,
1159                                            &req->stylesheet))
1160                     ;
1161                 else if (match_xsd_string(ptr, "database", o,
1162                                            &req->database))
1163                     ;
1164             }
1165         }
1166         else if (!xmlStrcmp(method->name, BAD_CAST "updateResponse"))
1167         {
1168             xmlNodePtr ptr = method->children;
1169             Z_SRW_updateResponse *res;
1170
1171             (*p)->which = Z_SRW_update_response;
1172             res = (*p)->u.update_response = (Z_SRW_updateResponse *)
1173                 odr_malloc(o, sizeof(*res));
1174
1175             res->operationStatus = 0;
1176             res->recordId = 0;
1177             res->recordVersions = 0;
1178             res->num_recordVersions = 0;
1179             res->diagnostics = 0;
1180             res->num_diagnostics = 0;
1181             res->record = 0;
1182             res->extra_record = 0;
1183             res->extraResponseData_buf = 0;
1184             res->extraResponseData_len = 0;
1185
1186             for (; ptr; ptr = ptr->next)
1187             {
1188                 if (match_xsd_string(ptr, "version", o,
1189                                      &(*p)->srw_version))
1190                     ;
1191                 else if (match_xsd_string(ptr, "operationStatus", o, 
1192                                       &res->operationStatus ))
1193                     ;
1194                 else if (match_xsd_string(ptr, "recordIdentifier", o, 
1195                                           &res->recordId))
1196                     ;
1197                 else if (match_element(ptr, "recordVersions" )) 
1198                     yaz_srw_versions(o, ptr, &res->recordVersions,
1199                                      &res->num_recordVersions,
1200                                      client_data, ns_ucp_str);
1201                 else if (match_element(ptr, "record"))
1202                 {
1203                     res->record = yaz_srw_get_record(o);
1204                     yaz_srw_record(o, ptr, res->record, &res->extra_record,
1205                                    client_data, ns_ucp_str);
1206                 }
1207                 else if (match_element(ptr, "diagnostics"))
1208                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
1209                                         &res->num_diagnostics,
1210                                         client_data, ns_ucp_str);
1211             }
1212         }
1213         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateRequest"))
1214         {
1215         }
1216         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateResponse"))
1217         {
1218         }
1219         else
1220         {
1221             *p = 0;
1222             return -1;
1223         }
1224     }
1225     else if (o->direction == ODR_ENCODE)
1226     {
1227         Z_SRW_PDU **p = handler_data;
1228         xmlNsPtr ns_ucp, ns_srw;
1229
1230
1231         if ((*p)->which == Z_SRW_update_request)
1232         {
1233             Z_SRW_updateRequest *req = (*p)->u.update_request;
1234             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "updateRequest", 0);
1235             ns_ucp = xmlNewNs(ptr, BAD_CAST ns_ucp_str, BAD_CAST "zu");
1236             xmlSetNs(ptr, ns_ucp);
1237             ns_srw = xmlNewNs(ptr, BAD_CAST ns_srw_str, BAD_CAST "zs");
1238
1239             add_xsd_string_ns(ptr, "version", (*p)->srw_version, ns_srw);
1240             add_xsd_string(ptr, "action", req->operation);
1241             add_xsd_string(ptr, "recordIdentifier", req->recordId );
1242             if (req->recordVersions)
1243                 yaz_srw_versions( o, ptr, &req->recordVersions,
1244                                   &req->num_recordVersions,
1245                                   client_data, ns_ucp_str);
1246             if (req->record && req->record->recordData_len)
1247             {
1248                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1249                 xmlSetNs(rptr, ns_srw);
1250                 yaz_srw_record(o, rptr, req->record, &req->extra_record,
1251                                client_data, ns_ucp_str);
1252             }
1253             if (req->extraRequestData_len)
1254             {
1255                 add_XML_n(ptr, "extraRequestData", 
1256                           req->extraRequestData_buf, 
1257                           req->extraRequestData_len, ns_srw);
1258             }
1259             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1260             add_xsd_string(ptr, "database", req->database);
1261         }
1262         else if ((*p)->which == Z_SRW_update_response)
1263         {
1264             Z_SRW_updateResponse *res = (*p)->u.update_response;
1265             xmlNodePtr ptr = xmlNewChild(pptr, 0, (xmlChar *) 
1266                                          "updateResponse", 0);
1267             ns_ucp = xmlNewNs(ptr, BAD_CAST ns_ucp_str, BAD_CAST "zu");
1268             xmlSetNs(ptr, ns_ucp);
1269             ns_srw = xmlNewNs(ptr, BAD_CAST ns_srw_str, BAD_CAST "zs");
1270             
1271             add_xsd_string_ns(ptr, "version", (*p)->srw_version, ns_srw);
1272             add_xsd_string(ptr, "operationStatus", res->operationStatus );
1273             add_xsd_string(ptr, "recordIdentifier", res->recordId );
1274             if (res->recordVersions)
1275                 yaz_srw_versions(o, ptr, &res->recordVersions,
1276                                  &res->num_recordVersions,
1277                                  client_data, ns_ucp_str);
1278             if (res->record && res->record->recordData_len)
1279             {
1280                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1281                 xmlSetNs(rptr, ns_srw);
1282                 yaz_srw_record(o, rptr, res->record, &res->extra_record,
1283                                client_data, ns_ucp_str);
1284             }
1285             if (res->num_diagnostics)
1286             {
1287                 xmlNsPtr ns_diag =
1288                     xmlNewNs(pptr, BAD_CAST YAZ_XMLNS_DIAG_v1_1,
1289                              BAD_CAST "diag" );
1290                 
1291                 xmlNodePtr rptr = xmlNewChild(ptr, ns_diag, BAD_CAST "diagnostics", 0);
1292                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1293                                     &res->num_diagnostics, client_data,
1294                                     ns_ucp_str);
1295             }
1296             if (res->extraResponseData_len)
1297                 add_XML_n(ptr, "extraResponseData", 
1298                           res->extraResponseData_buf, 
1299                           res->extraResponseData_len, ns_srw);
1300         }
1301         else
1302             return -1;
1303
1304     }
1305     return 0;
1306 }
1307
1308 #endif
1309
1310
1311 /*
1312  * Local variables:
1313  * c-basic-offset: 4
1314  * c-file-style: "Stroustrup"
1315  * indent-tabs-mode: nil
1316  * End:
1317  * vim: shiftwidth=4 tabstop=8 expandtab
1318  */
1319