Lines 23-28
use XML::LibXML;
Link Here
|
23 |
use XML::LibXSLT; |
23 |
use XML::LibXSLT; |
24 |
use URI; |
24 |
use URI; |
25 |
use File::Basename; |
25 |
use File::Basename; |
|
|
26 |
use RDF::Query; |
26 |
|
27 |
|
27 |
use C4::Context; |
28 |
use C4::Context; |
28 |
use C4::Biblio; |
29 |
use C4::Biblio; |
Lines 30-35
use C4::Biblio;
Link Here
|
30 |
use Koha::Database; |
31 |
use Koha::Database; |
31 |
use Koha::OAI::Harvester::Import::MARCXML; |
32 |
use Koha::OAI::Harvester::Import::MARCXML; |
32 |
use Koha::OAI::Harvester::Import::RDFXML; |
33 |
use Koha::OAI::Harvester::Import::RDFXML; |
|
|
34 |
use Koha::RDF; |
33 |
|
35 |
|
34 |
my $schema = Koha::Database->new()->schema(); |
36 |
my $schema = Koha::Database->new()->schema(); |
35 |
|
37 |
|
Lines 179-184
sub _find_koha_link {
Link Here
|
179 |
return $link_id; |
181 |
return $link_id; |
180 |
} |
182 |
} |
181 |
|
183 |
|
|
|
184 |
|
185 |
sub _find_rdf_link { |
186 |
my ($self, $args) = @_; |
187 |
my ($subject,$graph); |
188 |
my $repository = $self->{repository}; |
189 |
my $identifier = $self->{header_identifier}; |
190 |
|
191 |
my $context = C4::Context->new; |
192 |
my $triplestore = $context->triplestore('query'); |
193 |
if ($triplestore){ |
194 |
if ( URI->new($repository) && URI->new($identifier) ){ |
195 |
my $sparql = qq~ |
196 |
PREFIX koha-oai: <http://koha-community.org/vocab/oai-pmh/> |
197 |
SELECT ?g ?s ?identifier ?repository |
198 |
WHERE { |
199 |
GRAPH ?g { |
200 |
?s koha-oai:identifier ?identifier . |
201 |
?s koha-oai:repository ?repository . |
202 |
?s koha-oai:identifier <$identifier> . |
203 |
?s koha-oai:repository <$repository> . |
204 |
} |
205 |
} |
206 |
~; |
207 |
my $query = RDF::Query->new($sparql); |
208 |
my $iterator = $query->execute($triplestore); |
209 |
my @rows = $iterator->get_all; |
210 |
if (scalar @rows == 1){ |
211 |
my $row = $rows[0]; |
212 |
$subject = $row->{s}; |
213 |
$graph = $row->{g}; |
214 |
} |
215 |
} |
216 |
} |
217 |
return ($subject,$graph); |
218 |
} |
219 |
|
182 |
=head3 |
220 |
=head3 |
183 |
|
221 |
|
184 |
my ($action,$record_id) = $oai_record->import_record({ |
222 |
my ($action,$record_id) = $oai_record->import_record({ |
Lines 198-227
sub import_record {
Link Here
|
198 |
my $framework = $args->{framework} || ''; |
236 |
my $framework = $args->{framework} || ''; |
199 |
my $record_type = $args->{record_type} || 'biblio'; |
237 |
my $record_type = $args->{record_type} || 'biblio'; |
200 |
my $matcher = $args->{matcher}; |
238 |
my $matcher = $args->{matcher}; |
|
|
239 |
my $rdf_type = $args->{rdf_type}; #NOTE: RDF |
201 |
|
240 |
|
202 |
my $action = "error"; |
241 |
my $action = "error"; |
203 |
|
242 |
|
|
|
243 |
#NOTE: RDF |
204 |
#Find linkage between OAI-PMH repository-identifier and Koha record id |
244 |
#Find linkage between OAI-PMH repository-identifier and Koha record id |
205 |
my $linked_id = $self->_find_koha_link({ |
245 |
my $linked_id = $self->_find_koha_link({ |
206 |
record_type => $record_type, |
246 |
record_type => $record_type, |
207 |
}); |
247 |
}); |
208 |
|
248 |
|
|
|
249 |
#NOTE: RDF |
250 |
my $context = C4::Context->new(); |
251 |
#Find linkage between OAI-PMH repository-identifier and RDF records in the triplestore |
252 |
my ($linked_subject, $linked_graph) = $self->_find_rdf_link if $context && $context->triplestore('query'); |
253 |
|
209 |
if ($self->is_deleted_upstream){ |
254 |
if ($self->is_deleted_upstream){ |
210 |
#NOTE: If a record is deleted upstream, it will not contain a metadata element |
255 |
#FIXME: If a record is deleted upstream, it will not contain a metadata element, so we don't know what metadata |
|
|
256 |
#format we requested. Perhaps we should be recording the metadataPrefix during download and import, so we |
257 |
#can have more targeted deletes. |
258 |
#NOTE: "Other records, with different metadataPrefix but the same unique identifier, may remain available for the item." |
259 |
#https://www.openarchives.org/OAI/openarchivesprotocol.html#DeletedRecords |
260 |
|
261 |
if ($linked_graph){ |
262 |
my $model = $context->triplestore('update') if $context && $context->triplestore('update'); |
263 |
my $rdf = Koha::RDF->new(); |
264 |
if ($rdf){ |
265 |
$model->begin_bulk_ops; |
266 |
$rdf->DelNamedGraph({ |
267 |
model => $model, |
268 |
context => $linked_graph, |
269 |
}); |
270 |
$model->end_bulk_ops; |
271 |
} |
272 |
#NOTE: We don't set action here, since RDF::Trine doesn't return a useful value, plus |
273 |
#the RDF is meaningless without the Koha record mentioned below anyway. |
274 |
} |
275 |
|
211 |
if ($linked_id){ |
276 |
if ($linked_id){ |
212 |
$action = $self->delete_koha_record({ |
277 |
$action = $self->delete_koha_record({ |
213 |
record_id => $linked_id, |
278 |
record_id => $linked_id, |
214 |
record_type => $record_type, |
279 |
record_type => $record_type, |
215 |
}); |
280 |
}); |
216 |
#TODO: How to handle RDF deletions? |
|
|
217 |
#NOTE: If we delete the Koha record, then we lose the link to our downloaded record, so I don't know if it matters... |
218 |
#...although surely we'd want some way of cleaning up records that aren't needed anymore? I suppose that could come up with a cronjob that scans for triples that aren't linked to... |
219 |
} |
281 |
} |
220 |
else { |
282 |
else { |
221 |
$action = "not_found"; |
283 |
$action = "not_found"; |
222 |
#NOTE: If there's no OAI-PMH repository-identifier pair in the database, |
284 |
#NOTE: If there's no OAI-PMH repository-identifier pair in the database, |
223 |
#then there's no perfect way to find a linked record to delete. |
285 |
#then there's no perfect way to find a linked record to delete. |
224 |
} |
286 |
} |
|
|
287 |
#NOTE: RDF |
288 |
#TODO: Delete named graph found via $linked_graph... |
289 |
#TODO: Do we also unlink the Koha record from this OAI record? I suppose so... |
225 |
} |
290 |
} |
226 |
else { |
291 |
else { |
227 |
$self->set_filter($filter); |
292 |
$self->set_filter($filter); |
Lines 230-250
sub import_record {
Link Here
|
230 |
my $import_record = $self->filter(); |
295 |
my $import_record = $self->filter(); |
231 |
|
296 |
|
232 |
if ($import_record){ |
297 |
if ($import_record){ |
|
|
298 |
#NOTE: You can inspect the object's class here for special type handling if necessary... |
233 |
($action,$linked_id) = $import_record->import_record({ |
299 |
($action,$linked_id) = $import_record->import_record({ |
|
|
300 |
oai_pmh_repository => $self->{repository}, |
301 |
oai_pmh_identifier => $self->{header_identifier}, |
234 |
framework => $framework, |
302 |
framework => $framework, |
235 |
record_type => $record_type, |
303 |
record_type => $record_type, |
236 |
matcher => $matcher, |
304 |
matcher => $matcher, |
237 |
koha_id => $linked_id, |
305 |
koha_id => $linked_id, |
|
|
306 |
linked_subject => $linked_subject, #NOTE: RDF |
307 |
rdf_type => $rdf_type, #NOTE: RDF |
238 |
}); |
308 |
}); |
239 |
|
309 |
|
240 |
if ($linked_id){ |
310 |
if ($import_record->isa('Koha::Import::MARCXML')){ |
241 |
#Link Koha record ID to OAI-PMH details for this record type, |
311 |
if ($linked_id){ |
242 |
#if linkage doesn't already exist. |
312 |
#Link Koha record ID to OAI-PMH details for this record type, |
243 |
$self->link_koha_record({ |
313 |
#if linkage doesn't already exist. |
244 |
record_type => $record_type, |
314 |
$self->link_koha_record({ |
245 |
koha_id => $linked_id, |
315 |
record_type => $record_type, |
246 |
}); |
316 |
koha_id => $linked_id, |
|
|
317 |
}); |
318 |
} |
319 |
} |
320 |
|
321 |
#NOTE: Link Koha RDF to Imported RDF |
322 |
if ( ($record_type && $linked_id) && ($linked_subject) ){ |
323 |
my $rdf = Koha::RDF->new(); |
324 |
my $context = C4::Context->new(); |
325 |
my $triplestore = $context->triplestore('update') if $context && $context->triplestore('update'); |
326 |
if ( $triplestore && $rdf ){ |
327 |
my $koha_uri = $rdf->mint_uri($record_type, $linked_id); |
328 |
my $koha_subject = RDF::Trine::Node::Resource->new($koha_uri); |
329 |
$rdf->AddSeeAlso({ |
330 |
model => $triplestore, |
331 |
subject => $koha_subject, |
332 |
object => $linked_subject, |
333 |
}); |
334 |
} |
247 |
} |
335 |
} |
|
|
336 |
#NOTE: A link will only be successful when both a MARCXML record and a RDFXML record sharing the |
337 |
#same OAI-PMH repository and OAI-PMH identifier are in Koha. |
338 |
#NOTE: This action is idempotent. |
248 |
} |
339 |
} |
249 |
} |
340 |
} |
250 |
|
341 |
|