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) 2018, VU University Amsterdam 7 CWI, 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(rdf_prefixes, 37 [ rdf_prefix/2, % :Alias, +URI 38 rdf_current_prefix/2, % :Alias, ?URI 39 rdf_register_prefix/2, % +Alias, +URI 40 rdf_register_prefix/3, % +Alias, +URI, +Options 41 rdf_unregister_prefix/1, % +Alias 42 register_file_prefixes/1, % +Pairs 43 44 rdf_current_ns/2, % :Alias, ?URI 45 rdf_register_ns/2, % +Alias, +URI 46 rdf_register_ns/3, % +Alias, +URI, +Options 47 rdf_global_id/2, % ?NS:Name, :Global 48 rdf_global_object/2, % +Object, :NSExpandedObject 49 rdf_global_term/2, % +Term, :WithExpandedNS 50 51 (rdf_meta)/1, % +Heads 52 op(1150, fx, (rdf_meta)) 53 ]). 54:- autoload(library(error),[must_be/2,existence_error/2]). 55:- autoload(library(lists),[member/2]). 56:- autoload(library(option),[option/3]). 57:- autoload(library(pairs),[map_list_to_pairs/3,pairs_values/2]). 58 59:- meta_predicate 60 rdf_current_prefix( , ), 61 rdf_current_ns( , ), 62 rdf_global_id( , ), 63 rdf_global_term( , ), 64 rdf_global_object( , ).
74:- predicate_options(rdf_register_ns/3, 3, 75 [ force(boolean), 76 keep(boolean) 77 ]). 78:- predicate_options(rdf_register_prefix/3, 3, 79 [ force(boolean), 80 keep(boolean) 81 ]). 82 83 84 /******************************* 85 * HOOKS * 86 *******************************/
93:- multifile 94 rdf_empty_prefix_cache/2. 95 96% the ns/2 predicate is historically defined in `rdf_db`. We'll keep 97% that for compatibility reasons. 98:- multifile rdf_db:ns/2. 99:- dynamic rdf_db:ns/2. % ID, URL
rdf_current_prefix(Prefix, Expansion), atom_concat(Expansion, Local, URI),
115rdf_current_prefix(Module:Alias, URI) :- 116 nonvar(Alias), 117 !, 118 rdf_current_prefix(Module, Alias, URI), 119 !. 120rdf_current_prefix(Module:Alias, URI) :- 121 rdf_current_prefix(Module, Alias, URI). 122 123rdf_current_prefix(system, Alias, URI) :- 124 !, 125 rdf_db:ns(Alias, URI). 126rdf_current_prefix(Module, Alias, URI) :- 127 default_module(Module, M), 128 ( M == system 129 -> rdf_db:ns(Alias, URI) 130 ; '$flushed_predicate'(M:'rdf prefix'(_,_)), 131 call(M:'rdf prefix'(Alias,URI)) 132 ).
142rdf_prefix(Alias, URI) :- 143 throw(error(context_error(nodirective, rdf_prefix(Alias, URI)), _)). 144 145systemterm_expansion((:- rdf_prefix(AliasSpec, URI)), Clauses) :- 146 prolog_load_context(module, Module), 147 strip_module(Module:AliasSpec, TM, Alias), 148 must_be(atom, Alias), 149 must_be(atom, URI), 150 ( rdf_current_prefix(TM:Alias, URI) 151 -> Clauses = [] 152 ; TM == Module 153 -> Clauses = 'rdf prefix'(Alias, URI) 154 ; Clauses = TM:'rdf prefix'(Alias, URI) 155 ).
165rdf_dbns(dc, 'http://purl.org/dc/elements/1.1/'). 166rdf_dbns(dcterms, 'http://purl.org/dc/terms/'). 167rdf_dbns(eor, 'http://dublincore.org/2000/03/13/eor#'). 168rdf_dbns(foaf, 'http://xmlns.com/foaf/0.1/'). 169rdf_dbns(owl, 'http://www.w3.org/2002/07/owl#'). 170rdf_dbns(rdf, 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'). 171rdf_dbns(rdfs, 'http://www.w3.org/2000/01/rdf-schema#'). 172rdf_dbns(serql, 'http://www.openrdf.org/schema/serql#'). 173rdf_dbns(skos, 'http://www.w3.org/2004/02/skos/core#'). 174rdf_dbns(void, 'http://rdfs.org/ns/void#'). 175rdf_dbns(xsd, 'http://www.w3.org/2001/XMLSchema#').
true
, replace existing namespace alias. Please note
that replacing a namespace is dangerous as namespaces
affect preprocessing. Make sure all code that depends on
a namespace is compiled after changing the registration.true
and Alias is already defined, keep the
original binding for Prefix and succeed silently.Without options, an attempt to redefine an alias raises a permission error.
Predefined prefixes are:
211rdf_register_prefix(Alias, URI) :- 212 rdf_register_prefix(Alias, URI, []). 213 214rdf_register_prefix(Alias, URI, Options) :- 215 must_be(atom, Alias), 216 must_be(atom, URI), 217 ( rdf_current_prefix(system:Alias, URI) 218 -> true 219 ; register_global_prefix(Alias, URI, Options) 220 ).
226register_global_prefix(Alias, URI, Options) :- 227 rdf_db:ns(Alias, _), 228 !, 229 ( option(force(true), Options, false) 230 -> retractall(rdf_db:ns(Alias, _)), 231 rdf_register_prefix(Alias, URI, Options), 232 forall(rdf_empty_prefix_cache(Alias, URI), true) 233 ; option(keep(true), Options, false) 234 -> true 235 ; throw(error(permission_error(register, namespace, Alias), 236 context(_, 'Already defined'))) 237 ). 238register_global_prefix(Alias, URI, _) :- 239 findall(P-U, prefix_conflict(URI, P, U), Pairs), 240 order_prefixes([Alias-URI|Pairs], Ordered), 241 forall(member(P-U, Pairs), retract(rdf_db:ns(P,U))), 242 forall(member(P-U, Ordered), assert(rdf_db:ns(P,U))). 243 244prefix_conflict(URI, P, U) :- 245 rdf_db:ns(P,U), 246 ( sub_atom(URI, 0, _, _, U) 247 -> true 248 ; sub_atom(U, 0, _, _, URI) 249 ). 250 251order_prefixes(Pairs, Sorted) :- 252 map_list_to_pairs(prefix_uri_length, Pairs, ByLen), 253 sort(1, >=, ByLen, SortedByLen), 254 pairs_values(SortedByLen, Sorted). 255 256prefix_uri_length(_-URI, Len) :- 257 atom_length(URI, Len).
263rdf_unregister_prefix(Alias) :-
264 must_be(atom, Alias),
265 retractall(rdf_db:ns(Alias, _)).
272rdf_current_ns(Prefix, URI) :-
273 rdf_current_prefix(Prefix, URI).
282rdf_register_ns(Prefix, URI) :- 283 rdf_register_prefix(Prefix, URI). 284rdf_register_ns(Prefix, URI, Options) :- 285 rdf_register_prefix(Prefix, URI, Options).
298register_file_prefixes([]) :- !. 299register_file_prefixes([Decl|T]) :- 300 !, 301 register_file_prefixes(Decl), 302 register_file_prefixes(T). 303register_file_prefixes([]=_) :- !. % xmlns= (overall default) 304register_file_prefixes(NS=URL) :- % compatibility 305 !, 306 register_file_prefixes(NS-URL). 307register_file_prefixes(NS-URL) :- 308 ( rdf_db:ns(NS, URL) 309 -> true 310 ; rdf_db:ns(NS, _) 311 -> true % redefined abbreviation 312 ; rdf_db:ns(_, URL) 313 -> true % redefined URL 314 ; rdf_register_prefix(NS, URL) 315 ).
Note that this predicate is a meta-predicate on its output argument. This is necessary to get the module context while the first argument may be of the form (:)/2. The above mode description is correct, but should be interpreted as (?,?).
338rdf_global_id(Id, Module:Global) :- 339 rdf_global_id(Id, Global, Module). 340 341rdf_global_id(NS:Local, Global, Module) :- 342 global(NS, Local, Global, Module), 343 !. 344rdf_global_id(Global, Global, _).
358rdf_global_object(Object, Module:GlobalObject) :- 359 rdf_global_object(Object, GlobalObject, Module). 360 361rdf_global_object(Var, Global, _M) :- 362 var(Var), 363 !, 364 Global = Var. 365rdf_global_object(Prefix:Local, Global, M) :- 366 global(Prefix, Local, Global, M), 367 !. 368rdf_global_object(literal(type(Prefix:Local, Value)), 369 literal(type(Global, Value)), M) :- 370 global(Prefix, Local, Global, M), 371 !. 372rdf_global_object(^^(Value,Prefix:Local), 373 ^^(Value,Global), M) :- 374 global(Prefix, Local, Global, M), 375 !. 376rdf_global_object(literal(Query0, type(Prefix:Local, Value)), 377 literal(Query1, type(Global, Value)), M) :- 378 global(Prefix, Local, Global, M), 379 !, 380 rdf_global_term(Query0, Query1, M). 381rdf_global_object(literal(Query0, Value), 382 literal(Query1, Value), M) :- 383 !, 384 rdf_global_term(Query0, Query1, M). 385rdf_global_object(Global, Global, _). 386 387global(Prefix, Local, Global, Module) :- 388 ( atom(Global) 389 -> rdf_current_prefix(Module:Prefix, Full), 390 atom_concat(Full, Local, Global) 391 ; atom(Prefix), atom(Local), var(Global) 392 -> ( rdf_current_prefix(Module:Prefix, Full) 393 *-> atom_concat(Full, Local, Global) 394 ; current_prolog_flag(xref, true) 395 -> Global = Prefix:Local 396 ; existence_error(rdf_prefix, Prefix) 397 ) 398 ).
Terms of the form Prefix:Local
that appear in TermIn for which
Prefix is not defined are not replaced. Unlike rdf_global_id/2 and
rdf_global_object/2, no error is raised.
413rdf_global_term(TermIn, Module:TermOut) :- 414 rdf_global_term(TermIn, TermOut, Module). 415 416rdf_global_term(Var, Var, _M) :- 417 var(Var), 418 !. 419rdf_global_term(Prefix:Local, Global, Module) :- 420 atom(Prefix), atom(Local), 421 rdf_current_prefix(Module:Prefix, Full), 422 !, 423 atom_concat(Full, Local, Global). 424rdf_global_term([H0|T0], [H|T], M) :- 425 !, 426 rdf_global_term(H0, H, M), 427 rdf_global_term(T0, T, M). 428rdf_global_term(Term0, Term, M) :- 429 compound(Term0), 430 !, 431 Term0 =.. [H|L0], 432 rdf_global_term(L0, L, M), 433 Term =.. [H|L]. 434rdf_global_term(Term, Term, _).
440rdf_global_graph(Prefix:Local, Global, Module) :- 441 atom(Prefix), atom(Local), 442 !, 443 global(Prefix, Local, Global, Module). 444rdf_global_graph(G, G, _). 445 446 447 /******************************* 448 * EXPANSION * 449 *******************************/ 450 451:- multifile 452 system:term_expansion/2, 453 system:goal_expansion/2. 454 455systemterm_expansion((:- rdf_meta(Heads)), Clauses) :- 456 prolog_load_context(module, M), 457 phrase(mk_clauses(Heads, M), Clauses). 458 459mk_clauses((A,B), M) --> 460 mk_clause(A, M), 461 mk_clauses(B, M). 462mk_clauses(A, M) --> 463 mk_clause(A, M). 464 465mk_clause(Head0, M0) --> 466 { strip_module(M0:Head0, Module, Head), 467 valid_rdf_meta_head(Head), 468 functor(Head, Name, Arity), 469 functor(Unbound, Name, Arity), 470 qualify(Module, 'rdf meta specification'/2, Decl) 471 }, 472 [ (:- multifile(Decl)), 473 Module:'rdf meta specification'(Unbound, Head) 474 ]. 475 476qualify(Module, Decl, Decl) :- 477 prolog_load_context(module, Module), 478 !. 479qualify(Module, Decl, Module:Decl). 480 481 482valid_rdf_meta_head(Head) :- 483 callable(Head), 484 !, 485 Head =.. [_|Args], 486 valid_args(Args). 487valid_rdf_meta_head(Head) :- 488 throw(error(type_error(callable, Head), _)). 489 490valid_args([]). 491valid_args([H|T]) :- 492 valid_arg(H), 493 !, 494 valid_args(T). 495 496valid_arg(:). % meta argument 497valid_arg(+). % non-var 498valid_arg(-). % var 499valid_arg(?). % either var or non-var 500valid_arg(@). % not modified 501valid_arg(r). % RDF resource 502valid_arg(o). % RDF object 503valid_arg(t). % term with RDF resources 504valid_arg(g). % graph argument 505valid_arg(A) :- 506 throw(error(type_error(rdf_meta_argument, A), _)).
As it is subject to term_expansion/2, the rdf_meta/1 declaration
can only be used as a directive. The directive must be processed
before the definition of the predicates as well as before
compiling code that uses the rdf meta-predicates. The atom
rdf_meta
is declared as an operator exported from
library(semweb/rdf_db). Files using rdf_meta/1 must explicitely
load this library.
Beginning with SWI-Prolog 7.3.17, the low-level RDF interface
(rdf/3, rdf_assert/3, etc.) perform runtime expansion of
Prefix:Local
terms. This eliminates the need for rdf_meta/1
for simple cases. However, runtime expansion comes at a
significant overhead and having two representations for IRIs (a
plain atom and a term Prefix:Local
) implies that simple
operations such as comparison of IRIs no longer map to native
Prolog operations such as IRI1 == IRI2
.
562rdf_meta(Heads) :-
563 throw(error(context_error(nodirective, rdf_meta(Heads)), _)).
572rdf_meta_specification(Unbounded, Module, Spec) :- 573 '$flushed_predicate'(Module:'rdf meta specification'(_,_)), 574 call(Module:'rdf meta specification'(Unbounded, Spec)). 575 576systemgoal_expansion(G, Expanded) :- 577 \+ predicate_property(G, iso), 578 prolog_load_context(module, LM), 579 predicate_property(LM:G, implementation_module(IM)), 580 rdf_meta_specification(G, IM, Spec), 581 rdf_expand(G, Spec, Expanded, LM). 582 583systemterm_expansion(Module:Fact, Expanded) :- 584 atom(Module), 585 rdf_meta_specification(Fact, Module, Spec), 586 rdf_expand(Fact, Spec, ExpandedFact, Module), 587 Fact \== ExpandedFact, 588 Expanded = (Module:ExpandedFact). 589systemterm_expansion(Fact, Expanded) :- 590 prolog_load_context(module, Module), 591 rdf_meta_specification(Fact, Module, Spec), 592 rdf_expand(Fact, Spec, Expanded, Module), 593 Fact \== Expanded. 594systemterm_expansion((Module:Head :- Body), (Expanded :- Body)) :- 595 atom(Module), 596 rdf_meta_specification(Head, Module, Spec), 597 rdf_expand(Head, Spec, ExpandedHead, Module), 598 Head \== ExpandedHead, 599 Expanded = (Module:ExpandedHead). 600systemterm_expansion((Head :- Body), (Expanded :- Body)) :- 601 prolog_load_context(module, Module), 602 rdf_meta_specification(Head, Module, Spec), 603 rdf_expand(Head, Spec, Expanded, Module), 604 Head \== Expanded. 605 606rdf_expand(G, Spec, Expanded, M) :- 607 functor(G, Name, Arity), 608 functor(Expanded, Name, Arity), 609 rdf_expand_args(0, Arity, G, Spec, Expanded, M). 610 611rdf_expand_args(Arity, Arity, _, _, _, _) :- !. 612rdf_expand_args(I0, Arity, Goal, Spec, Expanded, M) :- 613 I is I0 + 1, 614 arg(I, Goal, GA), 615 arg(I, Spec, SA), 616 arg(I, Expanded, EA), 617 rdf_expand_arg(SA, GA, EA, M), 618 rdf_expand_args(I, Arity, Goal, Spec, Expanded, M). 619 620rdf_expand_arg(r, A, E, M) :- 621 mk_global(A, E, M), 622 !. 623rdf_expand_arg(o, A, E, M) :- 624 rdf_global_object(A, E, M), 625 !. 626rdf_expand_arg(t, A, E, M) :- 627 rdf_global_term(A, E, M), 628 !. 629rdf_expand_arg(g, A, E, M) :- 630 rdf_global_graph(A, E, M), 631 !. 632rdf_expand_arg(:, A, E, _M) :- 633 !, 634 expand_goal(A, E). 635rdf_expand_arg(_, A, A, _M).
rdf_global_id(+, -)
, but adds compiletime checking,
notably to see whether a namespace is not yet defined.642mk_global(X, X, _) :- 643 var(X), 644 !. 645mk_global(X, X, _) :- 646 atom(X), 647 !. 648mk_global(Prefix:Local, Global, Module) :- 649 must_be(atom, Prefix), 650 must_be(atom, Local), 651 ( rdf_current_prefix(Module:Prefix, Full) 652 -> atom_concat(Full, Local, Global) 653 ; current_prolog_flag(xref, true) 654 -> Global = Prefix:Local 655 ; existence_error(rdf_prefix, Prefix) 656 )
RDF prefixes management
This module defines the expansion of
Prefix:Local
terms to full IRIs. This library is typically not intended for the end-user. It may be included into other RDF and XML libraries and relevant parts may be re-exported. */