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, 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(+, :).   65
   66/** <module> RDF prefixes management
   67
   68This module defines the expansion of  `Prefix:Local` terms to full IRIs.
   69This library is typically not  intended  for   the  end-user.  It may be
   70included into other RDF and XML  libraries   and  relevant  parts may be
   71re-exported.
   72*/
   73
   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		 *******************************/
   87
   88%!  rdf_empty_prefix_cache(+Alias, +URI)
   89%
   90%   Multifile hook called if the binding Alias   -> URI is modified. May
   91%   be used to update derived caches.
   92
   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
  100
  101%!  rdf_current_prefix(:Alias, ?URI) is nondet.
  102%
  103%   Query   predefined   prefixes   and    prefixes   defined   with
  104%   rdf_register_prefix/2   and   local   prefixes    defined   with
  105%   rdf_prefix/2. If Alias is unbound and one   URI is the prefix of
  106%   another, the longest is returned first.   This  allows turning a
  107%   resource into a prefix/local couple using the simple enumeration
  108%   below. See rdf_global_id/2.
  109%
  110%     ==
  111%     rdf_current_prefix(Prefix, Expansion),
  112%     atom_concat(Expansion, Local, URI),
  113%     ==
  114
  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    ).
  133
  134%!  rdf_prefix(:Alias, +URI) is det.
  135%
  136%   Register a _local_ prefix.  This   declaration  takes precedence
  137%   over globally defined prefixes   using  rdf_register_prefix/2,3.
  138%   Module local prefixes are notably required   to deal with SWISH,
  139%   where users need to  be  able   to  have  independent  namespace
  140%   declarations.
  141
  142rdf_prefix(Alias, URI) :-
  143    throw(error(context_error(nodirective, rdf_prefix(Alias, URI)), _)).
  144
  145system:term_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    ).
  156
  157%!  rdf_db:ns(?Alias, ?URI) is nondet.
  158%
  159%   Dynamic and multifile predicate that   maintains  the registered
  160%   namespace aliases.
  161%
  162%   @deprecated New code  must  modify   the  namespace  table using
  163%   rdf_register_ns/3 and query using rdf_current_ns/2.
  164
  165rdf_db:ns(dc,      'http://purl.org/dc/elements/1.1/').
  166rdf_db:ns(dcterms, 'http://purl.org/dc/terms/').
  167rdf_db:ns(eor,     'http://dublincore.org/2000/03/13/eor#').
  168rdf_db:ns(foaf,    'http://xmlns.com/foaf/0.1/').
  169rdf_db:ns(owl,     'http://www.w3.org/2002/07/owl#').
  170rdf_db:ns(rdf,     'http://www.w3.org/1999/02/22-rdf-syntax-ns#').
  171rdf_db:ns(rdfs,    'http://www.w3.org/2000/01/rdf-schema#').
  172rdf_db:ns(serql,   'http://www.openrdf.org/schema/serql#').
  173rdf_db:ns(skos,    'http://www.w3.org/2004/02/skos/core#').
  174rdf_db:ns(void,    'http://rdfs.org/ns/void#').
  175rdf_db:ns(xsd,     'http://www.w3.org/2001/XMLSchema#').
  176
  177%!  rdf_register_prefix(+Prefix, +URI) is det.
  178%!  rdf_register_prefix(+Prefix, +URI, +Options) is det.
  179%
  180%   Register Prefix as an abbreviation for URI. Options:
  181%
  182%           * force(Boolean)
  183%           If =true=, replace existing namespace alias. Please note
  184%           that replacing a namespace is dangerous as namespaces
  185%           affect preprocessing. Make sure all code that depends on
  186%           a namespace is compiled after changing the registration.
  187%
  188%           * keep(Boolean)
  189%           If =true= and Alias is already defined, keep the
  190%           original binding for Prefix and succeed silently.
  191%
  192%   Without options, an attempt  to  redefine   an  alias  raises  a
  193%   permission error.
  194%
  195%   Predefined prefixes are:
  196%
  197%   | **Alias** | **IRI prefix**                              |
  198%   | dc        | http://purl.org/dc/elements/1.1/            |
  199%   | dcterms   | http://purl.org/dc/terms/                   |
  200%   | eor       | http://dublincore.org/2000/03/13/eor#       |
  201%   | foaf      | http://xmlns.com/foaf/0.1/                  |
  202%   | owl       | http://www.w3.org/2002/07/owl#              |
  203%   | rdf       | http://www.w3.org/1999/02/22-rdf-syntax-ns# |
  204%   | rdfs      | http://www.w3.org/2000/01/rdf-schema#       |
  205%   | serql     | http://www.openrdf.org/schema/serql#        |
  206%   | skos      | http://www.w3.org/2004/02/skos/core#        |
  207%   | void      | http://rdfs.org/ns/void#                    |
  208%   | xsd       | http://www.w3.org/2001/XMLSchema#           |
  209
  210
  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    ).
  221
  222%!  register_global_prefix(+Alias, +URI, +Options)
  223%
  224%   Register a global prefix.
  225
  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).
  258
  259%!  rdf_unregister_prefix(+Alias) is det.
  260%
  261%   Delete a prefix global registration.
  262
  263rdf_unregister_prefix(Alias) :-
  264    must_be(atom, Alias),
  265    retractall(rdf_db:ns(Alias, _)).
  266
  267
  268%!  rdf_current_ns(:Prefix, ?URI) is nondet.
  269%
  270%   @deprecated  Use rdf_current_prefix/2.
  271
  272rdf_current_ns(Prefix, URI) :-
  273    rdf_current_prefix(Prefix, URI).
  274
  275%!  rdf_register_ns(:Prefix, ?URI) is det.
  276%!  rdf_register_ns(:Prefix, ?URI, +Options) is det.
  277%
  278%   Register an RDF prefix.
  279%
  280%   @deprecated  Use rdf_register_prefix/2 or rdf_register_prefix/3.
  281
  282rdf_register_ns(Prefix, URI) :-
  283    rdf_register_prefix(Prefix, URI).
  284rdf_register_ns(Prefix, URI, Options) :-
  285    rdf_register_prefix(Prefix, URI, Options).
  286
  287
  288%!  register_file_prefixes(+Map:list(pair)) is det.
  289%
  290%   Register a namespace as encounted in   the  namespace list of an
  291%   RDF document. We only register if  both the abbreviation and URL
  292%   are not already known. Is there a   better  way? This code could
  293%   also do checks on the consistency   of  RDF and other well-known
  294%   namespaces.
  295%
  296%   @tbd    Better error handling
  297
  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    ).
  316
  317
  318%!  rdf_global_id(?IRISpec, :IRI) is semidet.
  319%
  320%   Convert between Prefix:Local and full IRI   (an atom). If IRISpec is
  321%   an atom, it  is  simply  unified   with  IRI.  This  predicate fails
  322%   silently if IRI is an RDF literal.
  323%
  324%   Note that this predicate is a meta-predicate on its output argument.
  325%   This is necessary to get the module context while the first argument
  326%   may be of the form (:)/2. The above mode description is correct, but
  327%   should be interpreted as (?,?).
  328%
  329%   @error existence_error(rdf_prefix, Prefix)
  330%   @see   rdf_equal/2 provides a compile time alternative
  331%   @see   The rdf_meta/1 directive asks for compile time expansion
  332%          of arguments.
  333%   @bug   Error handling is incomplete.  In its current implementation
  334%	   the same code is used for compile-time expansion and to
  335%	   facilitate runtime conversion and checking.  These use cases
  336%	   have different requirements.
  337
  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, _).
  345
  346
  347%!  rdf_global_object(+Object, :GlobalObject) is semidet.
  348%!  rdf_global_object(-Object, :GlobalObject) is semidet.
  349%
  350%   Same as rdf_global_id/2,  but  intended   for  dealing  with the
  351%   object part of a  triple,  in   particular  the  type  for typed
  352%   literals. Note that the predicate  is   a  meta-predicate on the
  353%   output argument. This is necessary  to   get  the module context
  354%   while the first argument may be of the form (:)/2.
  355%
  356%   @error  existence_error(rdf_prefix, Prefix)
  357
  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    ).
  399
  400
  401%!  rdf_global_term(+TermIn, :GlobalTerm) is det.
  402%
  403%   Performs rdf_global_id/2 on predixed IRIs and rdf_global_object/2 on
  404%   RDF literals, by recursively  analysing  the   term.  Note  that the
  405%   predicate is a meta-predicate  on  the   output  argument.  This  is
  406%   necessary to get the module context while  the first argument may be
  407%   of the form (:)/2.
  408%
  409%   Terms of the form `Prefix:Local`  that   appear  in TermIn for which
  410%   `Prefix` is not defined are not replaced. Unlike rdf_global_id/2 and
  411%   rdf_global_object/2, no error is raised.
  412
  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, _).
  435
  436%!  rdf_global_graph(+TermIn, -GlobalTerm, +Module) is det.
  437%
  438%   Preforms rdf_global_id/2 on rdf/4, etc graph arguments
  439
  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
  455system:term_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), _)).
  507
  508%!  rdf_meta(+Heads)
  509%
  510%   This  directive  defines  the  argument    types  of  the  named
  511%   predicates, which will force compile   time  namespace expansion
  512%   for these predicates. Heads is a coma-separated list of callable
  513%   terms. Defined argument properties are:
  514%
  515%     $ : :
  516%     Argument is a goal. The goal is processed using expand_goal/2,
  517%     recursively applying goal transformation on the argument.
  518%
  519%     $ + :
  520%     The argument is instantiated at entry. Nothing is changed.
  521%
  522%     $ - :
  523%     The argument is not instantiated at entry. Nothing is changed.
  524%
  525%     $ ? :
  526%     The argument is unbound or instantiated at entry. Nothing is
  527%     changed.
  528%
  529%     $ @ :
  530%     The argument is not changed.
  531%
  532%     $ r :
  533%     The argument must be a resource. If it is a term
  534%     _prefix_:_local_ it is translated.
  535%
  536%     $ o :
  537%     The argument is an object or resource. See
  538%     rdf_global_object/2.
  539%
  540%     $ t :
  541%     The argument is a term that must be translated. Expansion will
  542%     translate all occurences of _prefix_:_local_ appearing
  543%     anywhere in the term. See rdf_global_term/2.
  544%
  545%   As it is subject to term_expansion/2, the rdf_meta/1 declaration
  546%   can only be used as a directive. The directive must be processed
  547%   before the definition of  the  predicates   as  well  as  before
  548%   compiling code that  uses  the   rdf  meta-predicates.  The atom
  549%   =rdf_meta=  is  declared   as   an    operator   exported   from
  550%   library(semweb/rdf_db). Files using rdf_meta/1  must explicitely
  551%   load this library.
  552%
  553%   Beginning with SWI-Prolog 7.3.17, the   low-level  RDF interface
  554%   (rdf/3,  rdf_assert/3,  etc.)  perform    runtime  expansion  of
  555%   `Prefix:Local` terms. This eliminates the   need  for rdf_meta/1
  556%   for  simple  cases.  However,  runtime   expansion  comes  at  a
  557%   significant overhead and having two  representations for IRIs (a
  558%   plain atom and  a  term   `Prefix:Local`)  implies  that  simple
  559%   operations such as comparison of IRIs   no  longer map to native
  560%   Prolog operations such as `IRI1 == IRI2`.
  561
  562rdf_meta(Heads) :-
  563    throw(error(context_error(nodirective, rdf_meta(Heads)), _)).
  564
  565%!  rdf_meta_specification(+General, +Module, -Spec) is semidet.
  566%
  567%   True when Spec is the RDF meta specification for Module:General.
  568%
  569%   @arg    General is the term Spec with all arguments replaced with
  570%           variables.
  571
  572rdf_meta_specification(Unbounded, Module, Spec) :-
  573    '$flushed_predicate'(Module:'rdf meta specification'(_,_)),
  574    call(Module:'rdf meta specification'(Unbounded, Spec)).
  575
  576system:goal_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
  583system:term_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).
  589system:term_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.
  594system:term_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).
  600system:term_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).
  636
  637%!  mk_global(+Src, -Resource, +Module)
  638%
  639%   Realised rdf_global_id(+, -), but adds compiletime checking,
  640%   notably to see whether a namespace is not yet defined.
  641
  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    )