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