annotate magnatune/sparql-archived/SeRQL/Triple20/src/rdf_util.pl @ 27:d95e683fbd35 tip

Enable CORS on urispace redirects as well
author Chris Cannam
date Tue, 20 Feb 2018 14:52:02 +0000
parents df9685986338
children
rev   line source
Chris@0 1 /* $Id: rdf_util.pl,v 1.32 2007/01/16 09:37:10 jan Exp $
Chris@0 2
Chris@0 3 Part of SWI-Prolog
Chris@0 4
Chris@0 5 Author: Jan Wielemaker
Chris@0 6 E-mail: jan@swi.psy.uva.nl
Chris@0 7 WWW: http://www.swi-prolog.org
Chris@0 8 Copyright (C): 1985-2002, University of Amsterdam
Chris@0 9
Chris@0 10 This program is free software; you can redistribute it and/or
Chris@0 11 modify it under the terms of the GNU General Public License
Chris@0 12 as published by the Free Software Foundation; either version 2
Chris@0 13 of the License, or (at your option) any later version.
Chris@0 14
Chris@0 15 This program is distributed in the hope that it will be useful,
Chris@0 16 but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 18 GNU General Public License for more details.
Chris@0 19
Chris@0 20 You should have received a copy of the GNU Lesser General Public
Chris@0 21 License along with this library; if not, write to the Free Software
Chris@0 22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Chris@0 23
Chris@0 24 As a special exception, if you link this library with other files,
Chris@0 25 compiled with a Free Software compiler, to produce an executable, this
Chris@0 26 library does not by itself cause the resulting executable to be covered
Chris@0 27 by the GNU General Public License. This exception does not however
Chris@0 28 invalidate any other reasons why the executable file might be covered by
Chris@0 29 the GNU General Public License.
Chris@0 30 */
Chris@0 31
Chris@0 32 :- module(rdf_util,
Chris@0 33 [ property_domain/3, % +Subject, +Property, -Domain
Chris@0 34 property_type/3, % +Subject, +Property, -Type
Chris@0 35 sort_by_label/2, % +Resources, -Sorted
Chris@0 36
Chris@0 37 rdf_default_file/2, % +Resources, -File
Chris@0 38 rdf_default_file/3, % +Resources, -File, -NS
Chris@0 39 rdf_default_ns/2, % +File, -Namespace
Chris@0 40 rdf_set_default_ns/2, % +File, +Namespace
Chris@0 41
Chris@0 42 rdf_set_dialect/1, % Set the RDF dialect
Chris@0 43 rdf_current_dialect/1, % Query the RDF dialect
Chris@0 44
Chris@0 45 % Edit operations
Chris@0 46 rdf_set_object/4, % +S, +P, +O, +NewObject
Chris@0 47 rdf_set_object_or_anon_instance/4,
Chris@0 48 % +S, +P, +O, +NewObject
Chris@0 49 rdf_set_object/3, % +S, +P, +Object
Chris@0 50 rdf_set_rev_object/4, % +S, +P, +Rev, +Object
Chris@0 51 rdf_add_object/3, % +S, +P, +O
Chris@0 52 rdf_add_object/4, % +S, +P, +O, +DB
Chris@0 53 rdf_add_object_or_anon_instance/3,
Chris@0 54 % +S, +P, +O
Chris@0 55 rdf_new_property/2, % +S, +P
Chris@0 56 rdf_new_property/3, % +S, +P, +O
Chris@0 57 rdf_list_operation/3, % +Action, +Triple, +Resource
Chris@0 58 rdf_delete_hierarchy/3, % +Root, +Relation, +Options
Chris@0 59
Chris@0 60 rdf_merge_files/2, % +Into, +From
Chris@0 61
Chris@0 62 rdf_change_resource/2 % +From, +To
Chris@0 63 ]).
Chris@0 64 :- use_module(library('semweb/rdf_db')).
Chris@0 65 :- use_module(library('semweb/rdfs')).
Chris@0 66 :- use_module(library('semweb/rdf_edit')).
Chris@0 67 :- use_module(owl).
Chris@0 68 :- use_module(library(option)).
Chris@0 69 :- use_module(library(lists)).
Chris@0 70 :- use_module(library(broadcast)).
Chris@0 71 :- use_module(rdf_rules).
Chris@0 72
Chris@0 73 % user:goal_expansion(+NSGoal, -Goal)
Chris@0 74 %
Chris@0 75 % This predicate allows for writing down rdf queries in a friendly
Chris@0 76 % name-space fashion.
Chris@0 77
Chris@0 78 :- multifile
Chris@0 79 user:goal_expansion/2.
Chris@0 80
Chris@0 81 user:goal_expansion(rdf_set_object(Subj0, Pred0, Obj0),
Chris@0 82 rdf_set_object(Subj, Pred, Obj)) :-
Chris@0 83 rdf_global_id(Subj0, Subj),
Chris@0 84 rdf_global_id(Pred0, Pred),
Chris@0 85 rdf_global_id(Obj0, Obj).
Chris@0 86 user:goal_expansion(rdf_set_rev_object(Subj0, Pred0, Rev0, Obj0),
Chris@0 87 rdf_set_rev_object(Subj, Pred, Rev, Obj)) :-
Chris@0 88 rdf_global_id(Subj0, Subj),
Chris@0 89 rdf_global_id(Pred0, Pred),
Chris@0 90 rdf_global_id(Rev0, Rev),
Chris@0 91 rdf_global_id(Obj0, Obj).
Chris@0 92 user:goal_expansion(rdf_set_object(Subj0, Pred0, Obj0, New0),
Chris@0 93 rdf_set_object(Subj, Pred, Obj, New)) :-
Chris@0 94 rdf_global_id(Subj0, Subj),
Chris@0 95 rdf_global_id(Pred0, Pred),
Chris@0 96 rdf_global_id(Obj0, Obj),
Chris@0 97 rdf_global_id(New0, New).
Chris@0 98 user:goal_expansion(rdf_add_object(Subj0, Pred0, Obj0),
Chris@0 99 rdf_add_object(Subj, Pred, Obj)) :-
Chris@0 100 rdf_global_id(Subj0, Subj),
Chris@0 101 rdf_global_id(Pred0, Pred),
Chris@0 102 rdf_global_id(Obj0, Obj).
Chris@0 103 user:goal_expansion(rdf_delete_hierarchy(Root0, Pred0, Opts0),
Chris@0 104 rdf_delete_hierarchy(Root, Pred, Opts)) :-
Chris@0 105 rdf_global_id(Root0, Root),
Chris@0 106 rdf_global_id(Pred0, Pred),
Chris@0 107 rdf_global_term(Opts0, Opts).
Chris@0 108
Chris@0 109
Chris@0 110 /*******************************
Chris@0 111 * DIALECT SELECTION *
Chris@0 112 *******************************/
Chris@0 113
Chris@0 114 :- dynamic
Chris@0 115 dialect/1.
Chris@0 116
Chris@0 117 dialect(owl_full). % initial default
Chris@0 118
Chris@0 119 % rdf_set_dialect(+Dialect)
Chris@0 120 % rdf_current_dialect(?Dialect).
Chris@0 121 %
Chris@0 122 % Set/query the current dialect. Allowed values are rdfs,
Chris@0 123 % owl_lite, owl_dl or owl_full.
Chris@0 124
Chris@0 125 rdf_set_dialect(Dialect) :-
Chris@0 126 ( dialect(Dialect)
Chris@0 127 -> true
Chris@0 128 ; retractall(dialect(_)),
Chris@0 129 assert(dialect(Dialect)),
Chris@0 130 broadcast(rdf_dialect(Dialect))
Chris@0 131 ).
Chris@0 132
Chris@0 133 rdf_current_dialect(Dialect) :-
Chris@0 134 ( dialect(Dialect)
Chris@0 135 -> true
Chris@0 136 ; Dialect == owl
Chris@0 137 -> \+ dialect(rdfs)
Chris@0 138 ).
Chris@0 139
Chris@0 140
Chris@0 141 /*******************************
Chris@0 142 * PROPERTY HANDLING *
Chris@0 143 *******************************/
Chris@0 144
Chris@0 145
Chris@0 146 % property_domain(+Subject, +Property, -Domain)
Chris@0 147 %
Chris@0 148 % Determine the domain of this property. Note that if the domain
Chris@0 149 % is a class we want the selector to select a class by browsing
Chris@0 150 % the class-hierarchy. There is some issue around meta-classes
Chris@0 151 % here. Maybe we need class(Root, Meta)!
Chris@0 152
Chris@0 153 property_domain(Subject, Property, Domain) :-
Chris@0 154 findall(R, property_restriction(Subject, Property, R), List),
Chris@0 155 sort(List, Set),
Chris@0 156 ( Set = [Domain]
Chris@0 157 -> true
Chris@0 158 ; Domain = intersection_of(Set)
Chris@0 159 ).
Chris@0 160
Chris@0 161 property_restriction(_, Property, R) :-
Chris@0 162 rdf_has(Property, rdfs:range, Range),
Chris@0 163 adjust_restriction(all_values_from(Range), R).
Chris@0 164 property_restriction(Subject, Property, R) :-
Chris@0 165 rdf_has(Subject, rdf:type, Class),
Chris@0 166 owl_restriction_on(Class, restriction(Property, R0)),
Chris@0 167 adjust_restriction(R0, R).
Chris@0 168
Chris@0 169 adjust_restriction(cardinality(_,_), _) :- !,
Chris@0 170 fail.
Chris@0 171 adjust_restriction(R, R).
Chris@0 172
Chris@0 173
Chris@0 174 % property_type(+Subject, +Property, -Type)
Chris@0 175 %
Chris@0 176 % Classify the type of the object. For now the return values are
Chris@0 177 % one of
Chris@0 178 %
Chris@0 179 % # resource
Chris@0 180 % Value is an arbitrary resource
Chris@0 181 % # literal(Type)
Chris@0 182 % Value is a literal
Chris@0 183 % # list
Chris@0 184 % Value is a an indivisual of rdf:List
Chris@0 185
Chris@0 186 property_type(Subject, Property, Type) :-
Chris@0 187 property_domain(Subject, Property, Domain),
Chris@0 188 ( Domain = all_values_from(Class)
Chris@0 189 -> ( rdfs_subclass_of(Class, rdfs:'Literal')
Chris@0 190 -> Type = literal(atom)
Chris@0 191 ; rdfs_subclass_of(Class, xsd:nonNegativeInteger)
Chris@0 192 -> Type = literal(integer(non_negative))
Chris@0 193 ; rdfs_subclass_of(Class, rdf:'List')
Chris@0 194 -> Type = list
Chris@0 195 ; Type = resource
Chris@0 196 )
Chris@0 197 ; Type = resource
Chris@0 198 ).
Chris@0 199
Chris@0 200 % sort_by_label(+Resources, -Sorted)
Chris@0 201 %
Chris@0 202 % Sort a list of resources by `ns'-label. Removes duplicates.
Chris@0 203 % Note that objects can have multiple labels. We will sort by
Chris@0 204 % the first for the time being. Maybe we should sort on the
Chris@0 205 % first in alphabetical order. I don't think we want alternative
Chris@0 206 % ordering on backtracking.
Chris@0 207
Chris@0 208 sort_by_label(Resources, Sorted) :-
Chris@0 209 tag_label(Resources, Tagged),
Chris@0 210 keysort(Tagged, Sorted0),
Chris@0 211 unique_unkey(Sorted0, Sorted).
Chris@0 212
Chris@0 213 tag_label([], []).
Chris@0 214 tag_label([H|T0], [K-H|T]) :-
Chris@0 215 ( H = literal(K)
Chris@0 216 -> true
Chris@0 217 ; rdfs_ns_label(H, K)
Chris@0 218 -> true
Chris@0 219 ),
Chris@0 220 tag_label(T0, T).
Chris@0 221
Chris@0 222 unique_unkey([], []).
Chris@0 223 unique_unkey([H0|T0], [H|T]) :-
Chris@0 224 remove_dups(H0, T0, T1),
Chris@0 225 H0 = _Key-H,
Chris@0 226 unique_unkey(T1, T).
Chris@0 227
Chris@0 228 remove_dups(H, [H|T0], T) :- !,
Chris@0 229 remove_dups(H, T0, T).
Chris@0 230 remove_dups(P, [H|T0], [H|T]) :- % Handle different resources with
Chris@0 231 same_label(P, H), !, % same label
Chris@0 232 remove_dups(P, T0, T).
Chris@0 233 remove_dups(_, L, L).
Chris@0 234
Chris@0 235 same_label(L-_, L-_).
Chris@0 236
Chris@0 237
Chris@0 238 % rdf_default_file(+Resource, -File, -NS)
Chris@0 239 % rdf_default_file(+Resource, -File)
Chris@0 240 %
Chris@0 241 % Where to store facts about Resource? Should be extended to
Chris@0 242 % include triples (or at least relations). Default rules:
Chris@0 243 %
Chris@0 244 % File of the rdf:type declaration
Chris@0 245 % File of any property on subject
Chris@0 246 % File of resource as object
Chris@0 247 % File of resource as property
Chris@0 248
Chris@0 249 rdf_default_file(Resource, File) :-
Chris@0 250 rdf_default_file(Resource, File, _NS).
Chris@0 251
Chris@0 252 rdf_default_file(_, File, NS) :-
Chris@0 253 rdfe_get_file_property(File, default(all)), !,
Chris@0 254 rdf_default_ns(File, NS).
Chris@0 255 rdf_default_file(Resource, File, NS) :-
Chris@0 256 ( rdf_has(Resource, rdf:type, Object, P),
Chris@0 257 Object \== '__not_filled',
Chris@0 258 rdf(Resource, P, Object, File:_)
Chris@0 259 ; rdf(Resource, _, Object, File:_),
Chris@0 260 Object \== '__not_filled'
Chris@0 261 ; rdf(_, _, Resource, File:_)
Chris@0 262 ; rdf(_, Resource, _, File:_)
Chris@0 263 ),
Chris@0 264 \+ rdfe_get_file_property(File, access(ro)), !,
Chris@0 265 ( rdf_global_id(NS:_, Resource)
Chris@0 266 -> true
Chris@0 267 ; rdf_default_ns(File, NS)
Chris@0 268 ).
Chris@0 269 rdf_default_file(_, File, NS) :-
Chris@0 270 rdfe_get_file_property(File, default(fallback)),
Chris@0 271 rdf_default_ns(File, NS).
Chris@0 272
Chris@0 273 % rdf_default_ns(+File, -NameSpace)
Chris@0 274 %
Chris@0 275 % Provide a default namespace identifier for a triple to be
Chris@0 276 % associated with the given File.
Chris@0 277
Chris@0 278 :- dynamic
Chris@0 279 default_ns/2.
Chris@0 280
Chris@0 281 rdf_default_ns(File, NS) :-
Chris@0 282 ( default_ns(File, NS0)
Chris@0 283 -> NS = NS0
Chris@0 284 ; NS = t20
Chris@0 285 ).
Chris@0 286
Chris@0 287 % rdf_set_default_ns(+File, +Namespace)
Chris@0 288 %
Chris@0 289 % Set the default namespace for this file. If File is
Chris@0 290 % uninstantiated it will be added as a fallback clause at the end.
Chris@0 291
Chris@0 292 rdf_set_default_ns(File, NS) :-
Chris@0 293 ( var(File)
Chris@0 294 -> ( clause(default_ns(V, _), _, Ref),
Chris@0 295 var(V),
Chris@0 296 erase(Ref),
Chris@0 297 fail
Chris@0 298 ; true
Chris@0 299 ),
Chris@0 300 assertz(default_ns(File, NS))
Chris@0 301 ; retractall(default_ns(File, NS)),
Chris@0 302 asserta(default_ns(File, NS))
Chris@0 303 ),
Chris@0 304 broadcast(rdf_default_ns(File, NS)).
Chris@0 305
Chris@0 306 % pick messages from load_base_ontology/2.
Chris@0 307
Chris@0 308 :- initialization
Chris@0 309 listen(rdf_set_default_ns(Path, NS),
Chris@0 310 rdf_set_default_ns(Path, NS)).
Chris@0 311
Chris@0 312
Chris@0 313 /*******************************
Chris@0 314 * EDIT OPERATIONS *
Chris@0 315 *******************************/
Chris@0 316
Chris@0 317 % rdf_set_object(+Subject, +Predicate, +Old, +New)
Chris@0 318 %
Chris@0 319 % Modify object aspect of a triple. This code also checks checks
Chris@0 320 % the domain, but does not yet check the cardinality.
Chris@0 321
Chris@0 322 rdf_set_object(Subject, Predicate, Old, New) :-
Chris@0 323 property_domain(Subject, Predicate, Domain),
Chris@0 324 ( owl_satisfies(Domain, New)
Chris@0 325 -> rdfe_transaction(set_object(Subject, Predicate, Old, New),
Chris@0 326 modify_property_value)
Chris@0 327 ; throw(error(domain_error(Domain, New), _))
Chris@0 328 ).
Chris@0 329
Chris@0 330 set_object(Subject, Predicate, '__not_filled', _New) :-
Chris@0 331 rdf_default_file(Subject, File),
Chris@0 332 rdfe_update(Subject, Predicate, '__not_filled', source(File)),
Chris@0 333 fail. % next clause
Chris@0 334 set_object(Subject, Predicate, Old, New) :-
Chris@0 335 rdfe_update(Subject, Predicate, Old, object(New)).
Chris@0 336
Chris@0 337 % rdf_set_object_or_anon_instance(+Subject, +Predicate, +Old, +New)
Chris@0 338 %
Chris@0 339 % As rdf_set_object/4, but create an anonymous instance when
Chris@0 340 % setting a property that allows for all_values_from(C) to a
Chris@0 341 % subclass of C.
Chris@0 342
Chris@0 343 rdf_set_object_or_anon_instance(Subject, Predicate, Old, New) :-
Chris@0 344 property_domain(Subject, Predicate, Domain),
Chris@0 345 ( owl_satisfies(Domain, New)
Chris@0 346 -> rdfe_transaction(set_object(Subject, Predicate, Old, New),
Chris@0 347 modify_property_value)
Chris@0 348 ; owl_satisfies(Domain, individual_of(New))
Chris@0 349 -> rdfe_transaction(set_object_anon(Subject, Predicate, Old, New),
Chris@0 350 modify_property_value)
Chris@0 351 ; throw(error(domain_error(Domain, New), _))
Chris@0 352 ).
Chris@0 353
Chris@0 354 set_object_anon(Subject, Predicate, Old, Class) :-
Chris@0 355 rdf_bnode(New),
Chris@0 356 rdf_default_file(Subject, File),
Chris@0 357 rdfe_assert(New, rdf:type, Class, File),
Chris@0 358 set_object(Subject, Predicate, Old, New).
Chris@0 359
Chris@0 360
Chris@0 361 % rdf_set_object(+Subject, +Predicate, +New)
Chris@0 362 %
Chris@0 363 % Remove all rdf(Subject, Predicate, _) and add rdf(Subject,
Chris@0 364 % Predicate, New).
Chris@0 365
Chris@0 366 rdf_set_object(Subject, Predicate, Object) :-
Chris@0 367 property_domain(Subject, Predicate, Domain),
Chris@0 368 ( owl_satisfies(Domain, Object)
Chris@0 369 -> rdfe_transaction(set_object(Subject, Predicate, Object),
Chris@0 370 modify_property_value)
Chris@0 371 ; throw(error(domain_error(Domain, Object), _))
Chris@0 372 ).
Chris@0 373
Chris@0 374 set_object(Subject, Predicate, Object) :-
Chris@0 375 findall(O-Predicate, rdf_has(Subject, Predicate, O), Pairs0),
Chris@0 376 sort(Pairs0, Pairs),
Chris@0 377 ( Pairs = []
Chris@0 378 -> rdf_default_file(Subject, File),
Chris@0 379 rdfe_assert(Subject, Predicate, Object, File)
Chris@0 380 ; Pairs = [Old-P|More]
Chris@0 381 -> rdfe_update(Subject, P, Old, object(Object)),
Chris@0 382 ( member(OM-PM, More),
Chris@0 383 rdfe_retractall(Subject, PM, OM),
Chris@0 384 fail
Chris@0 385 ; true
Chris@0 386 )
Chris@0 387 ).
Chris@0 388
Chris@0 389 % rdf_add_object(Subject, Predicate, Object, Database)
Chris@0 390 % rdf_add_object(Subject, Predicate, Object)
Chris@0 391 %
Chris@0 392 % Guarded adding of a new triple. Must validate cardinality
Chris@0 393 % constraints too.
Chris@0 394
Chris@0 395 rdf_add_object(Subject, Predicate, Object) :-
Chris@0 396 rdf_add_object(Subject, Predicate, Object, _DB).
Chris@0 397
Chris@0 398 rdf_add_object(Subject, Predicate, Object, DB) :-
Chris@0 399 property_domain(Subject, Predicate, Domain),
Chris@0 400 ( owl_satisfies(Domain, Object)
Chris@0 401 -> rdfe_transaction(add_object(Subject, Predicate, Object, DB),
Chris@0 402 add_property_value)
Chris@0 403 ; throw(error(domain_error(Domain, Object), _))
Chris@0 404 ).
Chris@0 405
Chris@0 406 add_object(Subject, Predicate, Object, DB) :-
Chris@0 407 nonvar(DB), !,
Chris@0 408 rdfe_assert(Subject, Predicate, Object, DB).
Chris@0 409 add_object(Subject, Predicate, Object, File) :-
Chris@0 410 ( Object == '__not_filled'
Chris@0 411 -> File = user
Chris@0 412 ; rdf_default_file(Subject, File)
Chris@0 413 ),
Chris@0 414 rdfe_assert(Subject, Predicate, Object, File).
Chris@0 415
Chris@0 416
Chris@0 417 % rdf_add_object_or_anon_instance(+Subject, +Predicate, +Object)
Chris@0 418 %
Chris@0 419 % See rdf_set_object_or_anon_instance/4
Chris@0 420
Chris@0 421 rdf_add_object_or_anon_instance(Subject, Predicate, Object) :-
Chris@0 422 property_domain(Subject, Predicate, Domain),
Chris@0 423 ( owl_satisfies(Domain, Object)
Chris@0 424 -> rdfe_transaction(add_object(Subject, Predicate, Object, _DB),
Chris@0 425 add_property_value)
Chris@0 426 ; owl_satisfies(Domain, individual_of(Object))
Chris@0 427 -> rdfe_transaction(add_object_anon(Subject, Predicate, Object),
Chris@0 428 modify_property_value)
Chris@0 429 ; throw(error(domain_error(Domain, Object), _))
Chris@0 430 ).
Chris@0 431
Chris@0 432 add_object_anon(Subject, Predicate, Class) :-
Chris@0 433 rdf_bnode(Object),
Chris@0 434 rdf_default_file(Subject, File),
Chris@0 435 rdfe_assert(Object, rdf:type, Class, File),
Chris@0 436 rdfe_assert(Subject, Predicate, Object, File).
Chris@0 437
Chris@0 438 % rdf_set_rev_object(+Subject, +Predicate, +Reverse, +New)
Chris@0 439 %
Chris@0 440 % Make a relation rdf(Subject, Predicate, New) and a relation
Chris@0 441 % rdf(New, Reverse, Subject) after deleting the old relations.
Chris@0 442
Chris@0 443 rdf_set_rev_object(Subject, Predicate, Reverse, Obj) :-
Chris@0 444 property_domain(Subject, Predicate, Domain),
Chris@0 445 ( owl_satisfies(Domain, Obj)
Chris@0 446 -> rdfe_transaction(set_rev_object(Subject, Predicate, Reverse, Obj),
Chris@0 447 modify_property_value)
Chris@0 448 ; throw(error(domain_error(Domain, Obj), _))
Chris@0 449 ).
Chris@0 450
Chris@0 451 set_rev_object(Subject, Predicate, Reverse, Object) :-
Chris@0 452 findall(O-Predicate, rdf_has(Subject, Predicate, O), Pairs0),
Chris@0 453 sort(Pairs0, Pairs),
Chris@0 454 ( Pairs = []
Chris@0 455 -> rdf_default_file(Subject, File),
Chris@0 456 rdfe_assert(Subject, Predicate, Object, File),
Chris@0 457 rdfe_assert(Object, Reverse, Subject, File)
Chris@0 458 ; Pairs = [Old-P|More]
Chris@0 459 -> rdfe_update(Subject, P, Old, object(Object)),
Chris@0 460 ignore(rdfe_update(Old, Reverse, Subject, subject(Object))),
Chris@0 461 ( member(OM-PM, More),
Chris@0 462 rdfe_retractall(Subject, PM, OM),
Chris@0 463 rdfe_retractall(OM, Reverse, Subject),
Chris@0 464 fail
Chris@0 465 ; true
Chris@0 466 )
Chris@0 467 ).
Chris@0 468
Chris@0 469
Chris@0 470 % rdf_new_property(+Subject, +Property, [Value])
Chris@0 471 %
Chris@0 472 % Add a dummy value for a new property on Subject that can be
Chris@0 473 % filled by editing or drag-and-drop modification.
Chris@0 474 %
Chris@0 475 % TBD: Check cardinality
Chris@0 476
Chris@0 477 rdf_new_property(Subject, Predicate) :-
Chris@0 478 rdf_new_property(Subject, Predicate, _).
Chris@0 479
Chris@0 480 rdf_new_property(Subject, Predicate, Object) :-
Chris@0 481 var(Object), !,
Chris@0 482 ( call_rules(@display, rdf_default(Subject, Predicate, Object))
Chris@0 483 -> true
Chris@0 484 ; Object = '__not_filled'
Chris@0 485 ),
Chris@0 486 rdf_new_property(Subject, Predicate, Object).
Chris@0 487 rdf_new_property(Subject, Predicate, Default) :-
Chris@0 488 rdfe_transaction(add_object(Subject, Predicate, Default, _DB),
Chris@0 489 new_property).
Chris@0 490
Chris@0 491
Chris@0 492 % rdf_list_operation(+Action, +Triple, +Resource)
Chris@0 493 %
Chris@0 494 % If Triple is a triple whose object is rdf:nil or a proper RDF
Chris@0 495 % list, merge Resource into this list according to Action:
Chris@0 496 %
Chris@0 497 % # append/prepend
Chris@0 498 % Add Resource at the start/end of the list
Chris@0 499 %
Chris@0 500 % # delete
Chris@0 501 % Remove resource from the list
Chris@0 502 %
Chris@0 503 % # Modify
Chris@0 504 % Replace the list by Resource (which must be a list)
Chris@0 505
Chris@0 506 rdf_list_operation(modify, rdf(S,P,O), New) :- !,
Chris@0 507 ( rdfs_individual_of(New, rdf:'List')
Chris@0 508 -> rdfe_transaction(set_object(S, P, O, New),
Chris@0 509 modify_property_value)
Chris@0 510 ; rdf_equal(rdf:'List', ListClass),
Chris@0 511 throw(error(domain_error(all_values_from(ListClass), New), _))
Chris@0 512 ).
Chris@0 513 rdf_list_operation(append, rdf(S, P, O), New) :-
Chris@0 514 tail_triple(S, P, O, Subject, Predicate, Object),
Chris@0 515 rdfe_transaction(list_append(Subject, Predicate, Object, New),
Chris@0 516 append).
Chris@0 517 rdf_list_operation(prepend, rdf(S, P, O), New) :-
Chris@0 518 rdfe_transaction(list_append(S, P, O, New),
Chris@0 519 prepend).
Chris@0 520 rdf_list_operation(delete, rdf(S, P, O), Resource) :-
Chris@0 521 rdfe_transaction(list_delete(S, P, O, Resource), delete_from_list).
Chris@0 522
Chris@0 523
Chris@0 524 tail_triple(S, P, O, S, P, O) :-
Chris@0 525 rdf_equal(O, rdf:nil), !. % must use owl:sameIndividual
Chris@0 526 tail_triple(_, _, L, S, P, O) :-
Chris@0 527 rdf_has(L, rdf:rest, O1, P1), !,
Chris@0 528 tail_triple(L, P1, O1, S, P, O).
Chris@0 529
Chris@0 530
Chris@0 531 list_append(S, P, O, New) :-
Chris@0 532 rdf_default_file(S, Source),
Chris@0 533 rdf_bnode(Node),
Chris@0 534 rdfe_assert(Node, rdf:type, rdf:'List', Source),
Chris@0 535 rdfe_assert(Node, rdf:rest, O, Source),
Chris@0 536 rdfe_assert(Node, rdf:first, New, Source),
Chris@0 537 rdfe_update(S, P, O, object(Node)).
Chris@0 538
Chris@0 539 % list_delete(+Subject, +Predicate, +List, +Resource)
Chris@0 540 %
Chris@0 541 % Delete Resource from List, which is connected to Subject using
Chris@0 542 % Predicate. Actually, this is extremely tricky. We cannot delete
Chris@0 543 % from a list while maintaining the identity of the list. We could
Chris@0 544 % shift the rdf:first, but we still loose on a list with one
Chris@0 545 % element that must be replaced by rdf:nil.
Chris@0 546
Chris@0 547 list_delete(S, P, O, Resource) :-
Chris@0 548 rdf_has(O, rdf:first, Resource), !,
Chris@0 549 rdf_has(O, rdf:rest, Rest),
Chris@0 550 rdfe_update(S, P, O, object(Rest)),
Chris@0 551 ( rdf(_, _, O)
Chris@0 552 -> true
Chris@0 553 ; rdfe_delete(O) % TBD: too much?
Chris@0 554 ).
Chris@0 555 list_delete(_, _, O, Resource) :-
Chris@0 556 rdf_has(O, rdf:rest, Rest, P1),
Chris@0 557 list_delete(O, P1, Rest, Resource).
Chris@0 558
Chris@0 559
Chris@0 560 /*******************************
Chris@0 561 * HIERACHY DELETE *
Chris@0 562 *******************************/
Chris@0 563
Chris@0 564 % rdf_delete_hierarchy(+Root, +Property, +Options)
Chris@0 565 %
Chris@0 566 % Delete all objects reachable from Root through property that
Chris@0 567 % have no relations of type property, unless they have another
Chris@0 568 % relation to the root. Options:
Chris@0 569 %
Chris@0 570 % * unless_reachable_from(Root)
Chris@0 571 % Do not delete resources that can be reached from the
Chris@0 572 % given Root.
Chris@0 573
Chris@0 574 rdf_delete_hierarchy(Root, Property, Options) :-
Chris@0 575 rdfe_transaction(delete_hierarchy(Root, Property, Options),
Chris@0 576 delete_hierarchy).
Chris@0 577
Chris@0 578 delete_hierarchy(Root, Property, Options) :-
Chris@0 579 rdf_equal(rdfs:'Resource', RdfsResource),
Chris@0 580 option(unless_reachable_from(Keep), Options, RdfsResource),
Chris@0 581 forall(rdfs_subproperty_of(P, Property),
Chris@0 582 rdfe_retractall(Root, P, _)),
Chris@0 583 findall(X, rdf_reachable(X, Property, Root), Set0),
Chris@0 584 findall(X, rdf_reachable(X, Property, Keep), KeepSet0),
Chris@0 585 sort(Set0, Set1),
Chris@0 586 sort(KeepSet0, KeepSet1),
Chris@0 587 oset_diff(Set1, KeepSet1, DelSet),
Chris@0 588 ( option(confirm(true), Options, false)
Chris@0 589 -> length(DelSet, Len),
Chris@0 590 send(@display, confirm,
Chris@0 591 'Delete %d classes and all associated properties?',
Chris@0 592 Len)
Chris@0 593 ; true
Chris@0 594 ),
Chris@0 595 forall(member(R, DelSet),
Chris@0 596 rdfe_delete(R)).
Chris@0 597
Chris@0 598
Chris@0 599 /*******************************
Chris@0 600 * FILES *
Chris@0 601 *******************************/
Chris@0 602
Chris@0 603 % rdf_merge_files(+Into, +From)
Chris@0 604 %
Chris@0 605 % Merge all triple that have From as their payload into Into.
Chris@0 606
Chris@0 607 rdf_merge_files(Into, From) :-
Chris@0 608 rdfe_transaction(merge_files(Into, From),
Chris@0 609 merge_files(Into, From)).
Chris@0 610
Chris@0 611 merge_files(Into, From) :-
Chris@0 612 findall(rdf(S,P,O,F),
Chris@0 613 rdf_in_file(S,P,O,F,From),
Chris@0 614 Triples),
Chris@0 615 forall(member(rdf(S,P,O,F), Triples),
Chris@0 616 rdfe_update(S, P, O, F, source(Into))).
Chris@0 617
Chris@0 618 rdf_in_file(S,P,O,From:Line,From) :-
Chris@0 619 rdf(S, P, O, From:Line).
Chris@0 620 rdf_in_file(S,P,O,From, From) :-
Chris@0 621 rdf(S, P, O, From).
Chris@0 622
Chris@0 623
Chris@0 624 /*******************************
Chris@0 625 * RESOURCES *
Chris@0 626 *******************************/
Chris@0 627
Chris@0 628 % rdf_change_resource(+From, +To)
Chris@0 629 %
Chris@0 630 % Change the resource From into To.
Chris@0 631
Chris@0 632 rdf_change_resource(To, To) :- !.
Chris@0 633 rdf_change_resource(From, To) :-
Chris@0 634 ( ( rdf(To, _, _)
Chris@0 635 ; rdf(_, To, _)
Chris@0 636 ; rdf(_, _, To)
Chris@0 637 )
Chris@0 638 -> send(@display, confirm, 'Target resource %s already exists.\n\
Chris@0 639 Do you want to merge these resources?',
Chris@0 640 To)
Chris@0 641 ; true
Chris@0 642 ),
Chris@0 643 rdfe_transaction(change_resource(From, To),
Chris@0 644 change_resource(From, To)).
Chris@0 645
Chris@0 646 change_resource(From, To) :-
Chris@0 647 change_subject(From, To),
Chris@0 648 change_predicate(From, To),
Chris@0 649 change_object(From, To).
Chris@0 650
Chris@0 651 change_subject(From, To) :-
Chris@0 652 S = From,
Chris@0 653 findall(rdf(S,P,O), rdf(S, P, O), Set),
Chris@0 654 forall(member(rdf(S,P,O), Set),
Chris@0 655 rdfe_update(S,P,O,subject(To))).
Chris@0 656 change_predicate(From, To) :-
Chris@0 657 P = From,
Chris@0 658 findall(rdf(S,P,O), rdf(S, P, O), Set),
Chris@0 659 forall(member(rdf(S,P,O), Set),
Chris@0 660 rdfe_update(S,P,O,predicate(To))).
Chris@0 661 change_object(From, To) :-
Chris@0 662 O = From,
Chris@0 663 findall(rdf(S,P,O), rdf(S, P, O), Set),
Chris@0 664 forall(member(rdf(S,P,O), Set),
Chris@0 665 rdfe_update(S,P,O,object(To))).
Chris@0 666