Index: /trunk/gsdl/perllib/plugins/CONTENTdmPlug.pm
===================================================================
--- /trunk/gsdl/perllib/plugins/CONTENTdmPlug.pm	(revision 14006)
+++ /trunk/gsdl/perllib/plugins/CONTENTdmPlug.pm	(revision 14006)
@@ -0,0 +1,894 @@
+###########################################################################
+#
+# CONTENTdmPlug.pm -- reasonably with-it pdf plugin
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999-2001 New Zealand Digital Library Project
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+package CONTENTdmPlug;
+
+use ConvertToPlug;
+use unicode;
+use ghtml;
+
+use strict;
+no strict 'refs'; # so we can use a var for filehandles (eg STDERR)
+
+
+use XMLParser;
+
+sub BEGIN {
+    @CONTENTdmPlug::ISA = ('ConvertToPlug');
+}
+
+
+my $convert_to_list =
+    [ {	'name' => "auto",
+	'desc' => "{ConvertToPlug.convert_to.auto}" },
+      {	'name' => "html",
+	'desc' => "{ConvertToPlug.convert_to.html}" },
+      {	'name' => "text",
+	'desc' => "{ConvertToPlug.convert_to.text}" },
+      { 'name' => "pagedimg",
+	'desc' => "{ConvertToPlug.convert_to.pagedimg}"},
+      ];
+
+
+
+my $arguments = 
+      [
+       { 'name' => "convert_to",
+	'desc' => "{ConvertToPlug.convert_to}",
+	'type' => "enum",
+	'reqd' => "yes",
+	'list' => $convert_to_list, 
+	'deft' => "html" },	 
+      { 'name' => "xslt",
+	'desc' => "{XMLPlug.xslt}",
+	'type' => "string",
+	'deft' => "",
+	'reqd' => "no" },
+       { 'name' => "process_exp",
+	'desc' => "{BasPlug.process_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_process_exp(),
+	'reqd' => "no" },
+      { 'name' => "block_exp",
+	'desc' => "{BasPlug.block_exp}",
+	'type' => "regexp",
+	'deft' => &get_default_block_exp() }
+];
+
+my $options = { 'name'     => "CONTENTdmPlug",
+		'desc'     => "{CONTENTdmPlug.desc}",
+		'abstract' => "no",
+		'inherits' => "yes",
+		'args'     => $arguments };
+
+our ($self);
+
+sub new {
+    my ($class) = shift (@_);
+    my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
+    push(@$pluginlist, $class);
+
+    push(@$inputargs,"-title_sub");
+    push(@$inputargs,'^(Page\s+\d+)?(\s*1\s+)?');
+
+    if(defined $arguments){ push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});}
+    if(defined $options) { push(@{$hashArgOptLists->{"OptList"}},$options)};
+
+    my @arg_array = @$inputargs;
+    $self = (defined $hashArgOptLists)? new ConvertToPlug($pluginlist,$inputargs,$hashArgOptLists): new ConvertToPlug($pluginlist,$inputargs);
+    
+    if ($self->{'info_only'}) {
+	# don't worry about any options etc
+	return bless $self, $class;
+    }
+
+    my $parser = new XML::Parser('Style' => 'Stream',
+				 'Handlers' => {'Char' => \&Char,
+						'XMLDecl' => \&XMLDecl,
+						'Entity' => \&Entity,
+						'Doctype' => \&Doctype,
+						'Default' => \&Default
+						});  
+    $self->{'parser'} = $parser;
+    $self->{'rdf_desc'} = undef;
+    $self->{'about_key'} = undef;
+    $self->{'metadata_name'} = undef;
+    $self->{'metadata_value'} = undef;
+
+    $self->{'convert_to'} = "PagedImg";
+    my $secondary_plugin_options = $self->{'secondary_plugin_options'};
+
+    if (!defined $secondary_plugin_options->{'PagedImgPlug'}){
+	$secondary_plugin_options->{'PagedImgPlug'} = [];
+	my $pagedimg_options = $secondary_plugin_options->{'PagedImgPlug'}; 
+	push(@$pagedimg_options, "-title_sub", '^(Page\s+\d+)?(\s*1\s+)?');
+	push(@$pagedimg_options, "-thumbnail", "-screenview");
+    }
+
+    $self = bless $self, $class;
+    $self->load_secondary_plugins($class,$secondary_plugin_options,$hashArgOptLists);
+    return $self;
+}
+
+sub get_default_process_exp {
+    my $self = shift (@_);
+
+    return q^(?i)\.rdf$^;
+}
+
+# so we don't inherit HTMLPlug's block exp...
+sub get_default_block_exp {
+    return q^(?i)\.(jpg|jpeg|gif)$^;
+}
+
+
+
+
+# A smarter (?) option would be to add XMLPlug into inheritence above
+# thereby avoiding a fair amount of code duplication
+
+sub apply_xslt
+{
+    my $self = shift @_;
+    my ($xslt,$filename) = @_;
+    
+    my $outhandle = $self->{'outhandle'};
+
+    my $xslt_filename = $xslt;
+
+    if (! -e $xslt_filename) {
+	# Look in main site directory
+	my $gsdlhome = $ENV{'GSDLHOME'};
+	$xslt_filename = &util::filename_cat($gsdlhome,$xslt);
+    }
+
+    if (! -e $xslt_filename) {
+	# Look in collection directory
+	my $coldir = $ENV{'GSDLCOLLECTDIR'};
+	$xslt_filename = &util::filename_cat($coldir,$xslt);
+    }
+
+    if (! -e $xslt_filename) {
+	print $outhandle "Warning: Unable to find XSLT $xslt\n";
+	if (open(XMLIN,"<$filename")) {
+
+	    my $untransformed_xml = "";
+	    while (defined (my $line = <XMLIN>)) {
+
+		$untransformed_xml .= $line;
+	    }
+	    close(XMLIN);
+	    
+	    return $untransformed_xml;
+	}
+	else {
+	    print $outhandle "Error: Unable to open file $filename\n";
+	    print $outhandle "       $!\n";
+	    return "";
+	}
+	
+    }
+
+    my $bin_java = &util::filename_cat($ENV{'GSDLHOME'},"bin","java");
+    my $jar_filename = &util::filename_cat($bin_java,"xalan.jar");
+    my $xslt_base_cmd = "java -jar $jar_filename";
+    my $xslt_cmd = "$xslt_base_cmd -IN \"$filename\" -XSL \"$xslt_filename\"";
+
+    my $transformed_xml = "";
+
+    if (open(XSLT_IN,"$xslt_cmd |")) {
+	while (defined (my $line = <XSLT_IN>)) {
+
+	    $transformed_xml .= $line;
+	}
+	close(XSLT_IN);
+    }
+    else {
+	print $outhandle "Error: Unable to run command $xslt_cmd\n";
+	print $outhandle "       $!\n";
+    }
+
+    return $transformed_xml;
+
+}
+
+
+
+sub rdf_desc_to_id
+{
+    my $self = shift (@_);
+    my ($rdf_desc) = @_;
+
+    my $rdf_id = {};
+
+    # initialise any .cpd (=complex multi page) structures 
+
+    foreach my $about_key (keys %{$rdf_desc}) {
+	if ($about_key =~ m/\.cpd$/) {
+	    my $about = $rdf_desc->{$about_key};
+	    my $id    = $about->{'dc:identifier'};
+
+	    if ($id =~ m/^\s*$/) {
+		# missing id, make one up based on about attribute
+
+		my ($tailname, $dirname, $suffix)
+		    = &File::Basename::fileparse($about_key, "\\.[^\\.]+\$");
+
+		$id = "about:$tailname";
+	    }
+
+	    $rdf_id->{$id} = $about;
+	    $rdf_id->{$id}->{'ex:filename'} = $about_key;
+	    $rdf_id->{$id}->{'ex:type'} = "complex";
+	    $rdf_id->{$id}->{'pages'} = [];
+	}
+
+    }
+
+    # now add in *non* .cpd items
+
+    foreach my $about_key (keys %{$rdf_desc}) {
+	if ($about_key !~ m/\.cpd$/) {
+	    my $about = $rdf_desc->{$about_key};	    
+	    my $id    = $about->{'dc:identifier'};
+
+
+	    if ($id =~ m/^\s*$/) {
+		# missing id, make one up based on about attribute
+
+		my ($tailname, $dirname, $suffix)
+		    = &File::Basename::fileparse($about_key, "\\.[^\\.]+\$");
+
+		$id = "about:$tailname";
+	    }
+
+	    if (defined $rdf_id->{$id}) {
+		$about->{'ex:filename'} = $about_key;
+
+		# dealing with complex multi-page situation
+		# Add to existing structure
+
+		my $pages = $rdf_id->{$id}->{'pages'};
+		push(@$pages,$about)
+	    }
+	    else {
+		# New entry
+
+		$rdf_id->{$id} = $about;
+		$rdf_id->{$id}->{'ex:type'} = "simple";	    
+		$rdf_id->{$id}->{'ex:filename'} = $about_key;
+	    }
+	}
+	
+    }
+
+    return $rdf_id;
+}
+
+
+sub metadata_table_txt_file
+{
+    my $self = shift (@_);
+    my ($output_root,$page_num) = @_;
+
+    my $txt_filename = $output_root."_page_$page_num.txt";
+
+    my ($tailname, $dirname, $suffix)
+	= &File::Basename::fileparse($txt_filename, "\\.[^\\.]+\$");
+
+    my $txt_file = "$tailname.$suffix";
+
+    return $txt_file;
+}
+
+
+sub output_metadata_table 
+{
+    my $self = shift (@_);
+    my ($page,$page_num,$tmp_dirname,$txt_file) = @_;
+    
+    my $txt_filename = &util::filename_cat($tmp_dirname,$txt_file);
+
+    open(TOUT,">$txt_filename") 
+	|| die "Error: unable to write metadata data out as txt file $txt_filename: $!\n";
+    
+    print TOUT $page->{'MetadataTable'};
+    delete $page->{'MetadataTable'};
+
+    close (TOUT);
+}
+
+
+sub rdf_id_to_item_file
+{
+    my $self = shift (@_);
+    my ($rdf_id,$tmp_dirname,$output_root) = @_;
+
+    my $item_file_list = [];
+    
+    foreach my $id (keys %{$rdf_id}) {
+
+	my $id_safe = $id;
+	$id_safe =~ s/ /-/g;
+
+	my $output_filename = $output_root."_$id_safe.item";
+	open(FOUT,">$output_filename") 
+	    || die "Unable to open $output_filename: $!\n";
+	
+
+	print FOUT "<PagedDocument>\n";
+
+	my $rdf_doc = $rdf_id->{$id};
+	foreach my $metadata_name (keys %$rdf_doc) {
+
+
+	    next if ($metadata_name eq "pages");
+
+	    my $metadata_value = $rdf_doc->{$metadata_name};
+
+	    # convert ns:name to ns.Name
+	    $metadata_name =~ s/^(.*?):(.*)/$1\.\u$2/; 
+
+	    print FOUT "  <Metadata name=\"$metadata_name\">$metadata_value</Metadata>\n";
+	}
+
+	if ($rdf_doc->{'ex:type'} eq "complex") {
+	    my $pages = $rdf_doc->{'pages'};
+	    my $page_num = 1;
+
+	    foreach my $page (@$pages) {
+
+		my $imgfile = $page->{'ex:filename'};
+		if ($imgfile =~ m/(http|ftp):/) {
+		    $imgfile = "empty.jpg";
+		}
+		else {
+		    $imgfile = &util::filename_cat("..","import",$imgfile);
+		}
+		
+		my $txt_file 
+		    = $self->metadata_table_txt_file($output_root,$page_num);
+
+		$self->output_metadata_table($page,$page_num,
+					     $tmp_dirname,$txt_file);
+
+
+		print FOUT "  <Page pagenum=\"$page_num\" imgfile=\"$imgfile\" txtfile=\"$txt_file\">\n";
+
+		foreach my $metadata_name (keys %$page) {
+		
+		    my $metadata_value = $rdf_doc->{$metadata_name};
+		    # convert ns:name to ns.Name
+		    $metadata_name =~ s/^(.*?):(.*)/$1\.\u$2/; 
+
+		    print FOUT "  <Metadata name=\"$metadata_name\">$metadata_value</Metadata>\n";
+		}
+		
+
+		$page_num++;
+
+
+		print FOUT "  </Page>\n";
+	    }
+	}
+	else {
+	    # simple
+	    # duplicate top-level metadata for now plus image to bind to
+
+	    my $imgfile = $rdf_doc->{'ex:filename'};
+	    if ($imgfile =~ m/(http|ftp):/) {
+		$imgfile = "empty.jpg";
+	    }
+	    else {
+		$imgfile = &util::filename_cat("..","import",$imgfile);
+		$imgfile = "../import/".$imgfile;
+	    }
+
+
+	    my $txt_file = $self->metadata_table_txt_file($output_root,1);
+	    $self->output_metadata_table($rdf_doc,1,$tmp_dirname,$txt_file);
+
+	    print FOUT "  <Page pagenum=\"1\" imgfile=\"$imgfile\" txtfile=\"$txt_file\">\n";	    
+	    foreach my $metadata_name (keys %$rdf_doc) {
+
+		my $metadata_value = $rdf_doc->{$metadata_name};
+		
+		# convert ns:name to ns.Name
+		$metadata_name =~ s/^(.*?):(.*)/$1\.\u$2/; 
+
+		print FOUT "  <Metadata name=\"$metadata_name\">$metadata_value</Metadata>\n";
+	    }
+	    print FOUT "  </Page>\n";
+
+	}
+
+	print FOUT "</PagedDocument>\n";
+	close(FOUT);
+
+	push(@$item_file_list,$output_filename);
+
+    }
+    
+
+    return $item_file_list;
+}
+
+
+
+sub xml_area_convert_file
+{
+    my $self = shift (@_);
+    my ($input_filename, $tmp_dirname, $output_root) = @_;
+
+    eval {
+	# Build up hash table/tree of all records
+
+	my $xslt = $self->{'xslt'};
+	if (defined $xslt && ($xslt ne "")) {
+	    # perform xslt
+	    my $transformed_xml = $self->apply_xslt($xslt,$input_filename);
+
+	    # feed transformed file (now in memory as string) into XML parser
+	    $self->{'parser'}->parse($transformed_xml);
+	}
+	else {
+	    $self->{'parser'}->parsefile($input_filename);
+	}
+    };
+  
+    if ($@) {
+
+	# parsefile may either croak somewhere in XML::Parser (e.g. because
+	# the document is not well formed) or die somewhere in XMLPlug or a
+	# derived plugin (e.g. because we're attempting to process a
+	# document whose DOCTYPE is not meant for this plugin). For the
+	# first case we'll print a warning and continue, for the second
+	# we'll just continue quietly
+
+	print STDERR "**** Error is: $@\n";
+
+	my $file = $self->{'file'};
+
+	my ($msg) = $@ =~ /Carp::croak\(\'(.*?)\'\)/;
+	if (defined $msg) {	
+	    my $outhandle = $self->{'outhandle'};
+	    my $plugin_name = ref ($self);
+	    print $outhandle "$plugin_name failed to process $file ($msg)\n";
+	}
+
+	my $gli = $self->{'gli'};
+
+	# reset ourself for the next document
+	$self->{'section_level'}=0;
+	print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	return ("fail",undef); # error during processing
+    }
+
+    my $rdf_desc = $self->{'rdf_desc'};    
+
+#    foreach my $about_key (keys %{$rdf_desc}) {
+#	my $about = $rdf_desc->{$about_key};
+#	foreach my $metadata_name (keys %{$about}) {
+#
+#	    my $metadata_value = $about->{$metadata_name};
+##	    print STDERR " $metadata_name: $metadata_value\n";
+#	}
+#    }
+
+
+    # Merge entries with same name
+
+
+    my $merged_rdf_id = $self->rdf_desc_to_id($rdf_desc);
+
+#    foreach my $about_key (keys %{$merged_rdf_id}) {
+#	my $about = $merged_rdf_id->{$about_key};
+#	foreach my $metadata_name (keys %{$about}) {
+#
+#	    my $metadata_value = $about->{$metadata_name};
+##	    print STDERR " $metadata_name: $metadata_value\n";
+#	}
+#    }
+
+
+
+    my $item_files = $self->rdf_id_to_item_file($merged_rdf_id,$tmp_dirname, 
+						$output_root);
+
+    return ("item",$item_files);
+}
+
+
+# Override ConvertToPlug tmp_area_convert_file() to provide solution specific 
+# to CONTENTdm
+#
+# A better (i.e. in the future) solution would be to see if this can be
+# shifted into gsConvert.pl so there is no need to override the
+# default tmp_area_convert_file()
+
+
+sub tmp_area_convert_file {
+    my $self = shift (@_);
+    my ($output_ext, $input_filename, $textref) = @_;
+
+    # is textref ever used?!?
+
+    my $outhandle = $self->{'outhandle'};
+    my $convert_to = $self->{'convert_to'};
+    my $failhandle = $self->{'failhandle'};
+    my $convert_to_ext = $self->{'convert_to_ext'};
+    
+    # softlink to collection tmp dir
+    my $tmp_dirname 
+	= &util::filename_cat($ENV{'GSDLCOLLECTDIR'}, "tmp");
+    &util::mk_dir($tmp_dirname) if (!-e $tmp_dirname);
+
+    # derive tmp filename from input filename
+    my ($tailname, $dirname, $suffix)
+	= &File::Basename::fileparse($input_filename, "\\.[^\\.]+\$");
+
+    # Remove any white space from filename -- no risk of name collision, and
+    # makes later conversion by utils simpler. Leave spaces in path...
+    # tidy up the filename with space, dot, hyphen between
+    $tailname =~ s/\s+//g; 
+    $tailname =~ s/\.+//g;
+    $tailname =~ s/\-+//g;
+    $suffix = lc($suffix);
+    my $tmp_filename = &util::filename_cat($tmp_dirname, "$tailname$suffix");
+
+    &util::soft_link($input_filename, $tmp_filename);
+    my $verbosity = $self->{'verbosity'};
+    if ($verbosity > 0) {
+	print $outhandle "Converting $tailname$suffix to $convert_to format\n";
+    }
+
+    my $errlog = &util::filename_cat($tmp_dirname, "err.log");
+    
+    # call xml_area_convert_file rather than gsConvert.pl
+
+    my $output_root = &util::filename_cat($tmp_dirname, "$tailname");
+
+    my ($output_type,$item_files) 
+	= $self->xml_area_convert_file($tmp_filename,$tmp_dirname,$output_root);
+
+
+    my $fakeimg_filename = &util::filename_cat($dirname, "empty.jpg");
+    my $fakeimg_tmp_filename = &util::filename_cat($tmp_dirname, "empty.jpg");
+
+    print STDERR "***** Setting up fake filename $fakeimg_filename -> $fakeimg_tmp_filename\n";
+
+    &util::soft_link($fakeimg_filename, $fakeimg_tmp_filename);
+   
+    # continue as before ...
+
+    # remove symbolic link to original file
+    &util::rm($tmp_filename);
+
+    # Check STDERR here
+    chomp $output_type;
+    if ($output_type eq "fail") {
+	print $outhandle "Could not convert $tailname$suffix to $convert_to format\n";
+	print $failhandle "$tailname$suffix: " . ref($self) . " failed to convert to $convert_to\n";
+	$self->{'num_not_processed'} ++;
+	if (-s "$errlog") {
+	    open(ERRLOG, "$errlog");
+	    while (<ERRLOG>) {
+		print $outhandle "$_";
+	    }
+	    print $outhandle "\n";
+	    close ERRLOG;
+	}
+	&util::rm("$errlog") if (-e "$errlog");
+	return [];
+    }
+
+    # store the *actual* output type and return the output filename
+    # it's possible we requested conversion to html, but only to text succeeded
+    #$self->{'convert_to_ext'} = $output_type;
+    if ($output_type =~ /html/i) {
+	$self->{'converted_to'} = "HTML";
+    } elsif ($output_type =~ /te?xt/i) {
+	$self->{'converted_to'} = "TEXT";
+    } elsif ($output_type =~ /item/i){
+	$self->{'converted_to'} = "PagedImg";
+    }
+
+    
+    return $item_files;
+}
+
+
+
+
+# Override ConvertToPlug read
+# Needed so multiple .item files generate are sent down secondary plugin
+
+sub read {
+    my $self = shift (@_);
+    my ($pluginfo, $base_dir, $file, $metadata, $processor, $maxdocs, $total_count, $gli) = @_;
+
+    $self->{'gli'} = $gli;
+    $self->{'file'} = $file;
+
+    my $successful_rv = -1;
+
+    my $outhandle = $self->{'outhandle'};
+    
+    my ($block_status,$filename) = $self->read_block(@_);
+    return $block_status if ((!defined $block_status) || ($block_status==0));
+    $file = $self->read_tidy_file($file);
+    
+    # read() deviates at this point from ConvertToPlug
+    # Need to work with list of filename returned
+
+    my $output_ext = $self->{'convert_to_ext'};
+    my $conv_filename_list = [];
+
+    $conv_filename_list = $self->tmp_area_convert_file($output_ext, $filename);
+    
+    if (scalar(@$conv_filename_list)==0) {
+	return -1;
+    } # had an error, will be passed down pipeline 
+
+    foreach my $conv_filename ( @$conv_filename_list ) {
+	if (! -e "$conv_filename") {return -1;} 
+	$self->{'conv_filename'} = $conv_filename; # is this used anywhere?
+	$self->convert_post_process($conv_filename);
+    
+	my $secondary_plugins =  $self->{'secondary_plugins'};
+	my $num_secondary_plugins = scalar(keys %$secondary_plugins);
+
+	if ($num_secondary_plugins == 0) {
+	    print $outhandle "Warning: No secondary plugin to use in conversion.  Skipping $file\n";
+	    return 0; # effectively block it
+	}
+
+	my @plugin_names = keys %$secondary_plugins;
+	my $plugin_name = shift @plugin_names;
+	
+	if ($num_secondary_plugins > 1) {
+	    print $outhandle "Warning: Multiple secondary plugins not supported yet!  Choosing $plugin_name\n.";
+	}
+	
+	my $secondary_plugin = $secondary_plugins->{$plugin_name};
+	
+	# note: metadata is not carried on to the next level
+	my ($rv,$doc_obj) 
+	    = $secondary_plugin->read_into_doc_obj ($pluginfo,"", $conv_filename, 
+						    $metadata, $processor, $maxdocs, $total_count,
+						    $gli);
+
+	if ((defined $rv) && ($rv>=0)) {
+	    $successful_rv = 1;
+	}
+
+	# Override previous gsdlsourcefilename set by secondary plugin
+	my $collect_file = &util::filename_within_collection($filename);
+	my $collect_conv_file = &util::filename_within_collection($conv_filename);
+	$doc_obj->set_source_filename ($collect_file); 
+	$doc_obj->set_converted_filename($collect_conv_file);
+	
+	my ($filemeta) = $file =~ /([^\\\/]+)$/;
+	$doc_obj->set_utf8_metadata_element($doc_obj->get_top_section(), "Source", &ghtml::dmsafe($filemeta));
+	$doc_obj->set_utf8_metadata_element($doc_obj->get_top_section(), "Plugin", "$self->{'plugin_type'}");
+	$doc_obj->set_utf8_metadata_element($doc_obj->get_top_section(), "FileSize", (-s $filename));
+	
+	if ($self->{'cover_image'}) {
+	    $self->associate_cover_image($doc_obj, $filename);
+	}
+	
+	# do plugin specific processing of doc_obj
+	unless (defined ($self->process(undef, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli))) {
+	    print STDERR "<ProcessingError n='$file'>\n" if ($gli);
+	    return -1;
+	}
+	# do any automatic metadata extraction
+	$self->auto_extract_metadata ($doc_obj);
+
+	# have we found a Title??
+	$self->title_fallback($doc_obj,$doc_obj->get_top_section(),$filemeta);
+
+	# add an OID
+	$doc_obj->set_OID();
+	# process the document
+	$processor->process($doc_obj);
+
+	$self->{'num_processed'} ++;
+    }
+
+    return $successful_rv;
+}
+
+
+
+sub process {
+    my $self = shift (@_);
+    my ($textref, $pluginfo, $base_dir, $file, $metadata, $doc_obj, $gli) = @_;
+
+    
+    my $secondary_plugins =  $self->{'secondary_plugins'};
+    my @plugin_names = keys %$secondary_plugins;
+    my $plugin_name = shift @plugin_names; # already checked there is only one
+	
+    my $secondary_plugin = $secondary_plugins->{$plugin_name};
+	
+    my $result = $secondary_plugin->process(@_);
+
+    return $result;
+}
+
+
+
+
+sub StartDocument {$self->xml_start_document(@_);}
+sub XMLDecl {$self->xml_xmldecl(@_);}
+sub Entity {$self->xml_entity(@_);}
+sub Doctype {$self->xml_doctype(@_);}
+sub StartTag {$self->xml_start_tag(@_);}
+sub EndTag {$self->xml_end_tag(@_);}
+sub Text {$self->xml_text(@_);}
+sub PI {$self->xml_pi(@_);}
+sub EndDocument {$self->xml_end_document(@_);}
+sub Default {$self->xml_default(@_);}
+
+# This Char function overrides the one in XML::Parser::Stream to overcome a
+# problem where $expat->{Text} is treated as the return value, slowing
+# things down significantly in some cases.
+sub Char {
+    use bytes;  # Necessary to prevent encoding issues with XML::Parser 2.31+
+    $_[0]->{'Text'} .= $_[1];
+    return undef;
+}
+
+# Called at the beginning of the XML document.
+sub xml_start_document {
+    my $self = shift(@_);
+    my ($expat) = @_;
+
+    $self->{'rdf_desc'} = {};
+}
+
+# Called for XML declarations
+sub xml_xmldecl {
+    my $self = shift(@_);
+    my ($expat, $version, $encoding, $standalone) = @_;
+}
+
+# Called for XML entities
+sub xml_entity {
+  my $self = shift(@_);
+  my ($expat, $name, $val, $sysid, $pubid, $ndata) = @_;
+}
+
+# Called for DOCTYPE declarations - use die to bail out if this doctype
+# is not meant for this plugin
+sub xml_doctype {
+    my $self = shift(@_);
+    my ($expat, $name, $sysid, $pubid, $internal) = @_;
+
+    die "" if ($name !~ /^rdf:RDF$/);
+
+    my $outhandle = $self->{'outhandle'};
+    print $outhandle "CONTENTdmPlug: processing $self->{'file'}\n" if $self->{'verbosity'} > 1;
+
+}
+
+# Called for every start tag. The $_ variable will contain a copy of the
+# tag and the %_ variable will contain the element's attributes.
+sub xml_start_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+
+    if ($element eq "rdf:Description") {
+
+	my $about_key = $_{'about'};
+
+	my $rdf_desc = $self->{'rdf_desc'};
+	$rdf_desc->{$about_key} = {};
+
+	$self->{'about_key'}  = $about_key;
+	$self->{'index_text'} = "";
+	$self->{'pp_text'}    = "<table width=\"100%\">\n";
+
+
+    }
+    elsif (defined $self->{'about_key'}) {	
+	$self->{'metadata_name'} = $element;
+	$self->{'metadata_value'} = "";
+    }
+
+}
+
+# Called for every end tag. The $_ variable will contain a copy of the tag.
+sub xml_end_tag {
+    my $self = shift(@_);
+    my ($expat, $element) = @_;
+
+    if ($element eq "rdf:Description") {
+	$self->{'pp_text'} .= "</table>\n";
+	## ghtml::htmlsafe($self->{'pp_text'});
+
+
+	my $about_key = $self->{'about_key'};
+	my $about = $self->{'rdf_desc'}->{$about_key};
+	$about->{'IndexText'}     = $self->{'index_text'};
+	$about->{'MetadataTable'} = $self->{'pp_text'};
+
+
+	$self->{'about_key'}   = undef;
+	$self->{'index_text'}  = undef;
+	$self->{'pp_text'}     = undef;
+
+    }
+    elsif (defined $self->{'metadata_name'}) {
+	my $metadata_name = $self->{'metadata_name'};
+	if ($element eq $metadata_name) {
+	    my $metadata_value = $self->{'metadata_value'};
+
+	    my $about_key = $self->{'about_key'};
+	    my $about = $self->{'rdf_desc'}->{$about_key};
+	    $about->{$metadata_name} = $metadata_value;
+
+	    $self->{'index_text'} .= "$metadata_value\n";
+	    $self->{'pp_text'} .= "  <tr><td>$metadata_name</td><td>$metadata_value</td></tr>\n";
+
+	    $self->{'metadata_name'}  = undef;
+	    $self->{'metadata_value'} = undef;
+	}
+    }
+}
+
+# Called just before start or end tags with accumulated non-markup text in
+# the $_ variable.
+sub xml_text {
+    my $self = shift(@_);
+    my ($expat) = @_;
+
+    if (defined $self->{'metadata_name'}) {
+	$self->{'metadata_value'} .= $_;
+    }
+}
+
+# Called for processing instructions. The $_ variable will contain a copy
+# of the pi.
+sub xml_pi {
+    my $self = shift(@_);
+    my ($expat, $target, $data) = @_;
+}
+
+# Called at the end of the XML document.
+sub xml_end_document {
+    my $self = shift(@_);
+    my ($expat) = @_;
+
+}
+
+# Called for any characters not handled by the above functions.
+sub xml_default {
+    my $self = shift(@_);
+    my ($expat, $text) = @_;
+}
+
+
+1;
