/* or number converted to a string */
/* defaults to 'any' */
char useattrbuff[30]; /* for converting numbers to strings */
- char *relation; /* @attr 2, defaults to '=' */
- int limit; /* for facet attributes */
+ int sortorder;
+ int limit;
+ int start;
};
YAZ_EXPORT
FacetField ::= SEQUENCE {
-- attributes will specify:
-- 1=use (field name)
- -- 2=sortorder 0=most frequent, 1=least frequent, ..
+ -- 2=sortorder 0=count descending, 1=alpha ascending ..
-- 3=limit (integer)
+ -- 4=start (integer)
attributes [1] IMPLICIT AttributeList,
terms [2] IMPLICIT SEQUENCE OF FacetTerm OPTIONAL
}
{
attr_values->errcode = 0;
attr_values->errstring = 0;
- attr_values->relation = 0;
+ attr_values->sortorder = 0;
attr_values->useattr = 0;
attr_values->useattrbuff[0] = 0;
attr_values->limit = 0;
+ attr_values->start = 0;
}
static const char *stringattr(Z_ComplexAttribute *c)
}
-static void sortorderattr(Z_AttributeElement *ae, struct yaz_facet_attr *av)
+static void numattr(Z_AttributeElement *ae, struct yaz_facet_attr *av,
+ int *v)
{
if (ae->which == Z_AttributeValue_numeric)
{
- if (*ae->value.numeric == 0)
- av->relation = "desc";
- else if (*ae->value.numeric == 1)
- av->relation = "asc";
- else if (*ae->value.numeric == 3)
- av->relation = "unknown/unordered";
- else
- {
- av->errcode = YAZ_BIB1_UNSUPP_RELATION_ATTRIBUTE;
- sprintf(av->useattrbuff, ODR_INT_PRINTF,
- *ae-> attributeType);
- av->errstring = av->useattrbuff;
- }
- }
- else
- {
- av->errcode = YAZ_BIB1_UNSUPP_RELATION_ATTRIBUTE;
- av->errstring = "non-numeric relation attribute";
- }
-}
-
-static void limitattr(Z_AttributeElement *ae, struct yaz_facet_attr *av)
-{
- if (ae->which == Z_AttributeValue_numeric)
- {
- av->limit = *ae->value.numeric;
+ *v = *ae->value.numeric;
}
else
{
av->errcode = YAZ_BIB1_UNSUPP_ATTRIBUTE;
- av->errstring = "non-numeric limit attribute";
+ av->errstring = "non-numeric limit/sort/start attribute";
}
}
useattr(ae, av);
}
else if (*ae->attributeType == 2)
- { /* sortorder */
- sortorderattr(ae, av);
+ {
+ numattr(ae, av, &av->sortorder);
}
else if (*ae->attributeType == 3)
- { /* limit */
- limitattr(ae, av);
+ {
+ numattr(ae, av, &av->limit);
+ }
+ else if (*ae->attributeType == 4)
+ {
+ numattr(ae, av, &av->start);
}
else
{ /* unknown attribute */
struct yaz_facet_attr attr_values;
yaz_facet_attr_init(&attr_values);
yaz_facet_attr_get_z_attributes(attribute_list, &attr_values);
- // TODO do we want to support server decided
if (attr_values.errcode)
return -1;
if (attr_values.useattr)
{
WRBUF wrbuf = wrbuf_alloc();
- wrbuf_puts(wrbuf, (char *) attr_values.useattr);
yaz_add_name_value_str(encode, name, value, i,
"facet.field",
- odr_strdup(encode, wrbuf_cstr(wrbuf)));
+ odr_strdup(encode, attr_values.useattr));
+
if (attr_values.limit > 0)
{
- WRBUF wrbuf2 = wrbuf_alloc();
- Odr_int olimit;
- wrbuf_puts(wrbuf2, "f.");
- wrbuf_puts(wrbuf2, wrbuf_cstr(wrbuf));
- wrbuf_puts(wrbuf2, ".facet.limit");
- olimit = attr_values.limit;
+ Odr_int v = attr_values.limit;
+ wrbuf_rewind(wrbuf);
+ wrbuf_printf(wrbuf, "f.%s.facet.limit", attr_values.useattr);
+ yaz_add_name_value_int(encode, name, value, i,
+ odr_strdup(encode, wrbuf_cstr(wrbuf)),
+ &v);
+ }
+ if (attr_values.start > 1)
+ {
+ Odr_int v = attr_values.start - 1;
+ wrbuf_rewind(wrbuf);
+ wrbuf_printf(wrbuf, "f.%s.facet.offset", attr_values.useattr);
yaz_add_name_value_int(encode, name, value, i,
- odr_strdup(encode, wrbuf_cstr(wrbuf2)),
- &olimit);
- wrbuf_destroy(wrbuf2);
+ odr_strdup(encode, wrbuf_cstr(wrbuf)),
+ &v);
+ }
+ if (attr_values.sortorder == 1)
+ {
+ wrbuf_rewind(wrbuf);
+ wrbuf_printf(wrbuf, "f.%s.facet.sort", attr_values.useattr);
+ yaz_add_name_value_str(encode, name, value, i,
+ odr_strdup(encode, wrbuf_cstr(wrbuf)),
+ "index");
}
wrbuf_destroy(wrbuf);
}
+ else
+ {
+ if (attr_values.limit > 0)
+ {
+ Odr_int v = attr_values.limit;
+ yaz_add_name_value_int(encode, name, value, i, "facet.limit", &v);
+ }
+ if (attr_values.start > 1)
+ {
+ Odr_int v = attr_values.start - 1;
+ yaz_add_name_value_int(encode, name, value, i, "facet.offset", &v);
+ }
+ if (attr_values.sortorder == 1)
+ {
+ yaz_add_name_value_str(encode, name, value, i, "facet.sort",
+ "index");
+ }
+ }
return 0;
}
char *yaz_negotiate_sru_version(char *input_ver);
-void yaz_sru_facet_request(ODR, Z_FacetList **facetList, const char **limit);
+void yaz_sru_facet_request(ODR, Z_FacetList **facetList,
+ const char **limit, const char **start,
+ const char **sort);
#if YAZ_HAVE_XML2
#include <libxml/parser.h>
#include <yaz/pquery.h>
#include <yaz/facet.h>
-void yaz_sru_facet_request(ODR o, Z_FacetList **facetList, const char **limit)
+static void insert_field(WRBUF w, const char *field, size_t length,
+ const char *attr)
+{
+ const char *cp0 = wrbuf_cstr(w);
+ const char *cp = cp0;
+
+ while (1)
+ {
+ const char *cp2 = strstr(cp, "@attr 1=");
+ if (!cp2)
+ break;
+ cp = cp2 + 8;
+ if (!strncmp(cp, field, length) &&
+ (cp[length] == ' ' || cp[length] == ',' || cp[length] == '\0'))
+ {
+ /* found the field */
+
+ cp += length;
+ wrbuf_insert(w, cp - cp0, attr, strlen(attr));
+ wrbuf_insert(w, cp - cp0, " ", 1);
+ return;
+ }
+ while (*cp && *cp != ',')
+ cp++;
+ }
+ if (wrbuf_len(w))
+ wrbuf_puts(w, ",");
+ wrbuf_puts(w, "@attr 1=");
+ wrbuf_write(w, field, length);
+ wrbuf_puts(w, " ");
+ wrbuf_puts(w, attr);
+}
+
+void yaz_sru_facet_request(ODR o, Z_FacetList **facetList, const char **limit,
+ const char **start, const char **sort)
{
if (o->direction == ODR_ENCODE)
{
Z_FacetList *fl = *facetList;
if (fl)
{
+ WRBUF w_limit = wrbuf_alloc();
+ WRBUF w_start = wrbuf_alloc();
+ WRBUF w_sort = wrbuf_alloc();
int i;
- WRBUF w = wrbuf_alloc();
for (i = 0; i < fl->num; i++)
{
struct yaz_facet_attr av;
&av);
if (av.errcode == 0)
{
- wrbuf_printf(w, "%d", av.limit ? av.limit : -1);
- if (av.useattr)
- wrbuf_printf(w, ":%s,", av.useattr);
- /* av.relation not considered yet */
+ if (av.limit)
+ {
+ wrbuf_printf(w_limit, "%d", av.limit);
+ if (av.useattr)
+ wrbuf_printf(w_limit, ":%s", av.useattr);
+ wrbuf_puts(w_limit, ",");
+ }
+ if (av.start || av.useattr)
+ {
+ wrbuf_printf(w_start, "%d", av.start);
+ if (av.useattr)
+ wrbuf_printf(w_start, ":%s", av.useattr);
+ wrbuf_puts(w_start, ",");
+ }
+ if (av.sortorder == 1)
+ {
+ /* allow sorting per field */
+ /* not really according to spec */
+ wrbuf_printf(w_sort, "alphanumeric");
+ if (av.useattr)
+ wrbuf_printf(w_sort, ":%s", av.useattr);
+ wrbuf_puts(w_sort, ",");
+ }
}
}
- if (wrbuf_len(w) > 0)
+ if (wrbuf_len(w_limit) > 1)
+ {
+ wrbuf_cut_right(w_limit, 1); /* remove , */
+ *limit = odr_strdup(o, wrbuf_cstr(w_limit));
+ }
+ if (wrbuf_len(w_start) > 1)
{
- wrbuf_cut_right(w, 1); /* remove , */
- *limit = odr_strdup(o, wrbuf_cstr(w));
+ wrbuf_cut_right(w_start, 1); /* remove , */
+ *start = odr_strdup(o, wrbuf_cstr(w_start));
}
- wrbuf_destroy(w);
+ if (wrbuf_len(w_sort) > 1)
+ {
+ wrbuf_cut_right(w_sort, 1); /* remove , */
+ *sort = odr_strdup(o, wrbuf_cstr(w_sort));
+ }
+ wrbuf_destroy(w_limit);
+ wrbuf_destroy(w_start);
+ wrbuf_destroy(w_sort);
}
}
else if (o->direction == ODR_DECODE)
{
- const char *cp = *limit;
- *facetList = 0;
- if (cp)
+ WRBUF w = wrbuf_alloc();
+
+ if (*limit)
+ {
+ const char *cp = *limit;
+ int nor = 0;
+ int val = 0;
+ while (sscanf(cp, "%d%n", &val, &nor) >= 1 && nor > 0)
+ {
+ cp += nor;
+ if (*cp == ':') /* field name follows */
+ {
+ char tmp[40];
+ const char *cp0 = ++cp;
+ while (*cp && *cp != ',')
+ cp++;
+ sprintf(tmp, "@attr 3=%d", val);
+ insert_field(w, cp0, cp - cp0, tmp);
+ }
+ if (*cp != ',')
+ break;
+ cp++;
+ }
+ }
+ if (*start)
{
+ const char *cp = *start;
int nor = 0;
- int limit_val = 0;
- WRBUF w = wrbuf_alloc();
- while (sscanf(cp, "%d%n", &limit_val, &nor) >= 1 && nor > 0)
+ int val = 0;
+ while (sscanf(cp, "%d%n", &val, &nor) >= 1 && nor > 0)
{
cp += nor;
- if (wrbuf_len(w))
- wrbuf_puts(w, ",");
if (*cp == ':') /* field name follows */
{
- wrbuf_puts(w, "@attr 1=");
- while (*++cp && *cp != ',')
- wrbuf_putc(w, *cp);
- wrbuf_puts(w, " ");
+ char tmp[40];
+ const char *cp0 = ++cp;
+ while (*cp && *cp != ',')
+ cp++;
+ sprintf(tmp, "@attr 4=%d", val);
+ insert_field(w, cp0, cp - cp0, tmp);
+ }
+ if (*cp != ',')
+ break;
+ cp++;
+ }
+ }
+
+ if (*sort)
+ {
+ const char *cp = *sort;
+ while (1)
+ {
+ int val = 0;
+ const char *cp0 = cp;
+ while (*cp && *cp != ':' && *cp != ',')
+ cp++;
+ if (!strncmp(cp0, "alphanumeric", cp - cp0))
+ val = 1;
+ if (*cp == ':') /* field name follows */
+ {
+ char tmp[40];
+ cp0 = ++cp;
+ while (*cp && *cp != ',')
+ cp++;
+ sprintf(tmp, "@attr 2=%d", val);
+ insert_field(w, cp0, cp - cp0, tmp);
}
- if (limit_val != -1)
- wrbuf_printf(w, "@attr 3=%d", limit_val);
if (*cp != ',')
break;
cp++;
}
- if (wrbuf_len(w))
- *facetList = yaz_pqf_parse_facet_list(o, wrbuf_cstr(w));
- wrbuf_destroy(w);
}
+
+ if (wrbuf_len(w))
+ *facetList = yaz_pqf_parse_facet_list(o, wrbuf_cstr(w));
+ else
+ *facetList = 0;
+ wrbuf_destroy(w);
}
}
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"))
{
add_xsd_string(ptr, "database", req->database);
{
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)
char *maximumTerms = 0;
char *responsePosition = 0;
const char *facetLimit = 0;
+ const char *facetStart = 0;
+ const char *facetSort = 0;
Z_SRW_extra_arg *extra_args = 0;
#endif
char **uri_name;
responsePosition = v;
else if (!strcmp(n, "facetLimit"))
facetLimit = v;
+ else if (!strcmp(n, "facetStart"))
+ facetStart = v;
+ else if (!strcmp(n, "facetSort"))
+ facetSort = v;
else if (!strcmp(n, "extraRequestData"))
; /* ignoring extraRequestData */
else if (n[0] == 'x' && n[1] == '-')
sr->u.request->packing = recordPacking;
sr->u.request->stylesheet = stylesheet;
yaz_sru_facet_request(decode , &sr->u.request->facetList,
- &facetLimit);
+ &facetLimit, &facetStart, &facetSort);
yaz_sru_decode_integer(decode, "maximumRecords", maximumRecords,
&sr->u.request->maximumRecords,
srw_pdu->u.request->resultSetTTL);
{
const char *facetLimit = 0;
+ const char *facetStart = 0;
+ const char *facetSort = 0;
yaz_sru_facet_request(encode, &srw_pdu->u.request->facetList,
- &facetLimit);
+ &facetLimit, &facetStart, &facetSort);
yaz_add_name_value_str(encode, name, value, &i, "facetLimit",
(char *) facetLimit);
+ yaz_add_name_value_str(encode, name, value, &i, "facetStart",
+ (char *) facetStart);
+ yaz_add_name_value_str(encode, name, value, &i, "facetSort",
+ (char *) facetSort);
}
break;
case Z_SRW_explain_request:
attrvalues.limit = 10;
yaz_facet_attr_get_z_attributes(facet_list->elements[index]->attributes,
&attrvalues);
- yaz_log(YLOG_LOG, "Attributes: %s %d ", attrvalues.useattr, attrvalues.limit);
+ yaz_log(YLOG_LOG, "Attributes: %s limit=%d start=%d sort=%d",
+ attrvalues.useattr,
+ attrvalues.limit,
+ attrvalues.start,
+ attrvalues.sortorder);
if (attrvalues.errstring)
yaz_log(YLOG_LOG, "Error parsing attributes: %s", attrvalues.errstring);
if (attrvalues.limit > 0 && attrvalues.useattr) {