1 package OpenILS::Application::SuperCat;
6 # All OpenSRF applications must be based on OpenSRF::Application or
7 # a subclass thereof. Makes sense, eh?
8 use OpenSRF::Application;
9 use base qw/OpenSRF::Application/;
11 # This is the client class, used for connecting to open-ils.storage
12 use OpenSRF::AppSession;
14 # This is an extention of Error.pm that supplies some error types to throw
15 use OpenSRF::EX qw(:try);
17 # This is a helper class for querying the OpenSRF Settings application ...
18 use OpenSRF::Utils::SettingsClient;
20 # ... and here we have the built in logging helper ...
21 use OpenSRF::Utils::Logger qw($logger);
23 # ... and this is our OpenILS object (en|de)coder and psuedo-ORM package.
24 use OpenILS::Utils::Fieldmapper;
27 # We'll be working with XML, so...
30 use Unicode::Normalize;
34 our ($_parser, $_mods_sheet, $_storage);
37 $_parser = new XML::LibXML;
38 my $mods_xslt = $_parser->parse_file(
39 OpenSRF::Utils::SettingsClient
41 ->config_value( dirs => 'xsl' ).
42 "/MARC21slim2MODS.xsl"
44 my $xslt = new XML::LibXSLT;
45 $_mods_sheet = $xslt->parse_stylesheet( $mods_xslt );
46 $_storage = OpenSRF::AppSession->create( 'open-ils.storage' );
51 my $stuff = NFC(shift());
52 $stuff =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
57 sub retrieve_record_marcxml {
65 ->request( 'open-ils.storage.direct.biblio.record_entry.retrieve' => $rid )
71 __PACKAGE__->register_method(
72 method => 'retrieve_record_marcxml',
73 api_name => 'open-ils.supercat.record.marcxml.retrieve',
78 Returns the MARCXML representation of the requested bibliographic record
83 desc => 'An OpenILS biblio::record_entry id',
87 { desc => 'The bib record in MARCXML',
92 sub retrieve_record_mods {
97 my $marc = $_storage->request(
98 'open-ils.storage.direct.biblio.record_entry.retrieve',
102 return entityize($_mods_sheet->transform( $_parser->parse_string( $marc ) )->toString);
105 __PACKAGE__->register_method(
106 method => 'retrieve_record_mods',
107 api_name => 'open-ils.supercat.record.mods.retrieve',
112 Returns the MODS representation of the requested bibliographic record
117 desc => 'An OpenILS biblio::record_entry id',
121 { desc => 'The bib record in MODS',
126 sub retrieve_metarecord_mods {
134 # Get the metarecord in question
137 'open-ils.storage.direct.metabib.metarecord.retrieve' => $rid
140 # Now get the map of all bib records for the metarecord
143 'open-ils.storage.direct.metabib.metarecord_source_map.search.metarecord.atomic',
147 $logger->debug("Adding ".scalar(@$recs)." bib record to the MODS of the metarecord");
149 # and retrieve the lead (master) record as MODS
151 $self ->method_lookup('open-ils.supercat.record.mods.retrieve')
152 ->run($mr->master_record);
153 my $master_mods = $_parser->parse_string($master)->documentElement;
154 $master_mods->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
156 # ... and a MODS clone to populate, with guts removed.
157 my $mods = $_parser->parse_string($master)->documentElement;
158 $mods->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
159 ($mods) = $mods->findnodes('//mods:mods');
160 $mods->removeChildNodes;
162 # Add the metarecord ID as a (locally defined) info URI
163 my $recordInfo = $mods
165 ->createElement("mods:recordInfo");
167 my $recordIdentifier = $mods
169 ->createElement("mods:recordIdentifier");
171 $recordIdentifier->setAttribute( source => 'oils:/metabib-metarecord/' );
174 $recordIdentifier->appendTextNode( $id );
176 $recordInfo->appendChild($recordIdentifier);
177 $mods->appendChild($recordInfo);
179 # Grab the title, author and ISBN for the master record and populate the metarecord
180 my ($title) = $master_mods->findnodes( './mods:titleInfo[not(@type)]' );
183 $title->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
184 $title = $mods->ownerDocument->importNode($title);
185 $mods->appendChild($title);
188 my ($author) = $master_mods->findnodes( './mods:name[mods:role/mods:text[text()="creator"]]' );
190 $author->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
191 $author = $mods->ownerDocument->importNode($author);
192 $mods->appendChild($author);
195 my ($isbn) = $master_mods->findnodes( './mods:identifier[@type="isbn"]' );
197 $isbn->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
198 $isbn = $mods->ownerDocument->importNode($isbn);
199 $mods->appendChild($isbn);
202 # ... and loop over the constituent records
203 for my $map ( @$recs ) {
207 $self ->method_lookup('open-ils.supercat.record.mods.retrieve')
210 my $part_mods = $_parser->parse_string($rec);
211 $part_mods->documentElement->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
212 ($part_mods) = $part_mods->findnodes('//mods:mods');
214 for my $node ( ($part_mods->findnodes( './mods:subject' )) ) {
215 $node->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
216 $node = $mods->ownerDocument->importNode($node);
217 $mods->appendChild( $node );
220 my $relatedItem = $mods
222 ->createElement("mods:relatedItem");
224 $relatedItem->setAttribute( type => 'constituent' );
226 my $identifier = $mods
228 ->createElement("mods:identifier");
230 $identifier->setAttribute( type => 'uri' );
232 my $recordInfo = $mods
234 ->createElement("mods:recordInfo");
236 my $recordIdentifier = $mods
238 ->createElement("mods:recordIdentifier");
240 $recordIdentifier->setAttribute( source => 'oils:/biblio-record_entry/' );
242 my $id = $map->source;
243 $recordIdentifier->appendTextNode( $id );
244 $recordInfo->appendChild($recordIdentifier);
246 $relatedItem->appendChild( $recordInfo );
248 my ($tor) = $part_mods->findnodes( './mods:typeOfResource' );
249 $tor->setNamespace( "http://www.loc.gov/mods/", "mods", 1 ) if ($tor);
250 $tor = $mods->ownerDocument->importNode($tor) if ($tor);
251 $relatedItem->appendChild($tor) if ($tor);
253 if ( my ($part_isbn) = $part_mods->findnodes( './mods:identifier[@type="isbn"]' ) ) {
254 $part_isbn->setNamespace( "http://www.loc.gov/mods/", "mods", 1 );
255 $part_isbn = $mods->ownerDocument->importNode($part_isbn);
256 $relatedItem->appendChild( $part_isbn );
259 $isbn = $mods->appendChild( $part_isbn->cloneNode(1) );
263 $mods->appendChild( $relatedItem );
267 $_storage->disconnect;
269 return entityize($mods->toString);
272 __PACKAGE__->register_method(
273 method => 'retrieve_metarecord_mods',
274 api_name => 'open-ils.supercat.metarecord.mods.retrieve',
279 Returns the MODS representation of the requested metarecord
283 { name => 'metarecordId',
284 desc => 'An OpenILS metabib::metarecord id',
288 { desc => 'The metarecord in MODS',
298 throw OpenSRF::EX::InvalidArg ('I need an ISBN please')
299 unless (length($isbn) >= 10);
301 # Create a storage session, since we'll be making muliple requests.
304 # Find the record that has that ISBN.
305 my $bibrec = $_storage->request(
306 'open-ils.storage.direct.metabib.full_rec.search_where.atomic',
307 { tag => '020', subfield => 'a', value => { like => $isbn.'%'} }
310 # Go away if we don't have one.
311 return {} unless (@$bibrec);
313 # Find the metarecord for that bib record.
314 my $mr = $_storage->request(
315 'open-ils.storage.direct.metabib.metarecord_source_map.search.source.atomic',
319 # Find the other records for that metarecord.
320 my $records = $_storage->request(
321 'open-ils.storage.direct.metabib.metarecord_source_map.search.metarecord.atomic',
325 # Just to be safe. There's currently no unique constraint on sources...
326 my %unique_recs = map { ($_->source, 1) } @$records;
327 my @rec_list = sort keys %unique_recs;
329 # And now fetch the ISBNs for thos records.
330 my $recs = $_storage->request(
331 'open-ils.storage.direct.metabib.full_rec.search_where.atomic',
332 { tag => '020', subfield => 'a', record => \@rec_list }
335 # We're done with the storage server session.
336 $_storage->disconnect;
338 # Return the oISBN data structure. This will be XMLized at a higher layer.
340 { metarecord => $mr->[0]->metarecord,
341 record_list => { map { ($_->record, $_->value) } @$recs } };
344 __PACKAGE__->register_method(
346 api_name => 'open-ils.supercat.oisbn',
351 Returns the ISBN list for the metarecord of the requested isbn
356 desc => 'An ISBN. Duh.',
360 { desc => 'record to isbn map',