/* This file is part of the YAZ toolkit.
- * Copyright (C) 1995-2013 Index Data
+ * Copyright (C) Index Data
* See the file LICENSE for details.
*/
/**
#include <libxml/tree.h>
#include <assert.h>
#include <yaz/facet.h>
+#include <yaz/proto.h>
#include "sru-p.h"
-static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len,
- xmlNsPtr ns_ptr)
-{
- if (val)
- {
- xmlDocPtr doc = xmlParseMemory(val,len);
- if (doc)
- {
- xmlNodePtr c = xmlNewChild(ptr, ns_ptr, BAD_CAST elem, 0);
- xmlNodePtr t = xmlDocGetRootElement(doc);
- xmlAddChild(c, xmlCopyNode(t,1));
- xmlFreeDoc(doc);
- }
- }
-}
-
-xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, const char *val,
- int len)
-{
- if (val)
- {
- xmlNodePtr c = xmlNewChild(ptr, 0, BAD_CAST elem, 0);
- xmlNodePtr t = xmlNewTextLen(BAD_CAST val, len);
- xmlAddChild(c, t);
- return t;
- }
- return 0;
-}
-
-xmlNodePtr add_xsd_string_ns(xmlNodePtr ptr, const char *elem, const char *val,
- xmlNsPtr ns_ptr)
-{
- if (val)
- {
- xmlNodePtr c = xmlNewChild(ptr, ns_ptr, BAD_CAST elem, 0);
- xmlNodePtr t = xmlNewText(BAD_CAST val);
- xmlAddChild(c, t);
- return t;
- }
- return 0;
-}
-
-xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, const char *val)
-{
- return add_xsd_string_ns(ptr, elem, val, 0);
-}
-
-void add_xsd_integer(xmlNodePtr ptr, const char *elem,
- const Odr_int *val)
-{
- if (val)
- {
- char str[40];
- sprintf(str, ODR_INT_PRINTF, *val);
- xmlNewTextChild(ptr, 0, BAD_CAST elem, BAD_CAST str);
- }
-}
-
-int yaz_match_xsd_element(xmlNodePtr ptr, const char *elem)
-{
- if (ptr->type == XML_ELEMENT_NODE && !xmlStrcmp(ptr->name, BAD_CAST elem))
- {
- return 1;
- }
- return 0;
-}
-
-#define CHECK_TYPE 0
-
-int yaz_match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
- char **val, int *len)
-{
-#if CHECK_TYPE
- struct _xmlAttr *attr;
-#endif
- if (!yaz_match_xsd_element(ptr, elem))
- return 0;
-#if CHECK_TYPE
- for (attr = ptr->properties; attr; attr = attr->next)
- if (!strcmp(attr->name, "type") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- {
- const char *t = strchr(attr->children->content, ':');
- if (t)
- t = t + 1;
- else
- t = attr->children->content;
- if (!strcmp(t, "string"))
- break;
- }
- if (!attr)
- return 0;
-#endif
- ptr = ptr->children;
- if (!ptr || ptr->type != XML_TEXT_NODE)
- {
- *val = "";
- return 1;
- }
- *val = odr_strdup(o, (const char *) ptr->content);
- if (len)
- *len = xmlStrlen(ptr->content);
- return 1;
-}
-
-
-int yaz_match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o, char **val)
-{
- return yaz_match_xsd_string_n(ptr, elem, o, val, 0);
-}
-
-static int yaz_match_xsd_XML_n2(xmlNodePtr ptr, const char *elem, ODR o,
- char **val, int *len, int fixup_root)
-{
- xmlBufferPtr buf;
- int no_root_nodes = 0;
-
- if (!yaz_match_xsd_element(ptr, elem))
- return 0;
-
- buf = xmlBufferCreate();
-
- /* Copy each element nodes at top.
- In most cases there is only one root node.. At least one server
- http://www.theeuropeanlibrary.org/sru/sru.pl
- has multiple root nodes in recordData.
- */
- for (ptr = ptr->children; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE)
- {
- /* copy node to get NS right (bug #740). */
- xmlNode *tmp = xmlCopyNode(ptr, 1);
-
- xmlNodeDump(buf, tmp->doc, tmp, 0, 0);
-
- xmlFreeNode(tmp);
- no_root_nodes++;
- }
- }
- if (no_root_nodes != 1 && fixup_root)
- {
- /* does not appear to be an XML document. Make it so */
- xmlBufferAddHead(buf, (const xmlChar *) "<yaz_record>", -1);
- xmlBufferAdd(buf, (const xmlChar *) "</yaz_record>", -1);
- }
- *val = (char *) odr_malloc(o, buf->use + 1);
- memcpy(*val, buf->content, buf->use);
- (*val)[buf->use] = '\0';
-
- if (len)
- *len = buf->use;
-
- xmlBufferFree(buf);
-
- return 1;
-}
-
-static int yaz_match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
- char **val, int *len)
-{
- return yaz_match_xsd_XML_n2(ptr, elem, o, val, len, 0);
-}
-
-int yaz_match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o,
- Odr_int **val)
-{
-#if CHECK_TYPE
- struct _xmlAttr *attr;
-#endif
- if (!yaz_match_xsd_element(ptr, elem))
- return 0;
-#if CHECK_TYPE
- for (attr = ptr->properties; attr; attr = attr->next)
- if (!strcmp(attr->name, "type") &&
- attr->children && attr->children->type == XML_TEXT_NODE)
- {
- const char *t = strchr(attr->children->content, ':');
- if (t)
- t = t + 1;
- else
- t = attr->children->content;
- if (!strcmp(t, "integer"))
- break;
- }
- if (!attr)
- return 0;
-#endif
- ptr = ptr->children;
- if (!ptr || ptr->type != XML_TEXT_NODE)
- return 0;
- *val = odr_intdup(o, odr_atoi((const char *) ptr->content));
- return 1;
-}
-
char *yaz_negotiate_sru_version(char *input_ver)
{
if (!input_ver)
int pack = rec->recordPacking;
const char *spack = yaz_srw_pack_to_str(pack);
- add_xsd_string(ptr, "recordSchema", rec->recordSchema);
+ /* recordSchema and recordData are required */
+ if (!rec->recordSchema)
+ xmlNewChild(ptr, 0, BAD_CAST "recordSchema", 0);
+ else
+ add_xsd_string(ptr, "recordSchema", rec->recordSchema);
if (spack)
{
if (version2)
else
add_xsd_string(ptr, "recordPacking", spack);
}
- switch (pack)
+ if (!rec->recordData_buf)
+ xmlNewChild(ptr, 0, BAD_CAST "recordData", 0);
+ else
{
- case Z_SRW_recordPacking_string:
- add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
- rec->recordData_len);
- break;
- case Z_SRW_recordPacking_XML:
- add_XML_n(ptr, "recordData", rec->recordData_buf,
- rec->recordData_len, 0);
- break;
- case Z_SRW_recordPacking_URL:
- add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
- rec->recordData_len);
- break;
+ switch (pack)
+ {
+ case Z_SRW_recordPacking_string:
+ add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
+ rec->recordData_len);
+ break;
+ case Z_SRW_recordPacking_XML:
+ add_XML_n(ptr, "recordData", rec->recordData_buf,
+ rec->recordData_len, 0);
+ break;
+ case Z_SRW_recordPacking_URL:
+ add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
+ rec->recordData_len);
+ break;
+ }
}
if (rec->recordPosition)
add_xsd_integer(ptr, "recordPosition", rec->recordPosition );
const char* name = yaz_element_attribute_value_get(ptr, "facet", "code");
yaz_log(YLOG_DEBUG, "sru-proxy facet type: %s", name);
- list = yaz_use_attribute_create(odr, name);
+ list = zget_AttributeList_use_string(odr, name);
for (node = ptr->children; node; node = node->next) {
if (yaz_match_xsd_element(node, "facetvalue"))
num_terms++;
}
static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
- int *num, void *client_data, const char *ns)
+ int *num, void *client_data, const char *ns,
+ int version2)
{
if (o->direction == ODR_DECODE)
{
{
int i;
xmlNsPtr ns_diag =
- xmlNewNs(pptr, BAD_CAST YAZ_XMLNS_DIAG_v1_1, BAD_CAST "diag" );
+ xmlNewNs(pptr, BAD_CAST (version2 ?
+ YAZ_XMLNS_DIAG_v2 : YAZ_XMLNS_DIAG_v1_1),
+ BAD_CAST "diag" );
for (i = 0; i < *num; i++)
{
const char *std_diag = "info:srw/diagnostic/1/";
xmlNodePtr rptr = xmlNewChild(pptr, ns_diag,
BAD_CAST "diagnostic", 0);
add_xsd_string(rptr, "uri", (*recs)[i].uri);
+ add_xsd_string(rptr, "details", (*recs)[i].details);
if ((*recs)[i].message)
add_xsd_string(rptr, "message", (*recs)[i].message);
else if ((*recs)[i].uri )
add_xsd_string(rptr, "message", message);
}
}
- add_xsd_string(rptr, "details", (*recs)[i].details);
}
}
return 0;
char *recordPacking = 0;
char *recordXMLEscaping = 0;
const char *facetLimit = 0;
+ const char *facetStart = 0;
+ const char *facetSort = 0;
(*p)->which = Z_SRW_searchRetrieve_request;
req = (*p)->u.request = (Z_SRW_searchRetrieveRequest *)
else if (yaz_match_xsd_string(ptr, "stylesheet", o,
&req->stylesheet))
;
- else if (yaz_match_xsd_string(ptr, "database", o, &req->database))
+ else if (yaz_match_xsd_string(ptr, "database", o,
+ &req->database))
;
else if (yaz_match_xsd_string(ptr, "facetLimit", o,
- (char**) &facetLimit))
+ (char**) &facetLimit))
+ ;
+ else if (yaz_match_xsd_string(ptr, "facetStart", o,
+ (char**) &facetStart))
+ ;
+ else if (yaz_match_xsd_string(ptr, "facetSort", o,
+ (char**) &facetSort))
;
}
if (!req->query)
{
req->recordPacking = recordPacking;
}
- yaz_sru_facet_request(o, &req->facetList, &facetLimit);
+ yaz_sru_facet_request(o, &req->facetList, &facetLimit, &facetStart,
+ &facetSort);
}
else if (!xmlStrcmp(method->name, BAD_CAST "searchRetrieveResponse"))
{
else if (yaz_match_xsd_element(ptr, "diagnostics"))
yaz_srw_diagnostics(o, ptr, &res->diagnostics,
&res->num_diagnostics,
- client_data, ns);
+ client_data, ns, 0);
else if (yaz_match_xsd_element(ptr, "facet_analysis"))
yaz_sru_proxy_decode_facets(o, ptr, &res->facetList);
else if (yaz_match_xsd_element(ptr, "facetedResults"))
else if (yaz_match_xsd_element(ptr, "diagnostics"))
yaz_srw_diagnostics(o, ptr, &res->diagnostics,
&res->num_diagnostics,
- client_data, ns);
+ client_data, ns, 0);
;
}
}
else if (yaz_match_xsd_element(ptr, "diagnostics"))
yaz_srw_diagnostics(o, ptr, &res->diagnostics,
&res->num_diagnostics,
- client_data, ns);
+ client_data, ns, 0);
}
}
else
ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
xmlSetNs(ptr, ns_srw);
- add_xsd_string(ptr, "version", (*p)->srw_version);
+ if (!version2)
+ add_xsd_string(ptr, "version", (*p)->srw_version);
if (version2)
{
- if (queryType)
- add_xsd_string(ptr, "queryType", queryType);
add_xsd_string(ptr, "query", req->query);
}
else
add_xsd_string(ptr, "xQuery", req->query);
else if (!strcmp(queryType, "pqf"))
add_xsd_string(ptr, "pQuery", req->query);
+ queryType = 0;
}
add_xsd_integer(ptr, "startRecord", req->startRecord);
add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
if (version2)
- {
add_xsd_string(ptr, "recordXMLEscaping", req->recordPacking);
- add_xsd_string(ptr, "recordPacking", req->packing);
- }
else
add_xsd_string(ptr, "recordPacking", req->recordPacking);
add_xsd_string(ptr, "recordSchema", req->recordSchema);
add_xsd_string(ptr, "recordXPath", req->recordXPath);
add_xsd_integer(ptr, "resultSetTTL", req->resultSetTTL);
+ add_xsd_string(ptr, "stylesheet", req->stylesheet);
+ add_xsd_string(ptr, "queryType", queryType);
switch (req->sort_type)
{
case Z_SRW_sort_type_none:
add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
break;
}
- add_xsd_string(ptr, "stylesheet", req->stylesheet);
+ /* still unsupported are: renderedBy, httpAccept, responseType */
add_xsd_string(ptr, "database", req->database);
+ if (version2)
+ add_xsd_string(ptr, "recordPacking", req->packing);
{
const char *limit = 0;
- yaz_sru_facet_request(o, &req->facetList, &limit);
+ const char *start = 0;
+ const char *sort = 0;
+ yaz_sru_facet_request(o, &req->facetList, &limit, &start,
+ &sort);
add_xsd_string(ptr, "facetLimit", limit);
+ add_xsd_string(ptr, "facetStart", start);
+ add_xsd_string(ptr, "facetSort", sort);
}
}
else if ((*p)->which == Z_SRW_searchRetrieve_response)
ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
xmlSetNs(ptr, ns_srw);
- add_xsd_string(ptr, "version", (*p)->srw_version);
+ if (!version2)
+ add_xsd_string(ptr, "version", (*p)->srw_version);
add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
add_xsd_string(ptr, "resultSetId", res->resultSetId);
- add_xsd_integer(ptr,
- version2 ? "resultSetTTL" : "resultSetIdleTime" ,
- res->resultSetIdleTime);
+ if (!version2)
+ add_xsd_integer(ptr, "resultSetIdleTime",
+ res->resultSetIdleTime);
if (res->num_records)
{
xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "records", 0);
xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
0);
yaz_srw_diagnostics(o, rptr, &res->diagnostics,
- &res->num_diagnostics, client_data, ns);
+ &res->num_diagnostics, client_data, ns,
+ version2);
}
- if (res->resultCountPrecision)
+ if (version2)
+ {
+ if (ptr && (*p)->extraResponseData_len)
+ add_XML_n(ptr, "extraResponseData",
+ (*p)->extraResponseData_buf,
+ (*p)->extraResponseData_len, ns_srw);
+ add_xsd_integer(ptr, "resultSetTTL", res->resultSetIdleTime);
add_xsd_string(ptr, "resultCountPrecision",
res->resultCountPrecision);
- yaz_sru_facet_response(o, &res->facetList, ptr);
+ yaz_sru_facet_response(o, &res->facetList, ptr);
+ return 0; /* so we don't make extra response data twice */
+ }
}
else if ((*p)->which == Z_SRW_explain_request)
{
Z_SRW_explainRequest *req = (*p)->u.explain_request;
+ if (version2)
+ ns = "http://docs.oasis-open.org/ns/search-ws/sruRequest";
ptr = xmlNewChild(pptr, 0, BAD_CAST "explainRequest", 0);
ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
xmlSetNs(ptr, ns_srw);
- add_xsd_string(ptr, "version", (*p)->srw_version);
+ if (!version2)
+ add_xsd_string(ptr, "version", (*p)->srw_version);
if (version2)
{
add_xsd_string(ptr, "recordXMLEscaping", req->recordPacking);
else if ((*p)->which == Z_SRW_explain_response)
{
Z_SRW_explainResponse *res = (*p)->u.explain_response;
+ if (version2)
+ ns = "http://docs.oasis-open.org/ns/search-ws/sruResponse";
ptr = xmlNewChild(pptr, 0, BAD_CAST "explainResponse", 0);
ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
xmlSetNs(ptr, ns_srw);
xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
0);
yaz_srw_diagnostics(o, rptr, &res->diagnostics,
- &res->num_diagnostics, client_data, ns);
+ &res->num_diagnostics, client_data, ns,
+ version2);
}
}
else if ((*p)->which == Z_SRW_scan_request)
ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
xmlSetNs(ptr, ns_srw);
- add_xsd_string(ptr, "version", (*p)->srw_version);
+ if (!version2)
+ add_xsd_string(ptr, "version", (*p)->srw_version);
if (version2)
{
ns_srw = xmlNewNs(ptr, BAD_CAST ns, BAD_CAST "zs");
xmlSetNs(ptr, ns_srw);
- add_xsd_string(ptr, "version", (*p)->srw_version);
+ if (!version2)
+ add_xsd_string(ptr, "version", (*p)->srw_version);
if (res->num_terms)
{
xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "terms", 0);
xmlNodePtr rptr = xmlNewChild(ptr, 0, BAD_CAST "diagnostics",
0);
yaz_srw_diagnostics(o, rptr, &res->diagnostics,
- &res->num_diagnostics, client_data, ns);
+ &res->num_diagnostics, client_data, ns,
+ version2);
}
}
else
else if (yaz_match_xsd_element(ptr, "diagnostics"))
yaz_srw_diagnostics(o, ptr, &res->diagnostics,
&res->num_diagnostics,
- client_data, ns_ucp_str);
+ client_data, ns_ucp_str, 0);
}
}
else if (!xmlStrcmp(method->name, BAD_CAST "explainUpdateRequest"))
xmlNodePtr rptr = xmlNewChild(ptr, ns_diag, BAD_CAST "diagnostics", 0);
yaz_srw_diagnostics(o, rptr, &res->diagnostics,
&res->num_diagnostics, client_data,
- ns_ucp_str);
+ ns_ucp_str, 0);
}
if (res->extraResponseData_len)
add_XML_n(ptr, "extraResponseData",