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