1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2003-2015, University of Amsterdam 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(rdfs, 37 [ rdfs_subproperty_of/2, % ?SubProperties, ?Property 38 rdfs_subclass_of/2, % ?SubClass, ?Class 39 rdfs_class_property/2, % +Class, ?Property 40 rdfs_individual_of/2, % ?Resource, ?Class 41 42 rdfs_label/2, % ?Resource, ?Label 43 rdfs_label/3, % ?Resource, ?Language, ?Label 44 rdfs_ns_label/2, % +Resource, -Label 45 rdfs_ns_label/3, % +Resource, ?Label, -Label 46 47 rdfs_member/2, % ?Object, +Set 48 rdfs_list_to_prolog_list/2, % +Set, -List 49 rdfs_assert_list/3, % +List, -Resource, +DB 50 rdfs_assert_list/2, % +List, -Resource 51 52 rdfs_find/5 % +String, +Dom, +Props, +Method, -Subj 53 ]). 54:- use_module(library(semweb/rdf_prefixes), 55 [ (rdf_meta)/1, op(_,_,rdf_meta) 56 ]). 57:- use_module(rdf_db, 58 [ rdf_reachable/3, rdf_equal/2, rdf_has/3, rdf_subject/1, 59 rdf_global_id/2, rdf/3, rdf_has/4, rdf_member_property/2, 60 rdf_bnode/1, rdf_assert/4, rdf_match_label/3 61 ]). 62 63:- autoload(library(lists),[member/2]).
78 /******************************* 79 * EXPANSION * 80 *******************************/ 81 82:- rdf_meta 83 rdfs_subproperty_of(r,r), 84 rdfs_subclass_of(r,r), 85 rdfs_class_property(r,r), 86 rdfs_individual_of(r,r), 87 rdfs_label(r,-), 88 rdfs_label(r,?,-). 89 90 91 /******************************* 92 * PROPERTY HIERARCHY * 93 *******************************/
100rdfs_subproperty_of(SubProperty, Property) :- 101 rdf_reachable(SubProperty, rdfs:subPropertyOf, Property). 102 103 104 /******************************* 105 * CLASS HIERARCHY * 106 *******************************/
According to production 2.4 "rdfs:Datatype", Each instance of rdfs:Datatype is a subclass of rdfs:Literal.
119rdfs_subclass_of(Class, Super) :- 120 rdf_equal(rdfs:'Resource', Resource), 121 Super == Resource, 122 !, 123 rdfs_individual_of(Class, rdfs:'Class'). 124rdfs_subclass_of(Class, Super) :- 125 rdf_reachable(Class, rdfs:subClassOf, Super). 126rdfs_subclass_of(Class, Super) :- 127 nonvar(Class), 128 var(Super), 129 \+ rdf_reachable(Class, rdfs:subClassOf, rdfs:'Resource'), 130 rdfs_individual_of(Class, rdfs:'Class'), 131 rdf_equal(Super, rdfs:'Resource'). 132rdfs_subclass_of(Class, Super) :- % production 2.4 133 ( nonvar(Class) 134 -> rdf_has(Class, rdf:type, CType), 135 rdf_reachable(CType, rdfs:subClassOf, rdfs:'Datatype'), 136 \+ rdf_reachable(Class, rdfs:subClassOf, rdfs:'Literal'), 137 rdf_equal(Super, rdfs:'Literal') 138 ; nonvar(Super) 139 -> rdf_reachable(Super, rdfs:subClassOf, rdfs:'Literal'), 140 rdfs_individual_of(Class, rdfs:'Datatype') 141 ). 142 143 144 /******************************* 145 * INDIVIDUALS * 146 *******************************/
rdfs_individual_of(+, -)
does not exploit domain and range
properties, deriving that if rdf(R, P, _)
is present R must
satisfy the domain of P (and similar for range).
There are a few hacks:
literal(_)
is an individual of rdfs:Literal165rdfs_individual_of(Resource, Class) :- 166 nonvar(Resource), 167 !, 168 ( nonvar(Class) 169 -> ( rdf_equal(Class, rdfs:'Resource') 170 -> true 171 ; rdfs_individual_of_r_c(Resource, Class) 172 -> true 173 ) 174 ; rdfs_individual_of_r_c(Resource, Class) 175 ). 176rdfs_individual_of(Resource, Class) :- 177 nonvar(Class), 178 !, 179 ( rdf_equal(Class, rdfs:'Resource') 180 -> rdf_subject(Resource) 181 ; rdfs_subclass_of(SubClass, Class), 182 rdf_has(Resource, rdf:type, SubClass) 183 ). 184rdfs_individual_of(_Resource, _Class) :- 185 throw(error(instantiation_error, _)).
189rdfs_individual_of_r_c(literal(_), Class) :- 190 !, 191 rdfs_subclass_of(Class, rdfs:'Literal'). 192rdfs_individual_of_r_c(^^(_,_), Class) :- 193 !, 194 rdfs_subclass_of(Class, rdfs:'Literal'). 195rdfs_individual_of_r_c(@(_,_), Class) :- 196 !, 197 rdfs_subclass_of(Class, rdfs:'Literal'). 198rdfs_individual_of_r_c(Resource, Class) :- 199 ( rdf_has(Resource, rdf:type, MyClass) 200 *-> rdfs_subclass_of(MyClass, Class) 201 ; rdf_equal(Class, rdfs:'Resource') 202 ).
212rdfs_label(Resource, Label) :-
213 rdfs_label(Resource, _, Label).
222rdfs_label(Resource, Lang, Label) :- 223 nonvar(Resource), 224 !, 225 take_label(Resource, Lang, Label). 226rdfs_label(Resource, Lang, Label) :- 227 rdf_has(Resource, rdfs:label, literal(lang(Lang, Label))).
237rdfs_ns_label(Resource, Label) :- 238 rdfs_ns_label(Resource, _, Label). 239 240rdfs_ns_label(Resource, Lang, Label) :- 241 rdfs_label(Resource, Lang, Label0), 242 ( rdf_global_id(NS:_, Resource), 243 Label0 \== '' 244 -> atomic_list_concat([NS, Label0], :, Label) 245 ; \+ rdf_has(Resource, rdfs:label, _) 246 -> Label = Resource 247 ; member(Sep, [#,/]), 248 sub_atom(Resource, B, L, A, Sep), 249 sub_atom(Resource, _, A, 0, Frag), 250 \+ sub_atom(Frag, _, _, _, Sep) 251 -> Len is B+L, 252 sub_atom(Resource, 0, Len, _, NS), 253 atomic_list_concat([NS, Label0], :, Label) 254 ; Label = Label0 255 ).
264take_label(Resource, Lang, Label) :- 265 ( label_of(Resource, Lang, Label) 266 *-> true 267 ; after_char(Resource, '#', Local) 268 -> Label = Local 269 ; after_char(Resource, '/', Local) 270 -> Label = Local 271 ; Label = Resource 272 ). 273 274after_char(Atom, Char, Rest) :- 275 State = last(-), 276 ( sub_atom(Atom, _, _, L, Char), 277 nb_setarg(1, State, L), 278 fail 279 ; arg(1, State, L), 280 L \== (-) 281 ), 282 sub_atom(Atom, _, L, 0, Rest).
rdf_has(Resource, rdfs:label, literal(Lang, Label))
is
true, but guaranteed to generate rdfs:label before any
subproperty thereof.291label_of(Resource, Lang, Label) :- 292 rdf(Resource, rdfs:label, literal(lang(Lang, Label))), 293 nonvar(Lang). 294label_of(Resource, Lang, Label) :- 295 rdf_equal(rdfs:label, LabelP), 296 rdf_has(Resource, LabelP, literal(lang(Lang, Label)), P), 297 nonvar(Lang), 298 P \== LabelP. 299label_of(Resource, Lang, Label) :- 300 var(Lang), 301 rdf_has(Resource, rdfs:label, literal(type(xsd:string, Label))).
307rdfs_class_property(Class, Property) :- 308 rdfs_individual_of(Property, rdf:'Property'), 309 rdf_has(Property, rdfs:domain, Domain), 310 rdfs_subclass_of(Class, Domain). 311 312 313 /******************************* 314 * COLLECTIONS * 315 *******************************/
322rdfs_member(Element, Set) :- 323 rdf_has(Set, rdf:first, _), 324 !, 325 rdfs_collection_member(Element, Set). 326rdfs_member(Element, Set) :- 327 container_class(Class), 328 rdfs_individual_of(Set, Class), 329 !, 330 ( nonvar(Element) 331 -> rdf(Set, Predicate, Element), 332 rdf_member_property(Predicate, _N) 333 ; findall(N-V, rdf_nth(Set, N, V), Pairs), 334 keysort(Pairs, Sorted), 335 member(_-Element, Sorted) 336 ). 337 338rdf_nth(Set, N, V) :- 339 rdf(Set, P, V), 340 rdf_member_property(P, N). 341 342:- rdf_meta container_class(r). 343 344container_class(rdf:'Bag'). 345container_class(rdf:'Seq'). 346container_class(rdf:'Alt'). 347 348 349rdfs_collection_member(Element, Set) :- 350 rdf_has(Set, rdf:first, Element). 351rdfs_collection_member(Element, Set) :- 352 rdf_has(Set, rdf:rest, Tail), 353 !, 354 rdfs_collection_member(Element, Tail).
362rdfs_list_to_prolog_list(Set, []) :- 363 rdf_equal(Set, rdf:nil), 364 !. 365rdfs_list_to_prolog_list(Set, [H|T]) :- 366 rdf_has(Set, rdf:first, H), 367 rdf_has(Set, rdf:rest, Tail), 368 !, 369 rdfs_list_to_prolog_list(Tail, T).
377rdfs_assert_list(Resources, List) :- 378 rdfs_assert_list(Resources, List, user). 379 380rdfs_assert_list([], Nil, _) :- 381 rdf_equal(rdf:nil, Nil). 382rdfs_assert_list([H|T], List, DB) :- 383 rdfs_assert_list(T, Tail, DB), 384 rdf_bnode(List), 385 rdf_assert(List, rdf:rest, Tail, DB), 386 rdf_assert(List, rdf:first, H, DB), 387 rdf_assert(List, rdf:type, rdf:'List', DB). 388 389 390 /******************************* 391 * SEARCH IN HIERARCHY * 392 *******************************/
domain is defined by owl_satisfy from owl.pl
Note that the rdfs:label field is handled by rdfs_label/2, making the URI-ref fragment name the last resort to determine the label.
410rdfs_find(String, Domain, Fields, Method, Subject) :- 411 var(Fields), 412 !, 413 For =.. [Method,String], 414 rdf_has(Subject, Field, literal(For, _)), 415 owl_satisfies(Domain, Subject), 416 Fields = [Field]. % report where we found it. 417rdfs_find(String, Domain, Fields, Method, Subject) :- 418 globalise_list(Fields, GlobalFields), 419 For =.. [Method,String], 420 member(Field, GlobalFields), 421 ( Field == resource 422 -> rdf_subject(Subject), 423 rdf_match_label(Method, String, Subject) 424 ; rdf_has(Subject, Field, literal(For, _)) 425 ), 426 owl_satisfies(Domain, Subject). 427 428owl_satisfies(Domain, _) :- 429 rdf_equal(rdfs:'Resource', Domain), 430 !. 431 % Descriptions 432owl_satisfies(class(Domain), Resource) :- 433 !, 434 ( rdf_equal(Domain, rdfs:'Resource') 435 -> true 436 ; rdfs_subclass_of(Resource, Domain) 437 ). 438owl_satisfies(union_of(Domains), Resource) :- 439 !, 440 member(Domain, Domains), 441 owl_satisfies(Domain, Resource), 442 !. 443owl_satisfies(intersection_of(Domains), Resource) :- 444 !, 445 in_all_domains(Domains, Resource). 446owl_satisfies(complement_of(Domain), Resource) :- 447 !, 448 \+ owl_satisfies(Domain, Resource). 449owl_satisfies(one_of(List), Resource) :- 450 !, 451 memberchk(Resource, List). 452 % Restrictions 453owl_satisfies(all_values_from(Domain), Resource) :- 454 ( rdf_equal(Domain, rdfs:'Resource') 455 -> true 456 ; rdfs_individual_of(Resource, Domain) 457 ), 458 !. 459owl_satisfies(some_values_from(_Domain), _Resource) :- !. 460owl_satisfies(has_value(Value), Resource) :- 461 rdf_equal(Value, Resource). 462 463 464in_all_domains([], _). 465in_all_domains([H|T], Resource) :- 466 owl_satisfies(H, Resource), 467 in_all_domains(T, Resource). 468 469globalise_list([], []) :- !. 470globalise_list([H0|T0], [H|T]) :- 471 !, 472 globalise_list(H0, H), 473 globalise_list(T0, T). 474globalise_list(X, G) :- 475 rdf_global_id(X, G)
RDFS handling
This module provides various primitives for more high-level handling of RDF models from an RDFS viewpoint. Note that there exist two approaches for languages on top of RDF: