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