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