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

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

Setting macros needed for a second query.

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