source: main/trunk/greenstone2/perllib/basebuildproc.pm@ 25411

Last change on this file since 25411 was 25411, checked in by jmt12, 12 years ago

Adding in test when storing output handle to prevent binmode() function being called on output handles that aren't GLOBs (such as the objects returned by GDBMServer and TDBServer)

  • Property svn:keywords set to Author Date Id Revision
File size: 22.9 KB
Line 
1##########################################################################
2#
3# basebuildproc.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# This document processor outputs a document for indexing (should be
27# implemented by subclass) and storing in the database
28
29package basebuildproc;
30
31eval {require bytes};
32
33use classify;
34use dbutil;
35use doc;
36use docproc;
37use strict;
38no strict 'subs';
39no strict 'refs';
40use util;
41
42BEGIN {
43 @basebuildproc::ISA = ('docproc');
44}
45
46sub new()
47 {
48 my ($class, $collection, $source_dir, $build_dir, $keepold, $verbosity, $outhandle) = @_;
49 my $self = new docproc ();
50
51 # outhandle is where all the debugging info goes
52 # output_handle is where the output of the plugins is piped
53 # to (i.e. mg, database etc.)
54 $outhandle = STDERR unless defined $outhandle;
55
56 $self->{'collection'} = $collection;
57 $self->{'source_dir'} = $source_dir;
58 $self->{'build_dir'} = $build_dir;
59 $self->{'keepold'} = $keepold;
60 $self->{'verbosity'} = $verbosity;
61 $self->{'outhandle'} = $outhandle;
62
63 $self->{'classifiers'} = [];
64 $self->{'mode'} = "text";
65 $self->{'assocdir'} = $build_dir;
66 $self->{'dontdb'} = {};
67 $self->{'store_metadata_coverage'} = "false";
68
69 $self->{'index'} = "section:text";
70 $self->{'indexexparr'} = [];
71
72 $self->{'separate_cjk'} = 0;
73
74 my $found_num_data = 0;
75 my $buildconfigfile = undef;
76
77 if ($keepold) {
78 # For incremental building need to seed num_docs etc from values
79 # stored in build.cfg (if present)
80 $buildconfigfile = &util::filename_cat($build_dir, "build.cfg");
81 if (-e $buildconfigfile) {
82 $found_num_data = 1;
83 }
84 else {
85 # try the index dir
86 $buildconfigfile = &util::filename_cat($ENV{'GSDLCOLLECTDIR'},
87 "index", "build.cfg");
88 if (-e $buildconfigfile) {
89 $found_num_data = 1;
90 }
91 }
92
93 }
94
95 if ($found_num_data)
96 {
97 #print STDERR "Found_Num_Data!\n";
98 my $buildcfg = &colcfg::read_build_cfg($buildconfigfile);
99 $self->{'starting_num_docs'} = $buildcfg->{'numdocs'};
100 #print STDERR "- num_docs: $self->{'starting_num_docs'}\n";
101 $self->{'starting_num_sections'} = $buildcfg->{'numsections'};
102 #print STDERR "- num_sections: $self->{'starting_num_sections'}\n";
103 $self->{'starting_num_bytes'} = $buildcfg->{'numbytes'};
104 #print STDERR "- num_bytes: $self->{'starting_num_bytes'}\n";
105 }
106 else
107 {
108 #print STDERR "NOT Found_Num_Data!\n";
109 $self->{'starting_num_docs'} = 0;
110 $self->{'starting_num_sections'} = 0;
111 $self->{'starting_num_bytes'} = 0;
112 }
113
114 $self->{'output_handle'} = "STDOUT";
115 $self->{'num_docs'} = $self->{'starting_num_docs'};
116 $self->{'num_sections'} = $self->{'starting_num_sections'};
117 $self->{'num_bytes'} = $self->{'starting_num_bytes'};
118
119 $self->{'num_processed_bytes'} = 0;
120 $self->{'store_text'} = 1;
121
122 # what level (section/document) the database - indexer intersection is
123 $self->{'db_level'} = "section";
124 #used by browse interface
125 $self->{'doclist'} = [];
126
127 $self->{'indexing_text'} = 0;
128
129 return bless $self, $class;
130
131}
132
133sub reset {
134 my $self = shift (@_);
135
136 $self->{'num_docs'} = $self->{'starting_num_docs'};
137 $self->{'num_sections'} = $self->{'starting_num_sections'};
138 $self->{'num_bytes'} = $self->{'starting_num_bytes'};
139
140 $self->{'num_processed_bytes'} = 0;
141}
142
143sub zero_reset {
144 my $self = shift (@_);
145
146 $self->{'num_docs'} = 0;
147 $self->{'num_sections'} = 0;
148 # reconstructed docs have no text, just metadata, so we need to
149 # remember how many bytes we had initially
150 #$self->{'num_bytes'} = $self->{'starting_num_bytes'};
151 $self->{'num_bytes'} = 0; # we'll store num bytes in db for reconstructed docs.
152 $self->{'num_processed_bytes'} = 0;
153}
154
155sub is_incremental_capable
156{
157 # By default we return 'no' as the answer
158 # Safer to assume non-incremental to start with, and then override in
159 # inherited classes that are.
160
161 return 0;
162}
163
164sub get_num_docs {
165 my $self = shift (@_);
166
167 return $self->{'num_docs'};
168}
169
170sub get_num_sections {
171 my $self = shift (@_);
172
173 return $self->{'num_sections'};
174}
175
176# num_bytes is the actual number of bytes in the collection
177# this is normally the same as what's processed during text compression
178sub get_num_bytes {
179 my $self = shift (@_);
180
181 return $self->{'num_bytes'};
182}
183
184# num_processed_bytes is the number of bytes actually passed
185# to mg for the current index
186sub get_num_processed_bytes {
187 my $self = shift (@_);
188
189 return $self->{'num_processed_bytes'};
190}
191
192sub set_output_handle {
193 my $self = shift (@_);
194 my ($handle) = @_;
195
196 $self->{'output_handle'} = $handle;
197 # The output handle isn't always an actual handle. In a couple of the
198 # database drivers (MSSQL and GDBMServer) it's actually a reference
199 # to an object. Thus we need to test the type before setting binmode.
200 # [jmt12]
201 if (ref $handle eq "GLOB")
202 {
203 binmode($handle,":utf8");
204 }
205 binmode($handle,":utf8");
206}
207
208
209sub set_mode {
210 my $self = shift (@_);
211 my ($mode) = @_;
212
213 $self->{'mode'} = $mode;
214}
215
216sub get_mode {
217 my $self = shift (@_);
218
219 return $self->{'mode'};
220}
221
222sub set_assocdir {
223 my $self = shift (@_);
224 my ($assocdir) = @_;
225
226 $self->{'assocdir'} = $assocdir;
227}
228
229sub set_dontdb {
230 my $self = shift (@_);
231 my ($dontdb) = @_;
232
233 $self->{'dontdb'} = $dontdb;
234}
235
236sub set_infodbtype
237{
238 my $self = shift(@_);
239 my $infodbtype = shift(@_);
240 $self->{'infodbtype'} = $infodbtype;
241}
242
243sub set_index {
244 my $self = shift (@_);
245 my ($index, $indexexparr) = @_;
246
247 $self->{'index'} = $index;
248 $self->{'indexexparr'} = $indexexparr if defined $indexexparr;
249}
250
251sub set_index_languages {
252 my $self = shift (@_);
253 my ($lang_meta, $langarr) = @_;
254 $lang_meta =~ s/^ex\.([^.]+)$/$1/; # strip any ex. namespace iff it's the only namespace prefix (will leave ex.dc.* intact)
255
256 $self->{'lang_meta'} = $lang_meta;
257 $self->{'langarr'} = $langarr;
258}
259
260sub get_index {
261 my $self = shift (@_);
262
263 return $self->{'index'};
264}
265
266sub set_classifiers {
267 my $self = shift (@_);
268 my ($classifiers) = @_;
269
270 $self->{'classifiers'} = $classifiers;
271}
272
273sub set_indexing_text {
274 my $self = shift (@_);
275 my ($indexing_text) = @_;
276
277 $self->{'indexing_text'} = $indexing_text;
278}
279
280sub get_indexing_text {
281 my $self = shift (@_);
282
283 return $self->{'indexing_text'};
284}
285
286sub set_store_text {
287 my $self = shift (@_);
288 my ($store_text) = @_;
289
290 $self->{'store_text'} = $store_text;
291}
292
293sub set_store_metadata_coverage {
294 my $self = shift (@_);
295 my ($store_metadata_coverage) = @_;
296
297 $self->{'store_metadata_coverage'} = $store_metadata_coverage || "";
298}
299
300sub get_doc_list {
301 my $self = shift(@_);
302
303 return @{$self->{'doclist'}};
304}
305
306# the standard database level is section, but you may want to change it to document
307sub set_db_level {
308 my $self= shift (@_);
309 my ($db_level) = @_;
310
311 $self->{'db_level'} = $db_level;
312}
313
314sub set_sections_index_document_metadata {
315 my $self= shift (@_);
316 my ($index_type) = @_;
317
318 $self->{'sections_index_document_metadata'} = $index_type;
319}
320
321sub set_separate_cjk {
322 my $self = shift (@_);
323 my ($sep_cjk) = @_;
324
325 $self->{'separate_cjk'} = $sep_cjk;
326}
327
328sub process {
329 my $self = shift (@_);
330 my $method = $self->{'mode'};
331
332 $self->$method(@_);
333}
334
335# post process text depending on field. Currently don't do anything here
336# except cjk separation, and only for indexing
337# should only do this for indexed text (if $self->{'indexing_text'}),
338# but currently search term highlighting doesn't work if you do that.
339# once thats fixed up, then fix this.
340sub filter_text {
341 my $self = shift (@_);
342 my ($field, $text) = @_;
343
344 # lets do cjk seg here
345 my $new_text =$text;
346 if ($self->{'separate_cjk'}) {
347 $new_text = &cnseg::segment($text);
348 }
349 return $new_text;
350}
351
352
353sub infodb_metadata_stats
354{
355 my $self = shift (@_);
356 my ($field,$edit_mode) = @_;
357
358 # Keep some statistics relating to metadata sets used and
359 # frequency of particular metadata fields within each set
360
361 # Union of metadata prefixes and frequency of fields
362 # (both scoped for this document alone, and across whole collection)
363
364 if ($field =~ m/^(.+)\.(.*)$/) {
365 my $prefix = $1;
366 my $core_field = $2;
367
368 if (($edit_mode eq "add") || ($edit_mode eq "update")) {
369 $self->{'doc_mdprefix_fields'}->{$prefix}->{$core_field}++;
370 $self->{'mdprefix_fields'}->{$prefix}->{$core_field}++;
371 }
372 else {
373 # delete
374 $self->{'doc_mdprefix_fields'}->{$prefix}->{$core_field}--;
375 $self->{'mdprefix_fields'}->{$prefix}->{$core_field}--;
376 }
377
378 }
379 elsif ($field =~ m/^[[:upper:]]/) {
380 # implicit 'ex' metadata set
381
382 if (($edit_mode eq "add") || ($edit_mode eq "update")) {
383
384 $self->{'doc_mdprefix_fields'}->{'ex'}->{$field}++;
385 $self->{'mdprefix_fields'}->{'ex'}->{$field}++;
386 }
387 else {
388 # delete
389 $self->{'doc_mdprefix_fields'}->{'ex'}->{$field}--;
390 $self->{'mdprefix_fields'}->{'ex'}->{$field}--;
391 }
392 }
393
394}
395
396
397sub infodbedit {
398 my $self = shift (@_);
399 my ($doc_obj, $filename, $edit_mode) = @_;
400
401 # only output this document if it is a "indexed_doc" or "info_doc" (database only) document
402 my $doctype = $doc_obj->get_doc_type();
403 return if ($doctype ne "indexed_doc" && $doctype ne "info_doc");
404
405 my $archivedir = "";
406 if (defined $filename)
407 {
408 # doc_obj derived directly from file
409 my ($dir) = $filename =~ /^(.*?)(?:\/|\\)[^\/\\]*$/;
410 $dir = "" unless defined $dir;
411 $dir =~ s/\\/\//g;
412 $dir =~ s/^\/+//;
413 $dir =~ s/\/+$//;
414
415 $archivedir = $dir;
416
417 if ($edit_mode eq "delete") {
418 # record this doc so we don't process the reconstructed doc later
419 $self->{'dont_process_reconstructed'}->{$doc_obj->get_OID()} = 1;
420 # we don't need to do anything else for the info database for a deleted document. The infodb starts from scratch each time, so no deletion is necessary
421 $self->delete_assoc_files ($archivedir, "delete");
422 return;
423 }
424 if ($edit_mode eq "update") {
425 # we don't want to process the reconstructed doc later, but we will process this version now.
426 $self->{'dont_process_reconstructed'}->{$doc_obj->get_OID()} = 1;
427 # delete the old assoc files as they may have changed
428 $self->delete_assoc_files ($archivedir, "update");
429 }
430
431 # resolve the final filenames of the files associated with this document
432 # now save the new assoc files for an update/new doc.
433 $self->assoc_files ($doc_obj, $archivedir);
434 }
435 else
436 {
437 # doc_obj reconstructed from database (has metadata, doc structure but no text)
438 my $top_section = $doc_obj->get_top_section();
439 $archivedir = $doc_obj->get_metadata_element($top_section,"archivedir");
440 }
441
442 # rest of code used for add and update. In both cases, we add to the classifiers and to the info database.
443
444 #add this document to the browse structure
445 push(@{$self->{'doclist'}},$doc_obj->get_OID())
446 unless ($doctype eq "classification");
447 $self->{'num_docs'} += 1 unless ($doctype eq "classification");
448
449 if (!defined $filename) {
450 # a reconstructed doc
451 my $num_reconstructed_bytes = $doc_obj->get_metadata_element ($doc_obj->get_top_section (), "total_numbytes");
452 if (defined $num_reconstructed_bytes) {
453 $self->{'num_bytes'} += $num_reconstructed_bytes;
454 }
455 }
456 # classify the document
457 &classify::classify_doc ($self->{'classifiers'}, $doc_obj);
458
459 # now add all the sections to the infodb.
460
461 # is this a paged or a hierarchical document
462 my ($thistype, $childtype) = $self->get_document_type ($doc_obj);
463
464 my $section = $doc_obj->get_top_section ();
465 my $doc_OID = $doc_obj->get_OID();
466 my $first = 1;
467 my $infodb_handle = $self->{'output_handle'};
468
469 $self->{'doc_mdprefix_fields'} = {};
470
471 while (defined $section)
472 {
473 my $section_OID = $doc_OID;
474 if ($section ne "")
475 {
476 $section_OID = $doc_OID . "." . $section;
477 }
478 my %section_infodb = ();
479
480 # update a few statistics
481 $self->{'num_bytes'} += $doc_obj->get_text_length ($section);
482 $self->{'num_sections'} += 1 unless ($doctype eq "classification");
483
484 # output the fact that this document is a document (unless doctype
485 # has been set to something else from within a plugin
486 my $dtype = $doc_obj->get_metadata_element ($section, "doctype");
487 if (!defined $dtype || $dtype !~ /\w/) {
488 $section_infodb{"doctype"} = [ "doc" ];
489 }
490
491 if ($first && defined $filename) {
492 # if we are at the top level of the document, and we are not a reconstructed document, set the total_text_length - used to count bytes when we reconstruct later
493 my $length = $doc_obj->get_total_text_length();
494 $section_infodb{"total_numbytes"} = [ $length ];
495 }
496 # Output whether this node contains text
497 #
498 # If doc_obj reconstructed from database file then no need to
499 # explicitly add <hastxt> as this is preserved as metadata when
500 # the database file is loaded in
501 if (defined $filename)
502 {
503 # doc_obj derived directly from file
504 if ($doc_obj->get_text_length($section) > 0) {
505 $section_infodb{"hastxt"} = [ "1" ];
506 } else {
507 $section_infodb{"hastxt"} = [ "0" ];
508 }
509 }
510
511 # output all the section metadata
512 my $metadata = $doc_obj->get_all_metadata ($section);
513 foreach my $pair (@$metadata) {
514 my ($field, $value) = (@$pair);
515
516 if ($field ne "Identifier" && $field !~ /^gsdl/ &&
517 defined $value && $value ne "") {
518
519 # escape problematic stuff
520 $value =~ s/([^\\])\\([^\\])/$1\\\\$2/g;
521 $value =~ s/\n/\\n/g;
522 $value =~ s/\r/\\r/g;
523 # remove any ex. iff it's the only namespace prefix (will leave ex.dc.* intact)
524 $field =~ s/^ex\.([^.]+)$/$1/; # $field =~ s/^ex\.//;
525
526 # special case for UTF8URL metadata
527 if ($field =~ m/^UTF8URL$/i) {
528 &dbutil::write_infodb_entry($self->{'infodbtype'}, $infodb_handle,
529 $value, { 'section' => [ $section_OID ] });
530 }
531
532 if (!defined $self->{'dontdb'}->{$field}) {
533 push(@{$section_infodb{$field}}, $value);
534
535 if ($section eq ""
536 && (($self->{'store_metadata_coverage'} =~ /^true$/i)
537 || $self->{'store_metadata_coverage'} eq "1"))
538 {
539 $self->infodb_metadata_stats($field,$edit_mode);
540 }
541 }
542 }
543 }
544
545 if ($section eq "")
546 {
547 my $doc_mdprefix_fields = $self->{'doc_mdprefix_fields'};
548
549 foreach my $prefix (keys %$doc_mdprefix_fields)
550 {
551 push(@{$section_infodb{"metadataset"}}, $prefix);
552
553 foreach my $field (keys %{$doc_mdprefix_fields->{$prefix}})
554 {
555 push(@{$section_infodb{"metadatalist-$prefix"}}, $field);
556
557 my $val = $doc_mdprefix_fields->{$prefix}->{$field};
558 push(@{$section_infodb{"metadatafreq-$prefix-$field"}}, $val);
559 }
560 }
561 }
562
563 # If doc_obj reconstructed from database file then no need to
564 # explicitly add <archivedir> as this is preserved as metadata when
565 # the database file is loaded in
566 if (defined $filename)
567 {
568 # output archivedir if at top level
569 if ($section eq $doc_obj->get_top_section()) {
570 $section_infodb{"archivedir"} = [ $archivedir ];
571 }
572 }
573
574 # output document display type
575 if ($first) {
576 $section_infodb{"thistype"} = [ $thistype ];
577 }
578
579 if ($self->{'db_level'} eq "document") {
580 # doc num is num_docs not num_sections
581 # output the matching document number
582 $section_infodb{"docnum"} = [ $self->{'num_docs'} ];
583 }
584 else {
585 # output a list of children
586 my $children = $doc_obj->get_children ($section);
587 if (scalar(@$children) > 0) {
588 $section_infodb{"childtype"} = [ $childtype ];
589 my $contains = "";
590 foreach my $child (@$children)
591 {
592 $contains .= ";" unless ($contains eq "");
593 if ($child =~ /^.*?\.(\d+)$/)
594 {
595 $contains .= "\".$1";
596 }
597 else
598 {
599 $contains .= "\".$child";
600 }
601 }
602 $section_infodb{"contains"} = [ $contains ];
603 }
604 # output the matching doc number
605 $section_infodb{"docnum"} = [ $self->{'num_sections'} ];
606 }
607
608 &dbutil::write_infodb_entry($self->{'infodbtype'}, $infodb_handle, $section_OID, \%section_infodb);
609
610 # output a database entry for the document number, unless we are incremental
611 unless ($self->is_incremental_capable())
612 {
613 if ($self->{'db_level'} eq "document") {
614 &dbutil::write_infodb_entry($self->{'infodbtype'}, $infodb_handle, $self->{'num_docs'}, { 'section' => [ $doc_OID ] });
615 }
616 else {
617 &dbutil::write_infodb_entry($self->{'infodbtype'}, $infodb_handle, $self->{'num_sections'}, { 'section' => [ $section_OID ] });
618 }
619 }
620
621 $first = 0;
622 $section = $doc_obj->get_next_section($section);
623 last if ($self->{'db_level'} eq "document"); # if no sections wanted, only add the docs
624 } # while defined section
625
626}
627
628
629
630
631sub infodb {
632 my $self = shift (@_);
633 my ($doc_obj, $filename) = @_;
634
635 $self->infodbedit($doc_obj,$filename,"add");
636}
637
638sub infodbreindex {
639 my $self = shift (@_);
640 my ($doc_obj, $filename) = @_;
641
642 $self->infodbedit($doc_obj,$filename,"update");
643}
644
645sub infodbdelete {
646 my $self = shift (@_);
647 my ($doc_obj, $filename) = @_;
648
649 $self->infodbedit($doc_obj,$filename,"delete");
650}
651
652
653sub text {
654 my $self = shift (@_);
655 my ($doc_obj) = @_;
656
657 my $handle = $self->{'outhandle'};
658 print $handle "basebuildproc::text function must be implemented in sub classes\n";
659 die "\n";
660}
661
662sub textreindex
663{
664 my $self = shift @_;
665
666 my $outhandle = $self->{'outhandle'};
667 print $outhandle "basebuildproc::textreindex function must be implemented in sub classes\n";
668 if (!$self->is_incremental_capable()) {
669
670 print $outhandle " This operation is only possible with indexing tools with that support\n";
671 print $outhandle " incremental building\n";
672 }
673 die "\n";
674}
675
676sub textdelete
677{
678 my $self = shift @_;
679
680 my $outhandle = $self->{'outhandle'};
681 print $outhandle "basebuildproc::textdelete function must be implemented in sub classes\n";
682 if (!$self->is_incremental_capable()) {
683
684 print $outhandle " This operation is only possible with indexing tools with that support\n";
685 print $outhandle " incremental building\n";
686 }
687 die "\n";
688}
689
690
691# should the document be indexed - according to the subcollection and language
692# specification.
693sub is_subcollection_doc {
694 my $self = shift (@_);
695 my ($doc_obj) = @_;
696
697 my $indexed_doc = 1;
698 foreach my $indexexp (@{$self->{'indexexparr'}}) {
699 $indexed_doc = 0;
700 my ($field, $exp, $options) = split /\//, $indexexp;
701 if (defined ($field) && defined ($exp)) {
702 my ($bool) = $field =~ /^(.)/;
703 $field =~ s/^.// if $bool eq '!';
704 my @metadata_values;
705 if ($field =~ /^filename$/i) {
706 push(@metadata_values, $doc_obj->get_source_filename());
707 }
708 else {
709 $field =~ s/^ex\.([^.]+)$/$1/; # remove any ex. iff it's the only namespace prefix (will leave ex.dc.* intact)
710 @metadata_values = @{$doc_obj->get_metadata($doc_obj->get_top_section(), $field)};
711 }
712 next unless @metadata_values;
713 foreach my $metadata_value (@metadata_values) {
714 if ($bool eq '!') {
715 if ($options =~ /^i$/i) {
716 if ($metadata_value !~ /$exp/i) {$indexed_doc = 1; last;}
717 } else {
718 if ($metadata_value !~ /$exp/) {$indexed_doc = 1; last;}
719 }
720 } else {
721 if ($options =~ /^i$/i) {
722 if ($metadata_value =~ /$exp/i) {$indexed_doc = 1; last;}
723 } else {
724 if ($metadata_value =~ /$exp/) {$indexed_doc = 1; last;}
725 }
726 }
727 }
728
729 last if ($indexed_doc == 1);
730 }
731 }
732
733 # if this doc is so far in the sub collection, and we have lang info,
734 # now we check the languages to see if it matches
735 if($indexed_doc && defined $self->{'lang_meta'}) {
736 $indexed_doc = 0;
737 my $field = $doc_obj->get_metadata_element($doc_obj->get_top_section(), $self->{'lang_meta'});
738 if (defined $field) {
739 foreach my $lang (@{$self->{'langarr'}}) {
740 my ($bool) = $lang =~ /^(.)/;
741 if ($bool eq '!') {
742 $lang =~ s/^.//;
743 if ($field !~ /$lang/) {
744 $indexed_doc = 1; last;
745 }
746 } else {
747 if ($field =~ /$lang/) {
748 $indexed_doc = 1; last;
749 }
750 }
751 }
752 }
753 }
754 return $indexed_doc;
755
756}
757
758# use 'Paged' if document has no more than 2 levels
759# and each section at second level has a number for
760# Title metadata
761# also use Paged if gsdlthistype metadata is set to Paged
762sub get_document_type {
763 my $self = shift (@_);
764 my ($doc_obj) = @_;
765
766 my $thistype = "VList";
767 my $childtype = "VList";
768 my $title;
769 my @tmp = ();
770
771 my $section = $doc_obj->get_top_section ();
772
773 my $gsdlthistype = $doc_obj->get_metadata_element ($section, "gsdlthistype");
774 if (defined $gsdlthistype) {
775 if ($gsdlthistype eq "Paged") {
776 $childtype = "Paged";
777 if ($doc_obj->get_text_length ($doc_obj->get_top_section())) {
778 $thistype = "Paged";
779 } else {
780 $thistype = "Invisible";
781 }
782
783 return ($thistype, $childtype);
784 } elsif ($gsdlthistype eq "Hierarchy") {
785 return ($thistype, $childtype); # use VList, VList
786 }
787 }
788 my $first = 1;
789 while (defined $section) {
790 @tmp = split /\./, $section;
791 if (scalar(@tmp) > 1) {
792 return ($thistype, $childtype);
793 }
794 if (!$first) {
795 $title = $doc_obj->get_metadata_element ($section, "Title");
796 if (!defined $title || $title !~ /^\d+$/) {
797 return ($thistype, $childtype);
798 }
799 }
800 $first = 0;
801 $section = $doc_obj->get_next_section($section);
802 }
803 if ($doc_obj->get_text_length ($doc_obj->get_top_section())) {
804 $thistype = "Paged";
805 } else {
806 $thistype = "Invisible";
807 }
808 $childtype = "Paged";
809 return ($thistype, $childtype);
810}
811
812sub assoc_files
813{
814 my $self = shift (@_);
815 my ($doc_obj, $archivedir) = @_;
816 my ($afile);
817
818 foreach my $assoc_file (@{$doc_obj->get_assoc_files()}) {
819 #rint STDERR "Processing associated file - copy " . $assoc_file->[0] . " to " . $assoc_file->[1] . "\n";
820 # if assoc file starts with a slash, we put it relative to the assoc
821 # dir, otherwise it is relative to the HASH... directory
822 if ($assoc_file->[1] =~ m@^[/\\]@) {
823 $afile = &util::filename_cat($self->{'assocdir'}, $assoc_file->[1]);
824 } else {
825 $afile = &util::filename_cat($self->{'assocdir'}, $archivedir, $assoc_file->[1]);
826 }
827 &util::hard_link ($assoc_file->[0], $afile, $self->{'verbosity'});
828 }
829}
830
831sub delete_assoc_files
832{
833 my $self = shift (@_);
834 my ($archivedir, $edit_mode) = @_;
835
836 my $assoc_dir = &util::filename_cat($self->{'assocdir'}, $archivedir);
837 if (-d $assoc_dir) {
838 &util::rm_r($assoc_dir);
839 }
840}
Note: See TracBrowser for help on using the repository browser.