1 package OpenILS::Application::WoRM;
2 use base qw/OpenSRF::Application/;
5 use Unicode::Normalize;
6 use OpenSRF::EX qw/:try/;
8 use OpenSRF::Utils::SettingsClient;
9 use OpenSRF::Utils::Logger qw/:level/;
11 use OpenILS::Utils::FlatXML;
12 use OpenILS::Utils::Fieldmapper;
15 use OpenILS::Utils::Fieldmapper;
19 use Time::HiRes qw(time);
22 our $log = 'OpenSRF::Utils::Logger';
23 our $xml_util = OpenILS::Utils::FlatXML->new();
25 our $parser = XML::LibXML->new();
26 our $xslt = XML::LibXSLT->new();
34 $st_sess = $sess if ($sess);
44 $log->debug("Running post_init", DEBUG);
46 unless ($mods_sheet) {
47 $log->debug("Loading MODS XSLT", DEBUG);
48 my $xslt_doc = $parser->parse_file(
49 OpenSRF::Utils::SettingsClient->new->config_value(dirs => 'xsl') . "/MARC21slim2MODS.xsl");
50 $mods_sheet = $xslt->parse_stylesheet( $xslt_doc );
53 #if (!__PACKAGE__->st_sess()) {
54 # $log->debug("Creating cached storage server session", DEBUG);
55 # __PACKAGE__->st_sess( OpenSRF::AppSession->create('open-ils.storage') );
58 unless (keys %$xpathset) {
59 my $req = __PACKAGE__->storage_req('open-ils.storage.direct.config.metabib_field.retrieve.all.atomic');
61 $xpathset->{ $f->field_class }->{ $f->name }->{xpath} = $f->xpath;
62 $xpathset->{ $f->field_class }->{ $f->name }->{id} = $f->id;
63 $log->debug("Loaded XPath from DB: ".$f->field_class." => ".$f->name." : ".$f->xpath, DEBUG);
70 OpenILS::Application::WoRM->post_init();
71 return __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
74 sub begin_transaction {
78 OpenILS::Application::WoRM->post_init();
79 my $outer_xact = __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
83 $log->debug("WoRM isn't inside a transaction, starting one now.", INFO);
84 #__PACKAGE__->st_sess->connect;
85 my $r = __PACKAGE__->storage_req( 'open-ils.storage.transaction.begin', $client );
86 unless (defined $r and $r) {
87 __PACKAGE__->storage_req( 'open-ils.storage.transaction.rollback' );
88 #__PACKAGE__->st_sess->disconnect;
89 throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!")
93 $log->debug("WoRM Couldn't BEGIN transaction!", ERROR)
96 return __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
99 sub rollback_transaction {
103 OpenILS::Application::WoRM->post_init();
104 my $outer_xact = __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
108 __PACKAGE__->storage_req( 'open-ils.storage.transaction.rollback' );
110 $log->debug("WoRM isn't inside a transaction.", INFO);
113 throw OpenSRF::EX::PANIC ("WoRM Couldn't COMMIT transaction!")
119 sub commit_transaction {
123 OpenILS::Application::WoRM->post_init();
124 my $outer_xact = __PACKAGE__->storage_req( 'open-ils.storage.transaction.current' );
127 #if (__PACKAGE__->st_sess->connected && $outer_xact) {
129 my $r = __PACKAGE__->storage_req( 'open-ils.storage.transaction.commit' );
130 unless (defined $r and $r) {
131 __PACKAGE__->storage_req( 'open-ils.storage.transaction.rollback' );
132 throw OpenSRF::EX::PANIC ("Couldn't COMMIT transaction!")
134 #__PACKAGE__->st_sess->disconnect;
136 $log->debug("WoRM isn't inside a transaction.", INFO);
139 throw OpenSRF::EX::PANIC ("WoRM Couldn't COMMIT transaction!")
148 my @res = __PACKAGE__->method_lookup( $method )->run( @_ );
149 return shift( @res );
152 sub scrub_authority_record {
158 if (!OpenILS::Application::WoRM->in_transaction) {
159 OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
165 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.set', 'scrub_authority_record' );
167 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.full_rec.mass_delete', { record => $rec } );
168 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.record_descriptor.mass_delete', { record => $rec } );
170 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.release', 'scrub_authority_record' );
172 $log->debug('Scrubbing failed : '.shift(), ERROR);
173 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.rollback', 'scrub_authority_record' );
177 OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
178 OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
181 __PACKAGE__->register_method(
182 api_name => "open-ils.worm.scrub.authority",
183 method => "scrub_authority_record",
189 sub scrub_metabib_record {
195 if (!OpenILS::Application::WoRM->in_transaction) {
196 OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
202 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.set', 'scrub_metabib_record' );
204 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.full_rec.mass_delete', { record => $rec } );
205 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord_source_map.mass_delete', { source => $rec } );
206 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.record_descriptor.mass_delete', { record => $rec } );
207 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.title_field_entry.mass_delete', { source => $rec } );
208 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.author_field_entry.mass_delete', { source => $rec } );
209 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.subject_field_entry.mass_delete', { source => $rec } );
210 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.keyword_field_entry.mass_delete', { source => $rec } );
211 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.series_field_entry.mass_delete', { source => $rec } );
213 $log->debug( "Looking for metarecords whose master is $rec", DEBUG);
214 my $masters = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.search.master_record.atomic', $rec );
216 for my $mr (@$masters) {
217 $log->debug( "Found metarecord whose master is $rec", DEBUG);
218 my $others = OpenILS::Application::WoRM->storage_req(
219 'open-ils.storage.direct.metabib.metarecord_source_map.search.metarecord.atomic', $mr->id );
222 $log->debug("Metarecord ".$mr->id." had master of $rec, setting to ".$others->[0]->source, DEBUG);
223 $mr->master_record($others->[0]->source);
224 OpenILS::Application::WoRM->storage_req(
225 'open-ils.storage.direct.metabib.metarecord.remote_update',
227 { master_record => $others->[0]->source, mods => undef }
230 warn "Removing metarecord whose master is $rec";
231 $log->debug( "Removing metarecord whose master is $rec", DEBUG);
232 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.delete', $mr->id );
233 warn "Metarecord removed";
234 $log->debug( "Metarecord removed", DEBUG);
238 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.release', 'scrub_metabib_record' );
241 $log->debug('Scrubbing failed : '.shift(), ERROR);
242 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.rollback', 'scrub_metabib_record' );
246 OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
247 OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
250 __PACKAGE__->register_method(
251 api_name => "open-ils.worm.scrub.biblio",
252 method => "scrub_metabib_record",
257 sub wormize_biblio_record {
263 if (!OpenILS::Application::WoRM->in_transaction) {
264 OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
271 unless ($self->api_name =~ /noscrub/o) {
272 $self->method_lookup( 'open-ils.worm.scrub.biblio' )->run( $rec ) || throw OpenSRF::EX::PANIC ("Couldn't scrub record $rec!");
276 my $bibs = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.biblio.record_entry.search.id.atomic', $rec );
279 my @rec_descriptor = ();
290 my $xml = $parser->parse_string($r->marc);
293 for my $fr ( $self->method_lookup( 'open-ils.worm.flat_marc.biblio.xml' )->run( $xml ) ) {
294 $fr->record( $r->id );
298 # the rec_descriptor stuff
299 my ($rd) = $self->method_lookup( 'open-ils.worm.biblio_leader.xml' )->run( $xml );
300 $rd->record( $r->id );
301 push @rec_descriptor, $rd;
303 # the indexing field entry stuff
304 for my $class ( qw/title author subject keyword series/ ) {
305 for my $fe ( $self->method_lookup( 'open-ils.worm.field_entry.class.xml' )->run( $xml, $class ) ) {
306 $fe->source( $r->id );
307 push @{$field_entry{$class}}, $fe;
311 #update the fingerprint
312 my ($fp) = $self->method_lookup( 'open-ils.worm.fingerprint.marc' )->run( $xml );
313 OpenILS::Application::WoRM->storage_req(
314 'open-ils.storage.direct.biblio.record_entry.remote_update',
316 { fingerprint => $fp }
317 ) if ($fp ne $r->fingerprint);
319 unless ($self->api_name =~ /nomap/o) {
320 my $mr = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.search.fingerprint.atomic', $fp )->[0];
323 $mr = Fieldmapper::metabib::metarecord->new;
324 $mr->fingerprint( $fp );
325 $mr->master_record( $r->id );
326 $mr->id( OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord.create', $mr) );
329 my $mr_map = Fieldmapper::metabib::metarecord_source_map->new;
330 $mr_map->metarecord( $mr->id );
331 $mr_map->source( $r->id );
332 push @source_map, $mr_map;
337 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.set', 'wormize_record' );
339 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.metarecord_source_map.batch.create', @source_map ) if (@source_map);
340 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.record_descriptor.batch.create', @rec_descriptor ) if (@rec_descriptor);
341 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.full_rec.batch.create', @full_rec ) if (@full_rec);
342 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.title_field_entry.batch.create', @{ $field_entry{title} } ) if (@{ $field_entry{title} });
343 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.author_field_entry.batch.create', @{ $field_entry{author} } ) if (@{ $field_entry{author} });
344 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.subject_field_entry.batch.create', @{ $field_entry{subject} } ) if (@{ $field_entry{subject} });
345 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.keyword_field_entry.batch.create', @{ $field_entry{keyword} } ) if (@{ $field_entry{keyword} });
346 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.metabib.series_field_entry.batch.create', @{ $field_entry{series} } ) if (@{ $field_entry{series} });
348 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.release', 'wormize_record' );
351 $log->debug('Wormization failed : '.shift(), ERROR);
352 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.rollback', 'wormize_record' );
356 OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
357 OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
360 __PACKAGE__->register_method(
361 api_name => "open-ils.worm.wormize.biblio",
362 method => "wormize_biblio_record",
366 __PACKAGE__->register_method(
367 api_name => "open-ils.worm.wormize.biblio.nomap",
368 method => "wormize_biblio_record",
372 __PACKAGE__->register_method(
373 api_name => "open-ils.worm.wormize.biblio.noscrub",
374 method => "wormize_biblio_record",
378 __PACKAGE__->register_method(
379 api_name => "open-ils.worm.wormize.biblio.nomap.noscrub",
380 method => "wormize_biblio_record",
385 sub wormize_authority_record {
391 if (!OpenILS::Application::WoRM->in_transaction) {
392 OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
399 unless ($self->api_name =~ /noscrub/o) {
400 $self->method_lookup( 'open-ils.worm.scrub.authority' )->run( $rec ) || throw OpenSRF::EX::PANIC ("Couldn't scrub record $rec!");
404 my $bibs = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.record_entry.search.id.atomic', $rec );
407 my @rec_descriptor = ();
409 my $xml = $parser->parse_string($r->marc);
412 for my $fr ( $self->method_lookup( 'open-ils.worm.flat_marc.authority.xml' )->run( $xml ) ) {
413 $fr->record( $r->id );
417 # the rec_descriptor stuff -- XXX What does this mean for authority records?
418 #my ($rd) = $self->method_lookup( 'open-ils.worm.authority_leader.xml' )->run( $xml );
419 #$rd->record( $r->id );
420 #push @rec_descriptor, $rd;
424 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.set', 'wormize_authority_record' );
426 #OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.record_descriptor.batch.create', @rec_descriptor ) if (@rec_descriptor);
427 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.authority.full_rec.batch.create', @full_rec ) if (@full_rec);
429 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.release', 'wormize_authority_record' );
432 $log->debug('Wormization failed : '.shift(), ERROR);
433 OpenILS::Application::WoRM->storage_req( 'open-ils.storage.savepoint.rollback', 'wormize_authority_record' );
437 OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
438 OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
441 __PACKAGE__->register_method(
442 api_name => "open-ils.worm.wormize.authority",
443 method => "wormize_authority_record",
447 __PACKAGE__->register_method(
448 api_name => "open-ils.worm.wormize.authority.noscrub",
449 method => "wormize_authority_record",
455 # --------------------------------------------------------------------------------
456 # MARC index extraction
458 package OpenILS::Application::WoRM::XPATH;
459 use base qw/OpenILS::Application::WoRM/;
460 use Unicode::Normalize;
462 # give this a MODS documentElement and an XPATH expression
463 sub _xpath_to_string {
467 my $ns_prefix = shift;
470 $xml->setNamespace( $ns_uri, $ns_prefix, 1 ) if ($ns_uri && $ns_prefix);
474 # grab the set of matching nodes
475 my @nodes = $xml->findnodes( $xpath );
476 for my $value (@nodes) {
478 # grab all children of the node
479 my @children = $value->childNodes();
480 for my $child (@children) {
482 # add the childs content to the growing buffer
483 my $content = quotemeta($child->textContent);
484 next if ($unique && $string =~ /$content/); # uniquify the values
485 $string .= $child->textContent . " ";
488 $string .= $value->textContent . " ";
492 $string =~ s/(\pM)//gso;
496 sub class_all_index_string_xml {
502 OpenILS::Application::WoRM->post_init();
503 $xml = $parser->parse_string($xml) unless (ref $xml);
505 my $class_constructor = "Fieldmapper::metabib::${class}_field_entry";
506 for my $type ( keys %{ $xpathset->{$class} } ) {
507 my $value = _xpath_to_string(
508 $mods_sheet->transform($xml)->documentElement,
509 $xpathset->{$class}->{$type}->{xpath},
510 "http://www.loc.gov/mods/",
517 $value =~ s/(\pM|\pC)//sgoe;
518 $value =~ s/[\x80-\xff]//sgoe;
521 my $fm = $class_constructor->new;
522 $fm->value( $value );
523 $fm->field( $xpathset->{$class}->{$type}->{id} );
524 $client->respond($fm);
528 __PACKAGE__->register_method(
529 api_name => "open-ils.worm.field_entry.class.xml",
530 method => "class_all_index_string_xml",
536 sub class_all_index_string_record {
542 OpenILS::Application::WoRM->post_init();
543 my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec );
545 for my $fm ($self->method_lookup("open-ils.worm.field_entry.class.xml")->run($r->marc, $class)) {
547 $client->respond($fm);
551 __PACKAGE__->register_method(
552 api_name => "open-ils.worm.field_entry.class.record",
553 method => "class_all_index_string_record",
560 sub class_index_string_xml {
567 OpenILS::Application::WoRM->post_init();
568 $xml = $parser->parse_string($xml) unless (ref $xml);
569 return _xpath_to_string( $mods_sheet->transform($xml)->documentElement, $xpathset->{$class}->{$type}->{xpath}, "http://www.loc.gov/mods/", "mods", 1 );
571 __PACKAGE__->register_method(
572 api_name => "open-ils.worm.class.type.xml",
573 method => "class_index_string_xml",
578 sub class_index_string_record {
585 OpenILS::Application::WoRM->post_init();
586 my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec );
588 my ($d) = $self->method_lookup("open-ils.worm.class.type.xml")->run($r->marc, $class => $type);
589 $log->debug("XPath $class->$type for bib rec $rec returns ($d)", DEBUG);
592 __PACKAGE__->register_method(
593 api_name => "open-ils.worm.class.type.record",
594 method => "class_index_string_record",
608 OpenILS::Application::WoRM->post_init();
609 $xml = $parser->parse_string($xml) unless (ref $xml);
610 return _xpath_to_string( $xml->documentElement, $xpath, $uri, $prefix, $unique );
612 __PACKAGE__->register_method(
613 api_name => "open-ils.worm.xpath.xml",
614 method => "xml_xpath",
628 OpenILS::Application::WoRM->post_init();
629 my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec );
631 my ($d) = $self->method_lookup("open-ils.worm.xpath.xml")->run($r->marc, $xpath, $uri, $prefix, $unique );
632 $log->debug("XPath [$xpath] bib rec $rec returns ($d)", DEBUG);
635 __PACKAGE__->register_method(
636 api_name => "open-ils.worm.xpath.record",
637 method => "record_xpath",
643 # --------------------------------------------------------------------------------
646 package OpenILS::Application::WoRM::Biblio::Leader;
647 use base qw/OpenILS::Application::WoRM/;
648 use Unicode::Normalize;
650 our %biblio_descriptor_code = (
651 item_type => sub { substr($ldr,6,1); },
652 item_form => sub { (substr($ldr,6,1) =~ /^(?:f|g|i|m|o|p|r)$/o) ? substr($oo8,29,1) : substr($oo8,23,1); },
653 bib_level => sub { substr($ldr,7,1); },
654 control_type => sub { substr($ldr,8,1); },
655 char_encoding => sub { substr($ldr,9,1); },
656 enc_level => sub { substr($ldr,17,1); },
657 cat_form => sub { substr($ldr,18,1); },
658 pub_status => sub { substr($ldr,5,1); },
659 item_lang => sub { substr($oo8,35,3); },
660 #lit_form => sub { (substr($ldr,6,1) =~ /^(?:f|g|i|m|o|p|r)$/) ? substr($oo8,33,1) : "0"; },
661 audience => sub { substr($oo8,22,1); },
664 sub _extract_biblio_descriptors {
667 local $ldr = $xml->findvalue('//*[local-name()="leader"]');
668 local $oo8 = $xml->findvalue('//*[local-name()="controlfield" and @tag="008"]');
670 my $rd_obj = Fieldmapper::metabib::record_descriptor->new;
671 for my $rd_field ( keys %biblio_descriptor_code ) {
672 $rd_obj->$rd_field( $biblio_descriptor_code{$rd_field}->() );
678 sub extract_biblio_desc_xml {
683 $xml = $parser->parse_string($xml) unless (ref $xml);
685 return _extract_biblio_descriptors( $xml );
687 __PACKAGE__->register_method(
688 api_name => "open-ils.worm.biblio_leader.xml",
689 method => "extract_biblio_desc_xml",
694 sub extract_biblio_desc_record {
699 OpenILS::Application::WoRM->post_init();
700 my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.biblio.record_entry.retrieve" => $rec );
702 my ($d) = $self->method_lookup("open-ils.worm.biblio_leader.xml")->run($r->marc);
703 $log->debug("Record descriptor for bib rec $rec is ".JSON->perl2JSON($d), DEBUG);
706 __PACKAGE__->register_method(
707 api_name => "open-ils.worm.biblio_leader.record",
708 method => "extract_biblio_desc_record",
713 # --------------------------------------------------------------------------------
716 package OpenILS::Application::WoRM::FlatMARC;
717 use base qw/OpenILS::Application::WoRM/;
718 use Unicode::Normalize;
721 sub _marcxml_to_full_rows {
724 my $xmltype = shift || 'metabib';
726 my $type = "Fieldmapper::${xmltype}::full_rec";
730 my ($root) = $marcxml->findnodes('//*[local-name()="record"]');
732 for my $tagline ( @{$root->getChildrenByTagName("leader")} ) {
733 next unless $tagline;
738 my $val = $tagline->textContent;
740 $val =~ s/(\pM+)//gso;
746 for my $tagline ( @{$root->getChildrenByTagName("controlfield")} ) {
747 next unless $tagline;
751 $ns->tag( $tagline->getAttribute( "tag" ) );
752 my $val = $tagline->textContent;
754 $val =~ s/(\pM+)//gso;
760 for my $tagline ( @{$root->getChildrenByTagName("datafield")} ) {
761 next unless $tagline;
763 my $tag = $tagline->getAttribute( "tag" );
764 my $ind1 = $tagline->getAttribute( "ind1" );
765 my $ind2 = $tagline->getAttribute( "ind2" );
767 for my $data ( $tagline->childNodes ) {
775 $ns->subfield( $data->getAttribute( "code" ) );
776 my $val = $data->textContent;
778 $val =~ s/(\pM+)//gso;
779 $ns->value( lc($val) );
785 $log->debug("Returning ".scalar(@ns_list)." Fieldmapper nodes from $xmltype xml", DEBUG);
794 $xml = $parser->parse_string($xml) unless (ref $xml);
796 my $type = 'metabib';
797 $type = 'authority' if ($self->api_name =~ /authority/o);
799 OpenILS::Application::WoRM->post_init();
801 $client->respond($_) for (_marcxml_to_full_rows($xml, $type));
804 __PACKAGE__->register_method(
805 api_name => "open-ils.worm.flat_marc.authority.xml",
806 method => "flat_marc_xml",
811 __PACKAGE__->register_method(
812 api_name => "open-ils.worm.flat_marc.biblio.xml",
813 method => "flat_marc_xml",
819 sub flat_marc_record {
825 $type = 'authority' if ($self->api_name =~ /authority/o);
827 OpenILS::Application::WoRM->post_init();
828 my $r = OpenILS::Application::WoRM->storage_req( "open-ils.storage.direct.${type}.record_entry.retrieve" => $rec );
830 $client->respond($_) for ($self->method_lookup("open-ils.worm.flat_marc.$type.xml")->run($r->marc));
833 __PACKAGE__->register_method(
834 api_name => "open-ils.worm.flat_marc.biblio.record_entry",
835 method => "flat_marc_record",
840 __PACKAGE__->register_method(
841 api_name => "open-ils.worm.flat_marc.authority.record_entry",
842 method => "flat_marc_record",
849 # --------------------------------------------------------------------------------
852 package OpenILS::Application::WoRM::Biblio::Fingerprint;
853 use base qw/OpenILS::Application::WoRM/;
854 use Unicode::Normalize;
855 use OpenSRF::EX qw/:try/;
857 my @fp_mods_xpath = (
858 '//mods:mods/mods:typeOfResource[text()="text"]' => [
861 '//mods:mods/mods:titleInfo[mods:title and (@type="uniform")]',
862 '//mods:mods/mods:titleInfo[mods:title and (@type="translated")]',
863 '//mods:mods/mods:titleInfo[mods:title and (@type="alternative")]',
864 '//mods:mods/mods:titleInfo[mods:title and not(@type)]',
867 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
869 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
870 $text =~ s/\pM+//gso;
871 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
873 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
874 $text =~ s/\s+/ /sgo;
875 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
876 $text =~ s/^\s*(.+)\s*$/$1/sgo;
877 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
878 $text =~ s/\b(?:the|an?)\b//sgo;
879 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
880 $text =~ s/\[.[^\]]+\]//sgo;
881 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
882 $text =~ s/\s*[;\/\.]*$//sgo;
883 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
888 '//mods:mods/mods:name[mods:role/mods:text/text()="creator" and @type="personal"]/mods:namePart',
889 '//mods:mods/mods:name[mods:role/mods:text/text()="creator"]/mods:namePart',
892 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
894 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
895 $text =~ s/\pM+//gso;
896 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
898 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
899 $text =~ s/\s+/ /sgo;
900 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
901 $text =~ s/^\s*(.+)\s*$/$1/sgo;
902 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
903 $text =~ s/,?\s+.*$//sgo;
904 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
909 '//mods:mods/mods:relatedItem[@type!="host" and @type!="series"]' => [
912 '//mods:mods/mods:relatedItem/mods:titleInfo[mods:title and (@type="uniform")]',
913 '//mods:mods/mods:relatedItem/mods:titleInfo[mods:title and (@type="translated")]',
914 '//mods:mods/mods:relatedItem/mods:titleInfo[mods:title and (@type="alternative")]',
915 '//mods:mods/mods:relatedItem/mods:titleInfo[mods:title and not(@type)]',
916 '//mods:mods/mods:titleInfo[mods:title and (@type="uniform")]',
917 '//mods:mods/mods:titleInfo[mods:title and (@type="translated")]',
918 '//mods:mods/mods:titleInfo[mods:title and (@type="alternative")]',
919 '//mods:mods/mods:titleInfo[mods:title and not(@type)]',
922 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
924 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
925 $text =~ s/\pM+//gso;
926 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
928 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
929 $text =~ s/\s+/ /sgo;
930 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
931 $text =~ s/^\s*(.+)\s*$/$1/sgo;
932 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
933 $text =~ s/\b(?:the|an?)\b//sgo;
934 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
935 $text =~ s/\[.[^\]]+\]//sgo;
936 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
937 $text =~ s/\s*[;\/\.]*$//sgo;
938 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
943 '//mods:mods/mods:relatedItem/mods:name[mods:role/mods:text/text()="creator" and @type="personal"]/mods:namePart',
944 '//mods:mods/mods:relatedItem/mods:name[mods:role/mods:text/text()="creator"]/mods:namePart',
945 '//mods:mods/mods:name[mods:role/mods:text/text()="creator" and @type="personal"]/mods:namePart',
946 '//mods:mods/mods:name[mods:role/mods:text/text()="creator"]/mods:namePart',
949 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
951 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
952 $text =~ s/\pM+//gso;
953 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
955 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
956 $text =~ s/\s+/ /sgo;
957 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
958 $text =~ s/^\s*(.+)\s*$/$1/sgo;
959 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
960 $text =~ s/,?\s+.*$//sgo;
961 $log->debug("Fingerprint text /durring/ fixup : [$text]", INTERNAL);
968 push @fp_mods_xpath, '//mods:mods/mods:titleInfo' => $fp_mods_xpath[1];
972 $mods->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
978 while ( my $match_xpath = $fp_mods_xpath[$match_index] ) {
979 if ( my @nodes = $mods->findnodes( $match_xpath ) ) {
981 my $block_name_index = 0;
982 my $block_value_index = 1;
983 my $block = $fp_mods_xpath[$block_index];
984 while ( my $part = $$block[$block_value_index] ) {
986 for my $xpath ( @{ $part->{xpath} } ) {
987 $text = $mods->findvalue( $xpath );
991 $log->debug("Found fingerprint text using $$block[$block_name_index] : [$text]", DEBUG);
995 $log->debug("Fingerprint text after fixup : [$text]", DEBUG);
999 $block_name_index += 2;
1000 $block_value_index += 2;
1004 $fp_string =~ s/\W+//gso;
1005 $log->debug("Fingerprint is [$fp_string]", INFO);;
1015 sub refingerprint_bibrec {
1021 if (!OpenILS::Application::WoRM->in_transaction) {
1022 OpenILS::Application::WoRM->begin_transaction($client) || throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!");
1028 my $bibs = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.biblio.record_entry.search.id.atomic', $rec );
1029 OpenILS::Application::WoRM->storage_req(
1030 'open-ils.storage.direct.biblio.record_entry.remote_update',
1032 { fingerprint => $self->method_lookup( 'open-ils.worm.fingerprint.marc' )->run( $_->marc ) }
1035 $log->debug('Fingerprinting failed : '.shift(), ERROR);
1039 OpenILS::Application::WoRM->commit_transaction if ($commit && $success);
1040 OpenILS::Application::WoRM->rollback_transaction if ($commit && !$success);
1043 __PACKAGE__->register_method(
1044 api_name => "open-ils.worm.fingerprint.record.update",
1045 method => "refingerprint_bibrec",
1051 sub fingerprint_bibrec {
1056 OpenILS::Application::WoRM->post_init();
1057 my $r = OpenILS::Application::WoRM->storage_req( 'open-ils.storage.direct.biblio.record_entry.retrieve' => $rec );
1059 my ($fp) = $self->method_lookup('open-ils.worm.fingerprint.marc')->run($r->marc);
1060 $log->debug("Returning [$fp] as fingerprint for record $rec", INFO);
1064 __PACKAGE__->register_method(
1065 api_name => "open-ils.worm.fingerprint.record",
1066 method => "fingerprint_bibrec",
1071 sub fingerprint_mods {
1076 OpenILS::Application::WoRM->post_init();
1077 my $mods = $parser->parse_string($xml)->documentElement;
1079 return _fp_mods( $mods );
1081 __PACKAGE__->register_method(
1082 api_name => "open-ils.worm.fingerprint.mods",
1083 method => "fingerprint_mods",
1088 sub fingerprint_marc {
1093 $xml = $parser->parse_string($xml) unless (ref $xml);
1095 OpenILS::Application::WoRM->post_init();
1096 my $fp = _fp_mods( $mods_sheet->transform($xml)->documentElement );
1097 $log->debug("Returning [$fp] as fingerprint", INFO);
1100 __PACKAGE__->register_method(
1101 api_name => "open-ils.worm.fingerprint.marc",
1102 method => "fingerprint_marc",
1108 # --------------------------------------------------------------------------------
1121 my $create_source_map;
1136 my %descriptor_code = (
1137 item_type => 'substr($ldr,6,1)',
1138 item_form => '(substr($ldr,6,1) =~ /^(?:f|g|i|m|o|p|r)$/) ? substr($oo8,29,1) : substr($oo8,23,1)',
1139 bib_level => 'substr($ldr,7,1)',
1140 control_type => 'substr($ldr,8,1)',
1141 char_encoding => 'substr($ldr,9,1)',
1142 enc_level => 'substr($ldr,17,1)',
1143 cat_form => 'substr($ldr,18,1)',
1144 pub_status => 'substr($ldr,5,1)',
1145 item_lang => 'substr($oo8,35,3)',
1146 #lit_form => '(substr($ldr,6,1) =~ /^(?:f|g|i|m|o|p|r)$/) ? substr($oo8,33,1) : "0"',
1147 audience => 'substr($oo8,22,1)',
1157 if ($self->api_name =~ /no_map/o) {
1161 $in_xact = $self->method_lookup( 'open-ils.storage.transaction.current')
1163 $begin = $self->method_lookup( 'open-ils.storage.transaction.begin')
1165 $commit = $self->method_lookup( 'open-ils.storage.transaction.commit')
1167 $rollback = $self->method_lookup( 'open-ils.storage.transaction.rollback')
1169 $sm_lookup = $self->method_lookup('open-ils.storage.direct.metabib.metarecord_source_map.search.source')
1170 unless ($sm_lookup);
1171 $mr_lookup = $self->method_lookup('open-ils.storage.direct.metabib.metarecord.search.fingerprint')
1172 unless ($mr_lookup);
1173 $mr_update = $self->method_lookup('open-ils.storage.direct.metabib.metarecord.batch.update')
1174 unless ($mr_update);
1175 $lookup = $self->method_lookup('open-ils.storage.direct.biblio.record_entry.batch.retrieve')
1177 $update_entry = $self->method_lookup('open-ils.storage.direct.biblio.record_entry.batch.update')
1178 unless ($update_entry);
1179 $rm_old_sm = $self->method_lookup( 'open-ils.storage.direct.metabib.metarecord_source_map.mass_delete')
1180 unless ($rm_old_sm);
1181 $rm_old_rd = $self->method_lookup( 'open-ils.storage.direct.metabib.record_descriptor.mass_delete')
1182 unless ($rm_old_rd);
1183 $rm_old_fr = $self->method_lookup( 'open-ils.storage.direct.metabib.full_rec.mass_delete')
1184 unless ($rm_old_fr);
1185 $rm_old_tr = $self->method_lookup( 'open-ils.storage.direct.metabib.title_field_entry.mass_delete')
1186 unless ($rm_old_tr);
1187 $rm_old_ar = $self->method_lookup( 'open-ils.storage.direct.metabib.author_field_entry.mass_delete')
1188 unless ($rm_old_ar);
1189 $rm_old_sr = $self->method_lookup( 'open-ils.storage.direct.metabib.subject_field_entry.mass_delete')
1190 unless ($rm_old_sr);
1191 $rm_old_kr = $self->method_lookup( 'open-ils.storage.direct.metabib.keyword_field_entry.mass_delete')
1192 unless ($rm_old_kr);
1193 $rm_old_ser = $self->method_lookup( 'open-ils.storage.direct.metabib.series_field_entry.mass_delete')
1194 unless ($rm_old_ser);
1195 $mr_create = $self->method_lookup('open-ils.storage.direct.metabib.metarecord.create')
1196 unless ($mr_create);
1197 $create_source_map = $self->method_lookup('open-ils.storage.direct.metabib.metarecord_source_map.batch.create')
1198 unless ($create_source_map);
1199 $rd_create = $self->method_lookup( 'open-ils.storage.direct.metabib.record_descriptor.batch.create')
1200 unless ($rd_create);
1201 $fr_create = $self->method_lookup( 'open-ils.storage.direct.metabib.full_rec.batch.create')
1202 unless ($fr_create);
1203 $$create{title} = $self->method_lookup( 'open-ils.storage.direct.metabib.title_field_entry.batch.create')
1204 unless ($$create{title});
1205 $$create{author} = $self->method_lookup( 'open-ils.storage.direct.metabib.author_field_entry.batch.create')
1206 unless ($$create{author});
1207 $$create{subject} = $self->method_lookup( 'open-ils.storage.direct.metabib.subject_field_entry.batch.create')
1208 unless ($$create{subject});
1209 $$create{keyword} = $self->method_lookup( 'open-ils.storage.direct.metabib.keyword_field_entry.batch.create')
1210 unless ($$create{keyword});
1211 $$create{series} = $self->method_lookup( 'open-ils.storage.direct.metabib.series_field_entry.batch.create')
1212 unless ($$create{series});
1215 my ($outer_xact) = $in_xact->run;
1217 unless ($outer_xact) {
1218 $log->debug("WoRM isn't inside a transaction, starting one now.", INFO);
1219 my ($r) = $begin->run($client);
1220 unless (defined $r and $r) {
1222 throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!")
1225 } catch Error with {
1226 throw OpenSRF::EX::PANIC ("WoRM Couldn't BEGIN transaction!")
1236 for my $entry ( $lookup->run(@docids) ) {
1237 # step -1: grab the doc from storage
1238 next unless ($entry);
1241 my $xslt_doc = $parser->parse_file(
1242 OpenSRF::Utils::SettingsClient->new->config_value(dirs => 'xsl') . "/MARC21slim2MODS.xsl");
1243 $mods_sheet = $xslt->parse_stylesheet( $xslt_doc );
1246 my $xml = $entry->marc;
1247 my $docid = $entry->id;
1248 my $marcdoc = $parser->parse_string($xml);
1249 my $modsdoc = $mods_sheet->transform($marcdoc);
1251 my $mods = $modsdoc->documentElement;
1252 $mods->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
1254 $entry->fingerprint( fingerprint_mods( $mods ) );
1255 push @entry_list, $entry;
1257 $log->debug("Fingerprint for Record Entry ".$docid." is [".$entry->fingerprint."]", INFO);
1260 my ($mr) = $mr_lookup->run( $entry->fingerprint );
1261 if (!$mr || !@$mr) {
1262 $log->debug("No metarecord found for fingerprint [".$entry->fingerprint."]; Creating a new one", INFO);
1263 $mr = new Fieldmapper::metabib::metarecord;
1264 $mr->fingerprint( $entry->fingerprint );
1265 $mr->master_record( $entry->id );
1266 my ($new_mr) = $mr_create->run($mr);
1268 unless (defined $mr) {
1269 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.direct.metabib.metarecord.create!")
1272 $log->debug("Retrieved metarecord, id is ".$mr->id, INFO);
1277 my $sm = new Fieldmapper::metabib::metarecord_source_map;
1278 $sm->metarecord( $mr->id );
1279 $sm->source( $entry->id );
1280 push @source_maps, $sm;
1283 my $ldr = $marcdoc->documentElement->getChildrenByTagName('leader')->pop->textContent;
1284 my $oo8 = $marcdoc->documentElement->findvalue('//*[local-name()="controlfield" and @tag="008"]');
1286 my $rd_obj = Fieldmapper::metabib::record_descriptor->new;
1287 for my $rd_field ( keys %descriptor_code ) {
1288 $rd_obj->$rd_field( eval "$descriptor_code{$rd_field};" );
1290 $rd_obj->record( $docid );
1291 push @rd_list, $rd_obj;
1293 push @mods_data, { $docid => $self->modsdoc_to_values( $mods ) };
1295 # step 2: build the KOHA rows
1296 my @tmp_list = _marcxml_to_full_rows( $marcdoc );
1297 $_->record( $docid ) for (@tmp_list);
1298 push @ns_list, @tmp_list;
1302 last unless ($self->api_name =~ /batch$/o);
1305 $rm_old_rd->run( { record => \@docids } );
1306 $rm_old_fr->run( { record => \@docids } );
1307 $rm_old_sm->run( { source => \@docids } ) unless ($no_map);
1308 $rm_old_tr->run( { source => \@docids } );
1309 $rm_old_ar->run( { source => \@docids } );
1310 $rm_old_sr->run( { source => \@docids } );
1311 $rm_old_kr->run( { source => \@docids } );
1312 $rm_old_ser->run( { source => \@docids } );
1315 my ($sm) = $create_source_map->run(@source_maps);
1316 unless (defined $sm) {
1317 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.direct.metabib.metarecord_source_map.batch.create!")
1319 my ($mr) = $mr_update->run(@mr_list);
1320 unless (defined $mr) {
1321 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.direct.metabib.metarecord.batch.update!")
1325 my ($re) = $update_entry->run(@entry_list);
1326 unless (defined $re) {
1327 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.direct.biblio.record_entry.batch.update!")
1330 my ($rd) = $rd_create->run(@rd_list);
1331 unless (defined $rd) {
1332 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.direct.metabib.record_descriptor.batch.create!")
1335 my ($fr) = $fr_create->run(@ns_list);
1336 unless (defined $fr) {
1337 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.direct.metabib.full_rec.batch.create!")
1340 # step 5: insert the new metadata
1341 for my $class ( qw/title author subject keyword series/ ) {
1343 for my $doc ( @mods_data ) {
1344 my ($did) = keys %$doc;
1345 my ($data) = values %$doc;
1347 my $fm_constructor = "Fieldmapper::metabib::${class}_field_entry";
1348 for my $row ( keys %{ $$data{$class} } ) {
1349 next unless (exists $$data{$class}{$row});
1350 next unless ($$data{$class}{$row}{value});
1351 my $fm_obj = $fm_constructor->new;
1352 $fm_obj->value( $$data{$class}{$row}{value} );
1353 $fm_obj->field( $$data{$class}{$row}{field_id} );
1354 $fm_obj->source( $did );
1355 $log->debug("$class entry: ".$fm_obj->source." => ".$fm_obj->field." : ".$fm_obj->value, DEBUG);
1357 push @md_list, $fm_obj;
1361 my ($cr) = $$create{$class}->run(@md_list);
1362 unless (defined $cr) {
1363 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.direct.metabib.${class}_field_entry.batch.create!")
1367 unless ($outer_xact) {
1368 $log->debug("Commiting transaction started by the WoRM.", INFO);
1369 my ($c) = $commit->run;
1370 unless (defined $c and $c) {
1372 throw OpenSRF::EX::PANIC ("Couldn't COMMIT changes!")
1378 __PACKAGE__->register_method(
1379 api_name => "open-ils.worm.wormize",
1380 method => "wormize",
1384 __PACKAGE__->register_method(
1385 api_name => "open-ils.worm.wormize.no_map",
1386 method => "wormize",
1390 __PACKAGE__->register_method(
1391 api_name => "open-ils.worm.wormize.batch",
1392 method => "wormize",
1396 __PACKAGE__->register_method(
1397 api_name => "open-ils.worm.wormize.no_map.batch",
1398 method => "wormize",
1413 my $acreate_source_map;
1428 sub authority_wormize {
1435 if ($self->api_name =~ /no_map/o) {
1439 $in_xact = $self->method_lookup( 'open-ils.storage.transaction.current')
1441 $begin = $self->method_lookup( 'open-ils.storage.transaction.begin')
1443 $commit = $self->method_lookup( 'open-ils.storage.transaction.commit')
1445 $rollback = $self->method_lookup( 'open-ils.storage.transaction.rollback')
1447 $alookup = $self->method_lookup('open-ils.storage.direct.authority.record_entry.batch.retrieve')
1449 $aupdate_entry = $self->method_lookup('open-ils.storage.direct.authority.record_entry.batch.update')
1450 unless ($aupdate_entry);
1451 $arm_old_rd = $self->method_lookup( 'open-ils.storage.direct.authority.record_descriptor.mass_delete')
1452 unless ($arm_old_rd);
1453 $arm_old_fr = $self->method_lookup( 'open-ils.storage.direct.authority.full_rec.mass_delete')
1454 unless ($arm_old_fr);
1455 $ard_create = $self->method_lookup( 'open-ils.storage.direct.authority.record_descriptor.batch.create')
1456 unless ($ard_create);
1457 $afr_create = $self->method_lookup( 'open-ils.storage.direct.authority.full_rec.batch.create')
1458 unless ($afr_create);
1461 my ($outer_xact) = $in_xact->run;
1463 unless ($outer_xact) {
1464 $log->debug("WoRM isn't inside a transaction, starting one now.", INFO);
1465 my ($r) = $begin->run($client);
1466 unless (defined $r and $r) {
1468 throw OpenSRF::EX::PANIC ("Couldn't BEGIN transaction!")
1471 } catch Error with {
1472 throw OpenSRF::EX::PANIC ("WoRM Couldn't BEGIN transaction!")
1482 for my $entry ( $lookup->run(@docids) ) {
1483 # step -1: grab the doc from storage
1484 next unless ($entry);
1487 # my $xslt_doc = $parser->parse_file(
1488 # OpenSRF::Utils::SettingsClient->new->config_value(dirs => 'xsl') . "/MARC21slim2MODS.xsl");
1489 # $mads_sheet = $xslt->parse_stylesheet( $xslt_doc );
1492 my $xml = $entry->marc;
1493 my $docid = $entry->id;
1494 my $marcdoc = $parser->parse_string($xml);
1495 #my $madsdoc = $mads_sheet->transform($marcdoc);
1497 #my $mads = $madsdoc->documentElement;
1498 #$mads->setNamespace( "http://www.loc.gov/mads/", "mads", 1 );
1500 push @entry_list, $entry;
1502 my $ldr = $marcdoc->documentElement->getChildrenByTagName('leader')->pop->textContent;
1503 my $oo8 = $marcdoc->documentElement->findvalue('//*[local-name()="controlfield" and @tag="008"]');
1505 my $rd_obj = Fieldmapper::authority::record_descriptor->new;
1506 for my $rd_field ( keys %descriptor_code ) {
1507 $rd_obj->$rd_field( eval "$descriptor_code{$rd_field};" );
1509 $rd_obj->record( $docid );
1510 push @rd_list, $rd_obj;
1512 # step 2: build the KOHA rows
1513 my @tmp_list = _marcxml_to_full_rows( $marcdoc, 'Fieldmapper::authority::full_rec' );
1514 $_->record( $docid ) for (@tmp_list);
1515 push @ns_list, @tmp_list;
1519 last unless ($self->api_name =~ /batch$/o);
1522 $arm_old_rd->run( { record => \@docids } );
1523 $arm_old_fr->run( { record => \@docids } );
1525 my ($rd) = $ard_create->run(@rd_list);
1526 unless (defined $rd) {
1527 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.direct.authority.record_descriptor.batch.create!")
1530 my ($fr) = $fr_create->run(@ns_list);
1531 unless (defined $fr) {
1532 throw OpenSRF::EX::PANIC ("Couldn't run open-ils.storage.direct.authority.full_rec.batch.create!")
1535 unless ($outer_xact) {
1536 $log->debug("Commiting transaction started by the WoRM.", INFO);
1537 my ($c) = $commit->run;
1538 unless (defined $c and $c) {
1540 throw OpenSRF::EX::PANIC ("Couldn't COMMIT changes!")
1546 __PACKAGE__->register_method(
1547 api_name => "open-ils.worm.authortiy.wormize",
1548 method => "wormize",
1552 __PACKAGE__->register_method(
1553 api_name => "open-ils.worm.authority.wormize.batch",
1554 method => "wormize",
1560 # --------------------------------------------------------------------------------
1563 sub _marcxml_to_full_rows {
1565 my $marcxml = shift;
1566 my $type = shift || 'Fieldmapper::metabib::full_rec';
1570 my $root = $marcxml->documentElement;
1572 for my $tagline ( @{$root->getChildrenByTagName("leader")} ) {
1573 next unless $tagline;
1575 my $ns = new Fieldmapper::metabib::full_rec;
1578 my $val = NFD($tagline->textContent);
1579 $val =~ s/(\pM+)//gso;
1585 for my $tagline ( @{$root->getChildrenByTagName("controlfield")} ) {
1586 next unless $tagline;
1588 my $ns = new Fieldmapper::metabib::full_rec;
1590 $ns->tag( $tagline->getAttribute( "tag" ) );
1591 my $val = NFD($tagline->textContent);
1592 $val =~ s/(\pM+)//gso;
1598 for my $tagline ( @{$root->getChildrenByTagName("datafield")} ) {
1599 next unless $tagline;
1601 my $tag = $tagline->getAttribute( "tag" );
1602 my $ind1 = $tagline->getAttribute( "ind1" );
1603 my $ind2 = $tagline->getAttribute( "ind2" );
1605 for my $data ( $tagline->childNodes ) {
1608 my $ns = $type->new;
1613 $ns->subfield( $data->getAttribute( "code" ) );
1614 my $val = NFD($data->textContent);
1615 $val =~ s/(\pM+)//gso;
1616 $ns->value( lc($val) );
1624 sub _get_field_value {
1626 my( $root, $xpath ) = @_;
1630 # grab the set of matching nodes
1631 my @nodes = $root->findnodes( $xpath );
1632 for my $value (@nodes) {
1634 # grab all children of the node
1635 my @children = $value->childNodes();
1636 for my $child (@children) {
1638 # add the childs content to the growing buffer
1639 my $content = quotemeta($child->textContent);
1640 next if ($string =~ /$content/); # uniquify the values
1641 $string .= $child->textContent . " ";
1644 $string .= $value->textContent . " ";
1647 $string = NFD($string);
1648 $string =~ s/(\pM)//gso;
1653 sub modsdoc_to_values {
1654 my( $self, $mods ) = @_;
1656 for my $class (keys %$xpathset) {
1657 $data->{$class} = {};
1658 for my $type (keys %{$xpathset->{$class}}) {
1659 $data->{$class}->{$type} = {};
1660 $data->{$class}->{$type}->{field_id} = $xpathset->{$class}->{$type}->{id};