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

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

Added ability to combine two independant queries.

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