2 * Copyright (c) 2002-2004, Index Data.
3 * See the file LICENSE for details.
5 * $Id: srw.c,v 1.26 2004-10-02 13:28:26 adam Exp $
11 #include <libxml/parser.h>
12 #include <libxml/tree.h>
14 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
18 xmlDocPtr doc = xmlParseMemory(val,len);
21 xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
22 xmlNodePtr t = xmlDocGetRootElement(doc);
23 xmlAddChild(c, xmlCopyNode(t,1));
29 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, const char *val,
34 xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
35 xmlNodePtr t = xmlNewTextLen(val, len);
42 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, const char *val)
45 return xmlNewTextChild(ptr, 0, elem, val);
49 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, const int *val)
54 sprintf(str, "%d", *val);
55 xmlNewTextChild(ptr, 0, elem, str);
59 static int match_element(xmlNodePtr ptr, const char *elem)
61 if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
68 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
72 struct _xmlAttr *attr;
74 if (!match_element(ptr, elem))
77 for (attr = ptr->properties; attr; attr = attr->next)
78 if (!strcmp(attr->name, "type") &&
79 attr->children && attr->children->type == XML_TEXT_NODE)
81 const char *t = strchr(attr->children->content, ':');
85 t = attr->children->content;
86 if (!strcmp(t, "string"))
93 if (!ptr || ptr->type != XML_TEXT_NODE)
95 *val = odr_strdup(o, ptr->content);
97 *len = strlen(ptr->content);
102 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
105 return match_xsd_string_n(ptr, elem, o, val, 0);
108 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
109 char **val, int *len)
113 if (!match_element(ptr, elem))
116 while (ptr && (ptr->type == XML_TEXT_NODE || ptr->type == XML_COMMENT_NODE))
120 buf = xmlBufferCreate();
122 xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
124 *val = odr_malloc(o, buf->use+1);
125 memcpy (*val, buf->content, buf->use);
126 (*val)[buf->use] = '\0';
136 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
139 struct _xmlAttr *attr;
141 if (!match_element(ptr, elem))
144 for (attr = ptr->properties; attr; attr = attr->next)
145 if (!strcmp(attr->name, "type") &&
146 attr->children && attr->children->type == XML_TEXT_NODE)
148 const char *t = strchr(attr->children->content, ':');
152 t = attr->children->content;
153 if (!strcmp(t, "integer"))
160 if (!ptr || ptr->type != XML_TEXT_NODE)
162 *val = odr_intdup(o, atoi(ptr->content));
166 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
167 void *client_data, const char *ns)
169 if (o->direction == ODR_DECODE)
171 int pack = Z_SRW_recordPacking_string;
173 rec->recordSchema = 0;
174 rec->recordData_buf = 0;
175 rec->recordData_len = 0;
176 rec->recordPosition = 0;
177 for (ptr = pptr->children; ptr; ptr = ptr->next)
181 if (match_xsd_string(ptr, "recordSchema", o,
184 else if (match_xsd_string(ptr, "recordPacking", o, &spack))
186 if (spack && !strcmp(spack, "xml"))
187 pack = Z_SRW_recordPacking_XML;
188 if (spack && !strcmp(spack, "string"))
189 pack = Z_SRW_recordPacking_string;
191 else if (match_xsd_integer(ptr, "recordPosition", o,
192 &rec->recordPosition))
196 if (pack == Z_SRW_recordPacking_XML)
197 match_xsd_XML_n(ptr, "recordData", o,
198 &rec->recordData_buf,
199 &rec->recordData_len);
200 if (pack == Z_SRW_recordPacking_string)
201 match_xsd_string_n(ptr, "recordData", o,
202 &rec->recordData_buf,
203 &rec->recordData_len);
206 rec->recordPacking = pack;
208 else if (o->direction == ODR_ENCODE)
210 xmlNodePtr ptr = pptr;
211 add_xsd_string(ptr, "recordSchema", rec->recordSchema);
212 switch(rec->recordPacking)
214 case Z_SRW_recordPacking_string:
215 add_xsd_string(ptr, "recordPacking", "string");
216 add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
217 rec->recordData_len);
219 case Z_SRW_recordPacking_XML:
220 add_xsd_string(ptr, "recordPacking", "xml");
221 add_XML_n(ptr, "recordData", rec->recordData_buf,
222 rec->recordData_len);
225 add_xsd_integer(ptr, "recordPosition", rec->recordPosition);
230 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
231 int *num, void *client_data, const char *ns)
233 if (o->direction == ODR_DECODE)
238 for (ptr = pptr->children; ptr; ptr = ptr->next)
240 if (ptr->type == XML_ELEMENT_NODE &&
241 !strcmp(ptr->name, "record"))
246 *recs = (Z_SRW_record *) odr_malloc(o, *num * sizeof(**recs));
247 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
249 if (ptr->type == XML_ELEMENT_NODE &&
250 !strcmp(ptr->name, "record"))
252 yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
257 else if (o->direction == ODR_ENCODE)
260 for (i = 0; i < *num; i++)
262 xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
263 yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
269 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
270 int *num, void *client_data, const char *ns)
272 if (o->direction == ODR_DECODE)
277 for (ptr = pptr->children; ptr; ptr = ptr->next)
279 if (ptr->type == XML_ELEMENT_NODE &&
280 !strcmp(ptr->name, "diagnostic"))
285 *recs = (Z_SRW_diagnostic *) odr_malloc(o, *num * sizeof(**recs));
286 for (i = 0; i < *num; i++)
289 (*recs)[i].details = 0;
290 (*recs)[i].message = 0;
292 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
294 if (ptr->type == XML_ELEMENT_NODE &&
295 !strcmp(ptr->name, "diagnostic"))
299 (*recs)[i].details = 0;
300 (*recs)[i].message = 0;
301 for (rptr = ptr->children; rptr; rptr = rptr->next)
303 if (match_xsd_string(rptr, "uri", o,
306 else if (match_xsd_string(rptr, "details", o,
307 &(*recs)[i].details))
309 else if (match_xsd_string(rptr, "message", o,
310 &(*recs)[i].message))
317 else if (o->direction == ODR_ENCODE)
321 xmlNewNs(pptr, "info:srw/schema/1/diagnostic-v1.1", 0);
322 for (i = 0; i < *num; i++)
324 const char *std_diag = "info:srw/diagnostic/1/";
325 xmlNodePtr rptr = xmlNewChild(pptr, ns_diag, "diagnostic", 0);
326 add_xsd_string(rptr, "uri", (*recs)[i].uri);
327 if ((*recs)[i].message)
328 add_xsd_string(rptr, "message", (*recs)[i].message);
329 else if ((*recs)[i].uri &&
330 !strncmp((*recs)[i].uri, std_diag, strlen(std_diag)))
332 int no = atoi((*recs)[i].uri + strlen(std_diag));
333 const char *message = yaz_diag_srw_str(no);
335 add_xsd_string(rptr, "message", message);
337 add_xsd_string(rptr, "details", (*recs)[i].details);
343 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
344 void *client_data, const char *ns)
346 if (o->direction == ODR_DECODE)
350 term->numberOfRecords = 0;
351 term->displayTerm = 0;
352 for (ptr = pptr->children; ptr; ptr = ptr->next)
354 if (match_xsd_string(ptr, "value", o, &term->value))
356 else if (match_xsd_integer(ptr, "numberOfRecords", o,
357 &term->numberOfRecords))
359 else if (match_xsd_string(ptr, "displayTerm", o,
364 else if (o->direction == ODR_ENCODE)
366 xmlNodePtr ptr = pptr;
367 add_xsd_string(ptr, "value", term->value);
368 add_xsd_integer(ptr, "value", term->numberOfRecords);
369 add_xsd_string(ptr, "displayTerm", term->displayTerm);
374 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
375 int *num, void *client_data, const char *ns)
377 if (o->direction == ODR_DECODE)
382 for (ptr = pptr->children; ptr; ptr = ptr->next)
384 if (ptr->type == XML_ELEMENT_NODE &&
385 !strcmp(ptr->name, "term"))
390 *terms = (Z_SRW_scanTerm *) odr_malloc(o, *num * sizeof(**terms));
391 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
393 if (ptr->type == XML_ELEMENT_NODE &&
394 !strcmp(ptr->name, "term"))
395 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
398 else if (o->direction == ODR_ENCODE)
401 for (i = 0; i < *num; i++)
403 xmlNodePtr rptr = xmlNewChild(pptr, 0, "term", 0);
404 yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
410 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
411 void *client_data, const char *ns)
413 xmlNodePtr pptr = (xmlNodePtr) vptr;
414 if (o->direction == ODR_DECODE)
416 Z_SRW_PDU **p = handler_data;
417 xmlNodePtr method = pptr->children;
419 while (method && method->type == XML_TEXT_NODE)
420 method = method->next;
424 if (method->type != XML_ELEMENT_NODE)
427 *p = (Z_SRW_PDU *) odr_malloc(o, sizeof(**p));
428 (*p)->srw_version = odr_strdup(o, "1.1");
430 if (!strcmp(method->name, "searchRetrieveRequest"))
432 xmlNodePtr ptr = method->children;
433 Z_SRW_searchRetrieveRequest *req;
435 (*p)->which = Z_SRW_searchRetrieve_request;
436 req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *)
437 odr_malloc(o, sizeof(*req));
438 req->query_type = Z_SRW_query_type_cql;
440 req->sort_type = Z_SRW_sort_type_none;
442 req->startRecord = 0;
443 req->maximumRecords = 0;
444 req->recordSchema = 0;
445 req->recordPacking = 0;
446 req->recordXPath = 0;
447 req->resultSetTTL = 0;
451 for (; ptr; ptr = ptr->next)
453 if (match_xsd_string(ptr, "version", o,
456 else if (match_xsd_string(ptr, "query", o,
458 req->query_type = Z_SRW_query_type_cql;
459 else if (match_xsd_string(ptr, "pQuery", o,
461 req->query_type = Z_SRW_query_type_pqf;
462 else if (match_xsd_string(ptr, "xQuery", o,
464 req->query_type = Z_SRW_query_type_xcql;
465 else if (match_xsd_integer(ptr, "startRecord", o,
468 else if (match_xsd_integer(ptr, "maximumRecords", o,
469 &req->maximumRecords))
471 else if (match_xsd_string(ptr, "recordPacking", o,
472 &req->recordPacking))
474 else if (match_xsd_string(ptr, "recordSchema", o,
477 else if (match_xsd_string(ptr, "recordXPath", o,
480 else if (match_xsd_string(ptr, "resultSetTTL", o,
483 else if (match_xsd_string(ptr, "sortKeys", o,
484 &req->sort.sortKeys))
485 req->sort_type = Z_SRW_sort_type_sort;
486 else if (match_xsd_string(ptr, "stylesheet", o,
489 else if (match_xsd_string(ptr, "database", o,
492 /* missing is xQuery, xSortKeys .. */
495 else if (!strcmp(method->name, "searchRetrieveResponse"))
497 xmlNodePtr ptr = method->children;
498 Z_SRW_searchRetrieveResponse *res;
500 (*p)->which = Z_SRW_searchRetrieve_response;
501 res = (*p)->u.response = (Z_SRW_searchRetrieveResponse *)
502 odr_malloc(o, sizeof(*res));
504 res->numberOfRecords = 0;
505 res->resultSetId = 0;
506 res->resultSetIdleTime = 0;
508 res->num_records = 0;
509 res->diagnostics = 0;
510 res->num_diagnostics = 0;
511 res->nextRecordPosition = 0;
513 for (; ptr; ptr = ptr->next)
515 if (match_xsd_string(ptr, "version", o,
518 else if (match_xsd_integer(ptr, "numberOfRecords", o,
519 &res->numberOfRecords))
521 else if (match_xsd_string(ptr, "resultSetId", o,
524 else if (match_xsd_integer(ptr, "resultSetIdleTime", o,
525 &res->resultSetIdleTime))
527 else if (match_element(ptr, "records"))
528 yaz_srw_records(o, ptr, &res->records,
529 &res->num_records, client_data,
531 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
532 &res->nextRecordPosition))
534 else if (match_element(ptr, "diagnostics"))
535 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
536 &res->num_diagnostics,
540 else if (!strcmp(method->name, "explainRequest"))
542 Z_SRW_explainRequest *req;
543 xmlNodePtr ptr = method->children;
545 (*p)->which = Z_SRW_explain_request;
546 req = (*p)->u.explain_request = (Z_SRW_explainRequest *)
547 odr_malloc(o, sizeof(*req));
548 req->recordPacking = 0;
551 for (; ptr; ptr = ptr->next)
553 if (match_xsd_string(ptr, "version", o,
556 else if (match_xsd_string(ptr, "stylesheet", o,
559 else if (match_xsd_string(ptr, "recordPacking", o,
560 &req->recordPacking))
562 else if (match_xsd_string(ptr, "database", o,
567 else if (!strcmp(method->name, "explainResponse"))
569 Z_SRW_explainResponse *res;
570 xmlNodePtr ptr = method->children;
572 (*p)->which = Z_SRW_explain_response;
573 res = (*p)->u.explain_response = (Z_SRW_explainResponse*)
574 odr_malloc(o, sizeof(*res));
575 res->diagnostics = 0;
576 res->num_diagnostics = 0;
578 for (; ptr; ptr = ptr->next)
580 if (match_xsd_string(ptr, "version", o,
583 else if (match_element(ptr, "record"))
584 yaz_srw_record(o, ptr, &res->record, client_data, ns);
585 else if (match_element(ptr, "diagnostics"))
586 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
587 &res->num_diagnostics,
592 else if (!strcmp(method->name, "scanRequest"))
594 Z_SRW_scanRequest *req;
595 xmlNodePtr ptr = method->children;
597 (*p)->which = Z_SRW_scan_request;
598 req = (*p)->u.scan_request = (Z_SRW_scanRequest *)
599 odr_malloc(o, sizeof(*req));
603 req->responsePosition = 0;
604 req->maximumTerms = 0;
606 for (; ptr; ptr = ptr->next)
608 if (match_xsd_string(ptr, "version", o,
611 else if (match_xsd_string(ptr, "scanClause", o,
614 else if (match_xsd_integer(ptr, "responsePosition", o,
615 &req->responsePosition))
617 else if (match_xsd_integer(ptr, "maximumTerms", o,
620 else if (match_xsd_string(ptr, "stylesheet", o,
623 else if (match_xsd_string(ptr, "database", o,
628 else if (!strcmp(method->name, "scanResponse"))
630 Z_SRW_scanResponse *res;
631 xmlNodePtr ptr = method->children;
633 (*p)->which = Z_SRW_scan_response;
634 res = (*p)->u.scan_response = (Z_SRW_scanResponse *)
635 odr_malloc(o, sizeof(*res));
638 res->diagnostics = 0;
639 res->num_diagnostics = 0;
641 for (; ptr; ptr = ptr->next)
643 if (match_xsd_string(ptr, "version", o,
646 else if (match_element(ptr, "terms"))
647 yaz_srw_terms(o, ptr, &res->terms,
648 &res->num_terms, client_data,
650 else if (match_element(ptr, "diagnostics"))
651 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
652 &res->num_diagnostics,
662 else if (o->direction == ODR_ENCODE)
664 Z_SRW_PDU **p = handler_data;
667 if ((*p)->which == Z_SRW_searchRetrieve_request)
669 Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
670 xmlNodePtr ptr = xmlNewChild(pptr, 0,
671 "searchRetrieveRequest", 0);
672 ns_srw = xmlNewNs(ptr, ns, "zs");
673 xmlSetNs(ptr, ns_srw);
675 if ((*p)->srw_version)
676 add_xsd_string(ptr, "version", (*p)->srw_version);
677 switch(req->query_type)
679 case Z_SRW_query_type_cql:
680 add_xsd_string(ptr, "query", req->query.cql);
682 case Z_SRW_query_type_xcql:
683 add_xsd_string(ptr, "xQuery", req->query.xcql);
685 case Z_SRW_query_type_pqf:
686 add_xsd_string(ptr, "pQuery", req->query.pqf);
689 add_xsd_integer(ptr, "startRecord", req->startRecord);
690 add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
691 add_xsd_string(ptr, "recordPacking", req->recordPacking);
692 add_xsd_string(ptr, "recordSchema", req->recordSchema);
693 add_xsd_string(ptr, "recordXPath", req->recordXPath);
694 add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
695 switch(req->sort_type)
697 case Z_SRW_sort_type_none:
699 case Z_SRW_sort_type_sort:
700 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
702 case Z_SRW_sort_type_xSort:
703 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
706 add_xsd_string(ptr, "stylesheet", req->stylesheet);
707 add_xsd_string(ptr, "database", req->database);
709 else if ((*p)->which == Z_SRW_searchRetrieve_response)
711 Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
712 xmlNodePtr ptr = xmlNewChild(pptr, 0,
713 "searchRetrieveResponse", 0);
714 ns_srw = xmlNewNs(ptr, ns, "zs");
715 xmlSetNs(ptr, ns_srw);
717 if ((*p)->srw_version)
718 add_xsd_string(ptr, "version", (*p)->srw_version);
719 add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
720 add_xsd_string(ptr, "resultSetId", res->resultSetId);
721 add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
722 if (res->num_records)
724 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
725 yaz_srw_records(o, rptr, &res->records, &res->num_records,
728 add_xsd_integer(ptr, "nextRecordPosition",
729 res->nextRecordPosition);
730 if (res->num_diagnostics)
732 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
733 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
734 &res->num_diagnostics, client_data, ns);
737 else if ((*p)->which == Z_SRW_explain_request)
739 Z_SRW_explainRequest *req = (*p)->u.explain_request;
740 xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
741 ns_srw = xmlNewNs(ptr, ns, "zs");
742 xmlSetNs(ptr, ns_srw);
744 add_xsd_string(ptr, "version", (*p)->srw_version);
745 add_xsd_string(ptr, "recordPacking", req->recordPacking);
746 add_xsd_string(ptr, "stylesheet", req->stylesheet);
747 add_xsd_string(ptr, "database", req->database);
749 else if ((*p)->which == Z_SRW_explain_response)
751 Z_SRW_explainResponse *res = (*p)->u.explain_response;
752 xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
753 ns_srw = xmlNewNs(ptr, ns, "zs");
754 xmlSetNs(ptr, ns_srw);
756 add_xsd_string(ptr, "version", (*p)->srw_version);
759 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, "record", 0);
760 yaz_srw_record(o, ptr1, &res->record, client_data, ns);
762 if (res->num_diagnostics)
764 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
765 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
766 &res->num_diagnostics, client_data, ns);
769 else if ((*p)->which == Z_SRW_scan_request)
771 Z_SRW_scanRequest *req = (*p)->u.scan_request;
772 xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanRequest", 0);
773 ns_srw = xmlNewNs(ptr, ns, "zs");
774 xmlSetNs(ptr, ns_srw);
776 add_xsd_string(ptr, "version", (*p)->srw_version);
777 add_xsd_string(ptr, "scanClause", req->scanClause);
778 add_xsd_integer(ptr, "responsePosition", req->responsePosition);
779 add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
780 add_xsd_string(ptr, "stylesheet", req->stylesheet);
781 add_xsd_string(ptr, "database", req->database);
783 else if ((*p)->which == Z_SRW_scan_response)
785 Z_SRW_scanResponse *res = (*p)->u.scan_response;
786 xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanResponse", 0);
787 ns_srw = xmlNewNs(ptr, ns, "zs");
788 xmlSetNs(ptr, ns_srw);
790 add_xsd_string(ptr, "version", (*p)->srw_version);
794 xmlNodePtr rptr = xmlNewChild(ptr, 0, "terms", 0);
795 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
798 if (res->num_diagnostics)
800 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
801 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
802 &res->num_diagnostics, client_data, ns);