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