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