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