Fix: Work-around since zoom-sru handle_srw_response does not work with zero-based...
[yaz-moved-to-github.git] / src / solr.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2010 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file srwutil.c
7  * \brief Implements SRW/SRU utilities.
8  */
9
10 #include <stdlib.h>
11 #include <assert.h>
12 #include <yaz/srw.h>
13 #include <yaz/matchstr.h>
14 #include <yaz/yaz-iconv.h>
15 #include <yaz/log.h>
16
17 #include "sru-p.h"
18
19 #if YAZ_HAVE_XML2
20 #include <libxml/parser.h>
21 #include <libxml/tree.h>
22 #endif
23
24 int yaz_solr_decode_response(ODR o, Z_HTTP_Response *hres, Z_SRW_PDU **pdup)
25 {
26 #if YAZ_HAVE_XML2
27     const char *content_buf = hres->content_buf;
28     int content_len = hres->content_len;
29     xmlDocPtr doc = xmlParseMemory(content_buf, content_len);
30     int ret = 0;
31     xmlNodePtr ptr = 0;
32     Odr_int start = 0;
33     Z_SRW_PDU *pdu = yaz_srw_get(o, Z_SRW_searchRetrieve_response);
34     Z_SRW_searchRetrieveResponse *sr = pdu->u.response;
35
36     if (!doc)
37     {
38         ret = -1;
39     }
40     if (doc)
41     {
42         xmlNodePtr root = xmlDocGetRootElement(doc);
43         if (!root)
44         {
45             ret = -1;
46         }
47         else if (strcmp((const char *) root->name, "response"))
48         {
49             ret = -1;
50         }
51         else
52         {
53             /** look for result node */
54             for (ptr = root->children; ptr; ptr = ptr->next)
55             {
56                 if (ptr->type == XML_ELEMENT_NODE &&
57                     !strcmp((const char *) ptr->name, "result"))
58                     break;
59             }
60             if (!ptr)
61             {
62                 ret = -1;
63             }
64         }
65     }
66     if (ptr)
67     {   /* got result node */
68         struct _xmlAttr *attr;
69
70         for (attr = ptr->properties; attr; attr = attr->next)
71             if (attr->children && attr->children->type == XML_TEXT_NODE)
72             {
73                 if (!strcmp((const char *) attr->name, "numFound"))
74                 {
75                     sr->numberOfRecords =
76                         odr_intdup(o, 
77                                    odr_atoi(
78                                        (const char *) attr->children->content));
79                     yaz_log(YLOG_DEBUG, "SOLR total results: %d ", atoi( attr->children->content));
80                 }
81                 else if (!strcmp((const char *) attr->name, "start"))
82                 {
83                     start = odr_atoi((const char *) attr->children->content);
84                     yaz_log(YLOG_DEBUG, "SOLR start: %d ", atoi( attr->children->content));
85                 }
86             }
87     }
88     if (ptr)
89     {
90         xmlNodePtr node;
91         int offset = 0;
92         int i = 0;
93
94         sr->num_records = 0;
95         for (node = ptr->children; node; node = node->next)
96             if (node->type == XML_ELEMENT_NODE)
97                 sr->num_records++;
98         yaz_log(YLOG_DEBUG, "SOLR results in response: %d ", sr->num_records);
99
100         sr->records = odr_malloc(o, sizeof(*sr->records) * sr->num_records);
101
102         for (node = ptr->children; node; node = node->next)
103         {
104             if (node->type == XML_ELEMENT_NODE)
105             {
106                 Z_SRW_record *record = sr->records + i;
107                 xmlBufferPtr buf = xmlBufferCreate();
108                 xmlNode *tmp = xmlCopyNode(node, 1);
109
110                 xmlNodeDump(buf, tmp->doc, tmp, 0, 0);
111
112                 xmlFreeNode(tmp);
113
114                 record->recordSchema = 0;
115                 record->recordPacking = Z_SRW_recordPacking_XML;
116                 record->recordData_len = buf->use;
117                 record->recordData_buf = odr_malloc(o, buf->use + 1);
118                 memcpy(record->recordData_buf, buf->content, buf->use);
119                 record->recordData_buf[buf->use] = '\0';
120                 // TODO Solve the real problem: Making the recordPosition 1-based due to "funny" code in zoom-sru
121                 record->recordPosition = odr_intdup(o, start + offset + 1);
122                 yaz_log(YLOG_DEBUG, "SOLR pos=" ODR_INT_PRINTF, *record->recordPosition);
123
124                 xmlBufferFree(buf);
125
126                 offset++;
127                 i++;
128             }
129         }
130     }
131     if (doc)
132         xmlFreeDoc(doc);
133     if (ret == 0)
134         *pdup = pdu;
135     return ret;
136 #else
137     return -1;
138 #endif
139 }
140
141 int yaz_solr_encode_request(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
142                             ODR encode, const char *charset)
143 {
144     const char *solr_op = 0;
145     char *name[30], *value[30];
146     char *uri_args;
147     char *path;
148     int i = 0;
149
150     z_HTTP_header_add_basic_auth(encode, &hreq->headers, 
151                                  srw_pdu->username, srw_pdu->password);
152
153     switch (srw_pdu->which)
154     {
155     case Z_SRW_searchRetrieve_request:
156         solr_op = "select";
157         
158         switch(srw_pdu->u.request->query_type)
159         {
160         case Z_SRW_query_type_pqf:
161             yaz_add_name_value_str(encode, name, value, &i,
162                                    "q", srw_pdu->u.request->query.pqf);
163             break;
164         case Z_SRW_query_type_cql:
165             yaz_add_name_value_str(encode, name, value, &i,
166                                    "q", srw_pdu->u.request->query.cql);
167             break;
168         default:
169             return -1;
170         }
171         if (srw_pdu->u.request->startRecord)
172         {
173             Odr_int start = *srw_pdu->u.request->startRecord - 1;
174             yaz_add_name_value_int(encode, name, value, &i,
175                                    "start", &start);
176         }
177         yaz_add_name_value_int(encode, name, value, &i,
178                                "rows", srw_pdu->u.request->maximumRecords);
179         yaz_add_name_value_str(encode, name, value, &i,
180                                "fl", srw_pdu->u.request->recordSchema);
181         break;
182     default:
183         return -1;
184     }
185     name[i] = 0;
186     yaz_array_to_uri(&uri_args, encode, name, value);
187     
188     hreq->method = "GET";
189     
190     path = (char *)
191         odr_malloc(encode, strlen(hreq->path) +
192                    strlen(uri_args) + strlen(solr_op) + 4);
193
194     sprintf(path, "%s/%s?%s", hreq->path, solr_op, uri_args);
195     hreq->path = path;
196
197     z_HTTP_header_add_content_type(encode, &hreq->headers,
198                                    "text/xml", charset);
199     return 0;
200 }
201
202
203 /*
204  * Local variables:
205  * c-basic-offset: 4
206  * c-file-style: "Stroustrup"
207  * indent-tabs-mode: nil
208  * End:
209  * vim: shiftwidth=4 tabstop=8 expandtab
210  */
211