source: trunk/gsdl/perllib/classify/AZCompactList.pm@ 7023

Last change on this file since 7023 was 6985, checked in by kjdon, 20 years ago

changed some error messages, and put sort type back to string - I forgot about the nosort option

  • Property svn:keywords set to Author Date Id Revision
File size: 22.3 KB
Line 
1###########################################################################
2#
3# AZCompactList.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# classifier plugin for sorting alphabetically
26# options are:
27
28package AZCompactList;
29
30use BasClas;
31use sorttools;
32
33sub BEGIN {
34 @ISA = ('BasClas');
35}
36
37my $doclevel_list =
38 [ { 'name' => "top",
39 'desc' => "{AZCompactList.doclevel.top}" },
40 { 'name' => "section",
41 'desc' => "{AZCompactList.doclevel.section}" } ];
42
43my $arguments =
44 [ { 'name' => "metadata",
45 'desc' => "{AZCompactList.metadata}",
46 'type' => "metadata",
47 'reqd' => "yes" },
48 { 'name' => "buttonname",
49 'desc' => "{BasClas.buttonname}",
50 'type' => "string",
51 'deft' => "{BasClas.metadata.deft}",
52 'reqd' => "no" },
53 { 'name' => "sort",
54 'desc' => "{AZCompactList.sort}",
55 'type' => "string",
56 'deft' => "Title",
57 'reqd' => "no" },
58 { 'name' => "removeprefix",
59 'desc' => "{AZCompactList.removeprefix}",
60 'type' => "regexp",
61 'deft' => "",
62 'reqd' => "no" },
63 { 'name' => "removesuffix",
64 'desc' => "{AZCompactList.removesuffix}",
65 'type' => "regexp",
66 'deft' => "",
67 'reqd' => "no" },
68 { 'name' => "mingroup",
69 'desc' => "{AZCompactList.mingroup}",
70 'type' => "int",
71 'deft' => "2",
72 'reqd' => "no" },
73 { 'name' => "minnesting",
74 'desc' => "{AZCompactList.minnesting}",
75 'type' => "int",
76 'deft' => "20",
77 'reqd' => "no" },
78 { 'name' => "mincompact",
79 'desc' => "{AZCompactList.mincompact}",
80 'type' => "int",
81 'deft' => "10",
82 'reqd' => "no" },
83 { 'name' => "maxcompact",
84 'desc' => "{AZCompactList.maxcompact}",
85 'type' => "int",
86 'deft' => "30",
87 'reqd' => "no" },
88 { 'name' => "doclevel",
89 'desc' => "{AZCompactList.doclevel}",
90 'type' => "enum",
91 'list' => $doclevel_list,
92 'deft' => "top",
93 'reqd' => "no" },
94 { 'name' => "onlyfirst",
95 'desc' => "{AZCompactList.onlyfirst}",
96 'type' => "flag",
97 'reqd' => "no" },
98 { 'name' => "freqsort",
99 'desc' => "{AZCompactList.freqsort}",
100 'type' => "flag"},
101 { 'name' => "recopt",
102 'desc' => "{AZCompactList.recopt}",
103 'type' => "flag",
104 'reqd' => "no" } ];
105
106my $options =
107{ 'name' => "AZCompactList",
108 'desc' => "{AZCompactList.desc}",
109 'abstract' => "no",
110 'inherits' => "yes",
111 'args' => $arguments };
112
113
114sub new {
115 my $class = shift (@_);
116 my $self = new BasClas($class, @_);
117
118 # 14-05-02 To allow for proper inheritance of arguments - John Thompson
119 my $option_list = $self->{'option_list'};
120 push( @{$option_list}, $options );
121
122 if ($self->{'info_only'}) {
123 # created from classinfo.pl - don't need to parse the arguments
124 return bless $self, $class;
125 }
126
127 my ($metaname, $title, $removeprefix, $removesuffix);
128 my $sortname = "Title";
129 my $mingroup = 2;
130 my $minnesting = 20;
131 my $mincompact = 10;
132 my $maxcompact = 30;
133 my $doclevel = "top";
134 my $onlyfirst = 0;
135 my $freqsort = 0;
136 my $recopt = undef;
137
138 if (!parsargv::parse(\@_,
139 q^metadata/.*/^, \$metaname,
140 q^buttonname/.*/^, \$title,
141 q^sort/.*/^, \$sortname,
142 q^removeprefix/.*/^, \$removeprefix,
143 q^removesuffix/.*/^, \$removesuffix,
144 q^mingroup/.*/2^, \$mingroup,
145 q^minnesting/.*/20^, \$minnesting,
146 q^mincompact/.*/10^, \$mincompact,
147 q^maxcompact/.*/30^, \$maxcompact,
148 q^doclevel/.*/top^, \$doclevel,
149 q^onlyfirst/.*/0^, \$onlyfirst,
150 q^freqsort/.*/0^, \$freqsort,
151 q^recopt/.*/-1^, \$recopt, # Used in nested metadata such as -metadata Year/Organisation
152
153 "allow_extra_options")) {
154
155 print STDERR "\nIncorrect options passed to $class, check your collect.cfg file\n";
156 $self->print_txt_usage(""); # Use default resource bundle
157 die "\n";
158 }
159
160 if (!$metaname) {
161 my $outhandle = $self->{'outhandle'};
162 print $outhandle "AZCompactList Error: required option -metadata not supplied\n";
163 $self->print_txt_usage("");
164 die "AZCompactList Error: required option -metadata not supplied\n";
165 }
166
167 $title = $metaname unless ($title);
168
169 $self->{'list'} = {};
170 $self->{'listmetavalue'} = {};
171 $self->{'reclassify'} = {};
172 $self->{'reclassifylist'} = {};
173 $self->{'metaname'} = $metaname;
174 $self->{'title'} = "$title"; # title for the titlebar.
175 $self->{'sortname'} = $sortname;
176 if (defined($removeprefix) && $removeprefix) {
177 $removeprefix =~ s/^\^//; # don't need a leading ^
178 $self->{'removeprefix'} = $removeprefix;
179 }
180 if (defined($removesuffix) && $removesuffix) {
181 $removesuffix =~ s/\$$//; # don't need a trailing $
182 $self->{'removesuffix'} = $removesuffix;
183 }
184 $self->{'mingroup'} = $mingroup;
185 $self->{'minnesting'} = $minnesting;
186 $self->{'mincompact'} = $mincompact;
187 $self->{'maxcompact'} = $maxcompact;
188 $self->{'doclevel'} = $doclevel;
189
190 if ($onlyfirst != 0) {
191 $onlyfirst = 1;
192 }
193 $self->{'onlyfirst'} = $onlyfirst;
194
195 if ($freqsort != 0) {
196 $freqsort = 1;
197 }
198 $self->{'freqsort'} = $freqsort;
199
200 if ($recopt == -1) {
201 $recopt = undef;
202 } else {
203 $recopt = "on";
204 }
205 $self->{'recopt'} = $recopt;
206
207 return bless $self, $class;
208}
209
210sub init
211{
212 my $self = shift (@_);
213
214 $self->{'list'} = {};
215 $self->{'listmetavalue'} = {};
216 $self->{'reclassify'} = {};
217 $self->{'reclassifylist'} = {};
218}
219
220$tmp = 0;
221
222sub classify
223{
224 my $self = shift (@_);
225 my ($doc_obj) = @_;
226
227 my $doc_OID = $doc_obj->get_OID();
228
229 my @sectionlist = ();
230 my $topsection = $doc_obj->get_top_section();
231
232 my $metaname = $self->{'metaname'};
233 my $outhandle = $self->{'outhandle'};
234
235 $metaname =~ s/(\/.*)//; # grab first name in n1/n2/n3 list
236
237 if ($self->{'doclevel'} =~ /^top(level)?/i)
238 {
239 push(@sectionlist,$topsection);
240 }
241 else
242 {
243 my $thissection = $doc_obj->get_next_section($topsection);
244 while (defined $thissection)
245 {
246 push(@sectionlist,$thissection);
247 $thissection = $doc_obj->get_next_section ($thissection);
248 }
249 }
250
251 my $thissection;
252 foreach $thissection (@sectionlist)
253 {
254 my $full_doc_OID
255 = ($thissection ne "") ? "$doc_OID.$thissection" : $doc_OID;
256
257 if (defined $self->{'list'}->{$full_doc_OID})
258 {
259 print $outhandle "WARNING: AZCompactList::classify called multiple times for $full_doc_OID\n";
260 }
261 $self->{'list'}->{$full_doc_OID} = [];
262 $self->{'listmetavalue'}->{$full_doc_OID} = [];
263
264 my $metavalues = $doc_obj->get_metadata($thissection,$metaname);
265 my $metavalue;
266 foreach $metavalue (@$metavalues)
267 {
268 # if this document doesn't contain the metadata element we're
269 # sorting by we won't include it in this classification
270 if (defined $metavalue && $metavalue =~ /\w/)
271 {
272 if (defined($self->{'removeprefix'}) &&
273 length($self->{'removeprefix'})) {
274 $metavalue =~ s/^$self->{'removeprefix'}//;
275
276 # check that it's not now empty
277 if (!$metavalue) {next;}
278 }
279
280 if (defined($self->{'removesuffix'}) &&
281 length($self->{'removesuffix'})) {
282 $metavalue =~ s/$self->{'removesuffix'}$//;
283
284 # check that it's not now empty
285 if (!$metavalue) {next;}
286 }
287
288 my $formatted_metavalue = $metavalue;
289 $formatted_metavalue = $self->format_metadata_for_sorting($self->{'metaname'}, $formatted_metavalue, $doc_obj);
290
291 #### prefix-str
292 if (! defined($formatted_metavalue)) {
293 print $outhandle "Warning: AZCompactList: metavalue is ";
294 print $outhandle "empty\n";
295 $formatted_metavalue="";
296 }
297
298 push(@{$self->{'list'}->{$full_doc_OID}},$formatted_metavalue);
299 push(@{$self->{'listmetavalue'}->{$full_doc_OID}} ,$metavalue);
300
301 last if ($self->{'onlyfirst'});
302 }
303 }
304 my $date = $doc_obj->get_metadata_element($thissection,"Date");
305 $self->{'reclassify'}->{$full_doc_OID} = [$doc_obj,$date];
306 }
307}
308
309sub reinit
310{
311 my ($self,$classlist_ref) = @_;
312 my $outhandle = $self->{'outhandle'};
313
314 my %mtfreq = ();
315 my @single_classlist = ();
316 my @multiple_classlist = ();
317
318 # find out how often each metavalue occurs
319 map
320 {
321 my $mv;
322 foreach $mv (@{$self->{'listmetavalue'}->{$_}} )
323 {
324 $mtfreq{$mv}++;
325 }
326 } @$classlist_ref;
327
328 # use this information to split the list: single metavalue/repeated value
329 map
330 {
331 my $i = 1;
332 my $metavalue;
333 foreach $metavalue (@{$self->{'listmetavalue'}->{$_}})
334 {
335 if ($mtfreq{$metavalue} >= $self->{'mingroup'})
336 {
337 push(@multiple_classlist,[$_,$i,$metavalue]);
338 }
339 else
340 {
341 push(@single_classlist,[$_,$metavalue]);
342 $metavalue =~ tr/[A-Z]/[a-z]/;
343 $self->{'reclassifylist'}->{"Metavalue_$i.$_"} = $metavalue;
344 }
345 $i++;
346 }
347 } @$classlist_ref;
348
349
350 # Setup sub-classifiers for multiple list
351
352 $self->{'classifiers'} = {};
353
354 my $pm;
355 foreach $pm ("List", "SectionList")
356 {
357 my $listname
358 = &util::filename_cat($ENV{'GSDLHOME'},"perllib/classify/$pm.pm");
359 if (-e $listname) { require $listname; }
360 else
361 {
362 print $outhandle "AZCompactList ERROR - couldn't find classifier \"$listname\"\n";
363 die "\n";
364 }
365 }
366
367 # Create classifiers objects for each entry >= mingroup
368 my $metavalue;
369 foreach $metavalue (keys %mtfreq)
370 {
371 if ($mtfreq{$metavalue} >= $self->{'mingroup'})
372 {
373 my $listclassobj;
374 my $doclevel = $self->{'doclevel'};
375 my $metaname = $self->{'metaname'};
376 my $mingroup = $self->{'mingroup'};
377
378 my @metaname_list = split('/',$metaname);
379 $metaname = shift(@metaname_list);
380 if (@metaname_list==0)
381 {
382 my @args;
383 push @args, ("-metadata", "$metaname");
384 # buttonname is also used for the node's title
385 push @args, ("-buttonname", "$metavalue");
386 push @args, ("-sort", $self->{'sortname'});
387
388 if ($doclevel =~ m/^top(level)?/i)
389 {
390 eval ("\$listclassobj = new List(\@args)"); warn $@ if $@;
391 }
392 else
393 {
394 eval ("\$listclassobj = new SectionList(\@args)");
395 }
396 }
397 else
398 {
399 $metaname = join('/',@metaname_list);
400
401 my @args;
402 push @args, ("-metadata", "$metaname");
403 # buttonname is also used for the node's title
404 push @args, ("-buttonname", "$metavalue");
405 push @args, ("-doclevel", "$doclevel");
406 push @args, ("-mingroup", $mingroup);
407 push @args, "-recopt ";
408
409 eval ("\$listclassobj = new AZCompactList(\@args)");
410 }
411 if ($@) {
412 print $outhandle "$@";
413 die "\n";
414 }
415
416 $listclassobj->init();
417
418 if (defined $metavalue && $metavalue =~ /\w/)
419 {
420 my $formatted_node = $metavalue;
421
422 if (defined($self->{'removeprefix'}) &&
423 length($self->{'removeprefix'})) {
424 $formatted_node =~ s/^$self->{'removeprefix'}//;
425 # check that it's not now empty
426 if (!$formatted_node) {next;}
427 }
428 if (defined($self->{'removesuffix'}) &&
429 length($self->{'removesuffix'})) {
430 $formatted_node =~ s/$self->{'removesuffix'}$//;
431 # check that it's not now empty
432 if (!$formatted_node) {next;}
433 }
434
435 #$formatted_node = $self->format_metadata_for_sorting($self->{'metaname'}, $formatted_node, $doc_obj);
436 # should be using the above, but we have no doc obj any more
437 if ($self->{'metaname'} =~ m/^Creator(:.*)?$/)
438 {
439 &sorttools::format_string_name_english(\$formatted_node);
440 }
441 else
442 {
443 &sorttools::format_string_english(\$formatted_node);
444 }
445
446 # In case our formatted string is empty...
447 if (! defined($formatted_node)) {
448 print $outhandle "Warning: AZCompactList: metavalue is ";
449 print $outhandle "empty\n";
450 $formatted_node="";
451 }
452
453 # use the lower case, for speed of lookup.
454 my $meta_lc=lc($metavalue);
455 $self->{'classifiers'}->{$meta_lc}
456 = { 'classifyobj' => $listclassobj,
457 'formattednode' => $formatted_node };
458 }
459 }
460 }
461
462
463 return (\@single_classlist,\@multiple_classlist);
464}
465
466
467sub reclassify
468{
469 my ($self,$multiple_cl_ref) = @_;
470
471 # Entries in the current classify list that are "book nodes"
472 # should be recursively classified.
473 #--
474 foreach $dm_pair (@$multiple_cl_ref)
475 {
476 my ($doc_OID,$mdoffset,$metavalue) = @$dm_pair;
477 my $listclassobj;
478
479 # find metavalue in list of sub-classifiers
480 # check if we have a key (lower case) for this metadata value
481 my $node_name=lc($metavalue);
482 if (exists $self->{'classifiers'}->{$node_name})
483 {
484 my ($doc_obj,$date) = @{$self->{'reclassify'}->{$doc_OID}};
485
486 ## date appears to not be used in classifier call ####
487
488 if ($doc_OID =~ m/^[^\.]*\.([\d\.]+)$/)
489 {
490 my $section=$1;
491 if ($self->{'doclevel'} =~ m/^top/i) { # toplevel
492 $self->{'classifiers'}->{$node_name}->{'classifyobj'}
493 ->classify($doc_obj, "Section=$section");
494 } else { # section level
495 # Thanks to Don Gourley for this...
496 # classify can't handle multi-level section
497 $self->{'classifiers'}->{$node_name}->{'classifyobj'}
498 ->classify_section($section, $doc_obj, $date);
499 }
500 }
501 else
502 {
503 $self->{'classifiers'}->{$node_name}->{'classifyobj'}
504 ->classify($doc_obj);
505 }
506 } else { # this key is not in the hash
507 my $outhandle=$self->{outhandle};
508 print $outhandle "Warning: AZCompactList::reclassify ";
509 print $outhandle "could not find sub-node for metadata=`$metavalue' with doc_OID $doc_OID\n";
510 }
511 }
512}
513
514
515
516sub get_reclassify_info
517{
518 my $self = shift (@_);
519
520 my $node_name;
521 foreach $node_name (keys %{$self->{'classifiers'}})
522 {
523 my $classifyinfo
524 = $self->{'classifiers'}->{$node_name}->{'classifyobj'}
525 ->get_classify_info();
526 $self->{'classifiers'}->{$node_name}->{'classifyinfo'}
527 = $classifyinfo;
528 $self->{'reclassifylist'}->{"CLASSIFY.$node_name"}
529 = $self->{'classifiers'}->{$node_name}->{'formattednode'};
530 }
531}
532
533
534sub alpha_numeric_cmp
535{
536 my ($self,$a,$b) = @_;
537
538 my $title_a = $self->{'reclassifylist'}->{$a};
539 my $title_b = $self->{'reclassifylist'}->{$b};
540
541 if ($title_a =~ m/^(\d+(\.\d+)?)/)
542 {
543 my $val_a = $1;
544 if ($title_b =~ m/^(\d+(\.\d+)?)/)
545 {
546 my $val_b = $1;
547 if ($val_a != $val_b)
548 {
549 return ($val_a <=> $val_b);
550 }
551 }
552 }
553
554 return ($title_a cmp $title_b);
555}
556
557sub frequency_cmp
558{
559 my ($self,$a,$b) = @_;
560
561
562 my $title_a = $self->{'reclassifylist'}->{$a};
563 my $title_b = $self->{'reclassifylist'}->{$b};
564
565 my $a_freq = 1;
566 my $b_freq = 1;
567
568 if ($a =~ m/^CLASSIFY\.(.*)$/)
569 {
570 my $a_node = $1;
571 my $a_nodeinfo = $self->{'classifiers'}->{$a_node}->{'classifyinfo'};
572 $a_freq = scalar(@{$a_nodeinfo->{'contains'}});
573 }
574
575 if ($b =~ m/^CLASSIFY\.(.*)$/)
576 {
577 my $b_node = $1;
578 my $b_nodeinfo = $self->{'classifiers'}->{$b_node}->{'classifyinfo'};
579 $b_freq = scalar(@{$b_nodeinfo->{'contains'}});
580 }
581
582 return $b_freq <=> $a_freq;
583}
584
585sub get_classify_info {
586 my $self = shift (@_);
587
588 my @classlist =keys %{$self->{'list'}}; # list all doc oids
589
590 my ($single_cl_ref,$multiple_cl_ref) = $self->reinit(\@classlist);
591 $self->reclassify($multiple_cl_ref);
592 $self->get_reclassify_info();
593
594 my @reclassified_classlist;
595 if ($self->{'freqsort'})
596 {
597 @reclassified_classlist
598 = sort { $self->frequency_cmp($a,$b) } keys %{$self->{'reclassifylist'}};
599 # supress sub-grouping by alphabet
600 map { $self->{'reclassifylist'}->{$_} = "A".$self->{'reclassifylist'}; } keys %{$self->{'reclassifylist'}};
601 }
602 else
603 {
604# @reclassified_classlist
605# = sort {$self->{'reclassifylist'}->{$a} cmp $self->{'reclassifylist'}->{$b};} keys %{$self->{'reclassifylist'}};
606
607 # alpha_numeric_cmp is slower than "cmp" but handles numbers better ...
608
609 @reclassified_classlist
610 = sort { $self->alpha_numeric_cmp($a,$b) } keys %{$self->{'reclassifylist'}};
611
612 }
613
614 return $self->splitlist (\@reclassified_classlist);
615}
616
617sub get_entry {
618 my $self = shift (@_);
619 my ($title, $childtype, $metaname, $thistype) = @_;
620
621 # organise into classification structure
622 my %classifyinfo = ('childtype'=>$childtype,
623 'Title'=>$title,
624 'contains'=>[],
625 'mdtype'=>$metaname);
626
627 $classifyinfo{'thistype'} = $thistype
628 if defined $thistype && $thistype =~ /\w/;
629
630 return \%classifyinfo;
631}
632
633
634
635# splitlist takes an ordered list of classifications (@$classlistref) and
636# splits it up into alphabetical sub-sections.
637sub splitlist {
638 my $self = shift (@_);
639 my ($classlistref) = @_;
640 my $classhash = {};
641
642 # top level
643 my @metanames = split("/",$self->{'metaname'});
644 my $metaname = shift(@metanames);
645
646 my $childtype = "HList";
647 $childtype = "VList" if (scalar (@$classlistref) <= $self->{'minnesting'});
648
649 my $classifyinfo;
650 if (!defined($self->{'recopt'}))
651 {
652 my $title = $self->{'title'}; # should always be defined by now....
653 $title = $metaname unless defined $title;
654 $classifyinfo
655 = $self->get_entry ($title, $childtype, $metaname, "Invisible");
656 }
657 else
658 {
659 my $title = $self->{'title'};
660 $classifyinfo
661 = $self->get_entry ($title, $childtype, $metaname, "VList");
662 }
663
664 # don't need to do any splitting if there are less than 'minnesting' classifications
665 if ((scalar @$classlistref) <= $self->{'minnesting'}) {
666 foreach $subOID (@$classlistref) {
667 if ($subOID =~ /^CLASSIFY\.(.*)$/
668 && defined $self->{'classifiers'}->{$1})
669 {
670 push (@{$classifyinfo->{'contains'}},
671 $self->{'classifiers'}->{$1}->{'classifyinfo'});
672 }
673 else
674 {
675 $subOID =~ s/^Metavalue_(\d+)\.//;
676 my $metaname_offset = $1 -1;
677 my $oid_rec = {'OID'=>$subOID, 'offset'=>$metaname_offset};
678 push (@{$classifyinfo->{'contains'}}, $oid_rec);
679 }
680 }
681 return $classifyinfo;
682 }
683
684 # first split up the list into separate A-Z and 0-9 classifications
685 foreach $classification (@$classlistref) {
686 my $title = $self->{'reclassifylist'}->{$classification};
687 $title =~ s/&(.){2,4};//g; # remove any HTML special chars
688 $title =~ s/^\W+//g; # remove leading non-word chars
689
690# only want first character for classification
691 $title =~ m/^(.)/;
692 if ($1) {
693 $title=$1;
694 } else {
695 print STDERR "no first character found for \"$title\" - \"" .
696 $self->{'reclassifylist'}->{$classification} . "\"\n";
697 }
698 $title =~ tr/[a-z]/[A-Z]/;
699
700 if ($title =~ /^[0-9]$/) {$title = '0-9';}
701 elsif ($title !~ /^[A-Z]$/) {
702 my $outhandle = $self->{'outhandle'};
703 print $outhandle "AZCompactList: WARNING $classification has badly formatted title ($title)\n";
704 }
705 $classhash->{$title} = [] unless defined $classhash->{$title};
706 push (@{$classhash->{$title}}, $classification);
707 }
708 $classhash = $self->compactlist ($classhash);
709
710 my @tmparr = ();
711 foreach $subsection (sort keys (%$classhash)) {
712 push (@tmparr, $subsection);
713 }
714
715 # if there's a 0-9 section it will have been sorted to the beginning
716 # but we want it at the end
717 if ($tmparr[0] eq '0-9') {
718 shift @tmparr;
719 push (@tmparr, '0-9');
720 }
721
722 foreach $subclass (@tmparr)
723 {
724 my $tempclassify
725 = (scalar(@tmparr)==1)
726 ? ($self->get_entry(" ", "VList", $metaname))
727 : ($self->get_entry($subclass, "VList", $metaname));
728
729
730 foreach $subsubOID (@{$classhash->{$subclass}})
731 {
732 if ($subsubOID =~ /^CLASSIFY\.(.*)$/
733 && defined $self->{'classifiers'}->{$1})
734 {
735 push (@{$tempclassify->{'contains'}},
736 $self->{'classifiers'}->{$1}->{'classifyinfo'});
737 }
738 else
739 {
740 $subsubOID =~ s/^Metavalue_(\d+)\.//;
741 my $metaname_offset = $1 -1;
742 my $oid_rec = {'OID'=>$subsubOID, 'offset'=>$metaname_offset};
743 push (@{$tempclassify->{'contains'}}, $oid_rec);
744 }
745 }
746 push (@{$classifyinfo->{'contains'}}, $tempclassify);
747 }
748
749 return $classifyinfo;
750}
751
752sub compactlist {
753 my $self = shift (@_);
754 my ($classhashref) = @_;
755 my $compactedhash = {};
756 my @currentOIDs = ();
757 my $currentfirstletter = "";
758 my $currentlastletter = "";
759 my $lastkey = "";
760
761 # minimum and maximum documents to be displayed per page.
762 # the actual maximum will be max + (min-1).
763 # the smallest sub-section is a single letter at present
764 # so in this case there may be many times max documents
765 # displayed on a page.
766 my $min = $self->{'mincompact'};
767 my $max = $self->{'maxcompact'};
768
769 foreach $subsection (sort keys %$classhashref) {
770 if ($subsection eq '0-9') {
771 @{$compactedhash->{$subsection}} = @{$classhashref->{$subsection}};
772 next;
773 }
774 $currentfirstletter = $subsection if $currentfirstletter eq "";
775 if ((scalar (@currentOIDs) < $min) ||
776 ((scalar (@currentOIDs) + scalar (@{$classhashref->{$subsection}})) <= $max)) {
777 push (@currentOIDs, @{$classhashref->{$subsection}});
778 $currentlastletter = $subsection;
779 } else {
780
781 if ($currentfirstletter eq $currentlastletter) {
782 @{$compactedhash->{$currentfirstletter}} = @currentOIDs;
783 $lastkey = $currentfirstletter;
784 } else {
785 @{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
786 $lastkey = "$currentfirstletter-$currentlastletter";
787 }
788 if (scalar (@{$classhashref->{$subsection}}) >= $max) {
789 $compactedhash->{$subsection} = $classhashref->{$subsection};
790 @currentOIDs = ();
791 $currentfirstletter = "";
792 $lastkey=$subsection;
793 } else {
794 @currentOIDs = @{$classhashref->{$subsection}};
795 $currentfirstletter = $subsection;
796 $currentlastletter = $subsection;
797 }
798 }
799 }
800
801 # add final OIDs to last sub-classification if there aren't many otherwise
802 # add final sub-classification
803
804 # don't add if there aren't any oids
805 if (! scalar (@currentOIDs)) {return $compactedhash;}
806
807 if (scalar (@currentOIDs) < $min) {
808 my ($newkey) = $lastkey =~ /^(.)/;
809 @currentOIDs = (@{$compactedhash->{$lastkey}}, @currentOIDs);
810 delete $compactedhash->{$lastkey};
811 @{$compactedhash->{"$newkey-$currentlastletter"}} = @currentOIDs;
812 } else {
813 if ($currentfirstletter eq $currentlastletter) {
814 @{$compactedhash->{$currentfirstletter}} = @currentOIDs;
815 } else {
816 @{$compactedhash->{"$currentfirstletter-$currentlastletter"}} = @currentOIDs;
817 }
818 }
819
820 return $compactedhash;
821}
822
8231;
824
825
Note: See TracBrowser for help on using the repository browser.