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