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