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