source: trunk/gsdl/src/recpt/queryaction.cpp@ 400

Last change on this file since 400 was 400, checked in by rjmcnab, 25 years ago

Changed the logic for getting the results string slightly

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 17.9 KB
Line 
1/**********************************************************************
2 *
3 * queryaction.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * PUT COPYRIGHT NOTICE HERE
7 *
8 * $Id: queryaction.cpp 400 1999-07-16 08:33:36Z rjmcnab $
9 *
10 *********************************************************************/
11
12/*
13 $Log$
14 Revision 1.15 1999/07/16 08:33:36 rjmcnab
15 Changed the logic for getting the results string slightly
16
17 Revision 1.14 1999/07/16 03:41:29 sjboddie
18 changed isApprox
19
20 Revision 1.13 1999/07/16 00:19:01 sjboddie
21 some changes to the way quoted queries are handled
22
23 Revision 1.12 1999/07/09 02:17:55 rjmcnab
24 Setting macros needed for a second query.
25
26 Revision 1.11 1999/07/07 06:13:10 rjmcnab
27 Added ability to combine two independant queries.
28
29 Revision 1.10 1999/07/07 05:49:35 sjboddie
30 had another crack at the format string code - created a new formattools
31 module. It can now handle {If} and {Or} statements although there's a
32 bug preventing nested if's and or's.
33
34 Revision 1.9 1999/07/01 22:48:46 sjboddie
35 had a go at getting a query result format string working
36
37 Revision 1.8 1999/06/27 22:02:11 sjboddie
38 author is added to queryresults if there is one
39
40 Revision 1.7 1999/06/26 01:10:18 rjmcnab
41 Made h, i, and n arguments saved in the compressed arguments.
42
43 Revision 1.6 1999/06/24 05:12:25 sjboddie
44 lots of small changes
45
46 Revision 1.5 1999/06/16 04:03:48 sjboddie
47 Now sets "cl" arg to "search" when going to a document from a search
48 results page. This allows the close book icon (in hierarchy toc) to
49 take you back to the results page if that's where you came from.
50 If you got to the document page somehow other than from a
51 classification or a search (i.e. if "cl" isn't set) then the close
52 book icon is disabled
53
54 Revision 1.4 1999/06/16 02:08:38 sjboddie
55 got queryaction working
56
57 Revision 1.3 1999/03/25 03:06:45 sjboddie
58
59 altered receptionist slightly so it now passes *collectproto to
60 define_internal_macros and define_external_macros - need it
61 for browseaction
62
63 Revision 1.2 1999/03/03 20:26:50 rjmcnab
64
65 Modified stuff.
66
67 Revision 1.1 1999/02/28 22:45:21 rjmcnab
68
69 Initial revision.
70
71 */
72
73
74#include "queryaction.h"
75#include "querytools.h"
76#include "formattools.h"
77
78queryaction::queryaction () {
79 // this action uses cgi variable "a"
80 cgiarginfo arg_ainfo;
81 arg_ainfo.shortname = "a";
82 arg_ainfo.longname = "action";
83 arg_ainfo.multiplechar = true;
84 arg_ainfo.defaultstatus = cgiarginfo::weak;
85 arg_ainfo.argdefault = "q";
86 arg_ainfo.savedarginfo = cgiarginfo::must;
87 argsinfo.addarginfo (NULL, arg_ainfo);
88
89 // "h"
90 arg_ainfo.shortname = "h";
91 arg_ainfo.longname = "main index";
92 arg_ainfo.multiplechar = true;
93 arg_ainfo.defaultstatus = cgiarginfo::weak;
94 arg_ainfo.argdefault = "";
95 arg_ainfo.savedarginfo = cgiarginfo::must;
96 argsinfo.addarginfo (NULL, arg_ainfo);
97
98 // "h2"
99 arg_ainfo.shortname = "h2";
100 arg_ainfo.longname = "main index for second query";
101 arg_ainfo.multiplechar = true;
102 arg_ainfo.defaultstatus = cgiarginfo::weak;
103 arg_ainfo.argdefault = "";
104 arg_ainfo.savedarginfo = cgiarginfo::must;
105 argsinfo.addarginfo (NULL, arg_ainfo);
106
107 // "j"
108 arg_ainfo.shortname = "j";
109 arg_ainfo.longname = "sub collection index";
110 arg_ainfo.multiplechar = true;
111 arg_ainfo.defaultstatus = cgiarginfo::weak;
112 arg_ainfo.argdefault = "";
113 arg_ainfo.savedarginfo = cgiarginfo::must;
114 argsinfo.addarginfo (NULL, arg_ainfo);
115
116 // "j2"
117 arg_ainfo.shortname = "j2";
118 arg_ainfo.longname = "sub collection index for second query";
119 arg_ainfo.multiplechar = true;
120 arg_ainfo.defaultstatus = cgiarginfo::weak;
121 arg_ainfo.argdefault = "";
122 arg_ainfo.savedarginfo = cgiarginfo::must;
123 argsinfo.addarginfo (NULL, arg_ainfo);
124
125 // "n"
126 arg_ainfo.shortname = "n";
127 arg_ainfo.longname = "language index";
128 arg_ainfo.multiplechar = true;
129 arg_ainfo.defaultstatus = cgiarginfo::weak;
130 arg_ainfo.argdefault = "";
131 arg_ainfo.savedarginfo = cgiarginfo::must;
132 argsinfo.addarginfo (NULL, arg_ainfo);
133
134 // "n2"
135 arg_ainfo.shortname = "n2";
136 arg_ainfo.longname = "language index for second query";
137 arg_ainfo.multiplechar = true;
138 arg_ainfo.defaultstatus = cgiarginfo::weak;
139 arg_ainfo.argdefault = "";
140 arg_ainfo.savedarginfo = cgiarginfo::must;
141 argsinfo.addarginfo (NULL, arg_ainfo);
142
143 // "q"
144 arg_ainfo.shortname = "q";
145 arg_ainfo.longname = "query string";
146 arg_ainfo.multiplechar = true;
147 arg_ainfo.defaultstatus = cgiarginfo::weak;
148 arg_ainfo.argdefault = "";
149 arg_ainfo.savedarginfo = cgiarginfo::must;
150 argsinfo.addarginfo (NULL, arg_ainfo);
151
152 // "q2"
153 arg_ainfo.shortname = "q2";
154 arg_ainfo.longname = "query string for second query";
155 arg_ainfo.multiplechar = true;
156 arg_ainfo.defaultstatus = cgiarginfo::weak;
157 arg_ainfo.argdefault = "";
158 arg_ainfo.savedarginfo = cgiarginfo::must;
159 argsinfo.addarginfo (NULL, arg_ainfo);
160
161 // "cq2" ""=don't combine, "and", "or", "not"
162 arg_ainfo.shortname = "cq2";
163 arg_ainfo.longname = "combine queries";
164 arg_ainfo.multiplechar = true;
165 arg_ainfo.defaultstatus = cgiarginfo::weak;
166 arg_ainfo.argdefault = "";
167 arg_ainfo.savedarginfo = cgiarginfo::must;
168 argsinfo.addarginfo (NULL, arg_ainfo);
169
170 // "t" - 1 = ranked 0 = boolean
171 arg_ainfo.shortname = "t";
172 arg_ainfo.longname = "search type";
173 arg_ainfo.multiplechar = false;
174 arg_ainfo.defaultstatus = cgiarginfo::weak;
175 arg_ainfo.argdefault = "1";
176 arg_ainfo.savedarginfo = cgiarginfo::must;
177 argsinfo.addarginfo (NULL, arg_ainfo);
178
179 // "k"
180 arg_ainfo.shortname = "k";
181 arg_ainfo.longname = "casefolding";
182 arg_ainfo.multiplechar = false;
183 arg_ainfo.defaultstatus = cgiarginfo::weak;
184 arg_ainfo.argdefault = "1";
185 arg_ainfo.savedarginfo = cgiarginfo::must;
186 argsinfo.addarginfo (NULL, arg_ainfo);
187
188 // "s"
189 arg_ainfo.shortname = "s";
190 arg_ainfo.longname = "stemming";
191 arg_ainfo.multiplechar = false;
192 arg_ainfo.defaultstatus = cgiarginfo::weak;
193 arg_ainfo.argdefault ="0";
194 arg_ainfo.savedarginfo = cgiarginfo::must;
195 argsinfo.addarginfo (NULL, arg_ainfo);
196
197 // "m"
198 arg_ainfo.shortname = "m";
199 arg_ainfo.longname = "maximum number of documents";
200 arg_ainfo.multiplechar = true;
201 arg_ainfo.defaultstatus = cgiarginfo::weak;
202 arg_ainfo.argdefault = "50";
203 arg_ainfo.savedarginfo = cgiarginfo::must;
204 argsinfo.addarginfo (NULL, arg_ainfo);
205
206 // "o"
207 arg_ainfo.shortname = "o";
208 arg_ainfo.longname = "hits per page";
209 arg_ainfo.multiplechar = true;
210 arg_ainfo.defaultstatus = cgiarginfo::weak;
211 arg_ainfo.argdefault = "20";
212 arg_ainfo.savedarginfo = cgiarginfo::must;
213 argsinfo.addarginfo (NULL, arg_ainfo);
214
215 // "r"
216 arg_ainfo.shortname = "r";
217 arg_ainfo.longname = "start results from";
218 arg_ainfo.multiplechar = true;
219 arg_ainfo.defaultstatus = cgiarginfo::weak;
220 arg_ainfo.argdefault = "1";
221 arg_ainfo.savedarginfo = cgiarginfo::must;
222 argsinfo.addarginfo (NULL, arg_ainfo);
223}
224
225void queryaction::configure (const text_t &key, const text_tarray &cfgline) {
226 action::configure (key, cfgline);
227}
228
229bool queryaction::init (ostream &logout) {
230 return action::init (logout);
231}
232
233bool queryaction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
234 ostream &logout) {
235
236 // check t argument
237 int arg_t = args.getintarg("t");
238 if (arg_t != 0 && arg_t != 1) {
239 logout << "Warning: \"t\" argument out of range (" << arg_t << ")\n";
240 cgiarginfo *tinfo = argsinfo.getarginfo ("t");
241 if (tinfo != NULL) args["t"] = tinfo->argdefault;
242 }
243
244 // check k argument
245 int arg_k = args.getintarg("k");
246 if (arg_k != 0 && arg_k != 1) {
247 logout << "Warning: \"k\" argument out of range (" << arg_k << ")\n";
248 cgiarginfo *kinfo = argsinfo.getarginfo ("k");
249 if (kinfo != NULL) args["k"] = kinfo->argdefault;
250 }
251
252 // check s argument
253 int arg_s = args.getintarg("s");
254 if (arg_s != 0 && arg_s != 1) {
255 logout << "Warning: \"s\" argument out of range (" << arg_s << ")\n";
256 cgiarginfo *sinfo = argsinfo.getarginfo ("s");
257 if (sinfo != NULL) args["s"] = sinfo->argdefault;
258 }
259
260 // check m argument
261 int arg_m = args.getintarg("m");
262 if (arg_m < 0) {
263 logout << "Warning: \"m\" argument less than 0 (" << arg_m << ")\n";
264 cgiarginfo *minfo = argsinfo.getarginfo ("m");
265 if (minfo != NULL) args["m"] = minfo->argdefault;
266 }
267
268 // check o argument
269 int arg_o = args.getintarg("o");
270 if (arg_o < 0) {
271 logout << "Warning: \"o\" argument less than 0 (" << arg_o << ")\n";
272 cgiarginfo *oinfo = argsinfo.getarginfo ("o");
273 if (oinfo != NULL) args["o"] = oinfo->argdefault;
274 }
275
276 // check r argument
277 int arg_r = args.getintarg("r");
278 if (arg_r < 1) {
279 logout << "Warning: \"r\" argument less than 1 (" << arg_r << ")\n";
280 cgiarginfo *rinfo = argsinfo.getarginfo ("r");
281 if (rinfo != NULL) args["r"] = rinfo->argdefault;
282 }
283
284 return true;
285}
286
287void queryaction::get_cgihead_info (cgiargsclass &/*args*/, response_t &response,
288 text_t &response_data, ostream &/*logout*/) {
289 response = content;
290 response_data = "text/html";
291}
292
293void queryaction::define_internal_macros (displayclass &disp, cgiargsclass &args,
294 recptproto */*collectproto*/, ostream &/*logout*/) {
295
296 // define_internal_macros doesn't sets the following macros.
297
298 // _quotedquery_ the part of the query string that was quoted for post-processing
299
300
301
302 // The following macros are set later (in define_query_macros) as they can't be set until
303 // the query has been done.
304
305 // _freqmsg_ the term frequency string
306
307 // _resultline_ the "x documents matched the query" string
308
309 // _prevfirst_ these are used when setting up the links to previous/next
310 // _prevlast_ pages of results (_thisfirst_ and _thislast_ are used to set
311 // _nextfirst_ the 'results x-x for query: xxxx' string in the title bar)
312 // _nextlast_
313 // _thisfirst_
314 // _thislast_
315
316
317
318 // get the quoted bits of the query string and set _quotedquery_
319 text_t &arg_q = args["q"];
320 if (!arg_q.empty()) {
321
322 text_t::const_iterator end = arg_q.end();
323 text_t::const_iterator here = findchar (arg_q.begin(), end, '\"');
324 if (here != end) {
325 text_t quotedquery, tmptext;
326 bool first = true;
327 bool foundquote = false;
328 while (here != end) {
329 if (*here == '\"') {
330 if (foundquote) {
331 if (!tmptext.empty()) {
332 if (!first) quotedquery += " and ";
333 else first = false;
334 quotedquery += "\"" + tmptext + "\"";
335 tmptext.clear();
336 }
337 foundquote = false;
338 } else foundquote = true;
339 } else {
340 if (foundquote) tmptext.push_back (*here);
341 }
342 here ++;
343 }
344 disp.setmacro ("quotedquery", "query", quotedquery);
345 }
346 }
347}
348
349// sets the selection box macros _hselection_, _jselection_, and _nselection_.
350// each option will need an _optionxoption_ macro (i.e. an _hselection_ macro
351// with options stx and ptx will need _optionhstx_ and _optionhptx_ macros)
352void queryaction::set_option_macro (const text_t &macroname, text_t current_value,
353 const FilterOption_t &option, displayclass &disp) {
354
355 if (option.validValues.size() < 2) return;
356
357 text_t macrovalue = "<select name=\"" + macroname + "\">\n";
358
359 if (current_value.empty()) current_value = option.defaultValue;
360
361 text_tarray::const_iterator thisvalue = option.validValues.begin();
362 text_tarray::const_iterator endvalue = option.validValues.end();
363
364 while (thisvalue != endvalue) {
365 macrovalue += "<option value=\"" + *thisvalue + "\"";
366 if (*thisvalue == current_value)
367 macrovalue += " selected";
368 macrovalue += ">_option" + macroname + *thisvalue + "_\n";
369 thisvalue ++;
370 }
371 macrovalue += "</select>\n";
372 disp.setmacro (macroname + "selection", "Global", macrovalue);
373}
374
375void queryaction::define_external_macros (displayclass &disp, cgiargsclass &args,
376 recptproto *collectproto, ostream &logout) {
377
378 // define_external_macros sets the following macros:
379
380 // some or all of these may not be required to be set
381 // _hselection_, _h2selection_ the selection box for the main part of the index
382 // _jselection_, _j2selection_ the selection box for the subcollection part of the index
383 // _nselection_, _n2selection_ the selection box for the language part of the index
384 // _cq2selection the selection box for combining two queries
385
386
387 // can't do anything if collectproto is null (i.e. no collection was specified)
388 if (collectproto == NULL) return;
389
390 comerror_t err;
391 InfoFilterOptionsResponse_t response;
392 InfoFilterOptionsRequest_t request;
393 request.filterName = "QueryFilter";
394
395 collectproto->get_filteroptions (args["c"], request, response, err, logout);
396 if (err == noError) {
397
398 FilterOption_tmap::const_iterator it;
399 FilterOption_tmap::const_iterator end = response.filterOptions.end();
400
401 // _hselection_ and _h2selection_ (Index)
402 it = response.filterOptions.find ("Index");
403 if (it != end) set_option_macro ("h", args["h"], (*it).second, disp);
404 if (it != end) set_option_macro ("h2", args["h2"], (*it).second, disp);
405
406 // _jselection_ and _j2selection_ (Subcollection)
407 it = response.filterOptions.find ("Subcollection");
408 if (it != end) set_option_macro ("j", args["j"], (*it).second, disp);
409 if (it != end) set_option_macro ("j2", args["j2"], (*it).second, disp);
410
411 // _nselection_ and _n2selection_ (Language)
412 it = response.filterOptions.find ("Language");
413 if (it != end) set_option_macro ("n", args["n"], (*it).second, disp);
414 if (it != end) set_option_macro ("n2", args["n2"], (*it).second, disp);
415
416 // _cq2selection_ (CombineQuery)
417 it = response.filterOptions.find ("CombineQuery");
418 if (it != end) set_option_macro ("cq2", args["cq2"], (*it).second, disp);
419 }
420}
421
422bool queryaction::do_action (cgiargsclass &args, recptproto *collectproto,
423 displayclass &disp, outconvertclass &outconvert,
424 ostream &textout, ostream &logout) {
425
426 // if we have no format string see if the collection server has one
427 if (formatstring.empty()) {
428 ColInfoResponse_t collectinfo;
429 comerror_t err;
430 collectproto->get_collectinfo (args["c"], collectinfo, err, logout);
431 if (err == noError) {
432 text_tmap::const_iterator result = collectinfo.format.find("result");
433 if (result != collectinfo.format.end())
434 formatstring = (*result).second;
435 }
436 }
437 // if we still don't have a format string use the default
438 if (formatstring.empty())
439 formatstring = "<td valign=top nowrap>[link]_icontext_[/link]</td><td>[Title]</td>";
440
441 if (collectproto == NULL) {
442 logout << "queryaction::do_action called with NULL collectproto\n";
443 textout << outconvert << disp << "_query:header_\n"
444 << "Error: Attempt to do query without setting collection\n"
445 << "_query:footer_\n";
446 } else {
447
448 FilterRequest_t request;
449 FilterResponse_t response;
450 format_t *formatlistptr = new format_t();
451
452 parse_formatstring (formatstring, formatlistptr, request.fields, request.getParents);
453
454 // do the query
455 request.filterResultOptions = FROID | FRmetadata | FRtermFreq;
456 if (!do_query (request, args, collectproto, response, logout))
457 return false;
458
459 // set macros
460 define_query_macros (args, disp, response);
461
462 // output the header
463 textout << outconvert << disp << "_query:header_\n"
464 << "_query:content_";
465
466 // output the results
467 textout << "<table cellspacing=4>\n";
468 ResultDocInfo_tarray::const_iterator this_doc = response.docInfo.begin();
469 ResultDocInfo_tarray::const_iterator end_doc = response.docInfo.end();
470
471 while (this_doc != end_doc) {
472 textout << outconvert << disp << "<tr>\n"
473
474 // << "<td valign=top nowrap>r: " << (*this_doc).ranking
475 // << " t: " << (*this_doc).num_terms_matched << " p: "
476 // << (*this_doc).num_phrase_match << "</td>\n"
477
478 << get_formatted_string (*this_doc, formatlistptr) << "\n"
479 << "</tr>\n";
480 this_doc ++;
481 }
482 textout << "</table>\n";
483
484 delete (formatlistptr);
485
486 // output the footer
487 textout << outconvert << disp << "_query:footer_";
488 }
489
490 return true;
491}
492
493// define_query_macros sets the macros that couldn't be set until the
494// query had been done. Those macros are _freqmsg_, _quotedquery_,
495// _resultline_, _nextfirst_, _nextlast_, _prevfirst_, _prevlast_,
496// _thisfirst_, and _thislast_
497void queryaction::define_query_macros (cgiargsclass &args, displayclass &disp,
498 const FilterResponse_t &response) {
499 // set up _freqmsg_ and _quotedquery_ macros
500 text_t freqmsg = "_textfreqmsg1_";
501 TermInfo_tarray::const_iterator this_term = response.termInfo.begin();
502 TermInfo_tarray::const_iterator end_term = response.termInfo.end();
503 while (this_term != end_term) {
504 freqmsg += (*this_term).term + ": " + (*this_term).freq;
505 if ((this_term + 1) != end_term)
506 freqmsg += ", ";
507 this_term ++;
508 }
509
510 disp.setmacro ("freqmsg", "query", freqmsg);
511
512
513 // set up _resultline_ macro
514 text_t resline;
515 int maxdocs = args.getintarg("m");
516 int numdocs = response.numDocs;
517 if (response.isApprox == MoreThan && numdocs > maxdocs) numdocs = maxdocs;
518
519 if (response.isApprox == Approximate) resline = "_textapprox_";
520 else if (response.isApprox == MoreThan) resline = "_textmorethan_";
521
522 if (numdocs == 0) resline = "_textnodocs_";
523 else if (numdocs == 1) resline += "_text1doc_";
524 else resline += text_t(numdocs) + " _textlotsdocs_";
525
526 disp.setmacro("resultline", "query", resline);
527
528
529 int firstdoc = args.getintarg("r");
530 int hitsperpage = args.getintarg("o");
531
532 // set up _thisfirst_ and _thislast_ macros
533 disp.setmacro ("thisfirst", "query", firstdoc);
534 int thislast = firstdoc + (hitsperpage - 1);
535 if (thislast > numdocs) thislast = numdocs;
536 disp.setmacro ("thislast", "query", thislast);
537
538 // set up _prevfirst_ and _prevlast_ macros
539 if (firstdoc > 1) {
540 disp.setmacro ("prevlast", "query", firstdoc - 1);
541 int prevfirst = firstdoc - hitsperpage;
542 if (prevfirst < 1) prevfirst = 1;
543 disp.setmacro ("prevfirst", "query", prevfirst);
544 }
545
546 // set up _nextfirst_ and _nextlast_ macros
547 if (thislast < numdocs) {
548 disp.setmacro ("nextfirst", "query", thislast + 1);
549 int nextlast = thislast + hitsperpage;
550 if (nextlast > numdocs) nextlast = numdocs;
551 disp.setmacro ("nextlast", "query", nextlast);
552 }
553}
554
555
556
Note: See TracBrowser for help on using the repository browser.