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