source: trunk/gsdl/src/recpt/formattools.cpp@ 13017

Last change on this file since 13017 was 12567, checked in by kjdon, 18 years ago

changed the special metadata formatting for Language and Date. Now these both output macros rather than a final result. Language codes get turned into _iso639:iso639xx_, dates (yyyy-?mm-?dd) get turned into _format:date_(yyyy,mm,dd). This is now controlled by a new option for metadata names [format:Date]. Without this, Dates and Languages get output as raw text. format must coma after cgiSafe and before parent/sibling/child. If its used with a different metadata name, eg [format:dc.Title] the output will be _format:dc.Title_(title value), and the user can define _dc.Title_ macro in format package to handle it.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 46.5 KB
Line 
1/**********************************************************************
2 *
3 * formattools.cpp --
4 * Copyright (C) 1999 The New Zealand Digital Library Project
5 *
6 * A component of the Greenstone digital library software
7 * from the New Zealand Digital Library Project at the
8 * University of Waikato, New Zealand.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "formattools.h"
27#include "cgiutils.h"
28#include "OIDtools.h"
29#include "summarise.h"
30
31#include <assert.h>
32
33// a few function prototypes
34
35static text_t format_string (const text_t& collection, recptproto* collectproto,
36 ResultDocInfo_t &docinfo, displayclass &disp,
37 format_t *formatlistptr, text_tmap &options,
38 ostream& logout);
39
40static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end,
41 format_t *formatlistptr, text_tset &metadata, bool &getParents);
42
43static text_t format_summary (const text_t& collection, recptproto* collectproto,
44 ResultDocInfo_t &docinfo, displayclass &disp,
45 text_tmap &options, ostream& logout);
46static text_t format_text (const text_t& collection, recptproto* collectproto,
47 ResultDocInfo_t &docinfo, displayclass &disp,
48 text_tmap &options, ostream& logout);
49
50static text_t expand_metadata(const text_t &metavalue, const text_t& collection,
51 recptproto* collectproto, ResultDocInfo_t &docinfo,
52 displayclass &disp, text_tmap &options,
53 ostream &logout);
54
55
56void metadata_t::clear() {
57 metaname.clear();
58 metacommand = mNone;
59 mqualifier.parent = pNone;
60 mqualifier.sibling = sNone;
61 mqualifier.child = cNone;
62 parentoptions.clear();
63 siblingoptions.clear();
64 childoptions.clear();
65}
66
67void decision_t::clear() {
68 command = dMeta;
69 meta.clear();
70 text.clear();
71}
72
73void format_t::clear() {
74 command = comText;
75 decision.clear();
76 text.clear();
77 meta.clear();
78 nextptr = NULL;
79 ifptr = NULL;
80 elseptr = NULL;
81 orptr = NULL;
82}
83
84void formatinfo_t::clear() {
85 DocumentImages = false;
86 DocumentTitles = true;
87 DocumentHeading = "{Or}{[parent(Top):Title],[Title],untitled}<br>";
88 DocumentContents = true;
89 DocumentArrowsBottom = true;
90 DocumentArrowsTop = false;
91 DocumentButtons.erase (DocumentButtons.begin(), DocumentButtons.end());
92 // DocumentButtons.push_back ("Expand Text");
93 // DocumentButtons.push_back ("Expand Contents");
94 DocumentButtons.push_back ("Detach");
95 DocumentButtons.push_back ("Highlight");
96 RelatedDocuments = "";
97 DocumentText = "[Text]";
98 formatstrings.erase (formatstrings.begin(), formatstrings.end());
99 DocumentUseHTML = false;
100 AllowExtendedOptions = false;
101}
102
103// simply checks to see if formatstring begins with a <td> tag
104bool is_table_content (const text_t &formatstring) {
105 text_t::const_iterator here = formatstring.begin();
106 text_t::const_iterator end = formatstring.end();
107
108 while (here != end) {
109 if (*here != ' ') {
110 if ((*here == '<') && ((here+3) < end)) {
111 if ((*(here+1) == 't' || *(here+1) == 'T') &&
112 (*(here+2) == 'd' || *(here+2) == 'D') &&
113 (*(here+3) == '>' || *(here+3) == ' '))
114 return true;
115 } else return false;
116 }
117 ++here;
118 }
119 return false;
120}
121
122bool is_table_content (const format_t *formatlistptr) {
123
124 if (formatlistptr == NULL) return false;
125
126 if (formatlistptr->command == comText)
127 return is_table_content (formatlistptr->text);
128
129 return false;
130}
131
132// returns false if key isn't in formatstringmap
133bool get_formatstring (const text_t &key, const text_tmap &formatstringmap,
134 text_t &formatstring) {
135
136 formatstring.clear();
137 text_tmap::const_iterator it = formatstringmap.find(key);
138 if (it == formatstringmap.end()) return false;
139 formatstring = (*it).second;
140 return true;
141}
142
143// tries to find "key1key2" then "key1" then "key2"
144bool get_formatstring (const text_t &key1, const text_t &key2,
145 const text_tmap &formatstringmap,
146 text_t &formatstring) {
147
148 formatstring.clear();
149 text_tmap::const_iterator it = formatstringmap.find(key1 + key2);
150 if (it != formatstringmap.end()) {
151 formatstring = (*it).second;
152 return true;
153 }
154 it = formatstringmap.find(key1);
155 if (it != formatstringmap.end()) {
156 formatstring = (*it).second;
157 return true;
158 }
159 it = formatstringmap.find(key2);
160 if (it != formatstringmap.end()) {
161 formatstring = (*it).second;
162 return true;
163 }
164 return false;
165}
166
167
168text_t remove_namespace(const text_t &meta_name) {
169 text_t::const_iterator end = meta_name.end();
170 text_t::const_iterator it = findchar(meta_name.begin(), end, '.');
171 if (it != end) {
172 return substr(it+1, end);
173 }
174
175 return meta_name;
176
177}
178// returns a date of form _format:date_(year, month, day)
179// input is date of type yyyy-?mm-?dd
180// at least the year must be present in date
181text_t format_date (const text_t &date) {
182
183 if (date.size() < 4) return "";
184
185 text_t::const_iterator datebegin = date.begin();
186
187 text_t year = substr (datebegin, datebegin+4);
188 int chars_seen_so_far = 4;
189
190 if (date[chars_seen_so_far] == '-') ++chars_seen_so_far ;
191 if (date.size() < chars_seen_so_far+2) return "_format:date_("+year+")";
192
193 text_t month = substr (datebegin+chars_seen_so_far, datebegin+chars_seen_so_far+2);
194 int imonth = month.getint();
195 if (imonth <= 0 || imonth > 12) return "_format:date_("+year+")";
196
197 chars_seen_so_far += 2;
198 if (date[chars_seen_so_far] == '-') ++chars_seen_so_far ;
199
200 if (date.size() < chars_seen_so_far+2) return "_format:date_("+year+","+month+")";
201
202 text_t day = substr (datebegin+chars_seen_so_far, datebegin+chars_seen_so_far+2);
203 if (day[0] == '0') day = substr (day.begin()+1, day.end());
204 int iday = day.getint();
205 if (iday <= 0 || iday > 31) return "_format:date_("+year+","+month+")";
206
207 return "_format:date_("+year+","+month+","+day+")";
208}
209
210// converts an iso639 language code to its English equivalent
211// should we be checking that the macro exists??
212text_t iso639 (const text_t &langcode) {
213 if (langcode.empty()) return "";
214 return "_iso639:iso639"+langcode+"_";
215}
216
217
218text_t get_href (const text_t &link) {
219
220 text_t href;
221
222 text_t::const_iterator here = findchar(link.begin(), link.end(), '"');
223 text_t::const_iterator end = link.end();
224
225 ++here;
226 while (here != end) {
227 if (*here == '"') break;
228 href.push_back(*here);
229 ++here;
230 }
231
232 return href;
233}
234
235//this function gets the information associated with the relation
236//metadata for the document associated with 'docinfo'. This relation
237//metadata consists of a line of pairs containing 'collection, document OID'
238//(this is the OID of the document related to the current document, and
239//the collection the related document belongs to). For each of these pairs
240//the title metadata is obtained and then an html link between the title
241//of the related doc and the document's position (the document will be
242//found in "<a href=\"_httpdocument_&c=collection&cl=search&d=OID">
243//(where collection is the related documents collection, and OID is the
244//related documents OID). A list of these html links are made for as many
245//related documents as there are. This list is then returned. If there are
246//no related documents available for the current document then the string
247//'.. no related documents .. ' is returned.
248text_t get_related_docs(const text_t& collection, recptproto* collectproto,
249 ResultDocInfo_t &docinfo, ostream& logout){
250
251 text_tset metadata;
252
253 //insert the metadata we wish to collect
254 metadata.insert("dc.Relation");
255 metadata.insert("Title");
256 metadata.insert("Subject"); //for emails, where title data doesn't apply
257
258 FilterResponse_t response;
259 text_t relation = ""; //string for displaying relation metadata
260 text_t relationTitle = ""; //the related documents Title (or subject)
261 text_t relationOID = ""; //the related documents OID
262
263 //get the information associated with the metadata for current doc
264 if (get_info (docinfo.OID, collection, "", metadata,
265 false, collectproto, response, logout)) {
266
267 //if the relation metadata exists, store for displaying
268 if(!response.docInfo[0].metadata["dc.Relation"].values.empty()){
269 relationOID += response.docInfo[0].metadata["dc.Relation"].values[0];
270
271 //split relation data into pairs of collectionname,ID number
272 text_tarray relationpairs;
273 splitchar (relationOID.begin(), relationOID.end(), ' ', relationpairs);
274
275 text_tarray::const_iterator currDoc = relationpairs.begin();
276 text_tarray::const_iterator lastDoc = relationpairs.end();
277
278 //iterate through the pairs to split and display
279 while(currDoc != lastDoc){
280
281 //split pairs into collectionname and ID
282 text_tarray relationdata;
283 splitchar ((*currDoc).begin(), (*currDoc).end(), ',', relationdata);
284
285 //get first element in the array (collection)
286 text_tarray::const_iterator doc_data = relationdata.begin();
287 text_t document_collection = *doc_data;
288 ++doc_data; //increment to get next item in array (oid)
289 text_t document_OID = *doc_data;
290
291 //create html link to related document
292 relation += "<a href=\"_httpdocument_&c=" + document_collection;
293 relation += "&cl=search&d=" + document_OID;
294
295 //get the information associated with the metadata for related doc
296 if (get_info (document_OID, document_collection, "", metadata,
297 false, collectproto, response, logout)) {
298
299 //if title metadata doesn't exist, collect subject metadata
300 //if that doesn't exist, just call it 'related document'
301 if (!response.docInfo[0].metadata["Title"].values[0].empty())
302 relationTitle = response.docInfo[0].metadata["Title"].values[0];
303 else if (!response.docInfo[0].metadata["Subject"].values.empty())
304 relationTitle = response.docInfo[0].metadata["Subject"].values[0];
305 else relationTitle = "RELATED DOCUMENT";
306
307 }
308
309 //link the related document's title to its page
310 relation += "\">" + relationTitle + "</a>";
311 relation += " (" + document_collection + ")<br>";
312
313 ++currDoc;
314 }
315 }
316
317 }
318
319 if(relation.empty()) //no relation data for documnet
320 relation = ".. no related documents .. ";
321
322 return relation;
323}
324
325
326
327static void get_parent_options (text_t &instring, metadata_t &metaoption) {
328
329 assert (instring.size() > 7);
330 if (instring.size() <= 7) return;
331
332 text_t meta, com, op;
333 bool inbraces = false;
334 bool inquotes = false;
335 bool foundcolon = false;
336 text_t::const_iterator here = instring.begin()+6;
337 text_t::const_iterator end = instring.end();
338 while (here != end) {
339 if (foundcolon) meta.push_back (*here);
340 else if (*here == '(') inbraces = true;
341 else if (*here == ')') inbraces = false;
342 else if (*here == '\'' && !inquotes) inquotes = true;
343 else if (*here == '\'' && inquotes) inquotes = false;
344 else if (*here == ':' && !inbraces) foundcolon = true;
345 else if (inquotes) op.push_back (*here);
346 else com.push_back (*here);
347 ++here;
348 }
349
350 instring = meta;
351 if (com.empty())
352 metaoption.mqualifier.parent = pImmediate;
353 else if (com == "Top")
354 metaoption.mqualifier.parent = pTop;
355 else if (com == "All") {
356 metaoption.mqualifier.parent = pAll;
357 metaoption.parentoptions = op;
358 }
359}
360
361
362static void get_sibling_options (text_t &instring, metadata_t &metaoption) {
363
364 assert (instring.size() > 8);
365 if (instring.size() <= 8) return;
366 text_t meta, com, op;
367 bool inbraces = false;
368 bool inquotes = false;
369 bool foundcolon = false;
370 text_t::const_iterator here = instring.begin()+7;
371 text_t::const_iterator end = instring.end();
372 while (here != end) {
373 if (foundcolon) meta.push_back (*here);
374 else if (*here == '(') inbraces = true;
375 else if (*here == ')') inbraces = false;
376 else if (*here == '\'' && !inquotes) inquotes = true;
377 else if (*here == '\'' && inquotes) inquotes = false;
378 else if (*here == ':' && !inbraces) foundcolon = true;
379 else if (inquotes) op.push_back (*here);
380 else com.push_back (*here);
381 ++here;
382 }
383
384 instring = meta;
385 metaoption.siblingoptions.clear();
386
387 if (com.empty()) {
388 metaoption.mqualifier.sibling = sAll;
389 metaoption.siblingoptions = " ";
390 }
391 else if (com == "first") {
392 metaoption.mqualifier.sibling = sNum;
393 metaoption.siblingoptions = "0";
394 }
395 else if (com == "last") {
396 metaoption.mqualifier.sibling = sNum;
397 metaoption.siblingoptions = "-2"; // == last
398 }
399 else if (com.getint()>0) {
400 metaoption.mqualifier.sibling = sNum;
401 int pos = com.getint()-1;
402 metaoption.siblingoptions +=pos;
403 }
404 else {
405 metaoption.mqualifier.sibling = sAll;
406 metaoption.siblingoptions = op;
407 }
408}
409
410static void get_child_options (text_t &instring, metadata_t &metaoption) {
411
412 assert (instring.size() > 6);
413 if (instring.size() <= 6) return;
414 text_t meta, com, op;
415 bool inbraces = false;
416 bool inquotes = false;
417 bool foundcolon = false;
418 text_t::const_iterator here = instring.begin()+5;
419 text_t::const_iterator end = instring.end();
420 while (here != end) {
421 if (foundcolon) meta.push_back (*here);
422 else if (*here == '(') inbraces = true;
423 else if (*here == ')') inbraces = false;
424 else if (*here == '\'' && !inquotes) inquotes = true;
425 else if (*here == '\'' && inquotes) inquotes = false;
426 else if (*here == ':' && !inbraces) foundcolon = true;
427 else if (inquotes) op.push_back (*here);
428 else com.push_back (*here);
429 ++here;
430 }
431
432 instring = meta;
433 if (com.empty()) {
434 metaoption.mqualifier.child = cAll;
435 metaoption.childoptions = " ";
436 }
437 else if (com == "first") {
438 metaoption.mqualifier.child = cNum;
439 metaoption.childoptions = ".fc";
440 }
441 else if (com == "last") {
442 metaoption.mqualifier.child = cNum;
443 metaoption.childoptions = ".lc";
444 }
445 else if (com.getint()>0) {
446 metaoption.mqualifier.child = cNum;
447 metaoption.childoptions = "."+com;
448 }
449 else {
450 metaoption.mqualifier.child = cAll;
451 metaoption.childoptions = op;
452 }
453}
454
455
456
457static void parse_meta (text_t &meta, metadata_t &metaoption,
458 text_tset &metadata, bool &getParents) {
459
460 if (meta.size() > 8 && (substr(meta.begin(), meta.begin()+8) == "cgisafe:")) {
461 metaoption.metacommand |= mCgiSafe;
462 meta = substr (meta.begin()+8, meta.end());
463 }
464 if (meta.size() > 7 && (substr(meta.begin(), meta.begin()+7) == "format:")) {
465 metaoption.metacommand |= mSpecial;
466 meta = substr (meta.begin()+7, meta.end());
467 }
468
469 if (meta.size() > 7 && (substr (meta.begin(), meta.begin()+6) == "parent")) {
470 getParents = true;
471 metaoption.metacommand |= mParent;
472 get_parent_options (meta, metaoption);
473 }
474 else if (meta.size() > 6 && (substr (meta.begin(), meta.begin()+5) == "child")) {
475 metaoption.metacommand |= mChild;
476 get_child_options (meta, metaoption);
477 metadata.insert("contains");
478 }
479 // parent and child can have sibling also
480 if (meta.size() > 8 && (substr (meta.begin(), meta.begin()+7) == "sibling")) {
481 metaoption.metacommand |= mSibling;
482 get_sibling_options (meta, metaoption);
483 }
484
485 // check for ex. which may occur in format statements
486 if (meta.size()>3 && (substr(meta.begin(), meta.begin()+3) == "ex.")) {
487 meta = substr (meta.begin()+3, meta.end());
488 }
489 metadata.insert (meta);
490 metaoption.metaname = meta;
491}
492
493static void parse_coll_meta(text_t &meta, metadata_t &metaoption) {
494 if (meta == "collection") {
495 // no qualifiers
496 metaoption.metaname = g_EmptyText;
497 return;
498 }
499 meta = substr (meta.begin()+11, meta.end());
500 metaoption.metaname = meta;
501
502}
503
504static void parse_meta (text_t &meta, format_t *formatlistptr,
505 text_tset &metadata, bool &getParents) {
506
507 if (meta == "link")
508 formatlistptr->command = comLink;
509 else if (meta == "/link")
510 formatlistptr->command = comEndLink;
511
512 else if (meta == "href")
513 formatlistptr->command = comHref;
514
515 else if (meta == "num")
516 formatlistptr->command = comNum;
517
518 else if (meta == "icon")
519 formatlistptr->command = comIcon;
520
521 else if (meta == "Text")
522 formatlistptr->command = comDoc;
523
524 else if (meta == "RelatedDocuments")
525 formatlistptr->command = comRel;
526
527 else if (meta == "highlight")
528 formatlistptr->command = comHighlight;
529
530 else if (meta == "/highlight")
531 formatlistptr->command = comEndHighlight;
532
533 else if (meta == "Summary")
534 formatlistptr->command = comSummary;
535
536 else if (meta == "DocImage")
537 formatlistptr->command = comImage;
538
539 else if (meta == "DocTOC")
540 formatlistptr->command = comTOC;
541
542 else if (meta == "DocumentButtonDetach")
543 formatlistptr->command = comDocumentButtonDetach;
544
545 else if (meta == "DocumentButtonHighlight")
546 formatlistptr->command = comDocumentButtonHighlight;
547
548 else if (meta == "DocumentButtonExpandContents")
549 formatlistptr->command = comDocumentButtonExpandContents;
550
551 else if (meta == "DocumentButtonExpandText")
552 formatlistptr->command = comDocumentButtonExpandText;
553
554 else if (meta == "DocOID")
555 formatlistptr->command = comOID;
556 else if (meta == "DocRank")
557 formatlistptr->command = comRank;
558 else if (meta.size() >= 10 && (substr(meta.begin(), meta.begin()+10) == "collection")) {
559 formatlistptr->command = comCollection;
560 parse_coll_meta(meta, formatlistptr->meta);
561 }
562 else {
563 formatlistptr->command = comMeta;
564 parse_meta (meta, formatlistptr->meta, metadata, getParents);
565 }
566}
567
568
569static bool parse_string (const text_t &formatstring, format_t *formatlistptr,
570 text_tset &metadata, bool &getParents) {
571
572 text_t text;
573 text_t::const_iterator here = formatstring.begin();
574 text_t::const_iterator end = formatstring.end();
575
576 while (here != end) {
577
578 if (*here == '\\') {
579 ++here;
580 if (here != end) text.push_back (*here);
581
582 } else if (*here == '{') {
583 if (!text.empty()) {
584 formatlistptr->command = comText;
585 formatlistptr->text = text;
586 formatlistptr->nextptr = new format_t();
587 formatlistptr = formatlistptr->nextptr;
588
589 text.clear();
590 }
591 if (parse_action (++here, end, formatlistptr, metadata, getParents)) {
592
593 formatlistptr->nextptr = new format_t();
594 formatlistptr = formatlistptr->nextptr;
595 if (here == end) break;
596 }
597 } else if (*here == '[') {
598 if (!text.empty()) {
599 formatlistptr->command = comText;
600 formatlistptr->text = text;
601 formatlistptr->nextptr = new format_t();
602 formatlistptr = formatlistptr->nextptr;
603
604 text.clear();
605 }
606 text_t meta;
607 ++here;
608 while (*here != ']') {
609 if (here == end) return false;
610 meta.push_back (*here);
611 ++here;
612 }
613 parse_meta (meta, formatlistptr, metadata, getParents);
614 formatlistptr->nextptr = new format_t();
615 formatlistptr = formatlistptr->nextptr;
616
617 } else
618 text.push_back (*here);
619
620 if (here != end) ++here;
621 }
622 if (!text.empty()) {
623 formatlistptr->command = comText;
624 formatlistptr->text = text;
625 formatlistptr->nextptr = new format_t();
626 formatlistptr = formatlistptr->nextptr;
627
628 }
629 return true;
630}
631
632
633static bool parse_action (text_t::const_iterator &here, const text_t::const_iterator &end,
634 format_t *formatlistptr, text_tset &metadata, bool &getParents) {
635
636 text_t::const_iterator it = findchar (here, end, '}');
637 if (it == end) return false;
638
639 text_t com = substr (here, it);
640 here = findchar (it, end, '{');
641 if (here == end) return false;
642 else ++here;
643
644 if (com == "If" || com == "if" || com == "IF") formatlistptr->command = comIf;
645 else if (com == "Or" || com == "or" || com == "OR") formatlistptr->command = comOr;
646 else return false;
647
648 int commacount = 0;
649 text_t text;
650 while (here != end) {
651
652 if (*here == '\\') {
653 ++here;
654 if (here != end) text.push_back(*here);
655
656 }
657
658 else if (*here == ',' || *here == '}' || *here == '{') {
659
660 if (formatlistptr->command == comOr) {
661 // the {Or}{this, or this, or this, or this} statement
662 format_t *or_ptr;
663
664 // find the next unused orptr
665 if (formatlistptr->orptr == NULL) {
666 formatlistptr->orptr = new format_t();
667 or_ptr = formatlistptr->orptr;
668 } else {
669 or_ptr = formatlistptr->orptr;
670 while (or_ptr->nextptr != NULL)
671 or_ptr = or_ptr->nextptr;
672 or_ptr->nextptr = new format_t();
673 or_ptr = or_ptr->nextptr;
674 }
675
676 if (!text.empty())
677 {
678 if (!parse_string(text, or_ptr, metadata, getParents)) { return false; }
679 }
680
681 if (*here == '{')
682 {
683 // Supports: {Or}{[Booktitle],[Title],{If}{[XXXX],aaa,bbb}}
684 // but not : {Or}{[Booktitle],[Title]{If}{[XXXX],aaa,bbb}}
685 // The latter can always be re-written:
686 // {Or}{[Booktitle],{If}{[Title],[Title]{If}{[XXXX],aaa,bbb}}}
687
688 if (!text.empty()) // already used up allocated format_t
689 {
690 // => allocate new one for detected action
691 or_ptr->nextptr = new format_t();
692 or_ptr = or_ptr->nextptr;
693 }
694 if (!parse_action(++here, end, or_ptr, metadata, getParents))
695 {
696 return false;
697 }
698 }
699 else
700 {
701 if (*here == '}') break;
702 }
703 text.clear();
704
705 }
706
707 // Parse an {If}{decide,do,else} statement
708 else {
709
710 // Read the decision component.
711 if (commacount == 0) {
712 // Decsion can be a metadata element, or a piece of text.
713 // Originally Stefan's code, updated 25/10/2000 by Gordon.
714
715 text_t::const_iterator beginbracket = text.begin();
716 text_t::const_iterator endbracket = (text.end() - 1);
717
718 // Decision is based on a metadata element
719 if ((*beginbracket == '[') && (*endbracket == ']')) {
720 // Ignore the surrounding square brackets
721 text_t meta = substr (beginbracket+1, endbracket);
722 parse_meta (meta, formatlistptr->decision.meta, metadata, getParents);
723 ++commacount;
724 text.clear();
725 }
726
727 // Decision is a piece of text (probably a macro like _cgiargmode_).
728 else {
729
730 // hunt for any metadata in string, which might be uses in
731 // to test a condition, e.g. [Format] eq 'PDF'
732 format_t* dummyformat = new format_t();
733 // update which metadata fields needed
734 // (not interested in updatng formatlistptr)
735 parse_string (text, dummyformat, metadata, getParents);
736 delete dummyformat;
737
738 formatlistptr->decision.command = dText;
739 formatlistptr->decision.text = text;
740 ++commacount;
741 text.clear();
742 }
743 }
744
745 // Read the "then" and "else" components of the {If} statement.
746 else {
747 format_t** nextlistptr = NULL;
748 if (commacount == 1) {
749 nextlistptr = &formatlistptr->ifptr;
750 } else if (commacount == 2 ) {
751 nextlistptr = &formatlistptr->elseptr;
752 } else {
753 return false;
754 }
755
756 if (!text.empty()) {
757 if (*nextlistptr == NULL) {
758 *nextlistptr = new format_t();
759 } else {
760
761 // skip to the end of any format_t statements already added
762 while ((*nextlistptr)->nextptr != NULL)
763 {
764 nextlistptr = &(*nextlistptr)->nextptr;
765 }
766
767 (*nextlistptr)->nextptr = new format_t();
768 nextlistptr = &(*nextlistptr)->nextptr;
769 }
770
771 if (!parse_string (text, *nextlistptr, metadata, getParents))
772 {
773 return false;
774 }
775 text.clear();
776 }
777
778 if (*here == '{')
779 {
780 if (*nextlistptr == NULL) {
781 *nextlistptr = new format_t();
782 } else {
783 // skip to the end of any format_t statements already added
784 while ((*nextlistptr)->nextptr != NULL)
785 {
786 nextlistptr = &(*nextlistptr)->nextptr;
787 }
788
789 (*nextlistptr)->nextptr = new format_t();
790 nextlistptr = &(*nextlistptr)->nextptr;
791 }
792
793 if (!parse_action(++here, end, *nextlistptr, metadata, getParents))
794 {
795 return false;
796 }
797 }
798 else
799 {
800 if (*here == '}') break;
801 ++commacount;
802 }
803 }
804 }
805
806 } else text.push_back(*here);
807
808 if (here != end) ++here;
809 }
810
811 return true;
812}
813
814
815bool parse_formatstring (const text_t &formatstring, format_t *formatlistptr,
816 text_tset &metadata, bool &getParents) {
817
818 formatlistptr->clear();
819 getParents = false;
820
821 return (parse_string (formatstring, formatlistptr, metadata, getParents));
822}
823
824// position -1 for all, -2 for the last, 0 for the first, or x for a particular piece
825// metainfo has all the values for the metadata, meta has the request metadata name and options, position tells which values to get
826static text_t get_formatted_meta_text(MetadataInfo_t &metainfo, const metadata_t &meta, int position, bool no_cgisafe = false)
827{
828 text_t no_ns_metaname = remove_namespace(meta.metaname);
829 text_t tmp;
830 bool first = true;
831
832 const int start_i=0;
833 const int end_i = metainfo.values.size()-1;
834
835 if (position == -1) { // all
836 for (int i=start_i; i<=end_i; ++i) {
837 if (!first) tmp += meta.siblingoptions;
838 if (meta.metacommand & mSpecial) {
839 // special formatting
840 if (no_ns_metaname == "Date") tmp += format_date (metainfo.values[i]);
841 else if (no_ns_metaname == "Language") tmp += iso639(metainfo.values[i]);
842 else tmp += "_format:"+meta.metaname+"_("+metainfo.values[i]+")";
843 }
844 else tmp += metainfo.values[i];
845 first = false;
846
847 }
848 } else {
849 if (position == -2) { // end
850 position = end_i;
851 } else if (position < start_i || position > end_i) {
852 return "";
853 }
854 if (meta.metacommand & mSpecial) {
855 // special formatting
856 if (no_ns_metaname == "Date") tmp += format_date (metainfo.values[position]);
857 else if (no_ns_metaname == "Language") tmp += iso639(metainfo.values[position]);
858 else tmp += "_format:"+meta.metaname+"_("+metainfo.values[position]+")";
859 }
860 else tmp += metainfo.values[position];
861 }
862 if (meta.metacommand & mCgiSafe && !no_cgisafe) return cgi_safe (tmp);
863 else return tmp;
864}
865
866static text_t get_parent_meta (ResultDocInfo_t &docinfo, const metadata_t &meta, int siblings_values)
867{
868
869 MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
870 switch (meta.mqualifier.parent) {
871 case pNone:
872 return "Nothing!!";
873 break;
874
875 case pImmediate:
876 if (parent != NULL) {
877 return get_formatted_meta_text(*parent, meta, siblings_values);
878 }
879 break;
880
881 case pTop:
882 if (parent != NULL) {
883 while (parent->parent != NULL) parent = parent->parent;
884 return get_formatted_meta_text(*parent, meta, siblings_values);
885 }
886 break;
887
888 case pAll:
889 MetadataInfo_t *parent = docinfo.metadata[meta.metaname].parent;
890 if (parent != NULL) {
891 text_tarray tmparray;
892 while (parent != NULL) {
893 tmparray.push_back (get_formatted_meta_text(*parent, meta, siblings_values, true)); // set no_cgisafe to true, as we'll do it once we have all the metadata
894 parent = parent->parent;
895 }
896 // now join them up - use teh parent separator
897 bool first = true;
898 text_t tmp;
899 text_tarray::reverse_iterator here = tmparray.rbegin();
900 text_tarray::reverse_iterator end = tmparray.rend();
901 while (here != end) {
902 if (!first) tmp += meta.parentoptions;
903 tmp += *here;
904 first = false;
905 ++here;
906 }
907 if (meta.metacommand & mCgiSafe) return cgi_safe (tmp);
908 else return tmp;
909 }
910 }
911 return "";
912
913}
914
915static text_t get_child_meta (const text_t& collection,
916 recptproto* collectproto,
917 ResultDocInfo_t &docinfo, displayclass &disp,
918 const metadata_t &meta, text_tmap &options,
919 ostream& logout, int siblings_values)
920{
921 if (docinfo.metadata["contains"].values[0].size()==0) return ""; // no children
922
923 const text_t& child_metaname = meta.metaname;
924 const text_t& child_field = meta.childoptions;
925 text_tset child_metadata;
926 child_metadata.insert(child_metaname);
927
928 FilterResponse_t child_response;
929 if (meta.mqualifier.child == cNum) {
930 // just one child
931 //get the information associated with the metadata for child doc
932 if (!get_info (docinfo.OID+child_field, collection, "", child_metadata,
933 false, collectproto, child_response, logout)) return ""; // invalid child number
934
935 if (child_response.docInfo.empty()) return false; // no info for the child
936
937 ResultDocInfo_t& child_docinfo = child_response.docInfo[0];
938 MetadataInfo_t& metaname_rec = child_docinfo.metadata[child_metaname];
939
940 text_t child_metavalue = get_formatted_meta_text(metaname_rec,meta,siblings_values);
941 return expand_metadata(child_metavalue,collection,collectproto,
942 child_docinfo,disp,options,logout);
943 }
944
945
946 if (meta.mqualifier.child != cAll) return false; // invalid qualifier
947
948 // we need to get all children
949 text_t result = "";
950 text_tarray children;
951 text_t contains = docinfo.metadata["contains"].values[0];
952 splitchar (contains.begin(), contains.end(), ';', children);
953 text_tarray::const_iterator here = children.begin();
954 text_tarray::const_iterator end = children.end();
955 bool first = true;
956 while (here !=end) {
957 text_t oid = *here;
958 here++;
959 if (*(oid.begin()) == '"') translate_parent (oid, docinfo.OID);
960
961
962 //get the information associated with the metadata for child doc
963 if (!get_info (oid, collection, "", child_metadata,
964 false, collectproto, child_response, logout) ||
965 child_response.docInfo.empty()) {
966 first = false;
967 continue;
968 }
969
970
971 ResultDocInfo_t& child_docinfo = child_response.docInfo[0];
972 MetadataInfo_t& metaname_rec = child_docinfo.metadata[child_metaname];
973
974 text_t child_metavalue = get_formatted_meta_text(metaname_rec,meta,siblings_values);
975 if (!first) result += child_field;
976 first = false;
977 // need to do this here cos otherwise we are in the wrong document
978 result += expand_metadata(child_metavalue,collection,collectproto,
979 child_docinfo,disp,options,logout);
980 }
981 return result;
982
983}
984
985static text_t get_meta (const text_t& collection, recptproto* collectproto,
986 ResultDocInfo_t &docinfo, displayclass &disp,
987 const metadata_t &meta, text_tmap &options,
988 ostream& logout) {
989
990 // make sure we have the requested metadata
991 MetadataInfo_tmap::iterator it = docinfo.metadata.find (meta.metaname);
992 if (it == docinfo.metadata.end()) return "";
993
994 int siblings_values = 0; // default is no siblings, just the first metadata available
995 if (meta.metacommand & mSibling) {
996 if (meta.mqualifier.sibling == sAll) {
997 siblings_values = -1; //all
998 } else if (meta.mqualifier.sibling == sNum) {
999 siblings_values = meta.siblingoptions.getint();
1000 }
1001 }
1002 if (meta.metacommand & mParent) {
1003 return get_parent_meta(docinfo,meta,siblings_values);
1004 }
1005
1006 else if (meta.metacommand & mChild) {
1007 return get_child_meta(collection,collectproto,docinfo,disp,meta,
1008 options,logout, siblings_values);
1009 }
1010 else if (meta.metacommand & mSibling) { // only siblings
1011 MetadataInfo_t& metaname_rec = docinfo.metadata[meta.metaname];
1012 return get_formatted_meta_text(docinfo.metadata[meta.metaname],meta, siblings_values);
1013 }
1014 else {
1015
1016 // straightforward metadata request (nothing fancy)
1017
1018 text_t classifier_metaname = docinfo.classifier_metadata_type;
1019 int metaname_index
1020 = (classifier_metaname == meta.metaname) ? docinfo.classifier_metadata_offset : 0;
1021 return get_formatted_meta_text(docinfo.metadata[meta.metaname], meta, metaname_index);
1022 }
1023
1024 return "";
1025}
1026
1027static text_t get_or (const text_t& collection, recptproto* collectproto,
1028 ResultDocInfo_t &docinfo, displayclass &disp,
1029 format_t *orptr, text_tmap &options,
1030 ostream& logout) {
1031
1032 text_t tmp;
1033 while (orptr != NULL) {
1034
1035 tmp = format_string (collection,collectproto,docinfo, disp, orptr,
1036 options, logout);
1037 if (!tmp.empty()) return tmp;
1038
1039 orptr = orptr->nextptr;
1040 }
1041 return "";
1042}
1043
1044static bool char_is_whitespace(const char c)
1045{
1046 return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
1047
1048}
1049
1050static int scan_over_whitespace(const text_t& outstring, const int start_pos)
1051{
1052 int pos = start_pos;
1053 while (pos<outstring.size()) {
1054 if (!char_is_whitespace(outstring[pos])) {
1055 break;
1056 }
1057 ++pos;
1058 }
1059
1060 return pos;
1061}
1062
1063static int rscan_over_whitespace(const text_t& outstring, const int start_pos)
1064{
1065 int pos = start_pos;
1066 while (pos>=0) {
1067 if (!char_is_whitespace(outstring[pos])) {
1068 break;
1069 }
1070 --pos;
1071 }
1072
1073 return pos;
1074}
1075
1076static int rscan_for_whitespace(const text_t& outstring, const int start_pos)
1077{
1078 int pos = start_pos;
1079 while (pos>=0) {
1080 if (char_is_whitespace(outstring[pos])) {
1081 break;
1082 }
1083 --pos;
1084 }
1085
1086 return pos;
1087}
1088
1089
1090static int rscan_for(const text_t& outstring, const int start_pos,
1091 const char find_c)
1092{
1093 int pos = start_pos;
1094 while (pos>=0) {
1095 char c = outstring[pos];
1096 if (outstring[pos] == find_c) {
1097 break;
1098 }
1099 --pos;
1100 }
1101
1102 return pos;
1103}
1104
1105text_t extract_substr(const text_t& outstring, const int start_pos,
1106 const int end_pos)
1107{
1108 text_t extracted_str;
1109 extracted_str.clear();
1110
1111 for (int pos=start_pos; pos<=end_pos; ++pos) {
1112 extracted_str.push_back(outstring[pos]);
1113 }
1114
1115 return extracted_str;
1116}
1117
1118
1119static text_t expand_potential_metadata(const text_t& collection,
1120 recptproto* collectproto,
1121 ResultDocInfo_t &docinfo,
1122 displayclass &disp,
1123 const text_t& intext,
1124 text_tmap &options,
1125 ostream& logout)
1126{
1127 text_t outtext;
1128
1129 // decide if dealing with metadata or text
1130
1131 text_t::const_iterator beginbracket = intext.begin();
1132 text_t::const_iterator endbracket = (intext.end() - 1);
1133
1134 // Decision is based on a metadata element
1135 if ((*beginbracket == '[') && (*endbracket == ']')) {
1136 // Ignore the surrounding square brackets
1137 text_t meta_text = substr (beginbracket+1, endbracket);
1138
1139 if (meta_text == "Text") {
1140 outtext = format_text(collection, collectproto, docinfo, disp, options, logout);
1141 } else {
1142
1143 text_tset metadata;
1144 bool getParents =false;
1145 metadata_t meta;
1146
1147 parse_meta (meta_text, meta, metadata, getParents);
1148 outtext
1149 = get_meta (collection,collectproto,docinfo,disp,meta,options,logout);
1150 }
1151
1152 }
1153 else {
1154 outtext = intext;
1155 }
1156
1157 return outtext;
1158}
1159
1160
1161
1162
1163static bool uses_expression(const text_t& collection, recptproto* collectproto,
1164 ResultDocInfo_t &docinfo,
1165 displayclass &disp,
1166 const text_t& outstring, text_t& lhs_expr,
1167 text_t& op_expr, text_t& rhs_expr,
1168 text_tmap &options,
1169 ostream& logout)
1170{
1171 // Note: the string may not be of the form: str1 op str2, however
1172 // to deterine this we have to process it on the assumption it is,
1173 // and if at any point an 'erroneous' value is encountered, return
1174 // false and let something else have a go at evaluating it
1175
1176 // Starting at the end of the string and working backwards ..
1177
1178 const int outstring_len = outstring.size();
1179
1180 // skip over white space
1181 int rhs_end = rscan_over_whitespace(outstring,outstring_len-1);
1182
1183 if (rhs_end<=0) {
1184 // no meaningful text or (rhs_end==0) no room for operator
1185 return false;
1186 }
1187
1188 // check for ' or " and then scan over token
1189 const char potential_quote = outstring[rhs_end];
1190 int rhs_start=rhs_end;
1191 bool quoted = false;
1192
1193 if ((potential_quote == '\'') || (potential_quote == '\"')) {
1194 --rhs_end;
1195 rhs_start = rscan_for(outstring,rhs_end-1,potential_quote) +1;
1196 quoted = true;
1197 }
1198 else {
1199 rhs_start = rscan_for_whitespace(outstring,rhs_end-1) +1;
1200 }
1201
1202 if ((rhs_end-rhs_start)<0) {
1203 // no meaningful rhs expression
1204 return false;
1205 }
1206
1207 // form rhs_expr
1208 rhs_expr = extract_substr(outstring,rhs_start,rhs_end);
1209
1210 // skip over white space
1211 const int to_whitespace = (quoted) ? 2 : 1;
1212
1213 int op_end = rscan_over_whitespace(outstring,rhs_start-to_whitespace);
1214 int op_start = rscan_for_whitespace(outstring,op_end-1)+1;
1215
1216
1217 if (op_end-op_start<0) {
1218 // no meaningful expression operator
1219 return false;
1220 }
1221
1222 op_expr = extract_substr(outstring,op_start,op_end);
1223
1224
1225 // check for operator
1226 if ((op_expr != "eq") && (op_expr != "ne") && (op_expr != "gt") &&
1227 (op_expr != "ge") && (op_expr != "lt") && (op_expr != "le") && (op_expr != "==") && (op_expr != "!=") && (op_expr != ">") && (op_expr != ">=") && (op_expr != "<") && (op_expr != "<=") && (op_expr != "sw") && (op_expr != "ew")) {
1228
1229 // not a valid operator
1230 return false;
1231 }
1232
1233 int lhs_end = rscan_over_whitespace(outstring,op_start-1);
1234 if (lhs_end<0) {
1235 // no meaningful lhs expression
1236 return false;
1237 }
1238
1239 int lhs_start = scan_over_whitespace(outstring,0);
1240
1241 // form lhs_expr from remainder of string
1242 lhs_expr = extract_substr(outstring,lhs_start,lhs_end);
1243
1244 // Now we know we have a valid expression, look up any
1245 // metadata terms
1246
1247 rhs_expr = expand_potential_metadata(collection,collectproto,docinfo,
1248 disp,rhs_expr,options,logout);
1249 lhs_expr = expand_potential_metadata(collection,collectproto,docinfo,
1250 disp,lhs_expr,options,logout);
1251
1252 return true;
1253}
1254
1255static bool eval_expression_true(const text_t& lhs_expr,const text_t& op_expr,
1256 const text_t& rhs_expr, ostream& logout)
1257{
1258 if (op_expr == "eq") return (lhs_expr == rhs_expr);
1259 else if (op_expr == "ne" ) return (lhs_expr != rhs_expr);
1260 else if (op_expr == "gt") return (lhs_expr > rhs_expr);
1261 else if (op_expr == "ge") return (lhs_expr >= rhs_expr);
1262 else if (op_expr == "lt") return (lhs_expr < rhs_expr);
1263 else if (op_expr == "le") return (lhs_expr <= rhs_expr);
1264 else if (op_expr == "==") return (lhs_expr.getint() == rhs_expr.getint());
1265 else if (op_expr == "!=") return (lhs_expr.getint() != rhs_expr.getint());
1266 else if (op_expr == ">") return (lhs_expr.getint() > rhs_expr.getint());
1267 else if (op_expr == ">=") return (lhs_expr.getint() >= rhs_expr.getint());
1268 else if (op_expr == "<") return (lhs_expr.getint() < rhs_expr.getint());
1269 else if (op_expr == "<=") return (lhs_expr.getint() <= rhs_expr.getint());
1270 else if (op_expr == "sw") return (starts_with(lhs_expr,rhs_expr));
1271 else if (op_expr == "ew") return (ends_with(lhs_expr,rhs_expr));
1272 else {
1273 logout << "Error: '" << op_expr << "' is not a recognised operator." << endl;
1274 }
1275
1276 return false;
1277}
1278
1279
1280static text_t get_if (const text_t& collection, recptproto* collectproto,
1281 ResultDocInfo_t &docinfo, displayclass &disp,
1282 const decision_t &decision,
1283 format_t *ifptr, format_t *elseptr,
1284 text_tmap &options, ostream& logout)
1285{
1286 // If the decision component is a metadata element, then evaluate it
1287 // to see whether we output the "then" or the "else" clause
1288 if (decision.command == dMeta) {
1289 if (get_meta (collection,collectproto,docinfo,disp,decision.meta,options,
1290 logout) != "") {
1291 if (ifptr != NULL)
1292 return get_formatted_string (collection,collectproto,docinfo, disp, ifptr,
1293 options, logout);
1294 }
1295 else {
1296 if (elseptr != NULL)
1297 return get_formatted_string (collection,collectproto,docinfo, disp, elseptr,
1298 options, logout);
1299 }
1300 }
1301
1302 // If the decision component is text, then evaluate it (it is probably a
1303 // macro like _cgiargmode_) to decide what to output.
1304 else if (decision.command == dText) {
1305
1306 text_t outstring;
1307 disp.expandstring (decision.text, outstring);
1308
1309 // Check for if expression in form: str1 op str2
1310 // (such as [x] eq "y")
1311 text_t lhs_expr, op_expr, rhs_expr;
1312 if (uses_expression(collection,collectproto,docinfo, disp, outstring,lhs_expr,op_expr,rhs_expr, options,logout)) {
1313 if (eval_expression_true(lhs_expr,op_expr,rhs_expr,logout)) {
1314 if (ifptr != NULL) {
1315 return get_formatted_string (collection, collectproto, docinfo, disp, ifptr,
1316 options, logout);
1317 }
1318 else {
1319 return "";
1320 }
1321 } else {
1322 if (elseptr != NULL) {
1323 return get_formatted_string (collection, collectproto, docinfo, disp, elseptr,
1324 options, logout);
1325 }
1326 else {
1327 return "";
1328 }
1329 }
1330 }
1331
1332
1333 // This is a tad tricky. When we expand a string like _cgiargmode_, that is
1334 // a cgi argument macro that has not been set, it evaluates to itself.
1335 // Therefore, were have to say that a piece of text evalautes true if
1336 // it is non-empty and if it is a cgi argument evaulating to itself.
1337
1338 if ((outstring != "") && !((outstring == decision.text) && (outstring[0] == '_'))) {
1339 if (ifptr != NULL)
1340 return get_formatted_string (collection, collectproto, docinfo, disp, ifptr,
1341 options, logout);
1342 } else {
1343 if (elseptr != NULL)
1344 return get_formatted_string (collection, collectproto, docinfo, disp, elseptr,
1345 options, logout);
1346 }
1347 }
1348
1349 return "";
1350}
1351
1352bool includes_metadata(const text_t& text)
1353{
1354 text_t::const_iterator here = text.begin();
1355 text_t::const_iterator end = text.end();
1356 while (here != end) {
1357 if (*here == '[') return true;
1358 ++here;
1359 }
1360
1361 return false;
1362}
1363
1364static text_t expand_metadata(const text_t &metavalue, const text_t& collection,
1365 recptproto* collectproto,
1366 ResultDocInfo_t &docinfo,
1367 displayclass &disp, text_tmap &options,
1368 ostream &logout) {
1369
1370 if (includes_metadata(metavalue)) {
1371
1372 // text has embedded metadata in it => expand it
1373 FilterRequest_t request;
1374 FilterResponse_t response;
1375
1376 request.getParents = false;
1377
1378 format_t *expanded_formatlistptr = new format_t();
1379 parse_formatstring (metavalue, expanded_formatlistptr,
1380 request.fields, request.getParents);
1381
1382 // retrieve metadata
1383 get_info(docinfo.OID, collection, "", request.fields, request.getParents,
1384 collectproto, response, logout);
1385
1386 if (!response.docInfo.empty()) {
1387
1388 text_t expanded_metavalue
1389 = get_formatted_string(collection, collectproto,
1390 response.docInfo[0], disp, expanded_formatlistptr,
1391 options, logout);
1392
1393 return expanded_metavalue;
1394 }
1395 else {
1396 return metavalue;
1397 }
1398 }
1399 else {
1400
1401 return metavalue;
1402 }
1403}
1404
1405text_t get_collection_meta(const text_t& collection, recptproto* collectproto,
1406 displayclass &disp,
1407 text_t meta_name, ostream& logout) {
1408
1409 ColInfoResponse_t collectinfo;
1410 comerror_t err;
1411 collectproto->get_collectinfo (collection, collectinfo,err,logout);
1412 text_t meta_value = "";
1413 text_t lang;
1414 disp.expandstring("_cgiargl_",lang);
1415 if (lang.empty()) {
1416 lang = "en";
1417 }
1418
1419 if (err == noError) {
1420 meta_value = collectinfo.get_collectionmeta(meta_name, lang);
1421 }
1422 return meta_value;
1423
1424
1425}
1426text_t format_string (const text_t& collection, recptproto* collectproto,
1427 ResultDocInfo_t &docinfo, displayclass &disp,
1428 format_t *formatlistptr, text_tmap &options,
1429 ostream& logout) {
1430
1431 if (formatlistptr == NULL) return "";
1432
1433 switch (formatlistptr->command) {
1434 case comOID:
1435 return docinfo.OID;
1436 case comRank:
1437 return text_t(docinfo.ranking);
1438 case comText:
1439 return formatlistptr->text;
1440 case comLink:
1441 return options["link"];
1442 case comEndLink:
1443 if (options["link"].empty()) return "";
1444 else return "</a>";
1445 case comHref:
1446 return get_href(options["link"]);
1447 case comIcon:
1448 return options["icon"];
1449 case comNum:
1450 return docinfo.result_num;
1451 case comRel: //if [RelatedDocuments] appears in format string, collect relation data
1452 return get_related_docs(collection, collectproto, docinfo, logout);
1453 case comSummary:
1454 return format_summary(collection, collectproto, docinfo, disp, options, logout);
1455 case comMeta:
1456 {
1457 const text_t& metavalue = get_meta (collection,collectproto, docinfo, disp,formatlistptr->meta,options,logout);
1458 return expand_metadata(metavalue, collection, collectproto, docinfo, disp, options, logout);
1459 }
1460 case comDoc:
1461 return format_text(collection, collectproto, docinfo, disp, options, logout);
1462 //return options["text"];
1463 case comImage:
1464 return expand_metadata(options["DocImage"], collection, collectproto, docinfo, disp, options, logout);
1465 case comTOC:
1466 return options["DocTOC"];
1467 case comDocumentButtonDetach:
1468 return options["DocumentButtonDetach"];
1469 case comDocumentButtonHighlight:
1470 return options["DocumentButtonHighlight"];
1471 case comDocumentButtonExpandContents:
1472 return options["DocumentButtonExpandContents"];
1473 case comDocumentButtonExpandText:
1474 return options["DocumentButtonExpandText"];
1475 case comHighlight:
1476 if (options["highlight"] == "1") return "<b>";
1477 break;
1478 case comEndHighlight:
1479 if (options["highlight"] == "1") return "</b>";
1480 break;
1481 case comIf:
1482 return get_if (collection, collectproto, docinfo, disp,
1483 formatlistptr->decision, formatlistptr->ifptr,
1484 formatlistptr->elseptr, options, logout);
1485 case comOr:
1486 return get_or (collection,collectproto, docinfo, disp, formatlistptr->orptr,
1487 options, logout);
1488 case comCollection:
1489 if (formatlistptr->meta.metaname == g_EmptyText) {
1490 return collection;
1491 }
1492 return get_collection_meta(collection, collectproto, disp, formatlistptr->meta.metaname, logout);
1493
1494 }
1495 return "";
1496}
1497
1498text_t get_formatted_string (const text_t& collection, recptproto* collectproto,
1499 ResultDocInfo_t &docinfo, displayclass &disp,
1500 format_t *formatlistptr, text_tmap &options,
1501 ostream& logout) {
1502
1503 text_t ft;
1504 while (formatlistptr != NULL)
1505 {
1506 ft += format_string (collection, collectproto, docinfo, disp, formatlistptr,
1507 options, logout);
1508 formatlistptr = formatlistptr->nextptr;
1509 }
1510
1511 return ft;
1512}
1513
1514
1515// we have only preloaded the text in DocumentAction. But you may want to get the text in query. so copy what we have done with format_summary and get the text here. probably is quite expensive?
1516text_t format_text (const text_t& collection, recptproto* collectproto,
1517 ResultDocInfo_t &docinfo, displayclass &disp,
1518 text_tmap &options, ostream& logout) {
1519 if(!options["text"].empty()) {
1520 return options["text"];
1521 }
1522 // else get document text here
1523 DocumentRequest_t docrequest;
1524 DocumentResponse_t docresponse;
1525 comerror_t err;
1526 docrequest.OID = docinfo.OID;
1527 collectproto->get_document (collection, docrequest, docresponse, err, logout);
1528 return docresponse.doc;
1529
1530}
1531
1532/* FUNCTION NAME: format_summary
1533 * DESC: this is invoked when a [Summary] special metadata is processed.
1534 * RETURNS: a query-biased summary for the document */
1535
1536text_t format_summary (const text_t& collection, recptproto* collectproto,
1537 ResultDocInfo_t &docinfo, displayclass &disp,
1538 text_tmap &options, ostream& logout) {
1539
1540 // GRB: added code here to ensure that the cstr (and other collections)
1541 // uses the document metadata item Summary, rather than compressing
1542 // the text of the document, processed via the methods in
1543 // summarise.cpp
1544 if (docinfo.metadata.count("Summary") > 0 &&
1545 docinfo.metadata["Summary"].values.size() > 0) {
1546 return docinfo.metadata["Summary"].values[0];
1547 }
1548
1549 text_t textToSummarise, query;
1550 if(options["text"].empty()) { // get document text
1551 DocumentRequest_t docrequest;
1552 DocumentResponse_t docresponse;
1553 comerror_t err;
1554 docrequest.OID = docinfo.OID;
1555 collectproto->get_document (collection, docrequest, docresponse, err, logout);
1556 textToSummarise = docresponse.doc;
1557 } else // in practice, this would not happen, because text is only
1558 // loaded with the [Text] command
1559 textToSummarise = options["text"];
1560 disp.expandstring("_cgiargq_",query);
1561 return summarise(textToSummarise,query,80);
1562}
Note: See TracBrowser for help on using the repository browser.