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