2 * Copyright (c) 2002-2005, Index Data.
3 * See the file LICENSE for details.
5 * $Id: srw.c,v 1.31 2005-01-11 10:48:47 adam Exp $
9 * \brief Implements SRW/SRU package encoding and decoding
15 #include <libxml/parser.h>
16 #include <libxml/tree.h>
18 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
22 xmlDocPtr doc = xmlParseMemory(val,len);
25 xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
26 xmlNodePtr t = xmlDocGetRootElement(doc);
27 xmlAddChild(c, xmlCopyNode(t,1));
33 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, const char *val,
38 xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
39 xmlNodePtr t = xmlNewTextLen(val, len);
46 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, const char *val)
49 return xmlNewTextChild(ptr, 0, elem, val);
53 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, const int *val)
58 sprintf(str, "%d", *val);
59 xmlNewTextChild(ptr, 0, elem, str);
63 static int match_element(xmlNodePtr ptr, const char *elem)
65 if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
72 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
76 struct _xmlAttr *attr;
78 if (!match_element(ptr, elem))
81 for (attr = ptr->properties; attr; attr = attr->next)
82 if (!strcmp(attr->name, "type") &&
83 attr->children && attr->children->type == XML_TEXT_NODE)
85 const char *t = strchr(attr->children->content, ':');
89 t = attr->children->content;
90 if (!strcmp(t, "string"))
97 if (!ptr || ptr->type != XML_TEXT_NODE)
99 *val = odr_strdup(o, ptr->content);
101 *len = strlen(ptr->content);
106 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
109 return match_xsd_string_n(ptr, elem, o, val, 0);
112 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
113 char **val, int *len)
117 if (!match_element(ptr, elem))
120 while (ptr && (ptr->type == XML_TEXT_NODE || ptr->type == XML_COMMENT_NODE))
124 buf = xmlBufferCreate();
126 xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
128 *val = odr_malloc(o, buf->use+1);
129 memcpy (*val, buf->content, buf->use);
130 (*val)[buf->use] = '\0';
140 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
143 struct _xmlAttr *attr;
145 if (!match_element(ptr, elem))
148 for (attr = ptr->properties; attr; attr = attr->next)
149 if (!strcmp(attr->name, "type") &&
150 attr->children && attr->children->type == XML_TEXT_NODE)
152 const char *t = strchr(attr->children->content, ':');
156 t = attr->children->content;
157 if (!strcmp(t, "integer"))
164 if (!ptr || ptr->type != XML_TEXT_NODE)
166 *val = odr_intdup(o, atoi(ptr->content));
170 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
171 void *client_data, const char *ns)
173 if (o->direction == ODR_DECODE)
175 int pack = Z_SRW_recordPacking_string;
177 rec->recordSchema = 0;
178 rec->recordData_buf = 0;
179 rec->recordData_len = 0;
180 rec->recordPosition = 0;
181 for (ptr = pptr->children; ptr; ptr = ptr->next)
185 if (match_xsd_string(ptr, "recordSchema", o,
188 else if (match_xsd_string(ptr, "recordPacking", o, &spack))
190 if (spack && !strcmp(spack, "xml"))
191 pack = Z_SRW_recordPacking_XML;
192 if (spack && !strcmp(spack, "string"))
193 pack = Z_SRW_recordPacking_string;
195 else if (match_xsd_integer(ptr, "recordPosition", o,
196 &rec->recordPosition))
200 if (pack == Z_SRW_recordPacking_XML)
201 match_xsd_XML_n(ptr, "recordData", o,
202 &rec->recordData_buf,
203 &rec->recordData_len);
204 if (pack == Z_SRW_recordPacking_string)
205 match_xsd_string_n(ptr, "recordData", o,
206 &rec->recordData_buf,
207 &rec->recordData_len);
210 rec->recordPacking = pack;
212 else if (o->direction == ODR_ENCODE)
214 xmlNodePtr ptr = pptr;
215 add_xsd_string(ptr, "recordSchema", rec->recordSchema);
216 switch(rec->recordPacking)
218 case Z_SRW_recordPacking_string:
219 add_xsd_string(ptr, "recordPacking", "string");
220 add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
221 rec->recordData_len);
223 case Z_SRW_recordPacking_XML:
224 add_xsd_string(ptr, "recordPacking", "xml");
225 add_XML_n(ptr, "recordData", rec->recordData_buf,
226 rec->recordData_len);
229 add_xsd_integer(ptr, "recordPosition", rec->recordPosition);
234 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
235 int *num, void *client_data, const char *ns)
237 if (o->direction == ODR_DECODE)
242 for (ptr = pptr->children; ptr; ptr = ptr->next)
244 if (ptr->type == XML_ELEMENT_NODE &&
245 !strcmp(ptr->name, "record"))
250 *recs = (Z_SRW_record *) odr_malloc(o, *num * sizeof(**recs));
251 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
253 if (ptr->type == XML_ELEMENT_NODE &&
254 !strcmp(ptr->name, "record"))
256 yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
261 else if (o->direction == ODR_ENCODE)
264 for (i = 0; i < *num; i++)
266 xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
267 yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
273 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
274 int *num, void *client_data, const char *ns)
276 if (o->direction == ODR_DECODE)
281 for (ptr = pptr->children; ptr; ptr = ptr->next)
283 if (ptr->type == XML_ELEMENT_NODE &&
284 !strcmp(ptr->name, "diagnostic"))
289 *recs = (Z_SRW_diagnostic *) odr_malloc(o, *num * sizeof(**recs));
290 for (i = 0; i < *num; i++)
293 (*recs)[i].details = 0;
294 (*recs)[i].message = 0;
296 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next)
298 if (ptr->type == XML_ELEMENT_NODE &&
299 !strcmp(ptr->name, "diagnostic"))
303 (*recs)[i].details = 0;
304 (*recs)[i].message = 0;
305 for (rptr = ptr->children; rptr; rptr = rptr->next)
307 if (match_xsd_string(rptr, "uri", o,
310 else if (match_xsd_string(rptr, "details", o,
311 &(*recs)[i].details))
313 else if (match_xsd_string(rptr, "message", o,
314 &(*recs)[i].message))
321 else if (o->direction == ODR_ENCODE)
325 xmlNewNs(pptr, "info:srw/schema/1/diagnostic-v1.1", 0);
326 for (i = 0; i < *num; i++)
328 const char *std_diag = "info:srw/diagnostic/1/";
329 xmlNodePtr rptr = xmlNewChild(pptr, ns_diag, "diagnostic", 0);
330 add_xsd_string(rptr, "uri", (*recs)[i].uri);
331 if ((*recs)[i].message)
332 add_xsd_string(rptr, "message", (*recs)[i].message);
333 else if ((*recs)[i].uri &&
334 !strncmp((*recs)[i].uri, std_diag, strlen(std_diag)))
336 int no = atoi((*recs)[i].uri + strlen(std_diag));
337 const char *message = yaz_diag_srw_str(no);
339 add_xsd_string(rptr, "message", message);
341 add_xsd_string(rptr, "details", (*recs)[i].details);
347 static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term,
348 void *client_data, const char *ns)
350 if (o->direction == ODR_DECODE)
354 term->numberOfRecords = 0;
355 term->displayTerm = 0;
356 term->whereInList = 0;
357 for (ptr = pptr->children; ptr; ptr = ptr->next)
359 if (match_xsd_string(ptr, "value", o, &term->value))
361 else if (match_xsd_integer(ptr, "numberOfRecords", o,
362 &term->numberOfRecords))
364 else if (match_xsd_string(ptr, "displayTerm", o,
367 else if (match_xsd_string(ptr, "whereInList", o,
372 else if (o->direction == ODR_ENCODE)
374 xmlNodePtr ptr = pptr;
375 add_xsd_string(ptr, "value", term->value);
376 add_xsd_integer(ptr, "numberOfRecords", term->numberOfRecords);
377 add_xsd_string(ptr, "displayTerm", term->displayTerm);
378 add_xsd_string(ptr, "whereInList", term->whereInList);
383 static int yaz_srw_terms(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm **terms,
384 int *num, void *client_data, const char *ns)
386 if (o->direction == ODR_DECODE)
391 for (ptr = pptr->children; ptr; ptr = ptr->next)
393 if (ptr->type == XML_ELEMENT_NODE &&
394 !strcmp(ptr->name, "term"))
399 *terms = (Z_SRW_scanTerm *) odr_malloc(o, *num * sizeof(**terms));
400 for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
402 if (ptr->type == XML_ELEMENT_NODE &&
403 !strcmp(ptr->name, "term"))
404 yaz_srw_term(o, ptr, (*terms)+i, client_data, ns);
407 else if (o->direction == ODR_ENCODE)
410 for (i = 0; i < *num; i++)
412 xmlNodePtr rptr = xmlNewChild(pptr, 0, "term", 0);
413 yaz_srw_term(o, rptr, (*terms)+i, client_data, ns);
419 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
420 void *client_data, const char *ns)
422 xmlNodePtr pptr = (xmlNodePtr) vptr;
423 if (o->direction == ODR_DECODE)
425 Z_SRW_PDU **p = handler_data;
426 xmlNodePtr method = pptr->children;
428 while (method && method->type == XML_TEXT_NODE)
429 method = method->next;
433 if (method->type != XML_ELEMENT_NODE)
436 *p = (Z_SRW_PDU *) odr_malloc(o, sizeof(**p));
437 (*p)->srw_version = odr_strdup(o, "1.1");
439 if (!strcmp(method->name, "searchRetrieveRequest"))
441 xmlNodePtr ptr = method->children;
442 Z_SRW_searchRetrieveRequest *req;
444 (*p)->which = Z_SRW_searchRetrieve_request;
445 req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *)
446 odr_malloc(o, sizeof(*req));
447 req->query_type = Z_SRW_query_type_cql;
449 req->sort_type = Z_SRW_sort_type_none;
451 req->startRecord = 0;
452 req->maximumRecords = 0;
453 req->recordSchema = 0;
454 req->recordPacking = 0;
455 req->recordXPath = 0;
456 req->resultSetTTL = 0;
460 for (; ptr; ptr = ptr->next)
462 if (match_xsd_string(ptr, "version", o,
465 else if (match_xsd_string(ptr, "query", o,
467 req->query_type = Z_SRW_query_type_cql;
468 else if (match_xsd_string(ptr, "pQuery", o,
470 req->query_type = Z_SRW_query_type_pqf;
471 else if (match_xsd_string(ptr, "xQuery", o,
473 req->query_type = Z_SRW_query_type_xcql;
474 else if (match_xsd_integer(ptr, "startRecord", o,
477 else if (match_xsd_integer(ptr, "maximumRecords", o,
478 &req->maximumRecords))
480 else if (match_xsd_string(ptr, "recordPacking", o,
481 &req->recordPacking))
483 else if (match_xsd_string(ptr, "recordSchema", o,
486 else if (match_xsd_string(ptr, "recordXPath", o,
489 else if (match_xsd_string(ptr, "resultSetTTL", o,
492 else if (match_xsd_string(ptr, "sortKeys", o,
493 &req->sort.sortKeys))
494 req->sort_type = Z_SRW_sort_type_sort;
495 else if (match_xsd_string(ptr, "stylesheet", o,
498 else if (match_xsd_string(ptr, "database", o,
501 /* missing is xQuery, xSortKeys .. */
504 else if (!strcmp(method->name, "searchRetrieveResponse"))
506 xmlNodePtr ptr = method->children;
507 Z_SRW_searchRetrieveResponse *res;
509 (*p)->which = Z_SRW_searchRetrieve_response;
510 res = (*p)->u.response = (Z_SRW_searchRetrieveResponse *)
511 odr_malloc(o, sizeof(*res));
513 res->numberOfRecords = 0;
514 res->resultSetId = 0;
515 res->resultSetIdleTime = 0;
517 res->num_records = 0;
518 res->diagnostics = 0;
519 res->num_diagnostics = 0;
520 res->nextRecordPosition = 0;
522 for (; ptr; ptr = ptr->next)
524 if (match_xsd_string(ptr, "version", o,
527 else if (match_xsd_integer(ptr, "numberOfRecords", o,
528 &res->numberOfRecords))
530 else if (match_xsd_string(ptr, "resultSetId", o,
533 else if (match_xsd_integer(ptr, "resultSetIdleTime", o,
534 &res->resultSetIdleTime))
536 else if (match_element(ptr, "records"))
537 yaz_srw_records(o, ptr, &res->records,
538 &res->num_records, client_data,
540 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
541 &res->nextRecordPosition))
543 else if (match_element(ptr, "diagnostics"))
544 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
545 &res->num_diagnostics,
549 else if (!strcmp(method->name, "explainRequest"))
551 Z_SRW_explainRequest *req;
552 xmlNodePtr ptr = method->children;
554 (*p)->which = Z_SRW_explain_request;
555 req = (*p)->u.explain_request = (Z_SRW_explainRequest *)
556 odr_malloc(o, sizeof(*req));
557 req->recordPacking = 0;
560 for (; ptr; ptr = ptr->next)
562 if (match_xsd_string(ptr, "version", o,
565 else if (match_xsd_string(ptr, "stylesheet", o,
568 else if (match_xsd_string(ptr, "recordPacking", o,
569 &req->recordPacking))
571 else if (match_xsd_string(ptr, "database", o,
576 else if (!strcmp(method->name, "explainResponse"))
578 Z_SRW_explainResponse *res;
579 xmlNodePtr ptr = method->children;
581 (*p)->which = Z_SRW_explain_response;
582 res = (*p)->u.explain_response = (Z_SRW_explainResponse*)
583 odr_malloc(o, sizeof(*res));
584 res->diagnostics = 0;
585 res->num_diagnostics = 0;
586 res->record.recordSchema = 0;
587 res->record.recordData_buf = 0;
588 res->record.recordData_len = 0;
589 res->record.recordPosition = 0;
591 for (; ptr; ptr = ptr->next)
593 if (match_xsd_string(ptr, "version", o,
596 else if (match_element(ptr, "record"))
597 yaz_srw_record(o, ptr, &res->record, client_data, ns);
598 else if (match_element(ptr, "diagnostics"))
599 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
600 &res->num_diagnostics,
605 else if (!strcmp(method->name, "scanRequest"))
607 Z_SRW_scanRequest *req;
608 xmlNodePtr ptr = method->children;
610 (*p)->which = Z_SRW_scan_request;
611 req = (*p)->u.scan_request = (Z_SRW_scanRequest *)
612 odr_malloc(o, sizeof(*req));
613 req->query_type = Z_SRW_query_type_cql;
614 req->scanClause.cql = 0;
615 req->responsePosition = 0;
616 req->maximumTerms = 0;
620 for (; ptr; ptr = ptr->next)
622 if (match_xsd_string(ptr, "version", o,
625 else if (match_xsd_string(ptr, "scanClause", o,
626 &req->scanClause.cql))
628 else if (match_xsd_string(ptr, "pScanClause", o,
629 &req->scanClause.cql))
631 req->query_type = Z_SRW_query_type_pqf;
633 else if (match_xsd_integer(ptr, "responsePosition", o,
634 &req->responsePosition))
636 else if (match_xsd_integer(ptr, "maximumTerms", o,
639 else if (match_xsd_string(ptr, "stylesheet", o,
642 else if (match_xsd_string(ptr, "database", o,
647 else if (!strcmp(method->name, "scanResponse"))
649 Z_SRW_scanResponse *res;
650 xmlNodePtr ptr = method->children;
652 (*p)->which = Z_SRW_scan_response;
653 res = (*p)->u.scan_response = (Z_SRW_scanResponse *)
654 odr_malloc(o, sizeof(*res));
657 res->diagnostics = 0;
658 res->num_diagnostics = 0;
660 for (; ptr; ptr = ptr->next)
662 if (match_xsd_string(ptr, "version", o,
665 else if (match_element(ptr, "terms"))
666 yaz_srw_terms(o, ptr, &res->terms,
667 &res->num_terms, client_data,
669 else if (match_element(ptr, "diagnostics"))
670 yaz_srw_diagnostics(o, ptr, &res->diagnostics,
671 &res->num_diagnostics,
681 else if (o->direction == ODR_ENCODE)
683 Z_SRW_PDU **p = handler_data;
686 if ((*p)->which == Z_SRW_searchRetrieve_request)
688 Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
689 xmlNodePtr ptr = xmlNewChild(pptr, 0,
690 "searchRetrieveRequest", 0);
691 ns_srw = xmlNewNs(ptr, ns, "zs");
692 xmlSetNs(ptr, ns_srw);
694 if ((*p)->srw_version)
695 add_xsd_string(ptr, "version", (*p)->srw_version);
696 switch(req->query_type)
698 case Z_SRW_query_type_cql:
699 add_xsd_string(ptr, "query", req->query.cql);
701 case Z_SRW_query_type_xcql:
702 add_xsd_string(ptr, "xQuery", req->query.xcql);
704 case Z_SRW_query_type_pqf:
705 add_xsd_string(ptr, "pQuery", req->query.pqf);
708 add_xsd_integer(ptr, "startRecord", req->startRecord);
709 add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
710 add_xsd_string(ptr, "recordPacking", req->recordPacking);
711 add_xsd_string(ptr, "recordSchema", req->recordSchema);
712 add_xsd_string(ptr, "recordXPath", req->recordXPath);
713 add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
714 switch(req->sort_type)
716 case Z_SRW_sort_type_none:
718 case Z_SRW_sort_type_sort:
719 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
721 case Z_SRW_sort_type_xSort:
722 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
725 add_xsd_string(ptr, "stylesheet", req->stylesheet);
726 add_xsd_string(ptr, "database", req->database);
728 else if ((*p)->which == Z_SRW_searchRetrieve_response)
730 Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
731 xmlNodePtr ptr = xmlNewChild(pptr, 0,
732 "searchRetrieveResponse", 0);
733 ns_srw = xmlNewNs(ptr, ns, "zs");
734 xmlSetNs(ptr, ns_srw);
736 if ((*p)->srw_version)
737 add_xsd_string(ptr, "version", (*p)->srw_version);
738 add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
739 add_xsd_string(ptr, "resultSetId", res->resultSetId);
740 add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
741 if (res->num_records)
743 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
744 yaz_srw_records(o, rptr, &res->records, &res->num_records,
747 add_xsd_integer(ptr, "nextRecordPosition",
748 res->nextRecordPosition);
749 if (res->num_diagnostics)
751 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
752 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
753 &res->num_diagnostics, client_data, ns);
756 else if ((*p)->which == Z_SRW_explain_request)
758 Z_SRW_explainRequest *req = (*p)->u.explain_request;
759 xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
760 ns_srw = xmlNewNs(ptr, ns, "zs");
761 xmlSetNs(ptr, ns_srw);
763 add_xsd_string(ptr, "version", (*p)->srw_version);
764 add_xsd_string(ptr, "recordPacking", req->recordPacking);
765 add_xsd_string(ptr, "stylesheet", req->stylesheet);
766 add_xsd_string(ptr, "database", req->database);
768 else if ((*p)->which == Z_SRW_explain_response)
770 Z_SRW_explainResponse *res = (*p)->u.explain_response;
771 xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
772 ns_srw = xmlNewNs(ptr, ns, "zs");
773 xmlSetNs(ptr, ns_srw);
775 add_xsd_string(ptr, "version", (*p)->srw_version);
778 xmlNodePtr ptr1 = xmlNewChild(ptr, 0, "record", 0);
779 yaz_srw_record(o, ptr1, &res->record, client_data, ns);
781 if (res->num_diagnostics)
783 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
784 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
785 &res->num_diagnostics, client_data, ns);
788 else if ((*p)->which == Z_SRW_scan_request)
790 Z_SRW_scanRequest *req = (*p)->u.scan_request;
791 xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanRequest", 0);
792 ns_srw = xmlNewNs(ptr, ns, "zs");
793 xmlSetNs(ptr, ns_srw);
795 add_xsd_string(ptr, "version", (*p)->srw_version);
796 switch(req->query_type)
798 case Z_SRW_query_type_cql:
799 add_xsd_string(ptr, "scanClause", req->scanClause.cql);
801 case Z_SRW_query_type_pqf:
802 add_xsd_string(ptr, "pScanClause", req->scanClause.pqf);
805 add_xsd_integer(ptr, "responsePosition", req->responsePosition);
806 add_xsd_integer(ptr, "maximumTerms", req->maximumTerms);
807 add_xsd_string(ptr, "stylesheet", req->stylesheet);
808 add_xsd_string(ptr, "database", req->database);
810 else if ((*p)->which == Z_SRW_scan_response)
812 Z_SRW_scanResponse *res = (*p)->u.scan_response;
813 xmlNodePtr ptr = xmlNewChild(pptr, 0, "scanResponse", 0);
814 ns_srw = xmlNewNs(ptr, ns, "zs");
815 xmlSetNs(ptr, ns_srw);
817 add_xsd_string(ptr, "version", (*p)->srw_version);
821 xmlNodePtr rptr = xmlNewChild(ptr, 0, "terms", 0);
822 yaz_srw_terms(o, rptr, &res->terms, &res->num_terms,
825 if (res->num_diagnostics)
827 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
828 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
829 &res->num_diagnostics, client_data, ns);