X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fsrw.c;h=dfd3aadb16616f24e29b60c5e3a59b653966ad20;hp=ae768d459f57e3d323e18dec04517670a2315261;hb=47d9d5ac3241f8db09ba19a1a5c1fdd5e140e75f;hpb=337f11f176f339be5957832bb418b6b39a6c1101 diff --git a/src/srw.c b/src/srw.c index ae768d4..dfd3aad 100644 --- a/src/srw.c +++ b/src/srw.c @@ -1,20 +1,26 @@ -/* - * Copyright (C) 1995-2007, Index Data ApS +/* This file is part of the YAZ toolkit. + * Copyright (C) 1995-2011 Index Data * See the file LICENSE for details. - * - * $Id: srw.c,v 1.56 2007-05-23 13:11:11 adam Exp $ */ /** * \file srw.c * \brief Implements SRW/SRU package encoding and decoding */ +#if HAVE_CONFIG_H +#include +#endif + +#include #include +#include #if YAZ_HAVE_XML2 #include #include #include +#include "sru-p.h" + static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len, xmlNsPtr ns_ptr) { @@ -62,12 +68,13 @@ xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, const char *val) return add_xsd_string_ns(ptr, elem, val, 0); } -static void add_xsd_integer(xmlNodePtr ptr, const char *elem, const int *val) +static void add_xsd_integer(xmlNodePtr ptr, const char *elem, + const Odr_int *val) { if (val) { - char str[30]; - sprintf(str, "%d", *val); + char str[40]; + sprintf(str, ODR_INT_PRINTF, *val); xmlNewTextChild(ptr, 0, BAD_CAST elem, BAD_CAST str); } } @@ -166,7 +173,8 @@ static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o, return 1; } -static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val) +static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, + Odr_int **val) { #if CHECK_TYPE struct _xmlAttr *attr; @@ -192,10 +200,20 @@ static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val) ptr = ptr->children; if (!ptr || ptr->type != XML_TEXT_NODE) return 0; - *val = odr_intdup(o, atoi((const char *) ptr->content)); + *val = odr_intdup(o, odr_atoi((const char *) ptr->content)); return 1; } +char *yaz_negotiate_sru_version(char *input_ver) +{ + if (!input_ver) + input_ver = "1.1"; + + if (!strcmp(input_ver, "1.1")) + return "1.1"; + return "1.2"; /* our latest supported version */ +} + static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec, Z_SRW_extra_record **extra, void *client_data, const char *ns) @@ -380,7 +398,7 @@ static int yaz_srw_version(ODR o, xmlNodePtr pptr, Z_SRW_recordVersion *rec, } } else if (o->direction == ODR_ENCODE) - { + { xmlNodePtr ptr = pptr; add_xsd_string(ptr, "versionType", rec->versionType); add_xsd_string(ptr, "versionValue", rec->versionValue); @@ -420,7 +438,7 @@ static int yaz_srw_versions(ODR o, xmlNodePtr pptr, { int i; for (i = 0; i < *num; i++) - { + { xmlNodePtr rptr = xmlNewChild(pptr, 0, BAD_CAST "version", 0); yaz_srw_version(o, rptr, (*vers)+i, client_data, ns); @@ -429,53 +447,169 @@ static int yaz_srw_versions(ODR o, xmlNodePtr pptr, return 0; } -static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs, - int *num, void *client_data, const char *ns) +Z_FacetTerm *yaz_sru_proxy_get_facet_term_count(ODR odr, xmlNodePtr node) { - if (o->direction == ODR_DECODE) + int freq; + xmlNodePtr child; + WRBUF wrbuf = wrbuf_alloc(); + const char *freq_string = yaz_element_attribute_value_get(node, "facetvalue", "est_representation"); + Z_Term *term; + if (freq_string) + freq = atoi(freq_string); + else + freq = -1; + + for (child = node->children; child ; child = child->next) { + if (child->type == XML_TEXT_NODE) + wrbuf_puts(wrbuf, (const char *) child->content); + } + term = term_create(odr, wrbuf_cstr(wrbuf)); + yaz_log(YLOG_DEBUG, "sru-proxy facet: %s %d", wrbuf_cstr(wrbuf), freq); + wrbuf_destroy(wrbuf); + return facet_term_create(odr, term, freq); +}; + +static Z_FacetField *yaz_sru_proxy_decode_facet_field(ODR odr, xmlNodePtr ptr) +{ + Z_AttributeList *list; + Z_FacetField *facet_field; + int num_terms = 0; + int index = 0; + xmlNodePtr node; + /* USE attribute */ + const char* name = yaz_element_attribute_value_get(ptr, "facet", "code"); + yaz_log(YLOG_DEBUG, "sru-proxy facet type: %s", name); + + list = yaz_use_atttribute_create(odr, name); + for (node = ptr->children; node; node = node->next) { + if (match_element(node, "facetvalue")) + num_terms++; + } + facet_field = facet_field_create(odr, list, num_terms); + index = 0; + for (node = ptr->children; node; node = node->next) { - int i; - xmlNodePtr ptr; - *num = 0; - for (ptr = pptr->children; ptr; ptr = ptr->next) + if (match_element(node, "facetvalue")) { - if (ptr->type == XML_ELEMENT_NODE && - !xmlStrcmp(ptr->name, BAD_CAST "diagnostic")) - (*num)++; + facet_field_term_set(odr, facet_field, yaz_sru_proxy_get_facet_term_count(odr, node), index); + index++; } - if (!*num) - return 1; - *recs = (Z_SRW_diagnostic *) odr_malloc(o, *num * sizeof(**recs)); - for (i = 0; i < *num; i++) + } + return facet_field; +} + +static int yaz_sru_proxy_decode_facets(ODR o, xmlNodePtr root, + Z_FacetList **facetList) +{ + xmlNodePtr ptr; + + for (ptr = root->children; ptr; ptr = ptr->next) + { + if (match_element(ptr, "facets")) { + xmlNodePtr node; + Z_FacetList *facet_list; + int num_facets = 0; + for (node = ptr->children; node; node= node->next) + { + if (node->type == XML_ELEMENT_NODE) + num_facets++; + } + facet_list = facet_list_create(o, num_facets); + num_facets = 0; + for (node = ptr->children; node; node= node->next) + { + if (match_element(node, "facet")) { + facet_list_field_set(o, facet_list, yaz_sru_proxy_decode_facet_field(o, node), num_facets); + num_facets++; + } + } + *facetList = facet_list; + break; + } + } + return 0; +} + + + +static int yaz_srw_decode_diagnostics(ODR o, xmlNodePtr pptr, + Z_SRW_diagnostic **recs, int *num, + void *client_data, const char *ns) +{ + int i; + xmlNodePtr ptr; + *num = 0; + for (ptr = pptr; ptr; ptr = ptr->next) + { + if (ptr->type == XML_ELEMENT_NODE && + !xmlStrcmp(ptr->name, BAD_CAST "diagnostic")) + (*num)++; + } + if (!*num) + return 1; + *recs = (Z_SRW_diagnostic *) odr_malloc(o, *num * sizeof(**recs)); + for (i = 0; i < *num; i++) + { + (*recs)[i].uri = 0; + (*recs)[i].details = 0; + (*recs)[i].message = 0; + } + for (i = 0, ptr = pptr; ptr; ptr = ptr->next) + { + if (ptr->type == XML_ELEMENT_NODE && + !xmlStrcmp(ptr->name, BAD_CAST "diagnostic")) + { + xmlNodePtr rptr; (*recs)[i].uri = 0; (*recs)[i].details = 0; (*recs)[i].message = 0; - } - for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next) - { - if (ptr->type == XML_ELEMENT_NODE && - !xmlStrcmp(ptr->name, BAD_CAST "diagnostic")) + for (rptr = ptr->children; rptr; rptr = rptr->next) { - xmlNodePtr rptr; - (*recs)[i].uri = 0; - (*recs)[i].details = 0; - (*recs)[i].message = 0; - for (rptr = ptr->children; rptr; rptr = rptr->next) - { - if (match_xsd_string(rptr, "uri", o, - &(*recs)[i].uri)) - ; - else if (match_xsd_string(rptr, "details", o, - &(*recs)[i].details)) - ; - else if (match_xsd_string(rptr, "message", o, - &(*recs)[i].message)) - ; - } - i++; + if (match_xsd_string(rptr, "uri", o, + &(*recs)[i].uri)) + ; + else if (match_xsd_string(rptr, "details", o, + &(*recs)[i].details)) + ; + else if (match_xsd_string(rptr, "message", o, + &(*recs)[i].message)) + ; } + i++; + } + } + return 0; +} + +int sru_decode_surrogate_diagnostics(const char *buf, size_t len, + Z_SRW_diagnostic **diag, + int *num, ODR odr) +{ + int ret = 0; + xmlDocPtr doc = xmlParseMemory(buf, len); + if (doc) + { + xmlNodePtr ptr = xmlDocGetRootElement(doc); + while (ptr && ptr->type != XML_ELEMENT_NODE) + ptr = ptr->next; + if (ptr && ptr->ns + && !xmlStrcmp(ptr->ns->href, + BAD_CAST "http://www.loc.gov/zing/srw/diagnostic/")) + { + ret = yaz_srw_decode_diagnostics(odr, ptr, diag, num, 0, 0); } + xmlFreeDoc(doc); + } + return ret; +} + +static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs, + int *num, void *client_data, const char *ns) +{ + if (o->direction == ODR_DECODE) + { + return yaz_srw_decode_diagnostics(o, pptr->children, recs, num, client_data, ns); } else if (o->direction == ODR_ENCODE) { @@ -529,7 +663,7 @@ static int yaz_srw_term(ODR o, xmlNodePtr pptr, Z_SRW_scanTerm *term, if (match_xsd_string(ptr, "value", o, &term->value)) ; else if (match_xsd_integer(ptr, "numberOfRecords", o, - &term->numberOfRecords)) + &term->numberOfRecords)) ; else if (match_xsd_string(ptr, "displayTerm", o, &term->displayTerm)) @@ -594,6 +728,7 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, { Z_SRW_PDU **p = handler_data; xmlNodePtr method = pptr->children; + char *neg_version; while (method && method->type == XML_TEXT_NODE) method = method->next; @@ -632,13 +767,13 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, &(*p)->srw_version)) ; else if (match_xsd_string(ptr, "query", o, - &req->query.cql)) + &req->query.cql)) req->query_type = Z_SRW_query_type_cql; else if (match_xsd_string(ptr, "pQuery", o, - &req->query.pqf)) + &req->query.pqf)) req->query_type = Z_SRW_query_type_pqf; else if (match_xsd_string(ptr, "xQuery", o, - &req->query.xcql)) + &req->query.xcql)) req->query_type = Z_SRW_query_type_xcql; else if (match_xsd_integer(ptr, "startRecord", o, &req->startRecord)) @@ -662,10 +797,10 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, &req->sort.sortKeys)) req->sort_type = Z_SRW_sort_type_sort; else if (match_xsd_string(ptr, "stylesheet", o, - &req->stylesheet)) + &req->stylesheet)) ; else if (match_xsd_string(ptr, "database", o, - &req->database)) + &req->database)) ; } if (!req->query.cql && !req->query.pqf && !req->query.xcql) @@ -691,14 +826,19 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, res->diagnostics = 0; res->num_diagnostics = 0; res->nextRecordPosition = 0; + res->facetList = 0; for (; ptr; ptr = ptr->next) { if (match_xsd_string(ptr, "version", o, &(*p)->srw_version)) ; + else if (match_xsd_XML_n(ptr, "extraResponseData", o, + &(*p)->extraResponseData_buf, + &(*p)->extraResponseData_len)) + ; else if (match_xsd_integer(ptr, "numberOfRecords", o, - &res->numberOfRecords)) + &res->numberOfRecords)) ; else if (match_xsd_string(ptr, "resultSetId", o, &res->resultSetId)) @@ -717,6 +857,8 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, yaz_srw_diagnostics(o, ptr, &res->diagnostics, &res->num_diagnostics, client_data, ns); + else if (match_element(ptr, "facet_analysis")) + yaz_sru_proxy_decode_facets(o, ptr, &res->facetList); } } else if (!xmlStrcmp(method->name, BAD_CAST "explainRequest")) @@ -733,16 +875,20 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, for (; ptr; ptr = ptr->next) { if (match_xsd_string(ptr, "version", o, - &(*p)->srw_version)) + &(*p)->srw_version)) + ; + else if (match_xsd_XML_n(ptr, "extraResponseData", o, + &(*p)->extraResponseData_buf, + &(*p)->extraResponseData_len)) ; else if (match_xsd_string(ptr, "stylesheet", o, &req->stylesheet)) ; else if (match_xsd_string(ptr, "recordPacking", o, - &req->recordPacking)) + &req->recordPacking)) ; else if (match_xsd_string(ptr, "database", o, - &req->database)) + &req->database)) ; } } @@ -764,7 +910,11 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, for (; ptr; ptr = ptr->next) { if (match_xsd_string(ptr, "version", o, - &(*p)->srw_version)) + &(*p)->srw_version)) + ; + else if (match_xsd_XML_n(ptr, "extraResponseData", o, + &(*p)->extraResponseData_buf, + &(*p)->extraResponseData_len)) ; else if (match_element(ptr, "record")) yaz_srw_record(o, ptr, &res->record, &res->extra_record, @@ -796,8 +946,12 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, if (match_xsd_string(ptr, "version", o, &(*p)->srw_version)) ; + else if (match_xsd_XML_n(ptr, "extraResponseData", o, + &(*p)->extraResponseData_buf, + &(*p)->extraResponseData_len)) + ; else if (match_xsd_string(ptr, "scanClause", o, - &req->scanClause.cql)) + &req->scanClause.cql)) ; else if (match_xsd_string(ptr, "pScanClause", o, &req->scanClause.pqf)) @@ -836,6 +990,10 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, if (match_xsd_string(ptr, "version", o, &(*p)->srw_version)) ; + else if (match_xsd_XML_n(ptr, "extraResponseData", o, + &(*p)->extraResponseData_buf, + &(*p)->extraResponseData_len)) + ; else if (match_element(ptr, "terms")) yaz_srw_terms(o, ptr, &res->terms, &res->num_terms, client_data, @@ -851,17 +1009,20 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, *p = 0; return -1; } + neg_version = yaz_negotiate_sru_version((*p)->srw_version); + if (neg_version) + (*p)->srw_version = neg_version; } else if (o->direction == ODR_ENCODE) { Z_SRW_PDU **p = handler_data; xmlNsPtr ns_srw; + xmlNodePtr ptr = 0; if ((*p)->which == Z_SRW_searchRetrieve_request) { Z_SRW_searchRetrieveRequest *req = (*p)->u.request; - xmlNodePtr ptr = xmlNewChild(pptr, 0, - BAD_CAST "searchRetrieveRequest", 0); + ptr = xmlNewChild(pptr, 0, BAD_CAST "searchRetrieveRequest", 0); ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs"); xmlSetNs(ptr, ns_srw); @@ -902,8 +1063,7 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, else if ((*p)->which == Z_SRW_searchRetrieve_response) { Z_SRW_searchRetrieveResponse *res = (*p)->u.response; - xmlNodePtr ptr = xmlNewChild(pptr, 0, - BAD_CAST "searchRetrieveResponse", 0); + ptr = xmlNewChild(pptr, 0, BAD_CAST "searchRetrieveResponse", 0); ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs"); xmlSetNs(ptr, ns_srw); @@ -932,8 +1092,7 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, else if ((*p)->which == Z_SRW_explain_request) { Z_SRW_explainRequest *req = (*p)->u.explain_request; - xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "explainRequest", - 0); + ptr = xmlNewChild(pptr, 0, BAD_CAST "explainRequest", 0); ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs"); xmlSetNs(ptr, ns_srw); @@ -945,8 +1104,7 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, else if ((*p)->which == Z_SRW_explain_response) { Z_SRW_explainResponse *res = (*p)->u.explain_response; - xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "explainResponse", - 0); + ptr = xmlNewChild(pptr, 0, BAD_CAST "explainResponse", 0); ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs"); xmlSetNs(ptr, ns_srw); @@ -968,7 +1126,7 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, else if ((*p)->which == Z_SRW_scan_request) { Z_SRW_scanRequest *req = (*p)->u.scan_request; - xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "scanRequest", 0); + ptr = xmlNewChild(pptr, 0, BAD_CAST "scanRequest", 0); ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs"); xmlSetNs(ptr, ns_srw); @@ -990,7 +1148,7 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, else if ((*p)->which == Z_SRW_scan_response) { Z_SRW_scanResponse *res = (*p)->u.scan_response; - xmlNodePtr ptr = xmlNewChild(pptr, 0, BAD_CAST "scanResponse", 0); + ptr = xmlNewChild(pptr, 0, BAD_CAST "scanResponse", 0); ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs"); xmlSetNs(ptr, ns_srw); @@ -1012,6 +1170,11 @@ int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, } else return -1; + if (ptr && (*p)->extraResponseData_len) + add_XML_n(ptr, "extraResponseData", + (*p)->extraResponseData_buf, + (*p)->extraResponseData_len, ns_srw); + } return 0; @@ -1087,10 +1250,10 @@ int yaz_ucp_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, client_data, ns_ucp_str); } else if (match_xsd_string(ptr, "stylesheet", o, - &req->stylesheet)) + &req->stylesheet)) ; else if (match_xsd_string(ptr, "database", o, - &req->database)) + &req->database)) ; } } @@ -1120,7 +1283,7 @@ int yaz_ucp_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, &(*p)->srw_version)) ; else if (match_xsd_string(ptr, "operationStatus", o, - &res->operationStatus )) + &res->operationStatus )) ; else if (match_xsd_string(ptr, "recordIdentifier", o, &res->recordId)) @@ -1242,6 +1405,7 @@ int yaz_ucp_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data, /* * Local variables: * c-basic-offset: 4 + * c-file-style: "Stroustrup" * indent-tabs-mode: nil * End: * vim: shiftwidth=4 tabstop=8 expandtab