source: trunk/gsdl/perllib/plugins/StructuredHTMLPlug.pm@ 10272

Last change on this file since 10272 was 10271, checked in by chi, 19 years ago

A new program to demonstrate HTML document (converted from other sources, e.g. WordToHtml) in a
hierarchical form based on user-defined headings.

  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
1###########################################################################
2#
3# StructuredHTMLPlug.pm -- html plugin with extra facilities for teasing out
4# hierarchical structure (such as h1, h2, h3 tags) in an HTML document
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# Copyright (C) 1999 New Zealand Digital Library Project
11#
12# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License as published by
14# the Free Software Foundation; either version 2 of the License, or
15# (at your option) any later version.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25#
26###########################################################################
27package StructuredHTMLPlug;
28
29use HTMLPlug;
30use ImagePlug;
31
32sub BEGIN {
33 @ISA = ('HTMLPlug');
34}
35
36my $arguments =
37 [ { 'name' => "check_toc",
38 'desc' => "StructuredHTMLPlug.check_toc'}",
39 'type' => "flag",
40 'reqd' => "no"},
41 { 'name' => "title_header",
42 'desc' => "{StructuredHTMLPlug.title_header}",
43 'type' => "regexp",
44 'reqd' => "no"},
45 { 'name' => "level1_header",
46 'desc' => "{StructuredHTMLPlug.level1_header}",
47 'type' => "regexp",
48 'reqd' => "no"},
49 { 'name' => "level2_header",
50 'desc' => "{StructuredHTMLPlug.level2_header}",
51 'type' => "regexp",
52 'reqd' => "no"},
53 { 'name' => "level3_header",
54 'desc' => "{StructuredHTMLPlug.level3_header}",
55 'type' => "regexp",
56 'reqd' => "no"},
57 { 'name' => "toc_header",
58 'desc' => "{StructuredHTMLPlug.toc_header}",
59 'type' => "regexp",
60 'reqd' => "no"},
61 { 'name' => "tof_header",
62 'desc' => "{StructuredHTMLPlug.tof_header}",
63 'type' => "regexp",
64 'reqd' => "no"}];
65
66my $options = { 'name' => "StructuredHTMLPlug",
67 'desc' => "{StructuredHTMLPlug.desc}",
68 'abstract' => "no",
69 'inherits' => "yes",
70 'args' => $arguments };
71
72sub new {
73 my ($class) = shift (@_);
74 my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
75 push(@$pluginlist, $class);
76
77 if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
78 if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
79
80 #my $self = (defined $hashArgOptLists)? new ConvertToPlug($pluginlist,$inputargs,$hashArgOptLists): new ConvertToPlug($pluginlist,$inputargs);
81 my $self = (defined $hashArgOptLists)? new HTMLPlug($pluginlist,$inputargs,$hashArgOptLists): new HTMLPlug($pluginlist,$inputargs);
82
83 print STDERR "*** StrucHTML = $self->{'assoc_files'}\n";
84
85 return bless $self, $class;
86
87}
88
89#sub new
90#{
91# my $class = shift (@_);
92# my $self = new HTMLPlug ($class, @_);
93# $self->{'plugin_type'} = "StructuredHTMLPlug";
94#
95# # 14-05-02 To allow for proper inheritance of arguments - John Thompson
96# my $option_list = $self->{'option_list'};
97# push( @{$option_list}, $options );
98
99# if (!parsargv::parse(\@_,
100# q^check_toc^,\$self->{'check_toc'},
101# q^title_header/.*/^,\$self->{'title_header'},
102# q^toc_header/.*/^,\$self->{'toc_header'},
103# q^tof_header/.*/^,\$self->{'tof_header'},
104# q^level1_header/.*/^,\$self->{'level1_header'},
105# q^level2_header/.*/^,\$self->{'level2_header'},
106# q^level3_header/.*/^,\$self->{'level3_header'},
107# "allow_extra_options")) {
108#
109# #my $self = new HTMLPlug($class, @_);
110# print STDERR "\nIncorrect options passed to $plugin_name, ";
111# print STDERR "check your collect.cfg configuration file\n";
112# $self->print_txt_usage(""); # Use default resource bundle
113# die "\n";
114# }
115# return bless $self, $class;
116#}
117
118
119sub read {
120 my $self = shift (@_);
121 my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $gli) = @_;
122
123 my $filename = $file;
124 $filename = &util::filename_cat ($base_dir, $file) if $base_dir =~ /\w/;
125
126 if ($filename =~ m/\.html?$/) {
127 my $poss_doc_filename = $filename;
128 $poss_doc_filename =~ s/\.html?$/.doc/;
129
130 if (-e $poss_doc_filename) {
131 # this file has already been processed by Word plugin
132 return 0;
133 }
134 }
135 return $self->SUPER::read(@_);
136}
137
138sub process {
139 my $self = shift (@_);
140 my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj) = @_;
141 my $outhandle = $self->{'outhandle'};
142
143 print $outhandle "StructuredHTMLPlug: processing $file\n"
144 if $self->{'verbosity'} > 1;
145
146 my @head_and_body = split(/<body/i,$$textref);
147 my $head = shift(@head_and_body);
148 my $body_text = join("<body", @head_and_body);
149
150 # get rid of TOC and TOF sections and their title
151 # If check_toc is enables, it means to get rid of toc and tof contents.
152 if ($self->{'check_toc'}){
153 #line-height:150%;mso-ansi-language:FR'>Contents<o:p></o:p></span></b></p>
154 # get rid of Table of Contents title and Table of Figures
155 $body_text =~ s/<p[^>]*><b><span[^>]*>(Table of Content.|Content.)<o:p><\/o:p><\/span><\/b><\/p>//isg;
156 $body_text =~ s/<p[^>]*><b><span[^>]*>(Table of Figure.|Figure.)<o:p><\/o:p><\/span><\/b><\/p>//isg;
157 $body_text =~ s/<p class=(($self->{'toc_header'})[^>]*)>(.+?)<\/p>//isg;
158 $body_text =~ s/<p class=(($self->{'tof_header'})[^>]*)>(.+?)<\/p>//isg;
159 }
160
161 if ($self->{'title_header'}){
162 $self->{'title_header'} =~ s/^(\()(.*)(\))/$2/is;
163 $body_text =~ s/<p class=(($self->{'title_header'})[^>]*)>(.+?)<\/p>/<p class=$1><title>$3<\/title><\/p>/isg;
164 }
165 if ($self->{'level1_header'}){
166 $self->{'level1_header'} =~ s/^(\()(.*)(\))/$2/is;
167 $body_text =~ s/<p class=(($self->{'level1_header'})[^>]*)>(.+?)<\/p>/<p class=$1><h1>$3<\/h1><\/p>/isg;
168 }
169 if ($self->{'level2_header'}){
170 $self->{'level2_header'} =~ s/^(\()(.*)(\))/$2/is;
171 $body_text =~ s/<p class=(($self->{'level2_header'})[^>]*)>(.+?)<\/p>/<p class=$1><h2>$3<\/h2><\/p>/isg;
172 }
173
174 if ($self->{'level3_header'}){
175 $self->{'level3_header'} =~ s/^(\()(.*)(\))/$2/is;
176 $body_text =~ s/<p class=(($self->{'level3_header'})[^>]*)>(.+?)<\/p>/<p class=$1><h3>$3<\/h3><\/p>/isg;
177 }
178
179 # Tidy up extra new lines
180 $body_text =~ s/(<p[^>]*><span[^>]*><o:p>&nbsp;<\/o:p><\/span><\/p>)//isg;
181 $body_text =~ s/(<p[^>]*><o:p>&nbsp;<\/o:p><\/p>)//isg;
182
183 my $body = "<body".$body_text;
184
185 my $section_text = $head;
186 $section_text .= "<!--\n<Section>\n-->\n";
187
188 # split HTML text on <h1>, <h2> etc tags
189 my @h_split = split(/<h/i,$body);
190
191 my $hnum = 0;
192
193 my $sectionh1 = 0;
194 $section_text .= shift(@h_split);
195
196 my $hc;
197 foreach $hc ( @h_split )
198 {
199 if ($hc =~ m/^([1-3])\s*.*?>(.*)$/s)
200 {
201 my $new_hnum = $1;
202 my $hc_after = $2;
203
204 if ($hc_after =~ m/^(.*?)<\/h$new_hnum>/is)
205 {
206 my $h_text = $1;
207 $hc =~ s/^(\&nbsp\;)+/\&nbsp\;/g;
208 # boil HTML down to some interesting text
209 $h_text =~ s/^[1-3]>//;
210 $h_text =~ s/<\/?.*?>//sg;
211 $h_text =~ s/\s+/ /sg;
212 $h_text =~ s/^\s$//s;
213 $h_text =~ s/(&nbsp;)+\W*/&nbsp;/sg;
214
215 if ($h_text =~ m/\w+/)
216 {
217 if ($new_hnum > $hnum)
218 {
219 # increase section nesting
220 $hnum++;
221 while ($hnum < $new_hnum)
222 {
223 my $spacing = " " x $hnum;
224 $section_text .= "<!--\n";
225 $section_text .= $spacing."<Section>\n";
226 $section_text .= "-->\n";
227 $hnum++;
228 }
229 }
230 else # ($new_hnum <= $hnum)
231 {
232 # descrease section nesting
233 while ($hnum >= $new_hnum)
234 {
235 my $spacing = " " x $hnum;
236 $section_text .= "<!--\n";
237 $section_text .= $spacing."</Section>\n";
238 $section_text .= "-->\n";
239 $hnum--;
240 }
241 $hnum++;
242 }
243
244 my $spacing = " " x $hnum;
245 $section_text .= "<!--\n";
246 $section_text .= $spacing."<Section>\n";
247 $section_text .= $spacing." <Description>\n";
248 $section_text .= $spacing." <Metadata name=\"Title\">$h_text</Metadata>";
249 $section_text .= $spacing." </Description>\n";
250 $section_text .= "-->\n";
251
252 print $outhandle $spacing."$h_text\n"
253 if $self->{'verbosity'} > 2;
254
255 $sectionh1++ if ($hnum==1);
256 }
257 }
258 else {
259### print STDERR "***** hc = <h$hc\n\n";
260
261 }
262 # $section_text .= "<!-- \n</Section>\n-->\n";
263 #print STDERR "***HC = $hc\n";
264 $section_text .= "<h$hc";
265 }
266 else
267 {
268 $section_text .= "<h$hc";
269 }
270 }
271
272 while ($hnum >= 1)
273 {
274 my $spacing = " " x $hnum;
275 $section_text .= "<!--\n";
276 $section_text .= $spacing."</Section>\n";
277 $section_text .= "-->\n";
278 $hnum--;
279 }
280
281 $section_text .= "<!--\n</Section>\n-->\n";
282
283 $$textref = $section_text;
284
285# should be textref not testref???
286# $$testref =~ s/<h(\d+)>(.*?)<\/h$1>/<Section><Metadata name=\"Title\">$1<\/Metadata></Section><h$1><\/h$1>/gi;
287
288 if ($sectionh1>0)
289 {
290 print $outhandle " Located section headings ..."
291 if $self->{'verbosity'} > 1;
292 }
293 print $outhandle " Passing on the HTMLPlug\n"
294 if $self->{'verbosity'} > 1;
295
296 $$textref =~ s/<!\[if !vml\]>/<![if vml]>/g;
297
298 $$textref =~ s/(&nbsp;)+/&nbsp;/sg;
299
300## $$textref =~ s/<o:p>&nbsp;<\/o:p>//g; # used with VML to space figures?
301
302 $self->SUPER::process(@_);
303
304 # associate original file with doc object
305 my $cursection = $doc_obj->get_top_section();
306 my $filename = &util::filename_cat($base_dir, $file);
307 if (-e $filename)
308 {
309 print $outhandle " Adding associated Word document\n"
310 if $self->{'verbosity'} > 1;
311
312 $doc_obj->associate_file($filename, "doc.doc", undef, $cursection);
313
314 my $doclink = "<a href=_httpcollection_/index/assoc/[archivedir]/doc.doc>";
315 $doc_obj->add_utf8_metadata ($cursection, "srclink", $doclink);
316 $doc_obj->add_utf8_metadata ($cursection, "srcicon", "_icondoc_");
317 $doc_obj->add_utf8_metadata ($cursection, "/srclink", "</a>");
318
319 my $file_size = -s $filename;
320 if ($file_size>1024)
321 {
322 my $fs_kbytes = sprintf("%d",$file_size/1024);
323 $doc_obj->add_utf8_metadata ($cursection, "filesize", "$fs_kbytes Kb");
324 }
325 else
326 {
327 $doc_obj->add_utf8_metadata ($cursection, "filesize", "$file_size bytes");
328 }
329
330 if ($file_size > 200000)
331 {
332 $doc_obj->add_utf8_metadata ($cursection, "fswarning", "1");
333 }
334 }
335}
336
337
338sub resize_if_necessary
339{
340 my ($self,$front,$back,$base_dir,$href) = @_;
341
342 # dig out width and height of image, if there
343 my $img_attributes = "$front back";
344 my ($img_width) = ($img_attributes =~ m/\s+width=\"?(\d+)\"?/i);
345 my ($img_height) = ($img_attributes =~ m/\s+height=\"?(\d+)\"?/i);
346
347 # derive local filename for image based on its URL
348 my $img_filename = $href;
349 $img_filename =~ s/^[^:]*:\/\///;
350 $img_filename = &util::filename_cat($base_dir, $img_filename);
351
352 # Replace %20's in URL with a space if required. Note that the filename
353 # may include the %20 in some situations
354 if ($img_filename =~ /\%20/) {
355 if (!-e $img_filename) {
356 $img_filename =~ s/\%20/ /g;
357 }
358 }
359 if ((-e $img_filename) && (defined $img_width) && (defined $img_height)) {
360 # get image info on width and height
361
362 my $outhandle = $self->{'outhandle'};
363 my $verbosity = $self->{'verbosity'};
364
365 my ($image_type, $actual_width, $actual_height, $image_size)
366 = &ImagePlug::identify($img_filename, $outhandle, $verbosity);
367
368 print STDERR "**** $actual_width x $actual_height";
369 print STDERR " (requested: $img_width x $img_height)\n";
370
371 if (($img_width < $actual_width) || ($img_height < $actual_height)) {
372 print $outhandle "Resizing $img_filename\n" if ($verbosity > 0);
373
374 # derive new image name based on current image
375 my ($tailname, $dirname, $suffix)
376 = &File::Basename::fileparse($input_filename, "\\.[^\\.]+\$");
377
378 my $resized_filename
379 = &util::filename_cat($dirname, $tailname."_resized".$suffix);
380
381 print STDERR "**** suffix = $suffix\n";
382
383 # Generate smaller image with convert
384 my $newsize = "$img_widthx$image_height";
385 my $command = "convert -interlace plane -verbose "
386 ."-geometry $newsize \"img_$filename\" \"$resized_filename\"";
387 print $outhandle "ImageResize: $command\n" if ($verbosity > 2);
388 my $result = '';
389 print $outhandle "ImageResize result: $result\n" if ($verbosity > 2);
390
391 }
392 }
393
394 return $href;
395}
396
397
398
399
400sub replace_images {
401 my $self = shift (@_);
402 my ($front, $link, $back, $base_dir,
403 $file, $doc_obj, $section) = @_;
404 # remove quotes from link at start and end if necessary
405 if ($link=~/^\"/) {
406 $link=~s/^\"//;$link=~s/\"$//;
407 $front.='"';
408 $back="\"$back";
409 }
410
411 $link =~ s/\n/ /g;
412
413 my ($href, $hash_part, $rl) = $self->format_link ($link, $base_dir, $file);
414
415## $href = $self->resize_if_necessary($front,$back,$base_dir,$href);
416
417 my $middle = $self->add_file ($href, $rl, $hash_part, $base_dir, $doc_obj, $section);
418
419 return $front . $middle . $back;
420}
421
422
4231;
Note: See TracBrowser for help on using the repository browser.