Deal with recordPacking, recordXMLEscaping
[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             char *recordPacking = 0;
759             char *recordXMLEscaping = 0;
760
761             (*p)->which = Z_SRW_searchRetrieve_request;
762             req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *)
763                 odr_malloc(o, sizeof(*req));
764             req->queryType = "cql";
765             req->query = 0;
766             req->sort_type = Z_SRW_sort_type_none;
767             req->sort.none = 0;
768             req->startRecord = 0;
769             req->maximumRecords = 0;
770             req->recordSchema = 0;
771             req->recordPacking = 0;
772             req->packing = 0;
773             req->recordXPath = 0;
774             req->resultSetTTL = 0;
775             req->stylesheet = 0;
776             req->database = 0;
777
778             for (; ptr; ptr = ptr->next)
779             {
780                 if (match_xsd_string(ptr, "version", o,
781                                      &(*p)->srw_version))
782                     ;
783                 else if (match_xsd_string(ptr, "queryType", o,
784                                           &req->queryType))
785                     ;
786                 else if (match_xsd_string(ptr, "query", o,
787                                           &req->query))
788                     ;
789                 else if (match_xsd_string(ptr, "pQuery", o,
790                                           &req->query))
791                     req->queryType = "pqf";
792                 else if (match_xsd_string(ptr, "xQuery", o,
793                                           &req->query))
794                     req->queryType = "xcql";
795                 else if (match_xsd_integer(ptr, "startRecord", o,
796                                            &req->startRecord))
797                     ;
798                 else if (match_xsd_integer(ptr, "maximumRecords", o,
799                                            &req->maximumRecords))
800                     ;
801                 else if (match_xsd_string(ptr, "recordPacking", o,
802                                           &recordPacking))
803                     ;
804                 else if (match_xsd_string(ptr, "recordXMLEscaping", o,
805                                           &recordXMLEscaping))
806                     ;
807                 else if (match_xsd_string(ptr, "recordSchema", o,
808                                           &req->recordSchema))
809                     ;
810                 else if (match_xsd_string(ptr, "recordXPath", o,
811                                           &req->recordXPath))
812                     ;
813                 else if (match_xsd_integer(ptr, "resultSetTTL", o,
814                                            &req->resultSetTTL))
815                     ;
816                 else if (match_xsd_string(ptr, "sortKeys", o,
817                                           &req->sort.sortKeys))
818                     req->sort_type = Z_SRW_sort_type_sort;
819                 else if (match_xsd_string(ptr, "stylesheet", o,
820                                           &req->stylesheet))
821                     ;
822                 else
823                     match_xsd_string(ptr, "database", o, &req->database);
824             }
825             if (!req->query)
826             {
827                 /* should put proper diagnostic here */
828                 return -1;
829             }
830             if (!strcmp((*p)->srw_version, "2.0"))
831             {
832                 req->recordPacking = recordXMLEscaping;
833                 req->packing = recordPacking;
834             }
835             else
836             {
837                 req->recordPacking = recordPacking;
838             }
839         }
840         else if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveResponse"))
841         {
842             xmlNodePtr ptr = method->children;
843             Z_SRW_searchRetrieveResponse *res;
844
845             (*p)->which = Z_SRW_searchRetrieve_response;
846             res = (*p)->u.response = (Z_SRW_searchRetrieveResponse *)
847                 odr_malloc(o, sizeof(*res));
848
849             res->numberOfRecords = 0;
850             res->resultSetId = 0;
851             res->resultSetIdleTime = 0;
852             res->records = 0;
853             res->num_records = 0;
854             res->diagnostics = 0;
855             res->num_diagnostics = 0;
856             res->nextRecordPosition = 0;
857             res->facetList = 0;
858             res->suggestions = 0;
859
860             for (; ptr; ptr = ptr->next)
861             {
862                 if (match_xsd_string(ptr, "version", o,
863                                      &(*p)->srw_version))
864                     ;
865                 else if (match_xsd_XML_n(ptr, "extraResponseData", o,
866                                          &(*p)->extraResponseData_buf,
867                                          &(*p)->extraResponseData_len))
868                     ;
869                 else if (match_xsd_integer(ptr, "numberOfRecords", o,
870                                            &res->numberOfRecords))
871                     ;
872                 else if (match_xsd_string(ptr, "resultSetId", o,
873                                           &res->resultSetId))
874                     ;
875                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o,
876                                            &res->resultSetIdleTime))
877                     ;
878                 else if (match_element(ptr, "records"))
879                     yaz_srw_records(o, ptr, &res->records,
880                                     &res->extra_records,
881                                     &res->num_records, client_data);
882                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
883                                            &res->nextRecordPosition))
884                     ;
885                 else if (match_element(ptr, "diagnostics"))
886                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
887                                         &res->num_diagnostics,
888                                         client_data, ns);
889                 else if (match_element(ptr, "facet_analysis"))
890                     yaz_sru_proxy_decode_facets(o, ptr, &res->facetList);
891             }
892         }
893         else if (!xmlStrcmp(method->name, BAD_CAST "explainRequest"))
894         {
895             Z_SRW_explainRequest *req;
896             xmlNodePtr ptr = method->children;
897
898             (*p)->which = Z_SRW_explain_request;
899             req = (*p)->u.explain_request = (Z_SRW_explainRequest *)
900                 odr_malloc(o, sizeof(*req));
901             req->recordPacking = 0;
902             req->packing = 0;
903             req->database = 0;
904             req->stylesheet = 0;
905             for (; ptr; ptr = ptr->next)
906             {
907                 if (match_xsd_string(ptr, "version", o,
908                                      &(*p)->srw_version))
909                     ;
910                 else if (match_xsd_XML_n(ptr, "extraResponseData", o,
911                                          &(*p)->extraResponseData_buf,
912                                          &(*p)->extraResponseData_len))
913                     ;
914                 else if (match_xsd_string(ptr, "stylesheet", o,
915                                           &req->stylesheet))
916                     ;
917                 else if (match_xsd_string(ptr, "recordPacking", o,
918                                           &req->recordPacking))
919                     ;
920                 else
921                     match_xsd_string(ptr, "database", o, &req->database);
922             }
923         }
924         else if (!xmlStrcmp(method->name, BAD_CAST "explainResponse"))
925         {
926             Z_SRW_explainResponse *res;
927             xmlNodePtr ptr = method->children;
928
929             (*p)->which = Z_SRW_explain_response;
930             res = (*p)->u.explain_response = (Z_SRW_explainResponse*)
931                 odr_malloc(o, sizeof(*res));
932             res->diagnostics = 0;
933             res->num_diagnostics = 0;
934             res->record.recordSchema = 0;
935             res->record.recordData_buf = 0;
936             res->record.recordData_len = 0;
937             res->record.recordPosition = 0;
938
939             for (; ptr; ptr = ptr->next)
940             {
941                 if (match_xsd_string(ptr, "version", o,
942                                      &(*p)->srw_version))
943                     ;
944                 else if (match_xsd_XML_n(ptr, "extraResponseData", o,
945                                          &(*p)->extraResponseData_buf,
946                                          &(*p)->extraResponseData_len))
947                     ;
948                 else if (match_element(ptr, "record"))
949                     yaz_srw_record(o, ptr, &res->record, &res->extra_record,
950                                    client_data);
951                 else if (match_element(ptr, "diagnostics"))
952                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
953                                         &res->num_diagnostics,
954                                         client_data, ns);
955                 ;
956             }
957         }
958         else if (!xmlStrcmp(method->name, BAD_CAST "scanRequest"))
959         {
960             Z_SRW_scanRequest *req;
961             xmlNodePtr ptr = method->children;
962
963             (*p)->which = Z_SRW_scan_request;
964             req = (*p)->u.scan_request = (Z_SRW_scanRequest *)
965                 odr_malloc(o, sizeof(*req));
966             req->queryType = "cql";
967             req->scanClause = 0;
968             req->responsePosition = 0;
969             req->maximumTerms = 0;
970             req->stylesheet = 0;
971             req->database = 0;
972
973             for (; ptr; ptr = ptr->next)
974             {
975                 if (match_xsd_string(ptr, "version", o,
976                                      &(*p)->srw_version))
977                     ;
978                 else if (match_xsd_XML_n(ptr, "extraResponseData", o,
979                                          &(*p)->extraResponseData_buf,
980                                          &(*p)->extraResponseData_len))
981                     ;
982                 else if (match_xsd_string(ptr, "scanClause", o,
983                                           &req->scanClause))
984                     ;
985                 else if (match_xsd_string(ptr, "pScanClause", o,
986                                           &req->scanClause))
987                 {
988                     req->queryType = "pqf";
989                 }
990                 else if (match_xsd_integer(ptr, "responsePosition", o,
991                                            &req->responsePosition))
992                     ;
993                 else if (match_xsd_integer(ptr, "maximumTerms", o,
994                                            &req->maximumTerms))
995                     ;
996                 else if (match_xsd_string(ptr, "stylesheet", o,
997                                           &req->stylesheet))
998                     ;
999                 else
1000                     match_xsd_string(ptr, "database", o, &req->database);
1001             }
1002         }
1003         else if (!xmlStrcmp(method->name, BAD_CAST "scanResponse"))
1004         {
1005             Z_SRW_scanResponse *res;
1006             xmlNodePtr ptr = method->children;
1007
1008             (*p)->which = Z_SRW_scan_response;
1009             res = (*p)->u.scan_response = (Z_SRW_scanResponse *)
1010                 odr_malloc(o, sizeof(*res));
1011             res->terms = 0;
1012             res->num_terms = 0;
1013             res->diagnostics = 0;
1014             res->num_diagnostics = 0;
1015
1016             for (; ptr; ptr = ptr->next)
1017             {
1018                 if (match_xsd_string(ptr, "version", o,
1019                                      &(*p)->srw_version))
1020                     ;
1021                 else if (match_xsd_XML_n(ptr, "extraResponseData", o,
1022                                          &(*p)->extraResponseData_buf,
1023                                          &(*p)->extraResponseData_len))
1024                     ;
1025                 else if (match_element(ptr, "terms"))
1026                     yaz_srw_terms(o, ptr, &res->terms,
1027                                   &res->num_terms, client_data,
1028                                   ns);
1029                 else if (match_element(ptr, "diagnostics"))
1030                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
1031                                         &res->num_diagnostics,
1032                                         client_data, ns);
1033             }
1034         }
1035         else
1036         {
1037             *p = 0;
1038             return -1;
1039         }
1040         neg_version = yaz_negotiate_sru_version((*p)->srw_version);
1041         if (neg_version)
1042             (*p)->srw_version = neg_version;
1043     }
1044     else if (o->direction == ODR_ENCODE)
1045     {
1046         Z_SRW_PDU **p = handler_data;
1047         xmlNsPtr ns_srw;
1048         xmlNodePtr ptr = 0;
1049         int version2 = !(*p)->srw_version ||
1050             strcmp((*p)->srw_version, "2.") > 0;
1051         if ((*p)->which == Z_SRW_searchRetrieve_request)
1052         {
1053             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
1054             const char *queryType = req->queryType;
1055             if (version2)
1056                 ns = "http://docs.oasis-open.org/ns/search-ws/sruRequest";
1057             ptr = xmlNewChild(pptr, 0, BAD_CAST "searchRetrieveRequest", 0);
1058             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1059             xmlSetNs(ptr, ns_srw);
1060
1061             if (!version2)
1062                 add_xsd_string(ptr, "version", (*p)->srw_version);
1063
1064             if (version2)
1065             {
1066                 if (queryType)
1067                     add_xsd_string(ptr, "queryType", queryType);
1068                 add_xsd_string(ptr, "query", req->query);
1069             }
1070             else
1071             {
1072                 if (!queryType || !strcmp(queryType, "cql"))
1073                     add_xsd_string(ptr, "query", req->query);
1074                 else if (!strcmp(queryType, "xcql"))
1075                     add_xsd_string(ptr, "xQuery", req->query);
1076                 else if (!strcmp(queryType, "pqf"))
1077                     add_xsd_string(ptr, "pQuery", req->query);
1078             }
1079             add_xsd_integer(ptr, "startRecord", req->startRecord);
1080             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
1081             if (version2)
1082             {
1083                 add_xsd_string(ptr, "recordXMLEscaping", req->recordPacking);
1084                 add_xsd_string(ptr, "recordPacking", req->packing);
1085             }
1086             else
1087                 add_xsd_string(ptr, "recordPacking", req->recordPacking);
1088             add_xsd_string(ptr, "recordSchema", req->recordSchema);
1089             add_xsd_string(ptr, "recordXPath", req->recordXPath);
1090             add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
1091             switch (req->sort_type)
1092             {
1093             case Z_SRW_sort_type_none:
1094                 break;
1095             case Z_SRW_sort_type_sort:
1096                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
1097                 break;
1098             case Z_SRW_sort_type_xSort:
1099                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
1100                 break;
1101             }
1102             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1103             add_xsd_string(ptr, "database", req->database);
1104         }
1105         else if ((*p)->which == Z_SRW_searchRetrieve_response)
1106         {
1107             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
1108             if (version2)
1109                 ns = "http://docs.oasis-open.org/ns/search-ws/sruResponse";
1110             ptr = xmlNewChild(pptr, 0, BAD_CAST "searchRetrieveResponse", 0);
1111             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1112             xmlSetNs(ptr, ns_srw);
1113
1114             if (!version2)
1115                 add_xsd_string(ptr, "version", (*p)->srw_version);
1116             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
1117             add_xsd_string(ptr, "resultSetId", res->resultSetId);
1118             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
1119             if (res->num_records)
1120             {
1121                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "records", 0);
1122                 yaz_srw_records(o, rptr, &res->records, &res->extra_records,
1123                                 &res->num_records,
1124                                 client_data);
1125             }
1126             add_xsd_integer(ptr, "nextRecordPosition",
1127                             res->nextRecordPosition);
1128             if (res->num_diagnostics)
1129             {
1130                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
1131                                               0);
1132                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1133                                     &res->num_diagnostics, client_data, ns);
1134             }
1135         }
1136         else if ((*p)->which == Z_SRW_explain_request)
1137         {
1138             Z_SRW_explainRequest *req = (*p)->u.explain_request;
1139             ptr = xmlNewChild(pptr, 0, BAD_CAST "explainRequest", 0);
1140             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1141             xmlSetNs(ptr, ns_srw);
1142
1143             if (!version2)
1144                 add_xsd_string(ptr, "version", (*p)->srw_version);
1145             if (version2)
1146             {
1147                 add_xsd_string(ptr, "recordXMLEscaping", req->recordPacking);
1148                 add_xsd_string(ptr, "recordPacking", req->packing);
1149             }
1150             else
1151                 add_xsd_string(ptr, "recordPacking", req->recordPacking);
1152             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1153             add_xsd_string(ptr, "database", req->database);
1154         }
1155         else if ((*p)->which == Z_SRW_explain_response)
1156         {
1157             Z_SRW_explainResponse *res = (*p)->u.explain_response;
1158             ptr = xmlNewChild(pptr, 0, BAD_CAST "explainResponse", 0);
1159             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1160             xmlSetNs(ptr, ns_srw);
1161
1162             add_xsd_string(ptr, "version", (*p)->srw_version);
1163             if (1)
1164             {
1165                 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1166                 yaz_srw_record(o, ptr1, &res->record, &res->extra_record,
1167                                client_data);
1168             }
1169             if (res->num_diagnostics)
1170             {
1171                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
1172                                               0);
1173                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1174                                     &res->num_diagnostics, client_data, ns);
1175             }
1176         }
1177         else if ((*p)->which == Z_SRW_scan_request)
1178         {
1179             Z_SRW_scanRequest *req = (*p)->u.scan_request;
1180             const char *queryType = req->queryType;
1181             if (version2)
1182                 ns = "http://docs.oasis-open.org/ns/search-ws/scan";
1183             ptr = xmlNewChild(pptr, 0, BAD_CAST "scanRequest", 0);
1184             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1185             xmlSetNs(ptr, ns_srw);
1186
1187             if (!version2)
1188                 add_xsd_string(ptr, "version", (*p)->srw_version);
1189
1190             if (strcmp((*p)->srw_version, "2.") > 0)
1191             {
1192                 if (queryType && strcmp(queryType, "cql"))
1193                     add_xsd_string(ptr, "queryType", queryType);
1194                 add_xsd_string(ptr, "scanClause", req->scanClause);
1195             }
1196             else
1197             {
1198                 if (!queryType || !strcmp(queryType, "cql"))
1199                     add_xsd_string(ptr, "scanClause", req->scanClause);
1200                 else if (!strcmp(queryType, "pqf"))
1201                     add_xsd_string(ptr, "pScanClause", req->scanClause);
1202             }
1203             add_xsd_integer(ptr, "responsePosition", req->responsePosition);
1204             add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
1205             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1206             add_xsd_string(ptr, "database", req->database);
1207         }
1208         else if ((*p)->which == Z_SRW_scan_response)
1209         {
1210             Z_SRW_scanResponse *res = (*p)->u.scan_response;
1211             if (version2)
1212                 ns = "http://docs.oasis-open.org/ns/search-ws/scan";
1213             ptr = xmlNewChild(pptr, 0, BAD_CAST "scanResponse", 0);
1214             ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
1215             xmlSetNs(ptr, ns_srw);
1216
1217             if (!version2)
1218                 add_xsd_string(ptr, "version", (*p)->srw_version);
1219
1220             if (res->num_terms)
1221             {
1222                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "terms", 0);
1223                 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
1224                               client_data, ns);
1225             }
1226             if (res->num_diagnostics)
1227             {
1228                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
1229                                               0);
1230                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1231                                     &res->num_diagnostics, client_data, ns);
1232             }
1233         }
1234         else
1235             return -1;
1236         if (ptr && (*p)->extraResponseData_len)
1237             add_XML_n(ptr, "extraResponseData",
1238                       (*p)->extraResponseData_buf,
1239                       (*p)->extraResponseData_len, ns_srw);
1240
1241
1242     }
1243     return 0;
1244 }
1245
1246 int yaz_ucp_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
1247                   void *client_data, const char *ns_ucp_str)
1248 {
1249     xmlNodePtr pptr = (xmlNodePtr) vptr;
1250     const char *ns_srw_str = YAZ_XMLNS_SRU_v1_1;
1251     if (o->direction == ODR_DECODE)
1252     {
1253         Z_SRW_PDU **p = handler_data;
1254         xmlNodePtr method = pptr->children;
1255
1256         while (method && method->type == XML_TEXT_NODE)
1257             method = method->next;
1258
1259         if (!method)
1260             return -1;
1261         if (method->type != XML_ELEMENT_NODE)
1262             return -1;
1263
1264         *p = yaz_srw_get_core_v_2_0(o);
1265
1266         if (!xmlStrcmp(method->name, BAD_CAST "updateRequest"))
1267         {
1268             xmlNodePtr ptr = method->children;
1269             Z_SRW_updateRequest *req;
1270             char *oper = 0;
1271
1272             (*p)->which = Z_SRW_update_request;
1273             req = (*p)->u.update_request = (Z_SRW_updateRequest *)
1274                 odr_malloc(o, sizeof(*req));
1275             req->database = 0;
1276             req->operation = 0;
1277             req->recordId = 0;
1278             req->recordVersions = 0;
1279             req->num_recordVersions = 0;
1280             req->record = 0;
1281             req->extra_record = 0;
1282             req->extraRequestData_buf = 0;
1283             req->extraRequestData_len = 0;
1284             req->stylesheet = 0;
1285
1286             for (; ptr; ptr = ptr->next)
1287             {
1288                 if (match_xsd_string(ptr, "version", o,
1289                                      &(*p)->srw_version))
1290                     ;
1291                 else if (match_xsd_string(ptr, "action", o,
1292                                           &oper)){
1293                     if (oper)
1294                     {
1295                         if (!strcmp(oper, "info:srw/action/1/delete"))
1296                             req->operation = "delete";
1297                         else if (!strcmp(oper,"info:srw/action/1/replace" ))
1298                             req->operation = "replace";
1299                         else if (!strcmp(oper, "info:srw/action/1/create"))
1300                             req->operation = "insert";
1301                     }
1302                 }
1303                 else if (match_xsd_string(ptr, "recordIdentifier", o,
1304                                           &req->recordId))
1305                     ;
1306                 else if (match_element(ptr, "recordVersions" ) )
1307                     yaz_srw_versions( o, ptr, &req->recordVersions,
1308                                       &req->num_recordVersions, client_data,
1309                                       ns_ucp_str);
1310                 else if (match_element(ptr, "record"))
1311                 {
1312                     req->record = yaz_srw_get_record(o);
1313                     yaz_srw_record(o, ptr, req->record, &req->extra_record,
1314                                    client_data);
1315                 }
1316                 else if (match_xsd_string(ptr, "stylesheet", o,
1317                                           &req->stylesheet))
1318                     ;
1319                 else
1320                     match_xsd_string(ptr, "database", o, &req->database);
1321             }
1322         }
1323         else if (!xmlStrcmp(method->name, BAD_CAST "updateResponse"))
1324         {
1325             xmlNodePtr ptr = method->children;
1326             Z_SRW_updateResponse *res;
1327
1328             (*p)->which = Z_SRW_update_response;
1329             res = (*p)->u.update_response = (Z_SRW_updateResponse *)
1330                 odr_malloc(o, sizeof(*res));
1331
1332             res->operationStatus = 0;
1333             res->recordId = 0;
1334             res->recordVersions = 0;
1335             res->num_recordVersions = 0;
1336             res->diagnostics = 0;
1337             res->num_diagnostics = 0;
1338             res->record = 0;
1339             res->extra_record = 0;
1340             res->extraResponseData_buf = 0;
1341             res->extraResponseData_len = 0;
1342
1343             for (; ptr; ptr = ptr->next)
1344             {
1345                 if (match_xsd_string(ptr, "version", o,
1346                                      &(*p)->srw_version))
1347                     ;
1348                 else if (match_xsd_string(ptr, "operationStatus", o,
1349                                           &res->operationStatus ))
1350                     ;
1351                 else if (match_xsd_string(ptr, "recordIdentifier", o,
1352                                           &res->recordId))
1353                     ;
1354                 else if (match_element(ptr, "recordVersions" ))
1355                     yaz_srw_versions(o, ptr, &res->recordVersions,
1356                                      &res->num_recordVersions,
1357                                      client_data, ns_ucp_str);
1358                 else if (match_element(ptr, "record"))
1359                 {
1360                     res->record = yaz_srw_get_record(o);
1361                     yaz_srw_record(o, ptr, res->record, &res->extra_record,
1362                                    client_data);
1363                 }
1364                 else if (match_element(ptr, "diagnostics"))
1365                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
1366                                         &res->num_diagnostics,
1367                                         client_data, ns_ucp_str);
1368             }
1369         }
1370         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateRequest"))
1371         {
1372         }
1373         else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateResponse"))
1374         {
1375         }
1376         else
1377         {
1378             *p = 0;
1379             return -1;
1380         }
1381     }
1382     else if (o->direction == ODR_ENCODE)
1383     {
1384         Z_SRW_PDU **p = handler_data;
1385         xmlNsPtr ns_ucp, ns_srw;
1386
1387         if ((*p)->which == Z_SRW_update_request)
1388         {
1389             Z_SRW_updateRequest *req = (*p)->u.update_request;
1390             xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "updateRequest", 0);
1391             ns_ucp = xmlNewNs(ptr, BAD_CAST ns_ucp_str, BAD_CAST "zu");
1392             xmlSetNs(ptr, ns_ucp);
1393             ns_srw = xmlNewNs(ptr, BAD_CAST ns_srw_str, BAD_CAST "zs");
1394
1395             add_xsd_string_ns(ptr, "version", (*p)->srw_version, ns_srw);
1396             add_xsd_string(ptr, "action", req->operation);
1397             add_xsd_string(ptr, "recordIdentifier", req->recordId );
1398             if (req->recordVersions)
1399                 yaz_srw_versions( o, ptr, &req->recordVersions,
1400                                   &req->num_recordVersions,
1401                                   client_data, ns_ucp_str);
1402             if (req->record && req->record->recordData_len)
1403             {
1404                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1405                 xmlSetNs(rptr, ns_srw);
1406                 yaz_srw_record(o, rptr, req->record, &req->extra_record,
1407                                client_data);
1408             }
1409             if (req->extraRequestData_len)
1410             {
1411                 add_XML_n(ptr, "extraRequestData",
1412                           req->extraRequestData_buf,
1413                           req->extraRequestData_len, ns_srw);
1414             }
1415             add_xsd_string(ptr, "stylesheet", req->stylesheet);
1416             add_xsd_string(ptr, "database", req->database);
1417         }
1418         else if ((*p)->which == Z_SRW_update_response)
1419         {
1420             Z_SRW_updateResponse *res = (*p)->u.update_response;
1421             xmlNodePtr ptr = xmlNewChild(pptr, 0, (xmlChar *)
1422                                          "updateResponse", 0);
1423             ns_ucp = xmlNewNs(ptr, BAD_CAST ns_ucp_str, BAD_CAST "zu");
1424             xmlSetNs(ptr, ns_ucp);
1425             ns_srw = xmlNewNs(ptr, BAD_CAST ns_srw_str, BAD_CAST "zs");
1426
1427             add_xsd_string_ns(ptr, "version", (*p)->srw_version, ns_srw);
1428             add_xsd_string(ptr, "operationStatus", res->operationStatus );
1429             add_xsd_string(ptr, "recordIdentifier", res->recordId );
1430             if (res->recordVersions)
1431                 yaz_srw_versions(o, ptr, &res->recordVersions,
1432                                  &res->num_recordVersions,
1433                                  client_data, ns_ucp_str);
1434             if (res->record && res->record->recordData_len)
1435             {
1436                 xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "record", 0);
1437                 xmlSetNs(rptr, ns_srw);
1438                 yaz_srw_record(o, rptr, res->record, &res->extra_record,
1439                                client_data);
1440             }
1441             if (res->num_diagnostics)
1442             {
1443                 xmlNsPtr ns_diag =
1444                     xmlNewNs(pptr, BAD_CAST YAZ_XMLNS_DIAG_v1_1,
1445                              BAD_CAST "diag" );
1446
1447                 xmlNodePtr rptr = xmlNewChild(ptr, ns_diag, BAD_CAST "diagnostics", 0);
1448                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
1449                                     &res->num_diagnostics, client_data,
1450                                     ns_ucp_str);
1451             }
1452             if (res->extraResponseData_len)
1453                 add_XML_n(ptr, "extraResponseData",
1454                           res->extraResponseData_buf,
1455                           res->extraResponseData_len, ns_srw);
1456         }
1457         else
1458             return -1;
1459     }
1460     return 0;
1461 }
1462
1463 #endif
1464
1465
1466 /*
1467  * Local variables:
1468  * c-basic-offset: 4
1469  * c-file-style: "Stroustrup"
1470  * indent-tabs-mode: nil
1471  * End:
1472  * vim: shiftwidth=4 tabstop=8 expandtab
1473  */
1474