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