source: main/tags/2.63/gsdl/perllib/classify/DateList.pm

Last change on this file was 10979, checked in by kjdon, 19 years ago

DateList can now take a comma separated list of metadata names.

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 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 # now can have comma separated list of Dates - we just use the first one (for now)
105 my @meta_list = split(/,/, $self->{"metadata"});
106 $self->{'meta_list'} = \@meta_list;
107
108 return bless $self, $class;
109}
110
111sub init {
112 my $self = shift (@_);
113
114 $self->{'list'} = {};
115}
116
117sub classify {
118 my $self = shift (@_);
119 my ($doc_obj) = @_;
120
121 my $doc_OID = $doc_obj->get_OID();
122
123 # find the first available metadata
124 my $date;
125 foreach my $m (@{$self->{'meta_list'}}) {
126 $date = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $m);
127 last if defined $date;
128 }
129
130 #my $date = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), $self->{'metadata'});
131 if (!defined $date || $date eq "") {
132 # if this document doesn't contain Date element we won't
133 # include it in this classification
134 return;
135 }
136
137 my $sort_other = "";
138 if (defined $self->{'sort'} && $self->{'sort'} ne "") {
139 $sort_other = $doc_obj->get_metadata_element ($doc_obj->get_top_section(), $self->{'sort'});
140 $sort_other = &sorttools::format_metadata_for_sorting($self->{'sort'}, $sort_other, $doc_obj) unless $self->{'no_metadata_formatting'};
141 }
142
143 if (defined $self->{'list'}->{$doc_OID}) {
144 my $outhandle = $self->{'outhandle'};
145 print $outhandle "WARNING: DateList::classify called multiple times for $doc_OID\n";
146 }
147
148 $self->{'list'}->{$doc_OID} = "$date$sort_other";
149
150}
151
152
153sub get_classify_info {
154 my $self = shift (@_);
155
156 my @classlist = sort {$self->{'list'}->{$a} cmp $self->{'list'}->{$b};} keys %{$self->{'list'}};
157 if ($self->{'reverse_sort'}) {
158 @classlist = reverse @classlist;
159 }
160
161 return $self->splitlist (\@classlist);
162}
163
164
165sub get_entry {
166 my $self = shift (@_);
167 my ($title, $childtype, $thistype) = @_;
168
169 # organise into classification structure
170 my %classifyinfo = ('childtype'=>$childtype,
171 'Title'=>$title,
172 'contains'=>[],
173 'mdtype'=>$self->{'metadata'});
174 $classifyinfo{'thistype'} = $thistype
175 if defined $thistype && $thistype =~ /\w/;
176
177 return \%classifyinfo;
178}
179
180# splitlist takes an ordered list of classifications (@$classlistref) and
181# splits it up into sub-sections by date
182sub splitlist {
183 my $self = shift (@_);
184 my ($classlistref) = @_;
185 my $classhash = {};
186
187 # top level
188 my $childtype = "HList";
189
190 if (scalar (@$classlistref) <= 39 &&
191 !$self->{'nogroup'}) {$childtype = "DateList";}
192 my $classifyinfo = $self->get_entry ("Date", $childtype, "Invisible");
193 # don't need to do any splitting if there are less than 39 (max + min -1)
194 # classifications, unless nogroup is specified
195 if ((scalar @$classlistref) <= 39 && !$self->{'nogroup'}) {
196 foreach my $subOID (@$classlistref) {
197 push (@{$classifyinfo->{'contains'}}, {'OID'=>$subOID});
198 }
199 return $classifyinfo;
200 }
201
202
203 if ($self->{'bymonth'}) {
204 # first split up the list into separate year+month classifications
205
206 if (!$self->{'nogroup'}) { # hlist of year+month pairs
207 # single level of classifications
208 foreach my $classification (@$classlistref) {
209 my $date = $self->{'list'}->{$classification};
210 $date =~ s/^(\d\d\d\d)(\d\d).*$/$1&nbsp;_textmonth$2_/;
211 # sanity check if month is zero
212 if ($date =~ /00_$/) {
213 $date =~ s/^(\d\d\d\d).*$/$1/g;
214 }
215 $classhash->{$date} = [] unless defined $classhash->{$date};
216 push (@{$classhash->{$date}}, $classification);
217 }
218
219 } else { # don't group - individual years and months
220 foreach my $classification (@$classlistref) {
221 my $date = $self->{'list'}->{$classification};
222 $date =~ s/^(\d\d\d\d)(\d\d).*$/$1&nbsp;_textmonth$2_/;
223 my ($year, $month)=($1,$2);
224 # sanity check if month is zero
225 if ($date =~ /00_$/) {
226 $date =~ s/^(\d\d\d\d).*$/$1/g;
227 }
228 # create subclass if it doesn't already exist
229 $classhash->{$year} = () unless defined $classhash->{$year};
230 $classhash->{$year}->{$month} = []
231 unless defined $classhash->{$year}->{$month};
232 push (@{$classhash->{$year}->{$month}}, $classification);
233 }
234 # create hlist of years containing hlists of months
235
236 foreach my $subclass (sort {$a <=> $b} keys %$classhash) {
237 my $yearclassify = $self->get_entry($subclass, "HList");
238 foreach my $subsubclass (sort {$a <=> $b}
239 (keys %{$classhash->{$subclass}})) {
240 my $monthname=$subsubclass;
241 if ($monthname >= 1 && $monthname <= 12) {
242 $monthname="_textmonth" . $monthname . "_";
243 }
244 my $monthclassify=$self->get_entry($monthname, "DateList");
245 push (@{$yearclassify->{'contains'}}, $monthclassify);
246
247 foreach my $subsubOID
248 (@{$classhash->{$subclass}->{$subsubclass}}) {
249 push (@{$monthclassify->{'contains'}},
250 {'OID'=>$subsubOID});
251 }
252 }
253 push (@{$classifyinfo->{'contains'}}, $yearclassify);
254 }
255 return $classifyinfo;
256 } # nogroup
257 } else {
258 # not by month
259 # first split up the list into separate year classifications
260 foreach my $classification (@$classlistref) {
261 my $date = $self->{'list'}->{$classification};
262 $date =~ s/^(\d\d\d\d).*$/$1/;
263 $classhash->{$date} = [] unless defined $classhash->{$date};
264 push (@{$classhash->{$date}}, $classification);
265 }
266 }
267
268 # only compact the list if nogroup not specified
269 if (!$self->{'nogroup'}) {
270 $classhash = $self->compactlist ($classhash);
271 }
272 foreach my $subclass (sort keys %$classhash) {
273 my $tempclassify = $self->get_entry($subclass, "DateList");
274 foreach my $subsubOID (@{$classhash->{$subclass}}) {
275 push (@{$tempclassify->{'contains'}}, {'OID'=>$subsubOID});
276 }
277 push (@{$classifyinfo->{'contains'}}, $tempclassify);
278 }
279
280 return $classifyinfo;
281}
282
283sub compactlist {
284 my $self = shift (@_);
285 my ($classhashref) = @_;
286 my $compactedhash = {};
287 my @currentOIDs = ();
288 my $currentfirstdate = "";
289 my $currentlastdate = "";
290 my $lastkey = "";
291
292 # minimum and maximum documents to be displayed per page.
293 # the actual maximum will be max + (min-1).
294 # the smallest sub-section is a single letter at present
295 # so in this case there may be many times max documents
296 # displayed on a page.
297 my $min = 10;
298 my $max = 30;
299 foreach my $subsection (sort keys %$classhashref) {
300 $currentfirstdate = $subsection if $currentfirstdate eq "";
301 if ((scalar (@currentOIDs) < $min) ||
302 ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
303 push (@currentOIDs, @{$classhashref->{$subsection}});
304 $currentlastdate = $subsection;
305 } else {
306
307 if ($currentfirstdate eq $currentlastdate) {
308 @{$compactedhash->{$currentfirstdate}} = @currentOIDs;
309 $lastkey = $currentfirstdate;
310 } else {
311 @{$compactedhash->{"$currentfirstdate-$currentlastdate"}} = @currentOIDs;
312 $lastkey = "$currentfirstdate-$currentlastdate";
313 }
314 if (scalar (@{$classhashref->{$subsection}}) >= $max) {
315 $compactedhash->{$subsection} = $classhashref->{$subsection};
316 @currentOIDs = ();
317 $currentfirstdate = "";
318 $lastkey = $subsection;
319 } else {
320 @currentOIDs = @{$classhashref->{$subsection}};
321 $currentfirstdate = $subsection;
322 $currentlastdate = $subsection;
323 }
324 }
325 }
326
327 # add final OIDs to last sub-classification if there aren't many otherwise
328 # add final sub-classification
329 if ((scalar (@currentOIDs) < $min) && (scalar (@currentOIDs) > 0)) {
330 # want every thing in previous up to the dash
331 my ($newkey) = $lastkey =~ /^([^\-]+)/;
332 @currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
333 delete $compactedhash->{$lastkey};
334 @{$compactedhash->{"$newkey-$currentlastdate"}} = @currentOIDs;
335 } else {
336 if ($currentfirstdate eq $currentlastdate) {
337 @{$compactedhash->{$currentfirstdate}} = @currentOIDs;
338 } else {
339 @{$compactedhash->{"$currentfirstdate-$currentlastdate"}} = @currentOIDs;
340 }
341 }
342
343 return $compactedhash;
344}
345
3461;
Note: See TracBrowser for help on using the repository browser.