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