source: main/trunk/greenstone2/perllib/plugins/LOMPlugin.pm@ 36470

Last change on this file since 36470 was 36470, checked in by davidb, 20 months ago

Tweaks after refactoring. Causes 'use strict' to report error as using variables that don't exist. Changes looked over by Kathy/David, yet to be tested however

  • Property svn:keywords set to Author Date Id Revision
File size: 19.6 KB
Line 
1###########################################################################
2#
3# LOMPlugin.pm -- plugin for import the collection from LOM
4#
5# A component of the Greenstone digital library software
6# from the New Zealand Digital Library Project at the
7# University of Waikato, New Zealand.
8#
9# Copyright (C) 2005 New Zealand Digital Library Project
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24#
25###########################################################################
26
27### Note this plugin currently can't download source documents from outside if you are behind a firewall.
28# Unless, you set the http_proxy environment variable to be your proxy server,
29# and set proxy_user and proxy_password in .wgetrc file in home directory.
30# (does that work on windows??)
31
32package LOMPlugin;
33
34use ReadTextFile;
35use MetadataPass;
36use MetadataRead;
37use util;
38use FileUtils;
39use XMLParser;
40use Cwd;
41
42# methods with identical signatures take precedence in the order given in the ISA list.
43sub BEGIN {
44 @ISA = ('MetadataRead', 'ReadTextFile', 'MetadataPass');
45}
46
47use strict; # every perl program should have this!
48no strict 'refs'; # make an exception so we can use variables as filehandles
49
50
51my $arguments =
52 [ { 'name' => "process_exp",
53 'desc' => "{BaseImporter.process_exp}",
54 'type' => "string",
55 'deft' => &get_default_process_exp(),
56 'reqd' => "no" },
57 { 'name' => "root_tag",
58 'desc' => "{LOMPlugin.root_tag}",
59 'type' => "regexp",
60 'deft' => q/^(?i)lom$/,
61 'reqd' => "no" },
62 { 'name' => "check_timestamp",
63 'desc' => "{LOMPlugin.check_timestamp}",
64 'type' => "flag" },
65 { 'name' => "download_srcdocs",
66 'desc' => "{LOMPlugin.download_srcdocs}",
67 'type' => "regexp",
68 'deft' => "",
69 'reqd' => "no" }];
70
71my $options = { 'name' => "LOMPlugin",
72 'desc' => "{LOMPlugin.desc}",
73 'abstract' => "no",
74 'inherits' => "yes",
75 'args' => $arguments };
76
77
78
79my ($self);
80sub new {
81 my $class = shift (@_);
82 my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
83 push(@$pluginlist, $class);
84
85 push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});
86 push(@{$hashArgOptLists->{"OptList"}},$options);
87
88 $self = new ReadTextFile($pluginlist, $inputargs, $hashArgOptLists);
89
90 if ($self->{'info_only'}) {
91 # don't worry about creating the XML parser as all we want is the
92 # list of plugin options
93 return bless $self, $class;
94 }
95
96 #create XML::Parser object for parsing dublin_core.xml files
97 my $parser = new XML::Parser('Style' => 'Stream',
98 'Handlers' => {'Char' => \&Char,
99 'Doctype' => \&Doctype
100 });
101 $self->{'parser'} = $parser;
102
103 $self->{'extra_blocks'} = {};
104
105 $self->{'endline'} = ($ENV{'GSDL3SRCHOME'}) ? "" : "\n";
106
107 return bless $self, $class;
108}
109
110sub get_default_process_exp {
111 my $self = shift (@_);
112
113 return q^(?i)\.xml$^;
114}
115
116
117sub can_process_this_file {
118 my $self = shift(@_);
119 my ($filename) = @_;
120
121 if ($self->SUPER::can_process_this_file($filename) && $self->check_doctype($filename)) {
122 return 1; # its a file for us
123 }
124 return 0;
125}
126
127sub metadata_read {
128 my $self = shift (@_);
129 my ($pluginfo, $base_dir, $file, $block_hash,
130 $extrametakeys, $extrametadata, $extrametafile,
131 $processor, $gli, $aux) = @_;
132
133 my $outhandle = $self->{'outhandle'};
134
135 # can we process this file??
136 my ($filename_full_path, $filename_no_path) = &util::get_full_filenames($base_dir, $file);
137 return undef unless $self->can_process_this_file_for_metadata($filename_full_path);
138
139 $file =~ s/^[\/\\]+//; # $file often begins with / so we'll tidy it up
140
141 print $outhandle "LOMPlugin: extracting metadata from $file\n"
142 if $self->{'verbosity'} > 1;
143
144 my ($dir,$tail) = $filename_full_path =~ /^(.*?)([^\/\\]*)$/;
145 $self->{'output_dir'} = $dir;
146
147 eval {
148 $self->{'parser'}->parsefile($filename_full_path);
149 };
150
151 if ($@) {
152 print $outhandle "LOMPlugin: skipping $filename_full_path as not conformant to LOM syntax\n" if ($self->{'verbosity'} > 1);
153 print $outhandle "\n Perl Error:\n $@\n" if ($self->{'verbosity'}>2);
154 return 0;
155 }
156
157 $self->{'output_dir'} = undef;
158
159 my $file_re;
160 my $lom_srcdoc = $self->{'lom_srcdoc'};
161
162 if (defined $lom_srcdoc) {
163 my $dirsep = &util::get_re_dirsep();
164 $lom_srcdoc =~ s/^$base_dir($dirsep)//;
165 $self->{'extra_blocks'}->{$file}++;
166 $file_re = $lom_srcdoc;
167 }
168 else {
169 $file_re = $tail;
170 }
171
172 if (defined $lom_srcdoc) {
173 $self->store_meta_in_extrametadata($file_re, $self->{'saved_metadata'}, $file, $filename_full_path, $extrametakeys, $extrametadata, $extrametafile);
174 } else {
175 $self->store_meta_in_extrametadata($file_re, $self->{'saved_metadata'}, undef, undef, $extrametakeys, $extrametadata, $extrametafile);
176 }
177 $self->{'lom_srcdoc'} = undef; # reset for next file to be processed
178
179 return 1;
180}
181
182sub check_doctype {
183 $self = shift (@_);
184
185 my ($filename) = @_;
186
187 if (open(XMLIN,"<$filename")) {
188 my $doctype = $self->{'root_tag'};
189 ## check whether the doctype has the same name as the root element tag
190 while (defined (my $line = <XMLIN>)) {
191 ## find the root element
192 if ($line =~ /<([\w\d:]+)[\s>]/){
193 my $root = $1;
194 if ($root !~ $doctype){
195 close(XMLIN);
196 return 0;
197 }
198 else {
199 close(XMLIN);
200 return 1;
201 }
202 }
203 }
204 close(XMLIN);
205 }
206
207 return undef; # haven't found a valid line
208
209}
210
211sub read_file {
212 my $self = shift (@_);
213 my ($filename, $encoding, $language, $textref) = @_;
214
215 my $metadata_table = $self->{'metadata_table'};
216
217 my $rawtext = $metadata_table->{'rawtext'};
218
219 delete $metadata_table->{'rawtext'};
220
221 $$textref = $rawtext;
222}
223
224sub read {
225 my $self = shift (@_);
226 my ($pluginfo, $base_dir, $file, $block_hash, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
227
228 my $outhandle = $self->{'outhandle'};
229
230 return 0 if (defined $self->{'extra_blocks'}->{$file});
231
232 # can we process this file??
233 my ($filename_full_path, $filename_no_path) = &util::get_full_filenames($base_dir, $file);
234 return undef unless $self->can_process_this_file($filename_full_path);
235
236 $self->{'metadata_table'} = $metadata;
237
238 my $lom_language = $metadata->{'lom_language'};
239
240 my $store_input_encoding;
241 my $store_extract_language;
242 my $store_default_language;
243 my $store_default_encoding;
244
245 if (defined $lom_language) {
246 delete $metadata->{'lom_language'};
247
248 $store_input_encoding = $self->{'input_encoding'};
249 $store_extract_language = $self->{'extract_language'};
250 $store_default_language = $self->{'default_language'};
251 $store_default_encoding = $self->{'default_encoding'};
252
253 $self->{'input_encoding'} = "utf8";
254 $self->{'extract_language'} = 0;
255 $self->{'default_language'} = $lom_language;
256 $self->{'default_encoding'} = "utf8";
257 }
258
259 my $rv = $self->SUPER::read(@_);
260
261 if (defined $lom_language) {
262 $self->{'input_encoding'} = $store_input_encoding;
263 $self->{'extract_language'} = $store_extract_language;
264 $self->{'default_language'} = $store_default_language;
265 $self->{'default_encoding'} = $store_default_encoding;
266 }
267
268 $self->{'metadata_table'} = undef;
269
270 return $rv;
271}
272
273# do plugin specific processing of doc_obj
274sub process {
275 my $self = shift (@_);
276 my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
277 my $outhandle = $self->{'outhandle'};
278
279 my $cursection = $doc_obj->get_top_section();
280 $doc_obj->add_utf8_text($cursection, $$textref);
281
282 return 1;
283}
284
285sub Doctype {
286 my ($expat, $name, $sysid, $pubid, $internal) = @_;
287
288 my $root_tag = $self->{'root_tag'};
289
290 if ($name !~ /$root_tag/) {
291 die "Root tag $name does not match regular expression $root_tag";
292 }
293}
294
295sub StartTag {
296 my ($expat, $element) = @_;
297
298 my %attr = %_;
299
300 my $raw_tag = "&lt;$element";
301 map { $raw_tag .= " $_=\"$attr{$_}\""; } keys %attr;
302 $raw_tag .= "&gt;";
303
304 if ($element =~ m/$self->{'root_tag'}/) {
305 $self->{'raw_text'} = $raw_tag;
306
307 $self->{'saved_metadata'} = {};
308 $self->{'metaname_stack'} = [];
309 $self->{'lom_datatype'} = "";
310 $self->{'lom_language'} = undef;
311 $self->{'metadatatext'} = "<table class=\"metadata\" width=\"_pagewidth_\" >".$self->{'endline'};
312 }
313 else {
314 my $xml_depth = scalar(@{$self->{'metaname_stack'}});
315 $self->{'raw_text'} .= "\n";
316 $self->{'raw_text'} .= "&nbsp;&nbsp;" x $xml_depth;
317 $self->{'raw_text'} .= $raw_tag;
318
319 my $metaname_stack = $self->{'metaname_stack'};
320 push(@$metaname_stack,$element);
321 if (scalar(@$metaname_stack)==1) {
322 # top level LOM category
323 my $style = "class=\"metadata\"";
324 my $open_close
325 = "<a id=\"${element}opencloselink\" href=\"javascript:hideTBodyArea('$element')\">".$self->{'endline'};
326 $open_close
327 .= "<img id=\"${element}openclose\" border=\"0\" src=\"_httpopenmdicon_\"></a>".$self->{'endline'};
328
329 my $header_line = " <tr $style ><th $style colspan=\"3\">$open_close \u$element</th></tr>".$self->{'endline'};
330 my $md_tbody = "<tbody id=\"$element\">".$self->{'endline'};
331
332 $self->{'mdheader'} = $header_line;
333 $self->{'mdtbody'} = $md_tbody;
334 $self->{'mdtbody_text'} = "";
335 }
336 }
337}
338
339sub EndTag {
340 my ($expat, $element) = @_;
341
342 my $raw_tag = "&lt;/$element&gt;";
343
344 if ($element =~ m/$self->{'root_tag'}/) {
345 $self->{'raw_text'} .= $raw_tag;
346
347 my $metadatatext = $self->{'metadatatext'};
348 $metadatatext .= "</table>";
349
350 my $raw_text = $self->{'raw_text'};
351
352 $self->{'saved_metadata'}->{'MetadataTable'} = $metadatatext;
353 $self->{'metadatatext'} = "";
354
355 $self->{'saved_metadata'}->{'rawtext'} = $raw_text;
356 $self->{'raw_text'} = "";
357
358 if (defined $self->{'lom_language'}) {
359 $self->{'saved_metadata'}->{'lom_language'} = $self->{'lom_language'};
360 $self->{'lom_language'} = undef;
361 }
362 }
363 else {
364 my $metaname_stack = $self->{'metaname_stack'};
365
366 if (scalar(@$metaname_stack)==1) {
367 my $header_line = $self->{'mdheader'};
368 my $tbody_start = $self->{'mdtbody'};
369 my $tbody_text = $self->{'mdtbody_text'};
370 if ($tbody_text !~ m/^\s*$/s) {
371 my $tbody_end = "</tbody>".$self->{'endline'};
372 my $table_chunk
373 = $header_line.$tbody_start.$tbody_text.$tbody_end;
374
375 $self->{'metadatatext'} .= $table_chunk;
376 }
377 $self->{'mdtheader'} = "";
378 $self->{'mdtbody'} = "";
379 $self->{'mdtbody_text'} = "";
380 }
381
382 pop(@$metaname_stack);
383
384 my $xml_depth = scalar(@{$self->{'metaname_stack'}});
385 $self->{'raw_text'} .= "\n";
386 $self->{'raw_text'} .= "&nbsp;&nbsp;" x $xml_depth;
387 $self->{'raw_text'} .= $raw_tag;
388 }
389}
390
391sub process_datatype_info
392{
393 my $self = shift(@_);
394 my ($metaname_stack,$md_content) = @_;
395
396 my @without_dt_stack = @$metaname_stack; # without datatype stack
397
398 my $innermost_element = $without_dt_stack[$#without_dt_stack];
399
400 # Loose last item if encoding datatype information
401 if ($innermost_element =~ m/^(lang)?string$/) {
402 $self->{'lom_datatype'} = $innermost_element;
403
404 pop @without_dt_stack;
405 $innermost_element = $without_dt_stack[$#without_dt_stack];
406 }
407 elsif ($innermost_element =~ m/^date(Time)?$/i) {
408 if ($innermost_element =~ m/^date$/i) {
409 $self->{'lom_datatype'} = "dateTime";
410 }
411 else {
412 $self->{'lom_datatype'} = $innermost_element;
413
414 pop @without_dt_stack;
415 $innermost_element = $without_dt_stack[$#without_dt_stack];
416 }
417
418 if ($md_content =~ m/^(\d{1,2})\s*(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\w*\s*(\d{4})/i) {
419 my ($day,$mon,$year) = ($1,$2,$3);
420
421 my %month_lookup = ( 'jan' => 1, 'feb' => 2, 'mar' => 3,
422 'apr' => 4, 'may' => 5, 'jun' => 6,
423 'jul' => 7, 'aug' => 8, 'sep' => 9,
424 'oct' => 10, 'nov' => 11, 'dec' => 12 );
425
426 my $mon_num = $month_lookup{lc($mon)};
427
428 $md_content = sprintf("%d%02d%02d",$year,$mon_num,$day);
429 }
430
431 $md_content =~ s/\-//g;
432 }
433
434 if ($innermost_element eq "source") {
435 $self->{'lom_source'} = $md_content;
436 }
437 elsif ($innermost_element eq "value") {
438 $self->{'lom_value'} = $md_content;
439 }
440
441 return (\@without_dt_stack,$innermost_element,$md_content);
442}
443
444sub reset_datatype_info
445{
446 my $self = shift(@_);
447
448 $self->{'lom_datatype'} = "";
449}
450
451
452sub pretty_print_text
453{
454 my $self = shift(@_);
455
456 my ($pretty_print_text) = @_;
457
458## $metavalue_utf8 = &util::hyperlink_text($metavalue_utf8);
459 $pretty_print_text = &util::hyperlink_text($pretty_print_text);
460
461#### $pretty_print_text =~ s/(BEGIN:vCard.*END:vCard)/<pre>$1<\/pre>/sg;
462
463 if ($self->{'lom_datatype'} eq "dateTime") {
464 if ($pretty_print_text =~ m/^(\d{4})(\d{2})(\d{2})$/) {
465 $pretty_print_text = "$1-$2-$3";
466 }
467 }
468
469 return $pretty_print_text;
470}
471
472sub pretty_print_table_tr
473{
474 my $self = shift (@_);
475 my ($without_dt_stack) = @_;
476
477 my $style = "class=\"metadata\"";
478
479 my $innermost_element = $without_dt_stack->[scalar(@$without_dt_stack)-1];
480 my $outermost_element = $without_dt_stack->[0];
481
482 # Loose top level stack item (already named in pretty print table)
483 my @pretty_print_stack = @$without_dt_stack;
484 shift @pretty_print_stack;
485
486 if ($innermost_element eq "source") {
487 return if (!defined $self->{'lom_value'});
488 }
489
490 if ($innermost_element eq "value") {
491 return if (!defined $self->{'lom_source'});
492 }
493
494 my $pretty_print_text = "";
495
496 if (($innermost_element eq "value") || ($innermost_element eq "source")) {
497 my $source = $self->{'lom_source'};
498 my $value = $self->pretty_print_text($self->{'lom_value'});
499
500 $self->{'lom_source'} = undef;
501 $self->{'lom_value'} = undef;
502
503 pop @pretty_print_stack;
504
505 $pretty_print_text = "<td $style>$source</td><td $style>$value</td>";
506 }
507 else {
508 $pretty_print_text = $self->pretty_print_text($_);
509 $pretty_print_text = "<td $style colspan=2>$pretty_print_text</td>";
510 }
511 my $pretty_print_fmn = join(' : ',map { "\u$_"; } @pretty_print_stack);
512
513
514 # my $tr_attr = "id=\"$outermost_element\" style=\"display:block;\"";
515 my $tr_attr = "$style id=\"$outermost_element\"";
516
517 my $mdtext_line = " <tr $tr_attr><td $style><nobr>$pretty_print_fmn</nobr></td>$pretty_print_text</tr>".$self->{'endline'};
518 $self->{'mdtbody_text'} .= $mdtext_line;
519}
520
521
522sub check_for_language
523{
524 my $self = shift(@_);
525 my ($innermost_element,$md_content) = @_;
526
527 # Look for 'language' tag
528 if ($innermost_element eq "language") {
529 my $lom_lang = $self->{'lom_language'};
530
531 if (defined $lom_lang) {
532 my $new_lom_lang = $md_content;
533 $new_lom_lang =~ s/-.*//; # remove endings like -US or -GB
534
535 if ($lom_lang ne $new_lom_lang) {
536 my $outhandle = $self->{'outhandle'};
537
538 print $outhandle "Warning: Conflicting general language in record\n";
539 print $outhandle " $new_lom_lang (previous value for language = $lom_lang)\n";
540 }
541 # otherwise, existing value OK => do nothing
542 }
543 else {
544 $lom_lang = $md_content;
545 $lom_lang =~ s/-.*//; # remove endings like -US or -GB
546
547 $self->{'lom_language'} = $lom_lang;
548 }
549 }
550}
551
552sub found_specific_identifier
553{
554 my $self = shift(@_);
555 my ($specific_id,$full_mname,$md_content) = @_;
556
557 my $found_id = 0;
558 if ($full_mname eq $specific_id) {
559 if ($md_content =~ m/^(http|ftp):/) {
560 $found_id = 1;
561 }
562 }
563
564 return $found_id;
565}
566
567sub download_srcdoc
568{
569 my $self = shift(@_);
570 my ($doc_url) = @_;
571
572 my $outhandle = $self->{'outhandle'};
573 my $output_dir = $self->{'output_dir'};
574
575 $output_dir = &FileUtils::filenameConcatenate($output_dir,"_gsdldown.all");
576
577 if (! -d $output_dir) {
578 mkdir $output_dir;
579 }
580
581 my $re_dirsep = &util::get_re_dirsep();
582 my $os_dirsep = &util::get_dirsep();
583
584 my $file_url = $doc_url;
585 $file_url =~ s/$re_dirsep/$os_dirsep/g;
586 $file_url =~ s/^(http|ftp):\/\///;
587 $file_url .= "index.html" if ($file_url =~ m/\/$/);
588
589 my $full_file_url = &FileUtils::filenameConcatenate($output_dir,$file_url);
590 # the path to srcdoc will be used later in extrametadata to associate
591 # the lom metadata with the document. Needs to be relative to current
592 # directory.
593 my $srcdoc_path = &FileUtils::filenameConcatenate("_gsdldown.all", $file_url);
594 my $check_timestamp = $self->{'check_timestamp'};
595 my $status;
596
597 if (($check_timestamp) || (!$check_timestamp && !-e $full_file_url)) {
598 if (!-e $full_file_url) {
599 print $outhandle "Mirroring $doc_url\n";
600 }
601 else {
602 print $outhandle "Checking to see if update needed for $doc_url\n";
603 }
604
605 # on linux, if we pass an absolute path as -P arg to wget, then it
606 # stuffs up the
607 # URL rewriting in the file. Need a relative path or none, so now
608 # we change working directory first.
609 my $changed_dir = 0;
610 my $current_dir = cwd();
611 my $wget_cmd = "";
612 if ($ENV{'GSDLOS'} ne "windows") {
613 $changed_dir = 1;
614
615 chdir "$output_dir";
616 $wget_cmd = "wget -nv --timestamping -k -p \"$doc_url\"";
617 } else {
618 $wget_cmd = "wget -nv -P \"$output_dir\" --timestamping -k -p \"$doc_url\"";
619 }
620 ##print STDERR "**** wget = $wget_cmd\n";
621
622 # the wget binary is dependent on the gnomelib_env (particularly lib/libiconv2.dylib) being set, particularly on Mac Lions (android too?)
623 &util::set_gnomelib_env(); # this will set the gnomelib env once for each subshell launched, by first checking if GEXTGNOME is not already set
624
625 $status = system($wget_cmd);
626 if ($changed_dir) {
627 chdir $current_dir;
628 }
629 if ($status==0) {
630 $self->{'lom_srcdoc'} = $srcdoc_path;
631 }
632 else {
633 $self->{'lom_srcdoc'} = undef;
634 print $outhandle "Error: failed to execute $wget_cmd\n";
635 }
636 }
637 else {
638 # not time-stamping and file already exists
639 $status=0;
640 $self->{'lom_srcdoc'} = $srcdoc_path;
641 }
642
643 return $status==0;
644
645}
646
647
648sub check_for_identifier
649{
650 my $self = shift(@_);
651 my ($full_mname,$md_content) = @_;
652
653 my $success = 0;
654
655 my $download_re = $self->{'download_srcdocs'};
656 if (($download_re ne "") && $md_content =~ m/$download_re/) {
657
658 if ($self->found_specific_identifier("general^identifier^entry",$full_mname,$md_content)) {
659 $success = $self->download_srcdoc($md_content);
660 }
661
662 if (!$success) {
663 if ($self->found_specific_identifier("technical^location",$full_mname,$md_content)) {
664 $success = $self->download_srcdoc($md_content);
665 }
666 }
667 }
668
669 return $success;
670}
671
672
673sub Text {
674 if ($_ !~ m/^\s*$/) {
675 #
676 # Work out indentations and line wraps for raw XML
677 #
678 my $xml_depth = scalar(@{$self->{'metaname_stack'}})+1;
679 my $indent = "&nbsp;&nbsp;" x $xml_depth;
680
681 my $formatted_text = "\n".$_;
682
683 # break into lines < 80 chars on space
684 $formatted_text =~ s/(.{50,80})\s+/$1\n/mg;
685 $formatted_text =~ s/^/$indent/mg;
686 ## $formatted_text =~ s/\s+$//s;
687
688 $self->{'raw_text'} .= $formatted_text;
689 }
690
691 my $metaname_stack = $self->{'metaname_stack'};
692 if (($_ !~ /^\s*$/) && (scalar(@$metaname_stack)>0)) {
693
694 my ($without_dt_stack,$innermost_element,$md_content)
695 = $self->process_datatype_info($metaname_stack,$_);
696
697 $self->pretty_print_table_tr($without_dt_stack);
698
699 my $full_mname = join('^',@{$without_dt_stack});
700 $self->set_filere_metadata(lc($full_mname),$md_content);
701
702 $self->check_for_language($innermost_element,$md_content);
703 $self->check_for_identifier($full_mname,$md_content); # source doc
704
705 $self->reset_datatype_info();
706 }
707}
708
709# This Char function overrides the one in XML::Parser::Stream to overcome a
710# problem where $expat->{Text} is treated as the return value, slowing
711# things down significantly in some cases.
712sub Char {
713 $_[0]->{'Text'} .= $_[1];
714 return undef;
715}
716
7171;
Note: See TracBrowser for help on using the repository browser.