Fix elements for which SRU facet NS is applied
[yaz-moved-to-github.git] / src / sru_facet.c
index 69925b4..7703f37 100644 (file)
 #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;
@@ -41,51 +77,132 @@ void yaz_sru_facet_request(ODR o, Z_FacetList **facetList, const char **limit)
                                                 &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 == 0 ? 1 : 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);
     }
 }
 
@@ -102,11 +219,10 @@ void yaz_sru_facet_response(ODR o, Z_FacetList **facetList, xmlNodePtr n)
                 "http://docs.oasis-open.org/ns/search-ws/facetedResults";
             xmlNode *p1 = xmlNewChild(n, 0, BAD_CAST "facetedResults", 0);
             xmlNsPtr ns_fr = xmlNewNs(p1, BAD_CAST ns, BAD_CAST "fr");
-            xmlSetNs(p1, ns_fr);
             for (i = 0; i < fl->num; i++)
             {
                 Z_FacetField *ff = fl->elements[i];
-                xmlNode *p2 = xmlNewChild(p1, 0, BAD_CAST "facet", 0);
+                xmlNode *p2 = xmlNewChild(p1, ns_fr, BAD_CAST "facet", 0);
                 int j;
                 xmlNode *p3;
                 struct yaz_facet_attr av;
@@ -136,7 +252,7 @@ void yaz_sru_facet_response(ODR o, Z_FacetList **facetList, xmlNodePtr n)
 
         fl->num = 0;
         for (p1 = n->children; p1; p1 = p1->next)
-            if (match_element(p1, "facet"))
+            if (yaz_match_xsd_element(p1, "facet"))
                 fl->num++;
         if (fl->num > 0)
         {
@@ -145,7 +261,7 @@ void yaz_sru_facet_response(ODR o, Z_FacetList **facetList, xmlNodePtr n)
             fl->elements = (Z_FacetField **)
                 odr_malloc(o, sizeof(*fl->elements) * fl->num);
             for (p1 = n->children; p1; p1 = p1->next)
-                if (match_element(p1, "facet"))
+                if (yaz_match_xsd_element(p1, "facet"))
                 {
                     char *index_name = 0;
                     xmlNode *p_terms = 0;
@@ -158,9 +274,9 @@ void yaz_sru_facet_response(ODR o, Z_FacetList **facetList, xmlNodePtr n)
                     ff->terms = 0;
                     for (; p2; p2 = p2->next)
                     {
-                        if (match_xsd_string(p2, "index", o, &index_name))
+                        if (yaz_match_xsd_string(p2, "index", o, &index_name))
                             ;
-                        else if (match_element(p2, "terms"))
+                        else if (yaz_match_xsd_element(p2, "terms"))
                             p_terms = p2;
                     }
                     if (index_name)
@@ -196,7 +312,7 @@ void yaz_sru_facet_response(ODR o, Z_FacetList **facetList, xmlNodePtr n)
                         int i = 0;
                         for (p = p_terms->children; p; p = p->next)
                         {
-                            if (match_element(p, "term"))
+                            if (yaz_match_xsd_element(p, "term"))
                                 ff->num_terms++;
                         }
                         if (ff->num_terms)
@@ -205,17 +321,17 @@ void yaz_sru_facet_response(ODR o, Z_FacetList **facetList, xmlNodePtr n)
                                            sizeof(*ff->terms) * ff->num_terms);
                         for (p = p_terms->children; p; p = p->next)
                         {
-                            if (match_element(p, "term"))
+                            if (yaz_match_xsd_element(p, "term"))
                             {
                                 char *cstr = 0;
                                 Odr_int *count = 0;
                                 xmlNode *p2 = p->children;
                                 for (; p2; p2 = p2->next)
                                 {
-                                    if (match_xsd_string(p2, "actualTerm", o,
+                                    if (yaz_match_xsd_string(p2, "actualTerm", o,
                                                          &cstr))
                                         ;
-                                    else if (match_xsd_integer(p2, "count", o,
+                                    else if (yaz_match_xsd_integer(p2, "count", o,
                                                                &count))
                                         ;
                                 }