1 package OpenILS::Application::Storage::WORM;
2 use base qw/OpenILS::Application::Storage/;
3 use strict; use warnings;
5 use OpenSRF::EX qw/:try/;
7 use OpenILS::Utils::FlatXML;
8 use OpenILS::Utils::Fieldmapper;
13 use Time::HiRes qw(time);
15 my $xml_util = OpenILS::Utils::FlatXML->new();
17 my $parser = XML::LibXML->new();
18 my $xslt = XML::LibXSLT->new();
19 my $xslt_doc = $parser->parse_file( "/home/miker/cvs/OpenILS/app_server/stylesheets/MARC21slim2MODS.xsl" );
20 #my $xslt_doc = $parser->parse_file( "/pines/cvs/ILS/Open-ILS/xsl/MARC21slim2MODS.xsl" );
21 my $mods_sheet = $xslt->parse_stylesheet( $xslt_doc );
28 # __PACKAGE__->method_lookup('i.do.not.exist');
35 # get me from the database
41 "//mods:mods/mods:titleInfo[mods:title and (\@type='abreviated')]",
44 "//mods:mods/mods:titleInfo[mods:title and (\@type='translated')]",
47 "//mods:mods/mods:titleInfo[mods:title and (\@type='uniform')]",
50 "//mods:mods/mods:titleInfo[mods:title and not (\@type)]",
56 "//mods:mods/mods:name[\@type='corporate']/mods:namePart".
57 "[../mods:role/mods:text[text()='creator']][1]",
60 "//mods:mods/mods:name[\@type='personal']/mods:namePart".
61 "[../mods:role/mods:text[text()='creator']][1]",
64 "//mods:mods/mods:name[\@type='conference']/mods:namePart".
65 "[../mods:role/mods:text[text()='creator']][1]",
68 "//mods:mods/mods:name[\@type='personal']/mods:namePart",
74 "//mods:mods/mods:subject/mods:geographic",
77 "//mods:mods/mods:subject/mods:name",
80 "//mods:mods/mods:subject/mods:temporal",
83 "//mods:mods/mods:subject/mods:topic",
86 "//mods:mods/mods:genre",
90 keyword => { keyword => "//mods:mods/*[not(local-name()='originInfo')]", },
95 # --------------------------------------------------------------------------------
97 __PACKAGE__->register_method(
98 api_name => "open-ils.worm.wormize",
106 my( $self, $client, $docid ) = @_;
108 # step -1: grab the doc from storage
109 my $meth = $self->method_lookup('open-ils.storage.biblio.record_marc.retrieve');
110 my ($marc) = $meth->run($docid);
111 return undef unless ($marc);
112 return $self->wormize_marc( $client, $docid, $marc->marc );
116 __PACKAGE__->register_method(
117 api_name => "open-ils.worm.wormize.marc",
137 my( $self, $client, $docid, $xml) = @_;
139 $rm_old_fr = $self->method_lookup( 'open-ils.storage.metabib.full_rec.mass_delete')
142 $rm_old_tr = $self->method_lookup( 'open-ils.storage.metabib.title_field_entry.mass_delete')
145 $rm_old_ar = $self->method_lookup( 'open-ils.storage.metabib.author_field_entry.mass_delete')
148 $rm_old_sr = $self->method_lookup( 'open-ils.storage.metabib.subject_field_entry.mass_delete')
151 $rm_old_kr = $self->method_lookup( 'open-ils.storage.metabib.keyword_field_entry.mass_delete')
154 $fr_create = $self->method_lookup( 'open-ils.storage.metabib.full_rec.batch.create')
156 $$create{title} = $self->method_lookup( 'open-ils.storage.metabib.title_field_entry.batch.create')
157 unless ($$create{title});
158 $$create{author} = $self->method_lookup( 'open-ils.storage.metabib.author_field_entry.batch.create')
159 unless ($$create{author});
160 $$create{subject} = $self->method_lookup( 'open-ils.storage.metabib.subject_field_entry.batch.create')
161 unless ($$create{subject});
162 $$create{keyword} = $self->method_lookup( 'open-ils.storage.metabib.keyword_field_entry.batch.create')
163 unless ($$create{keyword});
165 $begin = $self->method_lookup( 'open-ils.storage.transaction.begin')
167 $commit = $self->method_lookup( 'open-ils.storage.transaction.commit')
169 $rollback = $self->method_lookup( 'open-ils.storage.transaction.rollback')
173 my ($br) = $begin->run($client);
174 unless (defined $br) {
176 throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!")
179 # step 0: turn the doc into marcxml and delete old entries
180 my $marcdoc = $parser->parse_string($xml);
182 my ($res) = $rm_old_fr->run( { record => $docid } );
183 throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::full_rec entries!")
184 unless (defined $res);
187 ($res) = $rm_old_tr->run( { source => $docid } );
188 throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::title_field_entry entries!")
189 unless (defined $res);
192 ($res) = $rm_old_ar->run( { source => $docid } );
193 throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::author_field_entry entries!")
194 unless (defined $res);
197 ($res) = $rm_old_sr->run( { source => $docid } );
198 throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::subject_field_entry entries!")
199 unless (defined $res);
202 ($res) = $rm_old_kr->run( { source => $docid } );
203 throw OpenSRF::EX::PANIC ("Couldn't remove old metabib::keyword_field_entry entries!")
204 unless (defined $res);
206 # step 2: build the KOHA rows
207 my @ns_list = _marcxml_to_full_rows( $marcdoc );
208 $_->record( $docid ) for (@ns_list);
211 my ($fr) = $fr_create->run(@ns_list);
212 unless (defined $fr) {
214 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.metabib.full_rec.batch.create!")
217 # step 4: get the MODS based metadata
218 my $data = $self->modsdoc_to_values( $mods_sheet->transform($marcdoc) );
220 # step 5: insert the new metadata
221 for my $class ( keys %$data ) {
223 my $fm_constructor = "Fieldmapper::metabib::${class}_field_entry";
225 for my $row ( keys %{ $$data{$class} } ) {
226 next unless (exists $$data{$class}{$row});
227 next unless ($$data{$class}{$row});
228 my $fm_obj = $fm_constructor->new;
229 $fm_obj->value( $$data{$class}{$row} );
230 $fm_obj->source( $docid );
232 # XXX This needs to be a real thing once the xpath is in the DB
235 push @md_list, $fm_obj;
238 my ($cr) = $$create{$class}->run(@md_list);
239 unless (defined $cr) {
241 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.metabib.${class}_field_entry.batch.create!")
245 my ($c) = $commit->run;
246 unless (defined $c) {
248 throw OpenSRF::EX::PANIC ("Couldn't COMMIT changes!")
257 # --------------------------------------------------------------------------------
260 sub _marcxml_to_full_rows {
266 my $root = $marcxml->documentElement;
268 for my $tagline ( @{$root->getChildrenByTagName("leader")} ) {
269 next unless $tagline;
271 my $ns = new Fieldmapper::metabib::full_rec;
274 my $val = $tagline->textContent;
275 $val =~ s/(\pM)//gso;
281 for my $tagline ( @{$root->getChildrenByTagName("controlfield")} ) {
282 next unless $tagline;
284 my $ns = new Fieldmapper::metabib::full_rec;
286 $ns->tag( $tagline->getAttribute( "tag" ) );
287 my $val = $tagline->textContent;
288 $val =~ s/(\pM)//gso;
294 for my $tagline ( @{$root->getChildrenByTagName("datafield")} ) {
295 next unless $tagline;
297 for my $data ( @{$tagline->getChildrenByTagName("subfield")} ) {
298 next unless $tagline;
300 my $ns = new Fieldmapper::metabib::full_rec;
302 $ns->tag( $tagline->getAttribute( "tag" ) );
303 $ns->ind1( $tagline->getAttribute( "ind1" ) );
304 $ns->ind2( $tagline->getAttribute( "ind2" ) );
305 $ns->subfield( $data->getAttribute( "code" ) );
306 my $val = $data->textContent;
307 $val =~ s/(\pM)//gso;
308 $ns->value( lc($val) );
316 sub _get_field_value {
318 my( $mods, $xpath ) = @_;
321 my $root = $mods->documentElement;
322 $root->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
324 # grab the set of matching nodes
325 my @nodes = $root->findnodes( $xpath );
326 for my $value (@nodes) {
328 # grab all children of the node
329 my @children = $value->childNodes();
330 for my $child (@children) {
332 # add the childs content to the growing buffer
333 my $content = quotemeta($child->textContent);
334 next if ($string =~ /$content/); # uniquify the values
335 $string .= $child->textContent . " ";
338 $string .= $value->textContent . " ";
341 $string =~ s/(\pM)//gso;
346 sub modsdoc_to_values {
347 my( $self, $mods ) = @_;
349 for my $class (keys %$xpathset) {
350 $data->{$class} = {};
351 for my $type(keys %{$xpathset->{$class}}) {
352 my $value = _get_field_value( $mods, $xpathset->{$class}->{$type} );
353 $data->{$class}->{$type} = $value;