View source with formatted comments or as raw
    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-2022, VU University Amsterdam
    7			      CWI, Amsterdam
    8                              SWI-Prolog Solutions b.v.
    9    All rights reserved.
   10
   11    Redistribution and use in source and binary forms, with or without
   12    modification, are permitted provided that the following conditions
   13    are met:
   14
   15    1. Redistributions of source code must retain the above copyright
   16       notice, this list of conditions and the following disclaimer.
   17
   18    2. Redistributions in binary form must reproduce the above copyright
   19       notice, this list of conditions and the following disclaimer in
   20       the documentation and/or other materials provided with the
   21       distribution.
   22
   23    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   24    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   25    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   26    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   27    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   28    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   31    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   33    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   34    POSSIBILITY OF SUCH DAMAGE.
   35*/
   36
   37:- module(rdf_prefixes,
   38          [ rdf_prefix/2,               % :Alias, +URI
   39            rdf_current_prefix/2,       % :Alias, ?URI
   40            rdf_register_prefix/2,      % +Alias, +URI
   41            rdf_register_prefix/3,      % +Alias, +URI, +Options
   42            rdf_unregister_prefix/1,    % +Alias
   43            register_file_prefixes/1,   % +Pairs
   44
   45            rdf_current_ns/2,           % :Alias, ?URI
   46            rdf_register_ns/2,          % +Alias, +URI
   47            rdf_register_ns/3,          % +Alias, +URI, +Options
   48            rdf_global_id/2,            % ?NS:Name, :Global
   49            rdf_global_object/2,        % +Object, :NSExpandedObject
   50            rdf_global_term/2,          % +Term, :WithExpandedNS
   51
   52            (rdf_meta)/1,               % +Heads
   53            op(1150, fx, (rdf_meta))
   54          ]).   55:- autoload(library(error),[must_be/2,existence_error/2]).   56:- autoload(library(lists),[member/2]).   57:- autoload(library(option),[option/3]).   58:- autoload(library(pairs),[map_list_to_pairs/3,pairs_values/2]).   59
   60:- meta_predicate
   61    rdf_current_prefix(:, -),
   62    rdf_current_ns(:, -),
   63    rdf_global_id(?, :),
   64    rdf_global_term(+, :),
   65    rdf_global_object(+, :).   66
   67/** <module> RDF prefixes management
   68
   69This module defines the expansion of  `Prefix:Local` terms to full IRIs.
   70This library is typically not  intended  for   the  end-user.  It may be
   71included into other RDF and XML  libraries   and  relevant  parts may be
   72re-exported.
   73*/
   74
   75:- predicate_options(rdf_register_ns/3, 3,
   76                     [ force(boolean),
   77                       keep(boolean)
   78                     ]).   79:- predicate_options(rdf_register_prefix/3, 3,
   80                     [ force(boolean),
   81                       keep(boolean)
   82                     ]).   83
   84
   85		 /*******************************
   86		 *            HOOKS		*
   87		 *******************************/
   88
   89%!  rdf_empty_prefix_cache(+Alias, +URI)
   90%
   91%   Multifile hook called if the binding Alias   -> URI is modified. May
   92%   be used to update derived caches.
   93
   94:- multifile
   95    rdf_empty_prefix_cache/2.   96
   97% the ns/2 predicate is historically  defined   in  `rdf_db`. We'll keep
   98% that for compatibility reasons.
   99:- multifile rdf_db:ns/2.  100:- dynamic   rdf_db:ns/2.               % ID, URL
  101
  102%!  rdf_current_prefix(:Alias, ?URI) is nondet.
  103%
  104%   Query   predefined   prefixes   and    prefixes   defined   with
  105%   rdf_register_prefix/2   and   local   prefixes    defined   with
  106%   rdf_prefix/2. If Alias is unbound and one   URI is the prefix of
  107%   another, the longest is returned first.   This  allows turning a
  108%   resource into a prefix/local couple using the simple enumeration
  109%   below. See rdf_global_id/2.
  110%
  111%     ==
  112%     rdf_current_prefix(Prefix, Expansion),
  113%     atom_concat(Expansion, Local, URI),
  114%     ==
  115
  116rdf_current_prefix(Module:Alias, URI) :-
  117    nonvar(Alias),
  118    !,
  119    rdf_current_prefix(Module, Alias, URI),
  120    !.
  121rdf_current_prefix(Module:Alias, URI) :-
  122    rdf_current_prefix(Module, Alias, URI).
  123
  124rdf_current_prefix(system, Alias, URI) :-
  125    !,
  126    rdf_db:ns(Alias, URI).
  127rdf_current_prefix(Module, Alias, URI) :-
  128    default_module(Module, M),
  129    (   M == system
  130    ->  rdf_db:ns(Alias, URI)
  131    ;   '$flushed_predicate'(M:'rdf prefix'(_,_)),
  132        call(M:'rdf prefix'(Alias,URI))
  133    ).
  134
  135%!  rdf_prefix(:Alias, +URI) is det.
  136%
  137%   Register a _local_ prefix.  This   declaration  takes precedence
  138%   over globally defined prefixes   using  rdf_register_prefix/2,3.
  139%   Module local prefixes are notably required   to deal with SWISH,
  140%   where users need to  be  able   to  have  independent  namespace
  141%   declarations.
  142
  143rdf_prefix(Alias, URI) :-
  144    throw(error(context_error(nodirective, rdf_prefix(Alias, URI)), _)).
  145
  146system:term_expansion((:- rdf_prefix(AliasSpec, URI)), Clauses) :-
  147    prolog_load_context(module, Module),
  148    strip_module(Module:AliasSpec, TM, Alias),
  149    must_be(atom, Alias),
  150    must_be(atom, URI),
  151    (   rdf_current_prefix(TM:Alias, URI)
  152    ->  Clauses = []
  153    ;   TM == Module
  154    ->  Clauses = 'rdf prefix'(Alias, URI)
  155    ;   Clauses = TM:'rdf prefix'(Alias, URI)
  156    ).
  157
  158%!  rdf_db:ns(?Alias, ?URI) is nondet.
  159%
  160%   Dynamic and multifile predicate that   maintains  the registered
  161%   namespace aliases.
  162%
  163%   @deprecated New code  must  modify   the  namespace  table using
  164%   rdf_register_ns/3 and query using rdf_current_ns/2.
  165
  166rdf_db:ns(dc,      'http://purl.org/dc/elements/1.1/').
  167rdf_db:ns(dcterms, 'http://purl.org/dc/terms/').
  168rdf_db:ns(eor,     'http://dublincore.org/2000/03/13/eor#').
  169rdf_db:ns(foaf,    'http://xmlns.com/foaf/0.1/').
  170rdf_db:ns(owl,     'http://www.w3.org/2002/07/owl#').
  171rdf_db:ns(rdf,     'http://www.w3.org/1999/02/22-rdf-syntax-ns#').
  172rdf_db:ns(rdfs,    'http://www.w3.org/2000/01/rdf-schema#').
  173rdf_db:ns(serql,   'http://www.openrdf.org/schema/serql#').
  174rdf_db:ns(skos,    'http://www.w3.org/2004/02/skos/core#').
  175rdf_db:ns(void,    'http://rdfs.org/ns/void#').
  176rdf_db:ns(xsd,     'http://www.w3.org/2001/XMLSchema#').
  177
  178%!  rdf_register_prefix(+Prefix, +URI) is det.
  179%!  rdf_register_prefix(+Prefix, +URI, +Options) is det.
  180%
  181%   Register Prefix as an abbreviation for URI. Options:
  182%
  183%           * force(Boolean)
  184%           If =true=, replace existing namespace alias. Please note
  185%           that replacing a namespace is dangerous as namespaces
  186%           affect preprocessing. Make sure all code that depends on
  187%           a namespace is compiled after changing the registration.
  188%
  189%           * keep(Boolean)
  190%           If =true= and Alias is already defined, keep the
  191%           original binding for Prefix and succeed silently.
  192%
  193%   Without options, an attempt  to  redefine   an  alias  raises  a
  194%   permission error.
  195%
  196%   Predefined prefixes are:
  197%
  198%   | **Alias** | **IRI prefix**                              |
  199%   | dc        | http://purl.org/dc/elements/1.1/            |
  200%   | dcterms   | http://purl.org/dc/terms/                   |
  201%   | eor       | http://dublincore.org/2000/03/13/eor#       |
  202%   | foaf      | http://xmlns.com/foaf/0.1/                  |
  203%   | owl       | http://www.w3.org/2002/07/owl#              |
  204%   | rdf       | http://www.w3.org/1999/02/22-rdf-syntax-ns# |
  205%   | rdfs      | http://www.w3.org/2000/01/rdf-schema#       |
  206%   | serql     | http://www.openrdf.org/schema/serql#        |
  207%   | skos      | http://www.w3.org/2004/02/skos/core#        |
  208%   | void      | http://rdfs.org/ns/void#                    |
  209%   | xsd       | http://www.w3.org/2001/XMLSchema#           |
  210
  211
  212rdf_register_prefix(Alias, URI) :-
  213    rdf_register_prefix(Alias, URI, []).
  214
  215rdf_register_prefix(Alias, URI, Options) :-
  216    must_be(atom, Alias),
  217    must_be(atom, URI),
  218    (   rdf_current_prefix(system:Alias, URI)
  219    ->  true
  220    ;   register_global_prefix(Alias, URI, Options)
  221    ).
  222
  223%!  register_global_prefix(+Alias, +URI, +Options)
  224%
  225%   Register a global prefix.
  226
  227register_global_prefix(Alias, URI, Options) :-
  228    rdf_db:ns(Alias, _),
  229    !,
  230    (   option(force(true), Options, false)
  231    ->  retractall(rdf_db:ns(Alias, _)),
  232        rdf_register_prefix(Alias, URI, Options),
  233        forall(rdf_empty_prefix_cache(Alias, URI), true)
  234    ;   option(keep(true), Options, false)
  235    ->  true
  236    ;   throw(error(permission_error(register, namespace, Alias),
  237                    context(_, 'Already defined')))
  238    ).
  239register_global_prefix(Alias, URI, _) :-
  240    findall(P-U, prefix_conflict(URI, P, U), Pairs),
  241    order_prefixes([Alias-URI|Pairs], Ordered),
  242    forall(member(P-U, Pairs), retract(rdf_db:ns(P,U))),
  243    forall(member(P-U, Ordered), assert(rdf_db:ns(P,U))).
  244
  245prefix_conflict(URI, P, U) :-
  246    rdf_db:ns(P,U),
  247    (   sub_atom(URI, 0, _, _, U)
  248    ->  true
  249    ;   sub_atom(U, 0, _, _, URI)
  250    ).
  251
  252order_prefixes(Pairs, Sorted) :-
  253    map_list_to_pairs(prefix_uri_length, Pairs, ByLen),
  254    sort(1, >=, ByLen, SortedByLen),
  255    pairs_values(SortedByLen, Sorted).
  256
  257prefix_uri_length(_-URI, Len) :-
  258    atom_length(URI, Len).
  259
  260%!  rdf_unregister_prefix(+Alias) is det.
  261%
  262%   Delete a prefix global registration.
  263
  264rdf_unregister_prefix(Alias) :-
  265    must_be(atom, Alias),
  266    retractall(rdf_db:ns(Alias, _)).
  267
  268
  269%!  rdf_current_ns(:Prefix, ?URI) is nondet.
  270%
  271%   @deprecated  Use rdf_current_prefix/2.
  272
  273rdf_current_ns(Prefix, URI) :-
  274    rdf_current_prefix(Prefix, URI).
  275
  276%!  rdf_register_ns(:Prefix, ?URI) is det.
  277%!  rdf_register_ns(:Prefix, ?URI, +Options) is det.
  278%
  279%   Register an RDF prefix.
  280%
  281%   @deprecated  Use rdf_register_prefix/2 or rdf_register_prefix/3.
  282
  283rdf_register_ns(Prefix, URI) :-
  284    rdf_register_prefix(Prefix, URI).
  285rdf_register_ns(Prefix, URI, Options) :-
  286    rdf_register_prefix(Prefix, URI, Options).
  287
  288
  289%!  register_file_prefixes(+Map:list(pair)) is det.
  290%
  291%   Register a namespace as encounted in   the  namespace list of an
  292%   RDF document. We only register if  both the abbreviation and URL
  293%   are not already known. Is there a   better  way? This code could
  294%   also do checks on the consistency   of  RDF and other well-known
  295%   namespaces.
  296%
  297%   @tbd    Better error handling
  298
  299register_file_prefixes([]) :- !.
  300register_file_prefixes([Decl|T]) :-
  301    !,
  302    register_file_prefixes(Decl),
  303    register_file_prefixes(T).
  304register_file_prefixes([]=_) :- !.      % xmlns= (overall default)
  305register_file_prefixes(NS=URL) :-       % compatibility
  306    !,
  307    register_file_prefixes(NS-URL).
  308register_file_prefixes(NS-URL) :-
  309    (   rdf_db:ns(NS, URL)
  310    ->  true
  311    ;   rdf_db:ns(NS, _)
  312    ->  true                            % redefined abbreviation
  313    ;   rdf_db:ns(_, URL)
  314    ->  true                            % redefined URL
  315    ;   rdf_register_prefix(NS, URL)
  316    ).
  317
  318
  319%!  rdf_global_id(?IRISpec, :IRI) is semidet.
  320%
  321%   Convert between Prefix:Local and full IRI   (an atom). If IRISpec is
  322%   an atom, it  is  simply  unified   with  IRI.  This  predicate fails
  323%   silently if IRI is an RDF literal.
  324%
  325%   Note that this predicate is a meta-predicate on its output argument.
  326%   This is necessary to get the module context while the first argument
  327%   may be of the form (:)/2. The above mode description is correct, but
  328%   should be interpreted as (?,?).
  329%
  330%   @error existence_error(rdf_prefix, Prefix)
  331%   @see   rdf_equal/2 provides a compile time alternative
  332%   @see   The rdf_meta/1 directive asks for compile time expansion
  333%          of arguments.
  334%   @bug   Error handling is incomplete.  In its current implementation
  335%	   the same code is used for compile-time expansion and to
  336%	   facilitate runtime conversion and checking.  These use cases
  337%	   have different requirements.
  338
  339rdf_global_id(Id, Module:Global) :-
  340    rdf_global_id(Id, Global, Module).
  341
  342rdf_global_id(NS:Local, Global, Module) :-
  343    global(NS, Local, Global, Module),
  344    !.
  345rdf_global_id(Global, Global, _).
  346
  347
  348%!  rdf_global_object(+Object, :GlobalObject) is semidet.
  349%!  rdf_global_object(-Object, :GlobalObject) is semidet.
  350%
  351%   Same as rdf_global_id/2,  but  intended   for  dealing  with the
  352%   object part of a  triple,  in   particular  the  type  for typed
  353%   literals. Note that the predicate  is   a  meta-predicate on the
  354%   output argument. This is necessary  to   get  the module context
  355%   while the first argument may be of the form (:)/2.
  356%
  357%   @error  existence_error(rdf_prefix, Prefix)
  358
  359rdf_global_object(Object, Module:GlobalObject) :-
  360    rdf_global_object(Object, GlobalObject, Module).
  361
  362rdf_global_object(Var, Global, _M) :-
  363    var(Var),
  364    !,
  365    Global = Var.
  366rdf_global_object(Prefix:Local, Global, M) :-
  367    global(Prefix, Local, Global, M),
  368    !.
  369rdf_global_object(literal(type(Prefix:Local, Value)),
  370                  literal(type(Global, Value)), M) :-
  371    global(Prefix, Local, Global, M),
  372    !.
  373rdf_global_object(^^(Value,Prefix:Local),
  374                  ^^(Value,Global), M) :-
  375    global(Prefix, Local, Global, M),
  376    !.
  377rdf_global_object(literal(Query0, type(Prefix:Local, Value)),
  378                  literal(Query1, type(Global, Value)), M) :-
  379    global(Prefix, Local, Global, M),
  380    !,
  381    rdf_global_term(Query0, Query1, M).
  382rdf_global_object(literal(Query0, Value),
  383                  literal(Query1, Value), M) :-
  384    !,
  385    rdf_global_term(Query0, Query1, M).
  386rdf_global_object(Global, Global, _).
  387
  388global(Prefix, Local, Global, Module) :-
  389    (   atom(Global)
  390    ->  rdf_current_prefix(Module:Prefix, Full),
  391        atom_concat(Full, Local, Global)
  392    ;   atom(Prefix), atom(Local), var(Global)
  393    ->  (   rdf_current_prefix(Module:Prefix, Full)
  394        *-> atom_concat(Full, Local, Global)
  395        ;   current_prolog_flag(xref, true)
  396        ->  Global = Prefix:Local
  397        ;   existence_error(rdf_prefix, Prefix)
  398        )
  399    ).
  400
  401
  402%!  rdf_global_term(+TermIn, :GlobalTerm) is det.
  403%
  404%   Performs rdf_global_id/2 on predixed IRIs and rdf_global_object/2 on
  405%   RDF literals, by recursively  analysing  the   term.  Note  that the
  406%   predicate is a meta-predicate  on  the   output  argument.  This  is
  407%   necessary to get the module context while  the first argument may be
  408%   of the form (:)/2.
  409%
  410%   Terms of the form `Prefix:Local`  that   appear  in TermIn for which
  411%   `Prefix` is not defined are not replaced. Unlike rdf_global_id/2 and
  412%   rdf_global_object/2, no error is raised.
  413
  414rdf_global_term(TermIn, Module:TermOut) :-
  415    rdf_global_term(TermIn, TermOut, Module).
  416
  417rdf_global_term(Var, Var, _M) :-
  418    var(Var),
  419    !.
  420rdf_global_term(Prefix:Local, Global, Module) :-
  421    atom(Prefix), atom(Local),
  422    rdf_current_prefix(Module:Prefix, Full),
  423    !,
  424    atom_concat(Full, Local, Global).
  425rdf_global_term([H0|T0], [H|T], M) :-
  426    !,
  427    rdf_global_term(H0, H, M),
  428    rdf_global_term(T0, T, M).
  429rdf_global_term(Term0, Term, M) :-
  430    compound(Term0),
  431    !,
  432    compound_name_arguments(Term0, Name, L0),
  433    rdf_global_term(L0, L, M),
  434    compound_name_arguments(Term, Name, L).
  435rdf_global_term(Term, Term, _).
  436
  437%!  rdf_global_graph(+TermIn, -GlobalTerm, +Module) is det.
  438%
  439%   Preforms rdf_global_id/2 on rdf/4, etc graph arguments
  440
  441rdf_global_graph(Prefix:Local, Global, Module) :-
  442    atom(Prefix), atom(Local),
  443    !,
  444    global(Prefix, Local, Global, Module).
  445rdf_global_graph(G, G, _).
  446
  447
  448                 /*******************************
  449                 *            EXPANSION         *
  450                 *******************************/
  451
  452:- multifile
  453    system:term_expansion/2,
  454    system:goal_expansion/2.  455
  456system:term_expansion((:- rdf_meta(Heads)), Clauses) :-
  457    prolog_load_context(module, M),
  458    phrase(mk_clauses(Heads, M), Clauses).
  459
  460mk_clauses((A,B), M) -->
  461    mk_clause(A, M),
  462    mk_clauses(B, M).
  463mk_clauses(A, M) -->
  464    mk_clause(A, M).
  465
  466mk_clause(Head0, M0) -->
  467    { strip_module(M0:Head0, Module, Head),
  468      valid_rdf_meta_head(Head),
  469      functor(Head, Name, Arity),
  470      functor(Unbound, Name, Arity),
  471      qualify(Module, 'rdf meta specification'/2, Decl)
  472    },
  473    [ (:- multifile(Decl)),
  474      Module:'rdf meta specification'(Unbound, Head)
  475    ].
  476
  477qualify(Module, Decl, Decl) :-
  478    prolog_load_context(module, Module),
  479    !.
  480qualify(Module, Decl, Module:Decl).
  481
  482
  483valid_rdf_meta_head(Head) :-
  484    callable(Head),
  485    !,
  486    Head =.. [_|Args],
  487    valid_args(Args).
  488valid_rdf_meta_head(Head) :-
  489    throw(error(type_error(callable, Head), _)).
  490
  491valid_args([]).
  492valid_args([H|T]) :-
  493    valid_arg(H),
  494    !,
  495    valid_args(T).
  496
  497valid_arg(:).                           % meta argument
  498valid_arg(+).                           % non-var
  499valid_arg(-).                           % var
  500valid_arg(?).                           % either var or non-var
  501valid_arg(@).                           % not modified
  502valid_arg(r).                           % RDF resource
  503valid_arg(o).                           % RDF object
  504valid_arg(t).                           % term with RDF resources
  505valid_arg(g).                           % graph argument
  506valid_arg(A) :-
  507    throw(error(type_error(rdf_meta_argument, A), _)).
  508
  509%!  rdf_meta(+Heads)
  510%
  511%   This  directive  defines  the  argument    types  of  the  named
  512%   predicates, which will force compile   time  namespace expansion
  513%   for these predicates. Heads is a coma-separated list of callable
  514%   terms. Defined argument properties are:
  515%
  516%     $ : :
  517%     Argument is a goal. The goal is processed using expand_goal/2,
  518%     recursively applying goal transformation on the argument.
  519%
  520%     $ + :
  521%     The argument is instantiated at entry. Nothing is changed.
  522%
  523%     $ - :
  524%     The argument is not instantiated at entry. Nothing is changed.
  525%
  526%     $ ? :
  527%     The argument is unbound or instantiated at entry. Nothing is
  528%     changed.
  529%
  530%     $ @ :
  531%     The argument is not changed.
  532%
  533%     $ r :
  534%     The argument must be a resource. If it is a term
  535%     _prefix_:_local_ it is translated.
  536%
  537%     $ o :
  538%     The argument is an object or resource. See
  539%     rdf_global_object/2.
  540%
  541%     $ t :
  542%     The argument is a term that must be translated. Expansion will
  543%     translate all occurences of _prefix_:_local_ appearing
  544%     anywhere in the term. See rdf_global_term/2.
  545%
  546%   As it is subject to term_expansion/2, the rdf_meta/1 declaration
  547%   can only be used as a directive. The directive must be processed
  548%   before the definition of  the  predicates   as  well  as  before
  549%   compiling code that  uses  the   rdf  meta-predicates.  The atom
  550%   =rdf_meta=  is  declared   as   an    operator   exported   from
  551%   library(semweb/rdf_db). Files using rdf_meta/1  must explicitely
  552%   load this library.
  553%
  554%   Beginning with SWI-Prolog 7.3.17, the   low-level  RDF interface
  555%   (rdf/3,  rdf_assert/3,  etc.)  perform    runtime  expansion  of
  556%   `Prefix:Local` terms. This eliminates the   need  for rdf_meta/1
  557%   for  simple  cases.  However,  runtime   expansion  comes  at  a
  558%   significant overhead and having two  representations for IRIs (a
  559%   plain atom and  a  term   `Prefix:Local`)  implies  that  simple
  560%   operations such as comparison of IRIs   no  longer map to native
  561%   Prolog operations such as `IRI1 == IRI2`.
  562
  563rdf_meta(Heads) :-
  564    throw(error(context_error(nodirective, rdf_meta(Heads)), _)).
  565
  566%!  rdf_meta_specification(+General, +Module, -Spec) is semidet.
  567%
  568%   True when Spec is the RDF meta specification for Module:General.
  569%
  570%   @arg    General is the term Spec with all arguments replaced with
  571%           variables.
  572
  573rdf_meta_specification(Unbounded, Module, Spec) :-
  574    '$flushed_predicate'(Module:'rdf meta specification'(_,_)),
  575    call(Module:'rdf meta specification'(Unbounded, Spec)).
  576
  577split_rule((Module:Head :- Body), (Module:Expanded :- Body),
  578           Module, Head, Expanded) :-
  579    atom(Module),
  580    !.
  581split_rule((Head :- Body), (Expanded :- Body),
  582           Module, Head, Expanded) :-
  583    callable(Head),
  584    prolog_load_context(module, Module),
  585    !.
  586split_rule((Module:Head,Guard => Body), (Module:Expanded,Guard => Body),
  587           Module, Head, Expanded) :-
  588    callable(Head),
  589    atom(Module),
  590    !.
  591split_rule((Module:Head => Body), (Module:Expanded => Body),
  592           Module, Head, Expanded) :-
  593    callable(Head),
  594    atom(Module),
  595    !.
  596split_rule((Head,Guard => Body), (Expanded,Guard => Body),
  597           Module, Head, Expanded) :-
  598    callable(Head),
  599    prolog_load_context(module, Module),
  600    !.
  601split_rule((Head => Body), (Expanded => Body),
  602           Module, Head, Expanded) :-
  603    callable(Head),
  604    prolog_load_context(module, Module).
  605
  606system:goal_expansion(G, Expanded) :-
  607    \+ predicate_property(G, iso),
  608    prolog_load_context(module, LM),
  609    predicate_property(LM:G, implementation_module(IM)),
  610    rdf_meta_specification(G, IM, Spec),
  611    rdf_expand(G, Spec, Expanded, LM).
  612
  613system:term_expansion(Module:Fact, Expanded) :-
  614    atom(Module),
  615    rdf_meta_specification(Fact, Module, Spec),
  616    rdf_expand(Fact, Spec, ExpandedFact, Module),
  617    Fact \== ExpandedFact,
  618    Expanded = (Module:ExpandedFact).
  619system:term_expansion(Fact, Expanded) :-
  620    prolog_load_context(module, Module),
  621    rdf_meta_specification(Fact, Module, Spec),
  622    rdf_expand(Fact, Spec, Expanded, Module),
  623    Fact \== Expanded.
  624system:term_expansion(Clause0, Clause) :-
  625    split_rule(Clause0, Clause, Module, Head, Expanded),
  626    rdf_meta_specification(Head, Module, Spec),
  627    rdf_expand(Head, Spec, Expanded, Module),
  628    Head \== Expanded.
  629
  630rdf_expand(G, Spec, Expanded, M) :-
  631    functor(G, Name, Arity),
  632    functor(Expanded, Name, Arity),
  633    rdf_expand_args(0, Arity, G, Spec, Expanded, M).
  634
  635rdf_expand_args(Arity, Arity, _, _, _, _) :- !.
  636rdf_expand_args(I0, Arity, Goal, Spec, Expanded, M) :-
  637    I is I0 + 1,
  638    arg(I, Goal, GA),
  639    arg(I, Spec, SA),
  640    arg(I, Expanded, EA),
  641    rdf_expand_arg(SA, GA, EA, M),
  642    rdf_expand_args(I, Arity, Goal, Spec, Expanded, M).
  643
  644rdf_expand_arg(r, A, E, M) :-
  645    mk_global(A, E, M),
  646    !.
  647rdf_expand_arg(o, A, E, M) :-
  648    rdf_global_object(A, E, M),
  649    !.
  650rdf_expand_arg(t, A, E, M) :-
  651    rdf_global_term(A, E, M),
  652    !.
  653rdf_expand_arg(g, A, E, M) :-
  654    rdf_global_graph(A, E, M),
  655    !.
  656rdf_expand_arg(:, A, E, _M) :-
  657    !,
  658    expand_goal(A, E).
  659rdf_expand_arg(_, A, A, _M).
  660
  661%!  mk_global(+Src, -Resource, +Module)
  662%
  663%   Realised rdf_global_id(+, -), but adds compiletime checking,
  664%   notably to see whether a namespace is not yet defined.
  665
  666mk_global(X, X, _) :-
  667    var(X),
  668    !.
  669mk_global(X, X, _) :-
  670    atom(X),
  671    !.
  672mk_global(Prefix:Local, Global, Module) :-
  673    must_be(atom, Prefix),
  674    must_be(atom, Local),
  675    (   rdf_current_prefix(Module:Prefix, Full)
  676    ->  atom_concat(Full, Local, Global)
  677    ;   current_prolog_flag(xref, true)
  678    ->  Global = Prefix:Local
  679    ;   existence_error(rdf_prefix, Prefix)
  680    )