source: gsdl/tags/gsdl-2_62-distribution/gsdl/perllib/classify/DateList.pm@ 14162

Last change on this file since 14162 was 10630, checked in by kjdon, 19 years ago

added -no_metadata_formatting option to avoid the format_metadata_for_sorting call

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1###########################################################################
2#
3# DateList.pm --
4# A component of the Greenstone digital library software
5# from the New Zealand Digital Library Project at the
6# University of Waikato, New Zealand.
7#
8# Copyright (C) 1999 New Zealand Digital Library Project
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# classifier plugin for sorting by date
27
28# date is assumed to be in the form yyyymmdd
29
30# at present dates are split by year - this should change
31# jrm21 - added option "bymonth", which splits by year and month.
32
33# 23/09/03 Added some more options -kjdon.
34# these include:
35# -nogroup, which makes each year (or year+month) an individual entry in
36# the horizontal list and prevents compaction
37# -metadata, use a different metadata for the date (instead of Date), still expects yyyymmdd format. this affects display cos greenstone displays Date metadata as dd month yyyy, whereas any other date metadata is displayed as yyyymmdd - this needs fixing
38# -sort specifies an additional metadata to use in sorting, will take affect when two docs have the same date.
39
40package DateList;
41
42use BasClas;
43use sorttools;
44
45use strict;
46no strict 'refs'; # allow filehandles to be variables and viceversa
47
48sub BEGIN {
49 @DateList::ISA = ('BasClas');
50}
51
52my $arguments =
53 [ { 'name' => "metadata",
54 'desc' => "{DateList.metadata}",
55 'type' => "metadata",
56 'deft' => "Date",
57 'reqd' => "no" } ,
58 { 'name' => "sort",
59 'desc' => "{DateList.sort}",
60 'type' => "metadata",
61 'reqd' => "no" } ,
62 { 'name' => "reverse_sort",
63 'desc' => "{DateList.reverse_sort}",
64 'type' => "flag",
65 'reqd' => "no" },
66 { 'name' => "bymonth",
67 'desc' => "{DateList.bymonth}",
68 'type' => "flag",
69 'reqd' => "no" },
70 { 'name' => "nogroup",
71 'desc' => "{DateList.nogroup}",
72 'type' => "flag",
73 'reqd' => "no" }
74 ];
75
76my $options = { 'name' => "DateList",
77 'desc' => "{DateList.desc}",
78 'abstract' => "no",
79 'inherits' => "yes",
80 'args' => $arguments };
81
82
83sub new {
84 my ($class) = shift (@_);
85 my ($classifierslist,$inputargs,$hashArgOptLists) = @_;
86 push(@$classifierslist, $class);
87
88 if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
89 if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
90
91 my $self = (defined $hashArgOptLists)? new BasClas($classifierslist,$inputargs,$hashArgOptLists): new BasClas($classifierslist,$inputargs);
92
93 if ($self->{'info_only'}) {
94 # don't worry about any options etc
95 return bless $self, $class;
96 }
97
98 # Manually set $self parameters.
99 $self->{'list'} = {};
100
101 if (!defined $self->{"metadata"} || $self->{"metadata"} eq "") {
102 $self->{'metadata'} = "Date";
103 }
104
105 return bless $self, $class;
106}
107
108sub init {
109 my $self = shift (@_);
110
111 $self->{'list'} = {};
112}
113
114sub classify {
115 my $self = shift (@_);
116 my ($doc_obj) = @_;
117
118 my $doc_OID = $doc_obj->get_OID();
119 my $date = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), $self->{'metadata'});
120
121 my $sort_other = "";
122 if (defined $self->{'sort'} && $self->{'sort'} ne "") {
123 $sort_other = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), $self->{'sort'});
124 $sort_other = &sorttools::format_metadata_for_sorting($self->{'sort'}, $sort_other, $doc_obj) unless $self->{'no_metadata_formatting'};
125 }
126 # if this document doesn't contain Date element we won't
127 # include it in this classification
128 if (defined $date && $date =~ /\d/) {
129 if (defined $self->{'list'}->{$doc_OID}) {
130 my $outhandle = $self->{'outhandle'};
131 print $outhandle "WARNING: DateList::classify called multiple times for $doc_OID\n";
132 }
133
134 $self->{'list'}->{$doc_OID} = "$date$sort_other";
135 }
136}
137
138
139sub get_classify_info {
140 my $self = shift (@_);
141
142 my @classlist = sort {$self->{'list'}->{$a} cmp $self->{'list'}->{$b};} keys %{$self->{'list'}};
143 if ($self->{'reverse_sort'}) {
144 @classlist = reverse @classlist;
145 }
146
147 return $self->splitlist (\@classlist);
148}
149
150
151sub get_entry {
152 my $self = shift (@_);
153 my ($title, $childtype, $thistype) = @_;
154
155 # organise into classification structure
156 my %classifyinfo = ('childtype'=>$childtype,
157 'Title'=>$title,
158 'contains'=>[],
159 'mdtype'=>$self->{'metadata'});
160 $classifyinfo{'thistype'} = $thistype
161 if defined $thistype && $thistype =~ /\w/;
162
163 return \%classifyinfo;
164}
165
166# splitlist takes an ordered list of classifications (@$classlistref) and
167# splits it up into sub-sections by date
168sub splitlist {
169 my $self = shift (@_);
170 my ($classlistref) = @_;
171 my $classhash = {};
172
173 # top level
174 my $childtype = "HList";
175
176 if (scalar (@$classlistref) <= 39 &&
177 !$self->{'nogroup'}) {$childtype = "DateList";}
178 my $classifyinfo = $self->get_entry ("Date", $childtype, "Invisible");
179 # don't need to do any splitting if there are less than 39 (max + min -1)
180 # classifications, unless nogroup is specified
181 if ((scalar @$classlistref) <= 39 && !$self->{'nogroup'}) {
182 foreach my $subOID (@$classlistref) {
183 push (@{$classifyinfo->{'contains'}}, {'OID'=>$subOID});
184 }
185 return $classifyinfo;
186 }
187
188
189 if ($self->{'bymonth'}) {
190 # first split up the list into separate year+month classifications
191
192 if (!$self->{'nogroup'}) { # hlist of year+month pairs
193 # single level of classifications
194 foreach my $classification (@$classlistref) {
195 my $date = $self->{'list'}->{$classification};
196 $date =~ s/^(\d\d\d\d)(\d\d).*$/$1&nbsp;_textmonth$2_/;
197 # sanity check if month is zero
198 if ($date =~ /00_$/) {
199 $date =~ s/^(\d\d\d\d).*$/$1/g;
200 }
201 $classhash->{$date} = [] unless defined $classhash->{$date};
202 push (@{$classhash->{$date}}, $classification);
203 }
204
205 } else { # don't group - individual years and months
206 foreach my $classification (@$classlistref) {
207 my $date = $self->{'list'}->{$classification};
208 $date =~ s/^(\d\d\d\d)(\d\d).*$/$1&nbsp;_textmonth$2_/;
209 my ($year, $month)=($1,$2);
210 # sanity check if month is zero
211 if ($date =~ /00_$/) {
212 $date =~ s/^(\d\d\d\d).*$/$1/g;
213 }
214 # create subclass if it doesn't already exist
215 $classhash->{$year} = () unless defined $classhash->{$year};
216 $classhash->{$year}->{$month} = []
217 unless defined $classhash->{$year}->{$month};
218 push (@{$classhash->{$year}->{$month}}, $classification);
219 }
220 # create hlist of years containing hlists of months
221
222 foreach my $subclass (sort {$a <=> $b} keys %$classhash) {
223 my $yearclassify = $self->get_entry($subclass, "HList");
224 foreach my $subsubclass (sort {$a <=> $b}
225 (keys %{$classhash->{$subclass}})) {
226 my $monthname=$subsubclass;
227 if ($monthname >= 1 && $monthname <= 12) {
228 $monthname="_textmonth" . $monthname . "_";
229 }
230 my $monthclassify=$self->get_entry($monthname, "DateList");
231 push (@{$yearclassify->{'contains'}}, $monthclassify);
232
233 foreach my $subsubOID
234 (@{$classhash->{$subclass}->{$subsubclass}}) {
235 push (@{$monthclassify->{'contains'}},
236 {'OID'=>$subsubOID});
237 }
238 }
239 push (@{$classifyinfo->{'contains'}}, $yearclassify);
240 }
241 return $classifyinfo;
242 } # nogroup
243 } else {
244 # not by month
245 # first split up the list into separate year classifications
246 foreach my $classification (@$classlistref) {
247 my $date = $self->{'list'}->{$classification};
248 $date =~ s/^(\d\d\d\d).*$/$1/;
249 $classhash->{$date} = [] unless defined $classhash->{$date};
250 push (@{$classhash->{$date}}, $classification);
251 }
252 }
253
254 # only compact the list if nogroup not specified
255 if (!$self->{'nogroup'}) {
256 $classhash = $self->compactlist ($classhash);
257 }
258 foreach my $subclass (sort keys %$classhash) {
259 my $tempclassify = $self->get_entry($subclass, "DateList");
260 foreach my $subsubOID (@{$classhash->{$subclass}}) {
261 push (@{$tempclassify->{'contains'}}, {'OID'=>$subsubOID});
262 }
263 push (@{$classifyinfo->{'contains'}}, $tempclassify);
264 }
265
266 return $classifyinfo;
267}
268
269sub compactlist {
270 my $self = shift (@_);
271 my ($classhashref) = @_;
272 my $compactedhash = {};
273 my @currentOIDs = ();
274 my $currentfirstdate = "";
275 my $currentlastdate = "";
276 my $lastkey = "";
277
278 # minimum and maximum documents to be displayed per page.
279 # the actual maximum will be max + (min-1).
280 # the smallest sub-section is a single letter at present
281 # so in this case there may be many times max documents
282 # displayed on a page.
283 my $min = 10;
284 my $max = 30;
285 foreach my $subsection (sort keys %$classhashref) {
286 $currentfirstdate = $subsection if $currentfirstdate eq "";
287 if ((scalar (@currentOIDs) < $min) ||
288 ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
289 push (@currentOIDs, @{$classhashref->{$subsection}});
290 $currentlastdate = $subsection;
291 } else {
292
293 if ($currentfirstdate eq $currentlastdate) {
294 @{$compactedhash->{$currentfirstdate}} = @currentOIDs;
295 $lastkey = $currentfirstdate;
296 } else {
297 @{$compactedhash->{"$currentfirstdate-$currentlastdate"}} = @currentOIDs;
298 $lastkey = "$currentfirstdate-$currentlastdate";
299 }
300 if (scalar (@{$classhashref->{$subsection}}) >= $max) {
301 $compactedhash->{$subsection} = $classhashref->{$subsection};
302 @currentOIDs = ();
303 $currentfirstdate = "";
304 $lastkey = $subsection;
305 } else {
306 @currentOIDs = @{$classhashref->{$subsection}};
307 $currentfirstdate = $subsection;
308 $currentlastdate = $subsection;
309 }
310 }
311 }
312
313 # add final OIDs to last sub-classification if there aren't many otherwise
314 # add final sub-classification
315 if ((scalar (@currentOIDs) < $min) && (scalar (@currentOIDs) > 0)) {
316 # want every thing in previous up to the dash
317 my ($newkey) = $lastkey =~ /^([^\-]+)/;
318 @currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
319 delete $compactedhash->{$lastkey};
320 @{$compactedhash->{"$newkey-$currentlastdate"}} = @currentOIDs;
321 } else {
322 if ($currentfirstdate eq $currentlastdate) {
323 @{$compactedhash->{$currentfirstdate}} = @currentOIDs;
324 } else {
325 @{$compactedhash->{"$currentfirstdate-$currentlastdate"}} = @currentOIDs;
326 }
327 }
328
329 return $compactedhash;
330}
331
3321;
Note: See TracBrowser for help on using the repository browser.