View source with raw 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)  2003-2017, 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(rdf_db,
   37          [ rdf_version/1,              % -Version
   38
   39            rdf/3,                      % ?Subject, ?Predicate, ?Object
   40            rdf/4,                      % ?Subject, ?Predicate, ?Object, ?DB
   41            rdf_has/3,                  % ?Subject, +Pred, ?Obj
   42            rdf_has/4,                  % ?Subject, +Pred, ?Obj, -RealPred
   43            rdf_reachable/3,            % ?Subject, +Pred, ?Object
   44            rdf_reachable/5,            % ?Subject, +Pred, ?Object, +MaxD, ?D
   45            rdf_resource/1,             % ?Resource
   46            rdf_subject/1,              % ?Subject
   47
   48            rdf_member_property/2,      % ?Property, ?Index
   49
   50            rdf_assert/3,               % +Subject, +Predicate, +Object
   51            rdf_assert/4,               % +Subject, +Predicate, +Object, +DB
   52            rdf_retractall/3,           % ?Subject, ?Predicate, ?Object
   53            rdf_retractall/4,           % ?Subject, ?Predicate, ?Object, +DB
   54            rdf_update/4,               % +Subject, +Predicate, +Object, +Act
   55            rdf_update/5,               % +Subject, +Predicate, +Object, +Src, +Act
   56            rdf_set_predicate/2,        % +Predicate, +Property
   57            rdf_predicate_property/2,   % +Predicate, ?Property
   58            rdf_current_predicate/1,    % -Predicate
   59            rdf_current_literal/1,      % -Literal
   60            rdf_transaction/1,          % :Goal
   61            rdf_transaction/2,          % :Goal, +Id
   62            rdf_transaction/3,          % :Goal, +Id, +Options
   63            rdf_active_transaction/1,   % ?Id
   64
   65            rdf_monitor/2,              % :Goal, +Options
   66
   67            rdf_save_db/1,              % +File
   68            rdf_save_db/2,              % +File, +DB
   69            rdf_load_db/1,              % +File
   70            rdf_reset_db/0,
   71
   72            rdf_node/1,                 % -Id
   73            rdf_bnode/1,                % -Id
   74            rdf_is_bnode/1,             % +Id
   75
   76            rdf_is_resource/1,          % +Term
   77            rdf_is_literal/1,           % +Term
   78            rdf_literal_value/2,        % +Term, -Value
   79
   80            rdf_load/1,                 % +File
   81            rdf_load/2,                 % +File, +Options
   82            rdf_save/1,                 % +File
   83            rdf_save/2,                 % +File, +Options
   84            rdf_unload/1,               % +File
   85            rdf_unload_graph/1,         % +Graph
   86
   87            rdf_md5/2,                  % +DB, -MD5
   88            rdf_atom_md5/3,             % +Text, +Times, -MD5
   89
   90            rdf_create_graph/1,         % ?Graph
   91            rdf_graph_property/2,       % ?Graph, ?Property
   92            rdf_set_graph/2,            % +Graph, +Property
   93            rdf_graph/1,                % ?Graph
   94            rdf_source/1,               % ?File
   95            rdf_source/2,               % ?DB, ?SourceURL
   96            rdf_make/0,                 % Reload modified databases
   97            rdf_gc/0,                   % Garbage collection
   98
   99            rdf_source_location/2,      % +Subject, -Source
  100            rdf_statistics/1,           % -Key
  101            rdf_set/1,                  % +Term
  102            rdf_generation/1,           % -Generation
  103            rdf_snapshot/1,             % -Snapshot
  104            rdf_delete_snapshot/1,      % +Snapshot
  105            rdf_current_snapshot/1,     % +Snapshot
  106            rdf_estimate_complexity/4,  % +S,+P,+O,-Count
  107
  108            rdf_save_subject/3,         % +Stream, +Subject, +DB
  109            rdf_save_header/2,          % +Out, +Options
  110            rdf_save_footer/1,          % +Out
  111
  112            rdf_equal/2,                % ?Resource, ?Resource
  113            lang_equal/2,               % +Lang1, +Lang2
  114            lang_matches/2,             % +Lang, +Pattern
  115
  116            rdf_prefix/2,               % :Alias, +URI
  117            rdf_current_prefix/2,       % :Alias, ?URI
  118            rdf_register_prefix/2,      % +Alias, +URI
  119            rdf_register_prefix/3,      % +Alias, +URI, +Options
  120            rdf_current_ns/2,           % :Alias, ?URI
  121            rdf_register_ns/2,          % +Alias, +URI
  122            rdf_register_ns/3,          % +Alias, +URI, +Options
  123            rdf_global_id/2,            % ?NS:Name, :Global
  124            rdf_global_object/2,        % +Object, :NSExpandedObject
  125            rdf_global_term/2,          % +Term, :WithExpandedNS
  126
  127            rdf_compare/3,              % -Dif, +Object1, +Object2
  128            rdf_match_label/3,          % +How, +String, +Label
  129            rdf_split_url/3,            % ?Base, ?Local, ?URL
  130            rdf_url_namespace/2,        % +URL, ?Base
  131
  132            rdf_warm_indexes/0,
  133            rdf_warm_indexes/1,         % +Indexed
  134            rdf_update_duplicates/0,
  135
  136            rdf_debug/1,                % Set verbosity
  137
  138            rdf_new_literal_map/1,      % -Handle
  139            rdf_destroy_literal_map/1,  % +Handle
  140            rdf_reset_literal_map/1,    % +Handle
  141            rdf_insert_literal_map/3,   % +Handle, +Key, +Literal
  142            rdf_insert_literal_map/4,   % +Handle, +Key, +Literal, -NewKeys
  143            rdf_delete_literal_map/3,   % +Handle, +Key, +Literal
  144            rdf_delete_literal_map/2,   % +Handle, +Key
  145            rdf_find_literal_map/3,     % +Handle, +KeyList, -Literals
  146            rdf_keys_in_literal_map/3,  % +Handle, +Spec, -Keys
  147            rdf_statistics_literal_map/2, % +Handle, +Name(-Arg...)
  148
  149            rdf_graph_prefixes/2,       % ?Graph, -Prefixes
  150            rdf_graph_prefixes/3,       % ?Graph, -Prefixes, :Filter
  151
  152            (rdf_meta)/1,               % +Heads
  153            op(1150, fx, (rdf_meta))
  154          ]).  155:- use_module(library(rdf)).  156:- use_module(library(lists)).  157:- use_module(library(pairs)).  158:- use_module(library(shlib)).  159:- use_module(library(gensym)).  160:- use_module(library(sgml)).  161:- use_module(library(sgml_write)).  162:- use_module(library(option)).  163:- use_module(library(error)).  164:- use_module(library(uri)).  165:- use_module(library(debug)).  166:- use_module(library(apply)).  167:- use_module(library(xsdp_types)).  168:- if(exists_source(library(thread))).  169:- use_module(library(thread)).  170:- endif.  171:- use_module(library(semweb/rdf_cache)).  172
  173:- use_foreign_library(foreign(rdf_db)).  174:- public rdf_print_predicate_cloud/2.  % print matrix of reachable predicates
  175
  176:- meta_predicate
  177    rdf_current_prefix(:, -),
  178    rdf_current_ns(:, -),
  179    rdf_global_id(?, :),
  180    rdf_global_term(+, :),
  181    rdf_global_object(+, :),
  182    rdf_transaction(0),
  183    rdf_transaction(0, +),
  184    rdf_transaction(0, +, +),
  185    rdf_monitor(1, +),
  186    rdf_save(+, :),
  187    rdf_load(+, :).  188
  189:- predicate_options(rdf_graph_prefixes/3, 3,
  190                     [expand(callable), filter(callable), min_count(nonneg)]).  191:- predicate_options(rdf_load/2, 2,
  192                     [ base_uri(atom),
  193                       cache(boolean),
  194                       concurrent(positive_integer),
  195                       db(atom),
  196                       format(oneof([xml,triples,turtle,trig,nquads,ntriples])),
  197                       graph(atom),
  198                       if(oneof([true,changed,not_loaded])),
  199                       modified(-float),
  200                       silent(boolean),
  201                       register_namespaces(boolean)
  202                     ]).  203:- predicate_options(rdf_register_ns/3, 3, [force(boolean), keep(boolean)]).  204:- predicate_options(rdf_save/2, 2,
  205                     [ graph(atom),
  206                       db(atom),
  207                       anon(boolean),
  208                       base_uri(atom),
  209                       write_xml_base(boolean),
  210                       convert_typed_literal(callable),
  211                       encoding(encoding),
  212                       document_language(atom),
  213                       namespaces(list(atom)),
  214                       xml_attributes(boolean),
  215                       inline(boolean)
  216                     ]).  217:- predicate_options(rdf_save_header/2, 2,
  218                     [ graph(atom),
  219                       db(atom),
  220                       namespaces(list(atom))
  221                     ]).  222:- predicate_options(rdf_save_subject/3, 3,
  223                     [ graph(atom),
  224                       base_uri(atom),
  225                       convert_typed_literal(callable),
  226                       document_language(atom)
  227                     ]).  228:- predicate_options(rdf_transaction/3, 3,
  229                     [ snapshot(any)
  230                     ]).  231
  232:- multifile ns/2.  233:- dynamic   ns/2.                      % ID, URL
  234:- discontiguous
  235    term_expansion/2.

Core RDF database

The file library(semweb/rdf_db) provides the core of the SWI-Prolog RDF store.

deprecated
-
New applications should use library(semweb/rdf11), which provides a much more intuitive API to the RDF store, notably for handling literals. The library(semweb/rdf11) runs currently on top of this library and both can run side-by-side in the same application. Terms retrieved from the database however have a different shape and can not be exchanged without precautions. */
  251                 /*******************************
  252                 *           PREFIXES           *
  253                 *******************************/
 rdf_current_prefix(:Alias, ?URI) is nondet
Query predefined prefixes and prefixes defined with rdf_register_prefix/2 and local prefixes defined with rdf_prefix/2. If Alias is unbound and one URI is the prefix of another, the longest is returned first. This allows turning a resource into a prefix/local couple using the simple enumeration below. See rdf_global_id/2.
rdf_current_prefix(Prefix, Expansion),
atom_concat(Expansion, Local, URI),
  269rdf_current_prefix(Module:Alias, URI) :-
  270    nonvar(Alias),
  271    !,
  272    rdf_current_prefix(Module, Alias, URI),
  273    !.
  274rdf_current_prefix(Module:Alias, URI) :-
  275    rdf_current_prefix(Module, Alias, URI).
  276
  277rdf_current_prefix(system, Alias, URI) :-
  278    !,
  279    ns(Alias, URI).
  280rdf_current_prefix(Module, Alias, URI) :-
  281    default_module(Module, M),
  282    (   M == system
  283    ->  ns(Alias, URI)
  284    ;   '$flushed_predicate'(M:'rdf prefix'(_,_)),
  285        call(M:'rdf prefix'(Alias,URI))
  286    ).
 rdf_prefix(:Alias, +URI) is det
Register a local prefix. This declaration takes precedence over globally defined prefixes using rdf_register_prefix/2,3. Module local prefixes are notably required to deal with SWISH, where users need to be able to have independent namespace declarations.
  296rdf_prefix(Alias, URI) :-
  297    throw(error(context_error(nodirective, rdf_prefix(Alias, URI)), _)).
  298
  299system:term_expansion((:- rdf_prefix(AliasSpec, URI)), Clauses) :-
  300    prolog_load_context(module, Module),
  301    strip_module(Module:AliasSpec, TM, Alias),
  302    must_be(atom, Alias),
  303    must_be(atom, URI),
  304    (   rdf_current_prefix(TM:Alias, URI)
  305    ->  Clauses = []
  306    ;   TM == Module
  307    ->  Clauses = 'rdf prefix'(Alias, URI)
  308    ;   Clauses = TM:'rdf prefix'(Alias, URI)
  309    ).
 ns(?Alias, ?URI) is nondet
Dynamic and multifile predicate that maintains the registered namespace aliases.
deprecated
- New code must modify the namespace table using rdf_register_ns/3 and query using rdf_current_ns/2.
  319ns(dc,      'http://purl.org/dc/elements/1.1/').
  320ns(dcterms, 'http://purl.org/dc/terms/').
  321ns(eor,     'http://dublincore.org/2000/03/13/eor#').
  322ns(foaf,    'http://xmlns.com/foaf/0.1/').
  323ns(owl,     'http://www.w3.org/2002/07/owl#').
  324ns(rdf,     'http://www.w3.org/1999/02/22-rdf-syntax-ns#').
  325ns(rdfs,    'http://www.w3.org/2000/01/rdf-schema#').
  326ns(serql,   'http://www.openrdf.org/schema/serql#').
  327ns(skos,    'http://www.w3.org/2004/02/skos/core#').
  328ns(void,    'http://rdfs.org/ns/void#').
  329ns(xsd,     'http://www.w3.org/2001/XMLSchema#').
 rdf_register_prefix(+Prefix, +URI) is det
 rdf_register_prefix(+Prefix, +URI, +Options) is det
Register Prefix as an abbreviation for URI. Options:
force(Boolean)
If 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.
keep(Boolean)
If 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:

AliasIRI prefix
dchttp://purl.org/dc/elements/1.1/
dctermshttp://purl.org/dc/terms/
eorhttp://dublincore.org/2000/03/13/eor#
foafhttp://xmlns.com/foaf/0.1/
owlhttp://www.w3.org/2002/07/owl#
rdfhttp://www.w3.org/1999/02/22-rdf-syntax-ns#
rdfshttp://www.w3.org/2000/01/rdf-schema#
serqlhttp://www.openrdf.org/schema/serql#
skoshttp://www.w3.org/2004/02/skos/core#
voidhttp://rdfs.org/ns/void#
xsdhttp://www.w3.org/2001/XMLSchema#
  365rdf_register_prefix(Alias, URI) :-
  366    rdf_register_prefix(Alias, URI, []).
  367
  368rdf_register_prefix(Alias, URI, Options) :-
  369    must_be(atom, Alias),
  370    must_be(atom, URI),
  371    (   rdf_current_prefix(system:Alias, URI)
  372    ->  true
  373    ;   register_global_prefix(Alias, URI, Options)
  374    ).
 register_global_prefix(+Alias, +URI, +Options)
Register a global prefix.
  380register_global_prefix(Alias, URI, Options) :-
  381    ns(Alias, _),
  382    !,
  383    (   option(force(true), Options, false)
  384    ->  retractall(ns(Alias, _)),
  385        rdf_register_prefix(Alias, URI, Options),
  386        rdf_empty_prefix_cache
  387    ;   option(keep(true), Options, false)
  388    ->  true
  389    ;   throw(error(permission_error(register, namespace, Alias),
  390                    context(_, 'Already defined')))
  391    ).
  392register_global_prefix(Alias, URI, _) :-
  393    findall(P-U, prefix_conflict(URI, P, U), Pairs),
  394    order_prefixes([Alias-URI|Pairs], Ordered),
  395    forall(member(P-U, Pairs), retract(ns(P,U))),
  396    forall(member(P-U, Ordered), assert(ns(P,U))).
  397
  398prefix_conflict(URI, P, U) :-
  399    ns(P,U),
  400    (   sub_atom(URI, 0, _, _, U)
  401    ->  true
  402    ;   sub_atom(U, 0, _, _, URI)
  403    ).
  404
  405order_prefixes(Pairs, Sorted) :-
  406    map_list_to_pairs(prefix_uri_length, Pairs, ByLen),
  407    sort(1, >=, ByLen, SortedByLen),
  408    pairs_values(SortedByLen, Sorted).
  409
  410prefix_uri_length(_-URI, Len) :-
  411    atom_length(URI, Len).
 rdf_current_ns(:Prefix, ?URI) is nondet
deprecated
- . Use rdf_current_prefix/2.
  417rdf_current_ns(Prefix, URI) :-
  418    rdf_current_prefix(Prefix, URI).
 rdf_register_ns(:Prefix, ?URI) is det
 rdf_register_ns(:Prefix, ?URI, +Options) is det
Register an RDF prefix.
deprecated
- . Use rdf_register_prefix/2 or rdf_register_prefix/3.
  427rdf_register_ns(Prefix, URI) :-
  428    rdf_register_prefix(Prefix, URI).
  429rdf_register_ns(Prefix, URI, Options) :-
  430    rdf_register_prefix(Prefix, URI, Options).
 register_file_ns(+Map:list(pair)) is det
Register a namespace as encounted in the namespace list of an RDF document. We only register if both the abbreviation and URL are not already known. Is there a better way? This code could also do checks on the consistency of RDF and other well-known namespaces.
To be done
- Better error handling
  443register_file_ns([]) :- !.
  444register_file_ns([Decl|T]) :-
  445    !,
  446    register_file_ns(Decl),
  447    register_file_ns(T).
  448register_file_ns([]=_) :- !.            % xmlns= (overall default)
  449register_file_ns(NS=URL) :-            % compatibility
  450    !,
  451    register_file_ns(NS-URL).
  452register_file_ns(NS-URL) :-
  453    (   ns(NS, URL)
  454    ->  true
  455    ;   ns(NS, _)
  456    ->  true                        % redefined abbreviation
  457    ;   ns(_, URL)
  458    ->  true                        % redefined URL
  459    ;   rdf_register_ns(NS, URL)
  460    ).
 rdf_global_id(?IRISpec, :IRI) is semidet
Convert between Prefix:Local and full IRI (an atom). If IRISpec is an atom, it is simply unified with IRI. This predicate fails silently if IRI is an RDF literal.

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 (?,?).

Errors
- existence_error(rdf_prefix, Prefix)
See also
- rdf_equal/2 provides a compile time alternative
- The rdf_meta/1 directive asks for compile time expansion of arguments.
bug
- Error handling is incomplete. In its current implementation the same code is used for compile-time expansion and to facilitate runtime conversion and checking. These use cases have different requirements.
  483rdf_global_id(Id, Module:Global) :-
  484    rdf_global_id(Id, Global, Module).
  485
  486rdf_global_id(NS:Local, Global, Module) :-
  487    global(NS, Local, Global, Module),
  488    !.
  489rdf_global_id(Global, Global, _).
 rdf_global_object(+Object, :GlobalObject) is semidet
rdf_global_object(-Object, :GlobalObject) is semidet
Same as rdf_global_id/2, but intended for dealing with the object part of a triple, in particular the type for typed literals. Note that the predicate is a meta-predicate on the output argument. This is necessary to get the module context while the first argument may be of the form (:)/2.
Errors
- existence_error(rdf_prefix, Prefix)
  503rdf_global_object(Object, Module:GlobalObject) :-
  504    rdf_global_object(Object, GlobalObject, Module).
  505
  506rdf_global_object(Var, Global, _M) :-
  507    var(Var),
  508    !,
  509    Global = Var.
  510rdf_global_object(Prefix:Local, Global, M) :-
  511    global(Prefix, Local, Global, M),
  512    !.
  513rdf_global_object(literal(type(Prefix:Local, Value)),
  514                  literal(type(Global, Value)), M) :-
  515    global(Prefix, Local, Global, M),
  516    !.
  517rdf_global_object(^^(Value,Prefix:Local),
  518                  ^^(Value,Global), M) :-
  519    global(Prefix, Local, Global, M),
  520    !.
  521rdf_global_object(literal(Query0, type(Prefix:Local, Value)),
  522                  literal(Query1, type(Global, Value)), M) :-
  523    global(Prefix, Local, Global, M),
  524    !,
  525    rdf_global_term(Query0, Query1, M).
  526rdf_global_object(literal(Query0, Value),
  527                  literal(Query1, Value), M) :-
  528    !,
  529    rdf_global_term(Query0, Query1, M).
  530rdf_global_object(Global, Global, _).
  531
  532global(Prefix, Local, Global, Module) :-
  533    (   atom(Global)
  534    ->  rdf_current_prefix(Module:Prefix, Full),
  535        atom_concat(Full, Local, Global)
  536    ;   atom(Prefix), atom(Local), var(Global)
  537    ->  (   rdf_current_prefix(Module:Prefix, Full)
  538        *-> atom_concat(Full, Local, Global)
  539        ;   current_prolog_flag(xref, true)
  540        ->  Global = Prefix:Local
  541        ;   existence_error(rdf_prefix, Prefix)
  542        )
  543    ).
 rdf_global_term(+TermIn, :GlobalTerm) is det
Does rdf_global_id/2 on all terms NS:Local by recursively analysing the term. Note that the predicate is a meta-predicate on the output argument. This is necessary to get the module context while the first argument may be of the form (:)/2.

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.

  557rdf_global_term(TermIn, Module:TermOut) :-
  558    rdf_global_term(TermIn, TermOut, Module).
  559
  560rdf_global_term(Var, Var, _M) :-
  561    var(Var),
  562    !.
  563rdf_global_term(Prefix:Local, Global, Module) :-
  564    atom(Prefix), atom(Local),
  565    rdf_current_prefix(Module:Prefix, Full),
  566    !,
  567    atom_concat(Full, Local, Global).
  568rdf_global_term([H0|T0], [H|T], M) :-
  569    !,
  570    rdf_global_term(H0, H, M),
  571    rdf_global_term(T0, T, M).
  572rdf_global_term(Term0, Term, M) :-
  573    compound(Term0),
  574    !,
  575    Term0 =.. [H|L0],
  576    rdf_global_term(L0, L, M),
  577    Term =.. [H|L].
  578rdf_global_term(Term, Term, _).
 rdf_global_graph(+TermIn, -GlobalTerm, +Module) is det
Preforms rdf_global_id/2 on rdf/4, etc graph arguments
  584rdf_global_graph(Prefix:Local, Global, Module) :-
  585    atom(Prefix), atom(Local),
  586    !,
  587    global(Prefix, Local, Global, Module).
  588rdf_global_graph(G, G, _).
  589
  590
  591                 /*******************************
  592                 *            EXPANSION         *
  593                 *******************************/
  594
  595:- multifile
  596    system:term_expansion/2,
  597    system:goal_expansion/2.  598
  599system:term_expansion((:- rdf_meta(Heads)), Clauses) :-
  600    prolog_load_context(module, M),
  601    phrase(mk_clauses(Heads, M), Clauses).
  602
  603mk_clauses((A,B), M) -->
  604    mk_clause(A, M),
  605    mk_clauses(B, M).
  606mk_clauses(A, M) -->
  607    mk_clause(A, M).
  608
  609mk_clause(Head0, M0) -->
  610    { strip_module(M0:Head0, Module, Head),
  611      valid_rdf_meta_head(Head),
  612      functor(Head, Name, Arity),
  613      functor(Unbound, Name, Arity),
  614      qualify(Module, 'rdf meta specification'/2, Decl)
  615    },
  616    [ (:- multifile(Decl)),
  617      Module:'rdf meta specification'(Unbound, Head)
  618    ].
  619
  620qualify(Module, Decl, Decl) :-
  621    prolog_load_context(module, Module),
  622    !.
  623qualify(Module, Decl, Module:Decl).
  624
  625
  626valid_rdf_meta_head(Head) :-
  627    callable(Head),
  628    !,
  629    Head =.. [_|Args],
  630    valid_args(Args).
  631valid_rdf_meta_head(Head) :-
  632    throw(error(type_error(callable, Head), _)).
  633
  634valid_args([]).
  635valid_args([H|T]) :-
  636    valid_arg(H),
  637    !,
  638    valid_args(T).
  639
  640valid_arg(:).                           % meta argument
  641valid_arg(+).                           % non-var
  642valid_arg(-).                           % var
  643valid_arg(?).                           % either var or non-var
  644valid_arg(@).                           % not modified
  645valid_arg(r).                           % RDF resource
  646valid_arg(o).                           % RDF object
  647valid_arg(t).                           % term with RDF resources
  648valid_arg(g).                           % graph argument
  649valid_arg(A) :-
  650    throw(error(type_error(rdf_meta_argument, A), _)).
 rdf_meta +Heads
This directive defines the argument types of the named predicates, which will force compile time namespace expansion for these predicates. Heads is a coma-separated list of callable terms. Defined argument properties are:
:
Argument is a goal. The goal is processed using expand_goal/2, recursively applying goal transformation on the argument.
+
The argument is instantiated at entry. Nothing is changed.
-
The argument is not instantiated at entry. Nothing is changed.
?
The argument is unbound or instantiated at entry. Nothing is changed.
@
The argument is not changed.
r
The argument must be a resource. If it is a term prefix:local it is translated.
o
The argument is an object or resource. See rdf_global_object/2.
t
The argument is a term that must be translated. Expansion will translate all occurences of prefix:local appearing anywhere in the term. See rdf_global_term/2.

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.

  706rdf_meta(Heads) :-
  707    throw(error(context_error(nodirective, rdf_meta(Heads)), _)).
 rdf_meta_specification(+General, +Module, -Spec) is semidet
True when Spec is the RDF meta specification for Module:General.
Arguments:
General- is the term Spec with all arguments replaced with variables.
  716rdf_meta_specification(Unbounded, Module, Spec) :-
  717    '$flushed_predicate'(Module:'rdf meta specification'(_,_)),
  718    call(Module:'rdf meta specification'(Unbounded, Spec)).
  719
  720system:goal_expansion(G, Expanded) :-
  721    \+ predicate_property(G, iso),
  722    prolog_load_context(module, LM),
  723    predicate_property(LM:G, implementation_module(IM)),
  724    rdf_meta_specification(G, IM, Spec),
  725    rdf_expand(G, Spec, Expanded, LM).
  726
  727system:term_expansion(Fact, Expanded) :-
  728    prolog_load_context(module, Module),
  729    rdf_meta_specification(Fact, Module, Spec),
  730    rdf_expand(Fact, Spec, Expanded, Module),
  731    Fact \== Expanded.
  732system:term_expansion((Head :- Body), (Expanded :- Body)) :-
  733    prolog_load_context(module, Module),
  734    rdf_meta_specification(Head, Module, Spec),
  735    rdf_expand(Head, Spec, Expanded, Module),
  736    Head \== Expanded.
  737
  738rdf_expand(G, Spec, Expanded, M) :-
  739    functor(G, Name, Arity),
  740    functor(Expanded, Name, Arity),
  741    rdf_expand_args(0, Arity, G, Spec, Expanded, M).
  742
  743rdf_expand_args(Arity, Arity, _, _, _, _) :- !.
  744rdf_expand_args(I0, Arity, Goal, Spec, Expanded, M) :-
  745    I is I0 + 1,
  746    arg(I, Goal, GA),
  747    arg(I, Spec, SA),
  748    arg(I, Expanded, EA),
  749    rdf_expand_arg(SA, GA, EA, M),
  750    rdf_expand_args(I, Arity, Goal, Spec, Expanded, M).
  751
  752rdf_expand_arg(r, A, E, M) :-
  753    mk_global(A, E, M),
  754    !.
  755rdf_expand_arg(o, A, E, M) :-
  756    rdf_global_object(A, E, M),
  757    !.
  758rdf_expand_arg(t, A, E, M) :-
  759    rdf_global_term(A, E, M),
  760    !.
  761rdf_expand_arg(g, A, E, M) :-
  762    rdf_global_graph(A, E, M),
  763    !.
  764rdf_expand_arg(:, A, E, _M) :-
  765    !,
  766    expand_goal(A, E).
  767rdf_expand_arg(_, A, A, _M).
 mk_global(+Src, -Resource, +Module)
Realised rdf_global_id(+, -), but adds compiletime checking, notably to see whether a namespace is not yet defined.
  774mk_global(X, X, _) :-
  775    var(X),
  776    !.
  777mk_global(X, X, _) :-
  778    atom(X),
  779    !.
  780mk_global(Prefix:Local, Global, Module) :-
  781    must_be(atom, Prefix),
  782    must_be(atom, Local),
  783    (   rdf_current_prefix(Module:Prefix, Full)
  784    ->  atom_concat(Full, Local, Global)
  785    ;   current_prolog_flag(xref, true)
  786    ->  Global = Prefix:Local
  787    ;   existence_error(rdf_prefix, Prefix)
  788    ).
  789
  790:- rdf_meta
  791    rdf(r,r,o),
  792    rdf_has(r,r,o,r),
  793    rdf_has(r,r,o),
  794    rdf_assert(r,r,o),
  795    rdf_retractall(r,r,o),
  796    rdf(r,r,o,?),
  797    rdf_assert(r,r,o,+),
  798    rdf_retractall(r,r,o,?),
  799    rdf_reachable(r,r,o),
  800    rdf_reachable(r,r,o,+,?),
  801    rdf_update(r,r,o,t),
  802    rdf_update(r,r,o,+,t),
  803    rdf_equal(o,o),
  804    rdf_source_location(r,-),
  805    rdf_resource(r),
  806    rdf_subject(r),
  807    rdf_create_graph(r),
  808    rdf_graph(r),
  809    rdf_graph_property(r,?),
  810    rdf_set_graph(r,+),
  811    rdf_unload_graph(r),
  812    rdf_set_predicate(r, t),
  813    rdf_predicate_property(r, -),
  814    rdf_estimate_complexity(r,r,r,-),
  815    rdf_print_predicate_cloud(r,+).
 rdf_equal(?Resource1, ?Resource2)
Simple equality test to exploit goal-expansion
  821rdf_equal(Resource, Resource).
 lang_equal(+Lang1, +Lang2) is semidet
True if two RFC language specifiers denote the same language
See also
- lang_matches/2.
  829lang_equal(Lang, Lang) :- !.
  830lang_equal(Lang1, Lang2) :-
  831    downcase_atom(Lang1, LangCannon),
  832    downcase_atom(Lang2, LangCannon).
 lang_matches(+Lang, +Pattern) is semidet
True if Lang matches Pattern. This implements XML language matching conform RFC 4647. Both Lang and Pattern are dash-separated strings of identifiers or (for Pattern) the wildcart *. Identifiers are matched case-insensitive and a * matches any number of identifiers. A short pattern is the same as *.
  844                 /*******************************
  845                 *     BASIC TRIPLE QUERIES     *
  846                 *******************************/
 rdf(?Subject, ?Predicate, ?Object) is nondet
Elementary query for triples. Subject and Predicate are atoms representing the fully qualified URL of the resource. Object is either an atom representing a resource or literal(Value) if the object is a literal value. If a value of the form NameSpaceID:LocalName is provided it is expanded to a ground atom using expand_goal/2. This implies you can use this construct in compiled code without paying a performance penalty. Literal values take one of the following forms:
Atom
If the value is a simple atom it is the textual representation of a string literal without explicit type or language qualifier.
lang(LangID, Atom)
Atom represents the text of a string literal qualified with the given language.
type(TypeID, Value)
Used for attributes qualified using the rdf:datatype TypeID. The Value is either the textual representation or a natural Prolog representation. See the option convert_typed_literal(:Convertor) of the parser. The storage layer provides efficient handling of atoms, integers (64-bit) and floats (native C-doubles). All other data is represented as a Prolog record.

For literal querying purposes, Object can be of the form literal(+Query, -Value), where Query is one of the terms below. If the Query takes a literal argument and the value has a numeric type numerical comparison is performed.

plain(+Text)
Perform exact match and demand the language or type qualifiers to match. This query is fully indexed.
icase(+Text)
Perform a full but case-insensitive match. This query is fully indexed.
exact(+Text)
Same as icase(Text). Backward compatibility.
substring(+Text)
Match any literal that contains Text as a case-insensitive substring. The query is not indexed on Object.
word(+Text)
Match any literal that contains Text delimited by a non alpha-numeric character, the start or end of the string. The query is not indexed on Object.
prefix(+Text)
Match any literal that starts with Text. This call is intended for completion. The query is indexed using the skip list of literals.
ge(+Literal)
Match any literal that is equal or larger then Literal in the ordered set of literals.
gt(+Literal)
Match any literal that is larger then Literal in the ordered set of literals.
eq(+Literal)
Match any literal that is equal to Literal in the ordered set of literals.
le(+Literal)
Match any literal that is equal or smaller then Literal in the ordered set of literals.
lt(+Literal)
Match any literal that is smaller then Literal in the ordered set of literals.
between(+Literal1, +Literal2)
Match any literal that is between Literal1 and Literal2 in the ordered set of literals. This may include both Literal1 and Literal2.
like(+Pattern)
Match any literal that matches Pattern case insensitively, where the `*' character in Pattern matches zero or more characters.

Backtracking never returns duplicate triples. Duplicates can be retrieved using rdf/4. The predicate rdf/3 raises a type-error if called with improper arguments. If rdf/3 is called with a term literal(_) as Subject or Predicate object it fails silently. This allows for graph matching goals like rdf(S,P,O),rdf(O,P2,O2) to proceed without errors.

 rdf(?Subject, ?Predicate, ?Object, ?Source) is nondet
As rdf/3 but in addition query the graph to which the triple belongs. Unlike rdf/3, this predicate does not remove duplicates from the result set.
Arguments:
Source- is a term Graph:Line. If Source is instatiated, passing an atom is the same as passing Atom:_.
 rdf_has(?Subject, +Predicate, ?Object) is nondet
Succeeds if the triple rdf(Subject, Predicate, Object) is true exploiting the rdfs:subPropertyOf predicate as well as inverse predicates declared using rdf_set_predicate/2 with the inverse_of property.
 rdf_has(?Subject, +Predicate, ?Object, -RealPredicate) is nondet
Same as rdf_has/3, but RealPredicate is unified to the actual predicate that makes this relation true. RealPredicate must be Predicate or an rdfs:subPropertyOf Predicate. If an inverse match is found, RealPredicate is the term inverse_of(Pred).
 rdf_reachable(?Subject, +Predicate, ?Object) is nondet
Is true if Object can be reached from Subject following the transitive predicate Predicate or a sub-property thereof, while repecting the symetric(true) or inverse_of(P2) properties.

If used with either Subject or Object unbound, it first returns the origin, followed by the reachable nodes in breath-first search-order. The implementation internally looks one solution ahead and succeeds deterministically on the last solution. This predicate never generates the same node twice and is robust against cycles in the transitive relation.

With all arguments instantiated, it succeeds deterministically if a path can be found from Subject to Object. Searching starts at Subject, assuming the branching factor is normally lower. A call with both Subject and Object unbound raises an instantiation error. The following example generates all subclasses of rdfs:Resource:

?- rdf_reachable(X, rdfs:subClassOf, rdfs:'Resource').
X = 'http://www.w3.org/2000/01/rdf-schema#Resource' ;
X = 'http://www.w3.org/2000/01/rdf-schema#Class' ;
X = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Property' ;
...
 rdf_reachable(?Subject, +Predicate, ?Object, +MaxD, -D) is nondet
Same as rdf_reachable/3, but in addition, MaxD limits the number of edges expanded and D is unified with the `distance' between Subject and Object. Distance 0 means Subject and Object are the same resource. MaxD can be the constant infinite to impose no distance-limit.
 rdf_subject(?Resource) is nondet
True if Resource appears as a subject. This query respects the visibility rules implied by the logical update view.
See also
- rdf_resource/1.
 1012rdf_subject(Resource) :-
 1013    rdf_resource(Resource),
 1014    ( rdf(Resource, _, _) -> true ).
 rdf_resource(?Resource) is nondet
True when Resource is a resource used as a subject or object in a triple.

This predicate is primarily intended as a way to process all resources without processing resources twice. The user must be aware that some of the returned resources may not appear in any visible triple.

 1027                 /*******************************
 1028                 *     TRIPLE MODIFICATIONS     *
 1029                 *******************************/
 rdf_assert(+Subject, +Predicate, +Object) is det
Assert a new triple into the database. This is equivalent to rdf_assert/4 using Graph user. Subject and Predicate are resources. Object is either a resource or a term literal(Value). See rdf/3 for an explanation of Value for typed and language qualified literals. All arguments are subject to name-space expansion. Complete duplicates (including the same graph and `line' and with a compatible `lifespan') are not added to the database.
 rdf_assert(+Subject, +Predicate, +Object, +Graph) is det
As rdf_assert/3, adding the predicate to the indicated named graph.
Arguments:
Graph- is either the name of a graph (an atom) or a term Graph:Line, where Line is an integer that denotes a line number.
 rdf_retractall(?Subject, ?Predicate, ?Object) is det
Remove all matching triples from the database. As rdf_retractall/4 using an unbound graph.
 rdf_retractall(?Subject, ?Predicate, ?Object, ?Graph) is det
As rdf_retractall/3, also matching Graph. This is particulary useful to remove all triples coming from a loaded file. See also rdf_unload/1.
 rdf_update(+Subject, +Predicate, +Object, +Action) is det
Replaces one of the three fields on the matching triples depending on Action:
subject(Resource)
Changes the first field of the triple.
predicate(Resource)
Changes the second field of the triple.
object(Object)
Changes the last field of the triple to the given resource or literal(Value).
graph(Graph)
Moves the triple from its current named graph to Graph.
 rdf_update(+Subject, +Predicate, +Object, +Graph, +Action) is det
As rdf_update/4 but allows for specifying the graph.
 1081                 /*******************************
 1082                 *          COLLECTIONS         *
 1083                 *******************************/
 rdf_member_property(?Prop, ?Index)
Deal with the rdf:_1, ... properties.
 1089term_expansion(member_prefix(x),
 1090               member_prefix(Prefix)) :-
 1091    rdf_db:ns(rdf, NS),
 1092    atom_concat(NS, '_', Prefix).
 1093member_prefix(x).
 1094
 1095rdf_member_property(P, N) :-
 1096    integer(N),
 1097    !,
 1098    member_prefix(Prefix),
 1099    atom_concat(Prefix, N, P).
 1100rdf_member_property(P, N) :-
 1101    member_prefix(Prefix),
 1102    atom_concat(Prefix, Sub, P),
 1103    atom_number(Sub, N).
 1104
 1105
 1106                 /*******************************
 1107                 *      ANONYMOUS SUBJECTS      *
 1108                 *******************************/
 rdf_node(-Id)
Generate a unique blank node identifier for a subject.
deprecated
- New code should use rdf_bnode/1.
 1116rdf_node(Resource) :-
 1117    rdf_bnode(Resource).
 rdf_bnode(-Id)
Generate a unique anonymous identifier for a subject.
 1123rdf_bnode(Value) :-
 1124    repeat,
 1125    gensym('_:genid', Value),
 1126    \+ rdf(Value, _, _),
 1127    \+ rdf(_, _, Value),
 1128    \+ rdf(_, Value, _),
 1129    !.
 1130
 1131
 1132
 1133                 /*******************************
 1134                 *             TYPES            *
 1135                 *******************************/
 rdf_is_bnode(+Id)
Tests if a resource is a blank node (i.e. is an anonymous resource). A blank node is represented as an atom that starts with _:. For backward compatibility reason, __ is also considered to be a blank node.
See also
- rdf_bnode/1.
 rdf_is_resource(@Term) is semidet
True if Term is an RDF resource. Note that this is merely a type-test; it does not mean this resource is involved in any triple. Blank nodes are also considered resources.
See also
- rdf_is_bnode/1
 1154rdf_is_resource(Term) :-
 1155    atom(Term).
 rdf_is_literal(@Term) is semidet
True if Term is an RDF literal object. Currently only checks for groundness and the literal functor.
 1162rdf_is_literal(literal(Value)) :-
 1163    ground(Value).
 1164
 1165                 /*******************************
 1166                 *             LITERALS         *
 1167                 *******************************/
 rdf_current_literal(-Literal) is nondet
True when Literal is a currently known literal. Enumerates each unique literal exactly once. Note that it is possible that the literal only appears in already deleted triples. Deleted triples may be locked due to active queries, transactions or snapshots or may not yet be reclaimed by the garbage collector.
 rdf_literal_value(+Literal, -Value) is semidet
True when value is the appropriate Prolog representation of Literal in the RDF value space. Current mapping:
Plain literalsAtom
Language tagged literalAtom holding plain text
xsd:stringAtom
rdf:XMLLiteralXML DOM Tree
Numeric XSD typeNumber
To be done
- Well, this is the long-term idea.
- Add mode (-,+)
 1192:- rdf_meta
 1193    rdf_literal_value(o, -),
 1194    typed_value(r, +, -),
 1195    numeric_value(r, +, -). 1196
 1197rdf_literal_value(literal(String), Value) :-
 1198    atom(String),
 1199    !,
 1200    Value = String.
 1201rdf_literal_value(literal(lang(_Lang, String)), String).
 1202rdf_literal_value(literal(type(Type, String)), Value) :-
 1203    typed_value(Type, String, Value).
 1204
 1205typed_value(Numeric, String, Value) :-
 1206    xsdp_numeric_uri(Numeric, NumType),
 1207    !,
 1208    numeric_value(NumType, String, Value).
 1209typed_value(xsd:string, String, String).
 1210typed_value(rdf:'XMLLiteral', Value, DOM) :-
 1211    (   atom(Value)
 1212    ->  setup_call_cleanup(
 1213            ( atom_to_memory_file(Value, MF),
 1214              open_memory_file(MF, read, In, [free_on_close(true)])
 1215            ),
 1216            load_structure(stream(In), DOM, [dialect(xml)]),
 1217            close(In))
 1218    ;   DOM = Value
 1219    ).
 1220
 1221numeric_value(xsd:integer, String, Value) :-
 1222    atom_number(String, Value),
 1223    integer(Value).
 1224numeric_value(xsd:float, String, Value) :-
 1225    atom_number(String, Number),
 1226    Value is float(Number).
 1227numeric_value(xsd:double, String, Value) :-
 1228    atom_number(String, Number),
 1229    Value is float(Number).
 1230numeric_value(xsd:decimal, String, Value) :-
 1231    atom_number(String, Value).
 1232
 1233
 1234                 /*******************************
 1235                 *            SOURCE            *
 1236                 *******************************/
 rdf_source_location(+Subject, -Location) is nondet
True when triples for Subject are loaded from Location.
Arguments:
Location- is a term File:Line.
 1244rdf_source_location(Subject, Source) :-
 1245    findall(Source, rdf(Subject, _, _, Source), Sources),
 1246    sort(Sources, Unique),
 1247    member(Source, Unique).
 1248
 1249
 1250                 /*******************************
 1251                 *       GARBAGE COLLECT        *
 1252                 *******************************/
 rdf_create_gc_thread
Create the garbage collection thread.
 1258:- public
 1259    rdf_create_gc_thread/0. 1260
 1261rdf_create_gc_thread :-
 1262    thread_create(rdf_gc_loop, _,
 1263                  [ alias('__rdf_GC')
 1264                  ]).
 rdf_gc_loop
Take care of running the RDF garbage collection. This predicate is called from a thread started by creating the RDF DB.
 1271rdf_gc_loop :-
 1272    catch(rdf_gc_loop(0), E, recover_gc(E)).
 1273
 1274recover_gc('$aborted') :-
 1275    !,
 1276    thread_self(Me),
 1277    thread_detach(Me).
 1278recover_gc(Error) :-
 1279    print_message(error, Error),
 1280    rdf_gc_loop.
 1281
 1282rdf_gc_loop(CPU) :-
 1283    repeat,
 1284    (   consider_gc(CPU)
 1285    ->  rdf_gc(CPU1),
 1286        sleep(CPU1)
 1287    ;   sleep(0.1)
 1288    ),
 1289    fail.
 rdf_gc(-CPU) is det
Run RDF GC one time. CPU is the amount of CPU time spent. We update this in Prolog because portable access to thread specific CPU is really hard in C.
 1297rdf_gc(CPU) :-
 1298    statistics(cputime, CPU0),
 1299    (   rdf_gc_
 1300    ->  statistics(cputime, CPU1),
 1301        CPU is CPU1-CPU0,
 1302        rdf_add_gc_time(CPU)
 1303    ;   CPU = 0.0
 1304    ).
 rdf_gc is det
Run the RDF-DB garbage collector until no garbage is left and all tables are fully optimized. Under normal operation a seperate thread with identifier =__rdf_GC= performs garbage collection as long as it is considered `useful'.

Using rdf_gc/0 should only be needed to ensure a fully clean database for analysis purposes such as leak detection.

 1316rdf_gc :-
 1317    has_garbage,
 1318    !,
 1319    rdf_gc(_),
 1320    rdf_gc.
 1321rdf_gc.
 has_garbage is semidet
True if there is something to gain using GC.
 1327has_garbage :-
 1328    rdf_gc_info_(Info),
 1329    has_garbage(Info),
 1330    !.
 1331
 1332has_garbage(Info) :- arg(2, Info, Garbage),     Garbage > 0.
 1333has_garbage(Info) :- arg(3, Info, Reindexed),   Reindexed > 0.
 1334has_garbage(Info) :- arg(4, Info, Optimizable), Optimizable > 0.
 consider_gc(+CPU) is semidet
Arguments:
CPU- is the amount of CPU time spent in the most recent GC.
 1341consider_gc(_CPU) :-
 1342    (   rdf_gc_info_(gc_info(Triples,       % Total #triples in DB
 1343                             Garbage,       % Garbage triples in DB
 1344                             Reindexed,     % Reindexed & not reclaimed
 1345                             Optimizable,   % Non-optimized tables
 1346                             _KeepGen,      % Oldest active generation
 1347                             _LastGCGen,    % Oldest active gen at last GC
 1348                             _ReindexGen,
 1349                             _LastGCReindexGen))
 1350    ->  (   (Garbage+Reindexed) * 5 > Triples
 1351        ;   Optimizable > 4
 1352        )
 1353    ;   print_message(error, rdf(invalid_gc_info)),
 1354        sleep(10)
 1355    ),
 1356    !.
 1357
 1358
 1359                 /*******************************
 1360                 *           STATISTICS         *
 1361                 *******************************/
 rdf_statistics(?KeyValue) is nondet
Obtain statistics on the RDF database. Defined statistics are:
graphs(-Count)
Number of named graphs
triples(-Count)
Total number of triples in the database. This is the number of asserted triples minus the number of retracted ones. The number of visible triples in a particular context may be different due to visibility rules defined by the logical update view and transaction isolation.
resources(-Count)
Number of resources that appear as subject or object in a triple. See rdf_resource/1.
properties(-Count)
Number of current predicates. See rdf_current_predicate/1.
literals(-Count)
Number of current literals. See rdf_current_literal/1.
gc(GCCount, ReclaimedTriples, ReindexedTriples, Time)
Information about the garbage collector.
searched_nodes(-Count)
Number of nodes expanded by rdf_reachable/3 and rdf_reachable/5.
lookup(rdf(S, P, O, G), Count)
Number of queries for this particular instantiation pattern. Each of S,P,O,G is either + or -.
hash_quality(rdf(S, P, O, G), Buckets, Quality, PendingResize)
Statistics on the index for this pattern. Indices are created lazily on the first relevant query.
triples_by_graph(Graph, Count)
This statistics is produced for each named graph. See triples for the interpretation of this value.
 1406rdf_statistics(graphs(Count)) :-
 1407    rdf_statistics_(graphs(Count)).
 1408rdf_statistics(triples(Count)) :-
 1409    rdf_statistics_(triples(Count)).
 1410rdf_statistics(duplicates(Count)) :-
 1411    rdf_statistics_(duplicates(Count)).
 1412rdf_statistics(lingering(Count)) :-
 1413    rdf_statistics_(lingering(Count)).
 1414rdf_statistics(resources(Count)) :-
 1415    rdf_statistics_(resources(Count)).
 1416rdf_statistics(properties(Count)) :-
 1417    rdf_statistics_(predicates(Count)).
 1418rdf_statistics(literals(Count)) :-
 1419    rdf_statistics_(literals(Count)).
 1420rdf_statistics(gc(Count, Reclaimed, Reindexed, Time)) :-
 1421    rdf_statistics_(gc(Count, Reclaimed, Reindexed, Time)).
 1422rdf_statistics(searched_nodes(Count)) :-
 1423    rdf_statistics_(searched_nodes(Count)).
 1424rdf_statistics(lookup(Index, Count)) :-
 1425    functor(Indexed, indexed, 16),
 1426    rdf_statistics_(Indexed),
 1427    index(Index, I),
 1428    Arg is I + 1,
 1429    arg(Arg, Indexed, Count),
 1430    Count \== 0.
 1431rdf_statistics(hash_quality(Index, Size, Quality,Optimize)) :-
 1432    rdf_statistics_(hash_quality(List)),
 1433    member(hash(Place,Size,Quality,Optimize), List),
 1434    index(Index, Place).
 1435rdf_statistics(triples_by_graph(Graph, Count)) :-
 1436    rdf_graph_(Graph, Count).
 1437
 1438index(rdf(-,-,-,-), 0).
 1439index(rdf(+,-,-,-), 1).
 1440index(rdf(-,+,-,-), 2).
 1441index(rdf(+,+,-,-), 3).
 1442index(rdf(-,-,+,-), 4).
 1443index(rdf(+,-,+,-), 5).
 1444index(rdf(-,+,+,-), 6).
 1445index(rdf(+,+,+,-), 7).
 1446
 1447index(rdf(-,-,-,+), 8).
 1448index(rdf(+,-,-,+), 9).
 1449index(rdf(-,+,-,+), 10).
 1450index(rdf(+,+,-,+), 11).
 1451index(rdf(-,-,+,+), 12).
 1452index(rdf(+,-,+,+), 13).
 1453index(rdf(-,+,+,+), 14).
 1454index(rdf(+,+,+,+), 15).
 1455
 1456
 1457                 /*******************************
 1458                 *           PREDICATES         *
 1459                 *******************************/
 rdf_current_predicate(?Predicate) is nondet
True when Predicate is a currently known predicate. Predicates are created if a triples is created that uses this predicate or a property of the predicate is set using rdf_set_predicate/2. The predicate may (no longer) have triples associated with it.

Note that resources that have rdf:type rdf:Property are not automatically included in the result-set of this predicate, while all resources that appear as the second argument of a triple are included.

See also
- rdf_predicate_property/2.
 1475rdf_current_predicate(P, DB) :-
 1476    rdf_current_predicate(P),
 1477    (   rdf(_,P,_,DB)
 1478    ->  true
 1479    ).
 rdf_predicate_property(?Predicate, ?Property)
Query properties of a defined predicate. Currently defined properties are given below.
symmetric(Bool)
True if the predicate is defined to be symetric. I.e., {A} P {B} implies {B} P {A}. Setting symmetric is equivalent to inverse_of(Self).
inverse_of(Inverse)
True if this predicate is the inverse of Inverse. This property is used by rdf_has/3, rdf_has/4, rdf_reachable/3 and rdf_reachable/5.
transitive(Bool)
True if this predicate is transitive. This predicate is currently not used. It might be used to make rdf_has/3 imply rdf_reachable/3 for transitive predicates.
triples(Triples)
Unify Triples with the number of existing triples using this predicate as second argument. Reporting the number of triples is intended to support query optimization.
rdf_subject_branch_factor(-Float)
Unify Float with the average number of triples associated with each unique value for the subject-side of this relation. If there are no triples the value 0.0 is returned. This value is cached with the predicate and recomputed only after substantial changes to the triple set associated to this relation. This property is intended for path optimalisation when solving conjunctions of rdf/3 goals.
rdf_object_branch_factor(-Float)
Unify Float with the average number of triples associated with each unique value for the object-side of this relation. In addition to the comments with the subject_branch_factor property, uniqueness of the object value is computed from the hash key rather than the actual values.
rdfs_subject_branch_factor(-Float)
Same as rdf_subject_branch_factor, but also considering triples of `subPropertyOf' this relation. See also rdf_has/3.
rdfs_object_branch_factor(-Float)
Same as rdf_object_branch_factor, but also considering triples of `subPropertyOf' this relation. See also rdf_has/3.
See also
- rdf_set_predicate/2.
 1532rdf_predicate_property(P, Prop) :-
 1533    var(P),
 1534    !,
 1535    rdf_current_predicate(P),
 1536    rdf_predicate_property_(P, Prop).
 1537rdf_predicate_property(P, Prop) :-
 1538    rdf_predicate_property_(P, Prop).
 rdf_set_predicate(+Predicate, +Property) is det
Define a property of the predicate. This predicate currently supports the following properties:
symmetric(+Boolean)
Set/unset the predicate as being symmetric. Using symmetric(true) is the same as inverse_of(Predicate), i.e., creating a predicate that is the inverse of itself.
transitive(+Boolean)
Sets the transitive property.
inverse_of(+Predicate2)
Define Predicate as the inverse of Predicate2. An inverse relation is deleted using inverse_of([]).

The transitive property is currently not used. The symmetric and inverse_of properties are considered by rdf_has/3,4 and rdf_reachable/3.

To be done
- Maintain these properties based on OWL triples.
 1563                 /*******************************
 1564                 *            SNAPSHOTS         *
 1565                 *******************************/
 rdf_snapshot(-Snapshot) is det
Take a snapshot of the current state of the RDF store. Later, goals may be executed in the context of the database at this moment using rdf_transaction/3 with the snapshot option. A snapshot created outside a transaction exists until it is deleted. Snapshots taken inside a transaction can only be used inside this transaction.
 rdf_delete_snapshot(+Snapshot) is det
Delete a snapshot as obtained from rdf_snapshot/1. After this call, resources used for maintaining the snapshot become subject to garbage collection.
 rdf_current_snapshot(?Term) is nondet
True when Term is a currently known snapshot.
bug
- Enumeration of snapshots is slow.
 1588rdf_current_snapshot(Term) :-
 1589    current_blob(Term, rdf_snapshot).
 1590
 1591
 1592                 /*******************************
 1593                 *          TRANSACTION         *
 1594                 *******************************/
 rdf_transaction(:Goal) is semidet
Same as rdf_transaction(Goal, user, []). See rdf_transaction/3.
 rdf_transaction(:Goal, +Id) is semidet
Same as rdf_transaction(Goal, Id, []). See rdf_transaction/3.
 rdf_transaction(:Goal, +Id, +Options) is semidet
Run Goal in an RDF transaction. Compared to the ACID model, RDF transactions have the following properties:
  1. Modifications inside the transactions become all atomically visible to the outside world if Goal succeeds or remain invisible if Goal fails or throws an exception. I.e., the atomicy property is fully supported.
  2. Consistency is not guaranteed. Later versions may implement consistency constraints that will be checked serialized just before the actual commit of a transaction.
  3. Concurrently executing transactions do not infuence each other. I.e., the isolation property is fully supported.
  4. Durability can be activated by loading library(semweb/rdf_persistency).

Processed options are:

snapshot(+Snapshot)
Execute Goal using the state of the RDF store as stored in Snapshot. See rdf_snapshot/1. Snapshot can also be the atom true, which implies that an anonymous snapshot is created at the current state of the store. Modifications due to executing Goal are only visible to Goal.
 1630rdf_transaction(Goal) :-
 1631    rdf_transaction(Goal, user, []).
 1632rdf_transaction(Goal, Id) :-
 1633    rdf_transaction(Goal, Id, []).
 rdf_active_transaction(?Id) is nondet
True if Id is the identifier of a transaction in the context of which this call is executed. If Id is not instantiated, backtracking yields transaction identifiers starting with the innermost nested transaction. Transaction identifier terms are not copied, need not be ground and can be instantiated during the transaction.
 1644rdf_active_transaction(Id) :-
 1645    rdf_active_transactions_(List),
 1646    member(Id, List).
 rdf_monitor(:Goal, +Options)
Call Goal if specified actions occur on the database.
 1652rdf_monitor(Goal, Options) :-
 1653    monitor_mask(Options, 0xffff, Mask),
 1654    rdf_monitor_(Goal, Mask).
 1655
 1656monitor_mask([], Mask, Mask).
 1657monitor_mask([H|T], Mask0, Mask) :-
 1658    update_mask(H, Mask0, Mask1),
 1659    monitor_mask(T, Mask1, Mask).
 1660
 1661update_mask(-X, Mask0, Mask) :-
 1662    !,
 1663    monitor_mask(X, M),
 1664    Mask is Mask0 /\ \M.
 1665update_mask(+X, Mask0, Mask) :-
 1666    !,
 1667    monitor_mask(X, M),
 1668    Mask is Mask0 \/ M.
 1669update_mask(X, Mask0, Mask) :-
 1670    monitor_mask(X, M),
 1671    Mask is Mask0 \/ M.
 monitor_mask(Name, Mask)
Mask bit for the monitor events. Note that this must be kept consistent with the enum broadcast_id defined in rdf_db.c
 1678                                        % C-defined broadcasts
 1679monitor_mask(assert,       0x0001).
 1680monitor_mask(assert(load), 0x0002).
 1681monitor_mask(retract,      0x0004).
 1682monitor_mask(update,       0x0008).
 1683monitor_mask(new_literal,  0x0010).
 1684monitor_mask(old_literal,  0x0020).
 1685monitor_mask(transaction,  0x0040).
 1686monitor_mask(load,         0x0080).
 1687monitor_mask(create_graph, 0x0100).
 1688monitor_mask(reset,        0x0200).
 1689                                        % prolog defined broadcasts
 1690monitor_mask(parse,        0x1000).
 1691monitor_mask(unload,       0x1000).     % FIXME: Duplicate
 1692                                        % mask for all
 1693monitor_mask(all,          0xffff).
 1694
 1695%rdf_broadcast(Term, MaskName) :-
 1696%%      monitor_mask(MaskName, Mask),
 1697%%      rdf_broadcast_(Term, Mask).
 1698
 1699
 1700                 /*******************************
 1701                 *            WARM              *
 1702                 *******************************/
 rdf_warm_indexes
Warm all indexes. See rdf_warm_indexes/1.
 1708rdf_warm_indexes :-
 1709    findall(Index, rdf_index(Index), Indexes),
 1710    rdf_warm_indexes(Indexes).
 1711
 1712rdf_index(s).
 1713rdf_index(p).
 1714rdf_index(o).
 1715rdf_index(sp).
 1716rdf_index(o).
 1717rdf_index(po).
 1718rdf_index(spo).
 1719rdf_index(g).
 1720rdf_index(sg).
 1721rdf_index(pg).
 rdf_warm_indexes(+Indexes) is det
Create the named indexes. Normally, the RDF database creates indexes on lazily the first time they are needed. This predicate serves two purposes: it provides an explicit way to make sure that the required indexes are present and creating multiple indexes at the same time is more efficient.
 1732                 /*******************************
 1733                 *          DUPLICATES          *
 1734                 *******************************/
 rdf_update_duplicates is det
Update the duplicate administration of the RDF store. This marks every triple that is potentionally a duplicate of another as duplicate. Being potentially a duplicate means that subject, predicate and object are equivalent and the life-times of the two triples overlap.

The duplicates marks are used to reduce the administrative load of avoiding duplicate answers. Normally, the duplicates are marked using a background thread that is started on the first query that produces a substantial amount of duplicates.

 1749:- public
 1750    rdf_update_duplicates_thread/0.
 rdf_update_duplicates_thread
Start a thread to initialize the duplicate administration.
 1756rdf_update_duplicates_thread :-
 1757    thread_create(rdf_update_duplicates, _,
 1758                  [ detached(true),
 1759                    alias('__rdf_duplicate_detecter')
 1760                  ]).
 rdf_update_duplicates is det
Update the duplicate administration. If this adminstration is up-to-date, each triples that may have a duplicate is flagged. The predicate rdf/3 uses this administration to speedup checking for duplicate answers.

This predicate is normally executed from a background thread named =__rdf_duplicate_detecter= which is created when a query discovers that checking for duplicates becomes too expensive.

 1774                 /*******************************
 1775                 *    QUICK BINARY LOAD/SAVE    *
 1776                 *******************************/
 rdf_save_db(+File) is det
 rdf_save_db(+File, +Graph) is det
Save triples into File in a quick-to-load binary format. If Graph is supplied only triples flagged to originate from that database are added. Files created this way can be loaded using rdf_load_db/1.
 1786:- create_prolog_flag(rdf_triple_format, 3, [type(integer)]). 1787
 1788rdf_save_db(File) :-
 1789    current_prolog_flag(rdf_triple_format, Version),
 1790    setup_call_cleanup(
 1791        open(File, write, Out, [type(binary)]),
 1792        ( set_stream(Out, record_position(false)),
 1793          rdf_save_db_(Out, _, Version)
 1794        ),
 1795        close(Out)).
 1796
 1797
 1798rdf_save_db(File, Graph) :-
 1799    current_prolog_flag(rdf_triple_format, Version),
 1800    setup_call_cleanup(
 1801        open(File, write, Out, [type(binary)]),
 1802        ( set_stream(Out, record_position(false)),
 1803          rdf_save_db_(Out, Graph, Version)
 1804        ),
 1805        close(Out)).
 rdf_load_db_no_admin(+File, +Id, -Graphs) is det
Load triples from a .trp file without updating the source administration. Id is handled to monitor action. Graphs is a list of graph-names encountered in File.
 1814rdf_load_db_no_admin(File, Id, Graphs) :-
 1815    open(File, read, In, [type(binary)]),
 1816    set_stream(In, record_position(false)),
 1817    call_cleanup(rdf_load_db_(In, Id, Graphs), close(In)).
 check_loaded_cache(+Graph, +Graphs, +Modified) is det
Verify the loaded cache file and optionally fix the modification time (new versions save this along with the snapshot).
To be done
- What to do if there is a cache mismatch? Delete the loaded graphs and fail?
 1828check_loaded_cache(DB, [DB], _Modified) :- !.
 1829check_loaded_cache(DB, Graphs, _) :-
 1830    print_message(warning, rdf(inconsistent_cache(DB, Graphs))).
 rdf_load_db(+File) is det
Load triples from a file created using rdf_save_db/2.
 1837rdf_load_db(File) :-
 1838    uri_file_name(URL, File),
 1839    rdf_load_db_no_admin(File, URL, _Graphs).
 1840
 1841
 1842                 /*******************************
 1843                 *          LOADING RDF         *
 1844                 *******************************/
 1845
 1846:- multifile
 1847    rdf_open_hook/8,
 1848    rdf_open_decode/4,              % +Encoding, +File, -Stream, -Cleanup
 1849    rdf_load_stream/3,              % +Format, +Stream, +Options
 1850    rdf_file_type/2,                % ?Extension, ?Format
 1851    rdf_storage_encoding/2,         % ?Extension, ?Encoding
 1852    url_protocol/1.                 % ?Protocol
 rdf_load(+FileOrList) is det
Same as rdf_load(FileOrList, []). See rdf_load/2.
 rdf_load(+FileOrList, :Options) is det
Load RDF data. Options provides additional processing options. Defined options are:
blank_nodes(+ShareMode)
How to handle equivalent blank nodes. If share (default), equivalent blank nodes are shared in the same resource.
base_uri(+URI)
URI that is used for rdf:about="" and other RDF constructs that are relative to the base uri. Default is the source URL.
concurrent(+Jobs)
If FileOrList is a list of files, process the input files using Jobs threads concurrently. Default is the mininum of the number of cores and the number of inputs. Higher values can be useful when loading inputs from (slow) network connections. Using 1 (one) does not use separate worker threads.
format(+Format)
Specify the source format explicitly. Normally this is deduced from the filename extension or the mime-type. The core library understands the formats xml (RDF/XML) and triples (internal quick load and cache format). Plugins, such as library(semweb/turtle) extend the set of recognised extensions.
graph(?Graph)
Named graph in which to load the data. It is not allowed to load two sources into the same named graph. If Graph is unbound, it is unified to the graph into which the data is loaded. The default graph is a =file://= URL when loading a file or, if the specification is a URL, its normalized version without the optional #fragment.
if(Condition)
When to load the file. One of true, changed (default) or not_loaded.
modified(-Modified)
Unify Modified with one of not_modified, cached(File), last_modified(Stamp) or unknown.
cache(Bool)
If false, do not use or create a cache file.
register_namespaces(Bool)
If true (default false), register xmlns namespace declarations or Turtle @prefix prefixes using rdf_register_prefix/3 if there is no conflict.
silent(+Bool)
If true, the message reporting completion is printed using level silent. Otherwise the level is informational. See also print_message/2.

Other options are forwarded to process_rdf/3. By default, rdf_load/2 only loads RDF/XML from files. It can be extended to load data from other formats and locations using plugins. The full set of plugins relevant to support different formats and locations is below:

:- use_module(library(semweb/turtle)).        % Turtle and TRiG
:- use_module(library(semweb/rdf_ntriples)).
:- use_module(library(semweb/rdf_zlib_plugin)).
:- use_module(library(semweb/rdf_http_plugin)).
:- use_module(library(http/http_ssl_plugin)).
See also
- rdf_open_hook/3, library(semweb/rdf_persistency) and library(semweb/rdf_cache)
 1934:- dynamic
 1935    rdf_loading/3.                          % Graph, Queue, Thread
 1936
 1937rdf_load(Spec) :-
 1938    rdf_load(Spec, []).
 1939
 1940:- if(\+current_predicate(concurrent/3)). 1941concurrent(_, Goals, _) :-
 1942    forall(member(G, Goals), call(G)).
 1943:- endif. 1944
 1945% Note that we kill atom garbage collection.  This improves performance
 1946% with about 15% loading the LUBM Univ_50 benchmark.
 1947
 1948rdf_load(Spec, M:Options) :-
 1949    must_be(list, Options),
 1950    current_prolog_flag(agc_margin, Old),
 1951    setup_call_cleanup(
 1952        set_prolog_flag(agc_margin, 0),
 1953        rdf_load_noagc(Spec, M, Options),
 1954        set_prolog_flag(agc_margin, Old)).
 1955
 1956rdf_load_noagc(List, M, Options) :-
 1957    is_list(List),
 1958    !,
 1959    flatten(List, Inputs),          % Compatibility: allow nested lists
 1960    maplist(must_be(ground), Inputs),
 1961    length(Inputs, Count),
 1962    load_jobs(Count, Jobs, Options),
 1963    (   Jobs =:= 1
 1964    ->  forall(member(Spec, Inputs),
 1965               rdf_load_one(Spec, M, Options))
 1966    ;   maplist(load_goal(Options, M), Inputs, Goals),
 1967        concurrent(Jobs, Goals, [])
 1968    ).
 1969rdf_load_noagc(One, M, Options) :-
 1970    must_be(ground, One),
 1971    rdf_load_one(One, M, Options).
 1972
 1973load_goal(Options, M, Spec, rdf_load_one(Spec, M, Options)).
 1974
 1975load_jobs(_, Jobs, Options) :-
 1976    option(concurrent(Jobs), Options),
 1977    !,
 1978    must_be(positive_integer, Jobs).
 1979load_jobs(Count, Jobs, _) :-
 1980    current_prolog_flag(cpu_count, CPUs),
 1981    CPUs > 0,
 1982    !,
 1983    Jobs is max(1, min(CPUs, Count)).
 1984load_jobs(_, 1, _).
 1985
 1986
 1987rdf_load_one(Spec, M, Options) :-
 1988    source_url(Spec, Protocol, SourceURL),
 1989    load_graph(SourceURL, Graph, Options),
 1990    setup_call_cleanup(
 1991        with_mutex(rdf_load_file,
 1992                   rdf_start_load(SourceURL, Loading)),
 1993        rdf_load_file(Loading, Spec, SourceURL, Protocol,
 1994                      Graph, M, Options),
 1995        rdf_end_load(Loading)).
 rdf_start_load(+SourceURL, -WhatToDo) is det
 rdf_end_load(+WhatToDo) is det
 rdf_load_file(+WhatToDo, +Spec, +SourceURL, +Protocol, +Graph, +Module, +Options) is det
Of these three predicates, rdf_load_file/7 does the real work. The others deal with the possibility that the graph is being loaded by another thread. In that case, we wait for the other thread to complete the work.
See also
- Code is modelled closely after how concurrent loading is handled in SWI-Prolog's boot/init.pl
To be done
- What if both threads disagree on what is loaded into the graph?
 2012rdf_start_load(SourceURL, queue(Queue)) :-
 2013    rdf_loading(SourceURL, Queue, LoadThread),
 2014    \+ thread_self(LoadThread),
 2015    !,
 2016    debug(rdf(load), '~p is being loaded by thread ~w; waiting ...',
 2017          [ SourceURL, LoadThread]).
 2018rdf_start_load(SourceURL, Ref) :-
 2019    thread_self(Me),
 2020    message_queue_create(Queue),
 2021    assertz(rdf_loading(SourceURL, Queue, Me), Ref).
 2022
 2023rdf_end_load(queue(_)) :- !.
 2024rdf_end_load(Ref) :-
 2025    clause(rdf_loading(_, Queue, _), _, Ref),
 2026    erase(Ref),
 2027    thread_send_message(Queue, done),
 2028    message_queue_destroy(Queue).
 2029
 2030rdf_load_file(queue(Queue), _Spec, _SourceURL, _Protocol, _Graph, _M, _Options) :-
 2031    !,
 2032    catch(thread_get_message(Queue, _), _, true).
 2033rdf_load_file(_Ref, _Spec, SourceURL, Protocol, Graph, M, Options) :-
 2034    debug(rdf(load), 'RDF: Loading ~q into ~q', [SourceURL, Graph]),
 2035    statistics(cputime, T0),
 2036    rdf_open_input(SourceURL, Protocol, Graph,
 2037                   In, Cleanup, Modified, Format, Options),
 2038    supported_format(Format, Cleanup),
 2039    return_modified(Modified, Options),
 2040    (   Modified == not_modified
 2041    ->  Action = none
 2042    ;   Modified = cached(CacheFile)
 2043    ->  do_unload(Graph),
 2044        catch(rdf_load_db_no_admin(CacheFile, cache(Graph), Graphs), _, fail),
 2045        check_loaded_cache(Graph, Graphs, Modified),
 2046        Action = load
 2047    ;   option(base_uri(BaseURI), Options, Graph),
 2048        (   var(BaseURI)
 2049        ->  BaseURI = SourceURL
 2050        ;   true
 2051        ),
 2052        once(phrase(derived_options(Options, NSList), Extra)),
 2053        merge_options([ base_uri(BaseURI),
 2054                        graph(Graph),
 2055                        format(Format)
 2056                      | Extra
 2057                      ], Options, RDFOptions),
 2058        do_unload(Graph),
 2059        graph_modified(Modified, ModifiedStamp),
 2060        rdf_set_graph_source(Graph, SourceURL, ModifiedStamp),
 2061        call_cleanup(rdf_load_stream(Format, In, M:RDFOptions),
 2062                     Cleanup),
 2063        save_cache(Graph, SourceURL, Options),
 2064        register_file_ns(NSList),
 2065        format_action(Format, Action)
 2066    ),
 2067    rdf_statistics_(triples(Graph, Triples)),
 2068    report_loaded(Action, SourceURL, Graph, Triples, T0, Options).
 2069
 2070supported_format(Format, _Cleanup) :-
 2071    rdf_file_type(_, Format),
 2072    !.
 2073supported_format(Format, Cleanup) :-
 2074    call(Cleanup),
 2075    existence_error(rdf_format_plugin, Format).
 2076
 2077format_action(triples, load) :- !.
 2078format_action(_, parsed).
 2079
 2080save_cache(Graph, SourceURL, Options) :-
 2081    option(cache(true), Options, true),
 2082    rdf_cache_file(SourceURL, write, CacheFile),
 2083    !,
 2084    catch(save_cache(Graph, CacheFile), E,
 2085          print_message(warning, E)).
 2086save_cache(_, _, _).
 2087
 2088derived_options([], _) -->
 2089    [].
 2090derived_options([H|T], NSList) -->
 2091    (   {   H == register_namespaces(true)
 2092        ;   H == (register_namespaces = true)
 2093        }
 2094    ->  [ namespaces(NSList) ]
 2095    ;   []
 2096    ),
 2097    derived_options(T, NSList).
 2098
 2099graph_modified(last_modified(Stamp), Stamp).
 2100graph_modified(unknown, Stamp) :-
 2101    get_time(Stamp).
 2102
 2103return_modified(Modified, Options) :-
 2104    option(modified(M0), Options),
 2105    !,
 2106    M0 = Modified.
 2107return_modified(_, _).
 2108
 2109
 2110                 /*******************************
 2111                 *        INPUT HANDLING        *
 2112                 *******************************/
 2113
 2114/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 2115This section deals with pluggable input sources.  The task of the input
 2116layer is
 2117
 2118    * Decide on the graph-name
 2119    * Decide on the source-location
 2120    * Decide whether loading is needed (if-modified)
 2121    * Decide on the serialization in the input
 2122
 2123The protocol must ensure minimal  overhead,   in  particular for network
 2124protocols. E.g. for HTTP we want to make a single call on the server and
 2125use If-modified-since to verify that we need not reloading this file.
 2126- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 rdf_open_input(+SourceURL, +Protocol, +Graph, -Stream, -Cleanup, -Modified, -Format, +Options)
Open an input source.

Options processed:

Arguments:
Modified- is one of not_modified, last_modified(Time), cached(CacheFile) or unknown
 2144rdf_open_input(SourceURL, Protocol, Graph,
 2145               Stream, Cleanup, Modified, Format, Options) :-
 2146    option(if(If), Options, changed),
 2147    (   If == true
 2148    ->  true
 2149    ;   rdf_graph_source_(Graph, SourceURL, HaveModified)
 2150    ->  true
 2151    ;   option(cache(true), Options, true),
 2152        rdf_cache_file(SourceURL, read, CacheFile)
 2153    ->  time_file(CacheFile, HaveModified)
 2154    ;   true
 2155    ),
 2156    option(format(Format), Options, _),
 2157    open_input_if_modified(Protocol, SourceURL, HaveModified,
 2158                           Stream, Cleanup, Modified0, Format, Options),
 2159    (   Modified0 == not_modified
 2160    ->  (   nonvar(CacheFile)
 2161        ->  Modified = cached(CacheFile)
 2162        ;   Modified = not_modified
 2163        )
 2164    ;   Modified = Modified0
 2165    ).
 source_url(+Spec, -Class, -SourceURL) is det
Determine class and url of the source. Class is one of
 2176source_url(stream(In), stream(In), SourceURL) :-
 2177    !,
 2178    (   stream_property(In, file_name(File))
 2179    ->  to_url(File, SourceURL)
 2180    ;   gensym('stream://', SourceURL)
 2181    ).
 2182source_url(Stream, Class, SourceURL) :-
 2183    is_stream(Stream),
 2184    !,
 2185    source_url(stream(Stream), Class, SourceURL).
 2186source_url(Spec, Protocol, SourceURL) :-
 2187    compound(Spec),
 2188    !,
 2189    source_file(Spec, Protocol, SourceURL).
 2190source_url(FileURL, Protocol, SourceURL) :-             % or return FileURL?
 2191    uri_file_name(FileURL, File),
 2192    !,
 2193    source_file(File, Protocol, SourceURL).
 2194source_url(SourceURL0, Protocol, SourceURL) :-
 2195    is_url(SourceURL0, Protocol, SourceURL),
 2196    !.
 2197source_url(File, Protocol, SourceURL) :-
 2198    source_file(File, Protocol, SourceURL).
 2199
 2200source_file(Spec, file(SExt), SourceURL) :-
 2201    findall(Ext, valid_extension(Ext), Exts),
 2202    absolute_file_name(Spec, File, [access(read), extensions([''|Exts])]),
 2203    storage_extension(_Plain, SExt, File),
 2204    uri_file_name(SourceURL, File).
 2205
 2206to_url(URL, URL) :-
 2207    uri_is_global(URL),
 2208    !.
 2209to_url(File, URL) :-
 2210    absolute_file_name(File, Path),
 2211    uri_file_name(URL, Path).
 2212
 2213storage_extension(Plain, SExt, File) :-
 2214    file_name_extension(Plain, SExt, File),
 2215    SExt \== '',
 2216    rdf_storage_encoding(SExt, _),
 2217    !.
 2218storage_extension(File, '', File).
 load_graph(+SourceURL, -Graph, +Options) is det
Graph is the graph into which we load the data. Tries these options:
  1. The graph(Graph) option
  2. The db(Graph) option (backward compatibility)
  3. The base_uri(BaseURI) option
  4. The source URL
 2230load_graph(Source, Graph, Options) :-
 2231    (   option(graph(Graph), Options)
 2232    ;   option(db(Graph), Options)
 2233    ),
 2234    !,
 2235    load_graph2(Source, Graph, Options).
 2236load_graph(Source, Graph, Options) :-
 2237    load_graph2(Source, Graph, Options).
 2238
 2239load_graph2(_, Graph, _) :-
 2240    ground(Graph),
 2241    !.
 2242load_graph2(_Source, Graph, Options) :-
 2243    option(base_uri(Graph), Options),
 2244    Graph \== [],
 2245    ground(Graph),
 2246    !.
 2247load_graph2(Source, Graph, _) :-
 2248    load_graph(Source, Graph).
 2249
 2250load_graph(SourceURL, BaseURI) :-
 2251    file_name_extension(BaseURI, Ext, SourceURL),
 2252    rdf_storage_encoding(Ext, _),
 2253    !.
 2254load_graph(SourceURL, SourceURL).
 2255
 2256
 2257open_input_if_modified(stream(In), SourceURL, _, In, true,
 2258                       unknown, Format, _) :-
 2259    !,
 2260    (   var(Format)
 2261    ->  guess_format(SourceURL, Format)
 2262    ;   true
 2263    ).
 2264open_input_if_modified(file(SExt), SourceURL, HaveModified, Stream, Cleanup,
 2265                       Modified, Format, _) :-
 2266    !,
 2267    uri_file_name(SourceURL, File),
 2268    (   SExt == '' -> Plain = File; file_name_extension(Plain, SExt, File)),
 2269    time_file(File, LastModified),
 2270    (   nonvar(HaveModified),
 2271        HaveModified >= LastModified
 2272    ->  Modified = not_modified,
 2273        Cleanup = true
 2274    ;   storage_open(SExt, File, Stream, Cleanup),
 2275        Modified = last_modified(LastModified),
 2276        (   var(Format)
 2277        ->  guess_format(Plain, Format)
 2278        ;   true
 2279        )
 2280    ).
 2281open_input_if_modified(file, SourceURL, HaveModified, Stream, Cleanup,
 2282                       Modified, Format, Options) :-
 2283    !,
 2284    open_input_if_modified(file(''), SourceURL, HaveModified,
 2285                           Stream, Cleanup,
 2286                           Modified, Format, Options).
 2287open_input_if_modified(Protocol, SourceURL, HaveModified, Stream, Cleanup,
 2288                       Modified, Format, Options) :-
 2289    rdf_open_hook(Protocol, SourceURL, HaveModified, Stream, Cleanup,
 2290                  Modified, Format, Options).
 2291
 2292guess_format(File, Format) :-
 2293    file_name_extension(_, Ext, File),
 2294    (   rdf_file_type(Ext, Format)
 2295    ->  true
 2296    ;   Format = xml,
 2297        print_message(warning, rdf(guess_format(Ext)))
 2298    ).
 storage_open(+Extension, +File, -Stream, -Cleanup)
Open the low-level storage. Note that the file is opened as binary. This is the same as for HTTP resources. The correct encoding will be set by the XML parser or the Turtle parser.
 2306storage_open('', File, Stream, close(Stream)) :-
 2307    !,
 2308    open(File, read, Stream, [type(binary)]).
 2309storage_open(Ext, File, Stream, Cleanup) :-
 2310    rdf_storage_encoding(Ext, Encoding),
 2311    rdf_open_decode(Encoding, File, Stream, Cleanup).
 2312
 2313valid_extension(Ext) :-
 2314    rdf_file_type(Ext, _).
 2315valid_extension(Ext) :-
 2316    rdf_storage_encoding(Ext, _).
 is_url(@Term, -Scheme, -URL) is semidet
True if Term is an atom denoting URL of the given Scheme. URL is normalized (see uri_normalized/2) and a possible fragment identifier (#fragment) is removed. This predicate only succeeds if the scheme is registered using the multifile hook url_protocol/1.
 2326is_url(URL, Scheme, FetchURL) :-
 2327    atom(URL),
 2328    uri_is_global(URL),
 2329    uri_normalized(URL, URL1),              % case normalization
 2330    uri_components(URL1, Components),
 2331    uri_data(scheme, Components, Scheme0),
 2332    url_protocol(Scheme0),
 2333    !,
 2334    Scheme = Scheme0,
 2335    uri_data(fragment, Components, _, Components1),
 2336    uri_components(FetchURL, Components1).
 2337
 2338url_protocol(file).                     % built-in
 rdf_file_type(+Extension, -Format) is semidet
True if Format is the format belonging to the given file extension. This predicate is multifile and can thus be extended by plugins.
 2346rdf_file_type(xml,   xml).
 2347rdf_file_type(rdf,   xml).
 2348rdf_file_type(rdfs,  xml).
 2349rdf_file_type(owl,   xml).
 2350rdf_file_type(htm,   xhtml).
 2351rdf_file_type(html,  xhtml).
 2352rdf_file_type(xhtml, xhtml).
 2353rdf_file_type(trp,   triples).
 rdf_file_encoding(+Extension, -Format) is semidet
True if Format describes the storage encoding of file.
 2360rdf_storage_encoding('', plain).
 rdf_load_stream(+Format, +Stream, :Options)
Load RDF data from Stream.
To be done
- Handle mime-types?
 2369rdf_load_stream(xml, Stream, Options) :-
 2370    !,
 2371    graph(Options, Graph),
 2372    rdf_transaction(load_stream(Stream, Options),
 2373                    parse(Graph)).
 2374rdf_load_stream(xhtml, Stream, M:Options) :-
 2375    !,
 2376    graph(Options, Graph),
 2377    rdf_transaction(load_stream(Stream, M:[embedded(true)|Options]),
 2378                    parse(Graph)).
 2379rdf_load_stream(triples, Stream, Options) :-
 2380    !,
 2381    graph(Options, Graph),
 2382    rdf_load_db_(Stream, Graph, _Graphs).
 2383
 2384load_stream(Stream, M:Options) :-
 2385    process_rdf(Stream, assert_triples, M:Options),
 2386    option(graph(Graph), Options),
 2387    rdf_graph_clear_modified_(Graph).
 report_loaded(+Action, +Source, +DB, +Triples, +StartCPU, +Options)
 2392report_loaded(none, _, _, _, _, _) :- !.
 2393report_loaded(Action, Source, DB, Triples, T0, Options) :-
 2394    statistics(cputime, T1),
 2395    Time is T1 - T0,
 2396    (   option(silent(true), Options)
 2397    ->  Level = silent
 2398    ;   Level = informational
 2399    ),
 2400    print_message(Level,
 2401                  rdf(loaded(Action, Source, DB, Triples, Time))).
 rdf_unload(+Source) is det
Identify the graph loaded from Source and use rdf_unload_graph/1 to erase this graph.
deprecated
- For compatibility, this predicate also accepts a graph name instead of a source specification. Please update your code to use rdf_unload_graph/1.
 2414rdf_unload(Spec) :-
 2415    source_url(Spec, _Protocol, SourceURL),
 2416    rdf_graph_source_(Graph, SourceURL, _),
 2417    !,
 2418    rdf_unload_graph(Graph).
 2419rdf_unload(Graph) :-
 2420    atom(Graph),
 2421    rdf_graph(Graph),
 2422    !,
 2423    warn_deprecated_unload(Graph),
 2424    rdf_unload_graph(Graph).
 2425rdf_unload(_).
 2426
 2427:- dynamic
 2428    warned/0. 2429
 2430warn_deprecated_unload(_) :-
 2431    warned,
 2432    !.
 2433warn_deprecated_unload(Graph) :-
 2434    assertz(warned),
 2435    print_message(warning, rdf(deprecated(rdf_unload(Graph)))).
 rdf_unload_graph(+Graph) is det
Remove Graph from the RDF store. Succeeds silently if the named graph does not exist.
 2443rdf_unload_graph(Graph) :-
 2444    must_be(atom, Graph),
 2445    (   rdf_graph(Graph)
 2446    ->  rdf_transaction(do_unload(Graph), unload(Graph))
 2447    ;   true
 2448    ).
 2449
 2450do_unload(Graph) :-
 2451    (   rdf_graph_(Graph, Triples),
 2452        Triples > 0
 2453    ->  rdf_retractall(_,_,_,Graph)
 2454    ;   true
 2455    ),
 2456    rdf_destroy_graph(Graph).
 2457
 2458                 /*******************************
 2459                 *         GRAPH QUERIES        *
 2460                 *******************************/
 rdf_create_graph(+Graph) is det
Create an RDF graph without triples. Succeeds silently if the graph already exists.
 rdf_graph(?Graph) is nondet
True when Graph is an existing graph.
 2472rdf_graph(Graph) :-
 2473    rdf_graph_(Graph, _Triples).
 rdf_source(?Graph, ?SourceURL) is nondet
True if named Graph is loaded from SourceURL.
deprecated
- Use rdf_graph_property(Graph, source(SourceURL)).
 2481rdf_source(Graph, SourceURL) :-
 2482    rdf_graph(Graph),
 2483    rdf_graph_source_(Graph, SourceURL, _Modified).
 rdf_source(?Source)
True if Source is a loaded source.
deprecated
- Use rdf_graph/1 or rdf_source/2.
 2491rdf_source(SourceURL) :-
 2492    rdf_source(_Graph, SourceURL).
 rdf_make
Reload all loaded files that have been modified since the last time they were loaded.
 2499rdf_make :-
 2500    findall(Source-Graph, modified_graph(Source, Graph), Modified),
 2501    forall(member(Source-Graph, Modified),
 2502           catch(rdf_load(Source, [graph(Graph), if(changed)]), E,
 2503                 print_message(error, E))).
 2504
 2505modified_graph(SourceURL, Graph) :-
 2506    rdf_graph(Graph),
 2507    rdf_graph_source_(Graph, SourceURL, Modified),
 2508    \+ sub_atom(SourceURL, 0, _, _, 'stream://'),
 2509    Modified > 0.
 rdf_graph_property(?Graph, ?Property) is nondet
True when Property is a property of Graph. Defined properties are:
hash(Hash)
Hash is the (MD5-)hash for the content of Graph.
modified(Boolean)
True if the graph is modified since it was loaded or rdf_set_graph/2 was called with modified(false).
source(Source)
The graph is loaded from the Source (a URL)
source_last_modified(?Time)
Time is the last-modified timestamp of Source at the moment that the graph was loaded from Source.
triples(Count)
True when Count is the number of triples in Graph.

Additional graph properties can be added by defining rules for the multifile predicate property_of_graph/2. Currently, the following extensions are defined:

 2537rdf_graph_property(Graph, Property) :-
 2538    rdf_graph(Graph),
 2539    property_of_graph(Property, Graph).
 2540
 2541:- multifile
 2542    property_of_graph/2. 2543
 2544property_of_graph(hash(Hash), Graph) :-
 2545    rdf_md5(Graph, Hash).
 2546property_of_graph(modified(Boolean), Graph) :-
 2547    rdf_graph_modified_(Graph, Boolean, _).
 2548property_of_graph(source(URL), Graph) :-
 2549    rdf_graph_source_(Graph, URL, _).
 2550property_of_graph(source_last_modified(Time), Graph) :-
 2551    rdf_graph_source_(Graph, _, Time),
 2552    Time > 0.0.
 2553property_of_graph(triples(Count), Graph) :-
 2554    rdf_graph_(Graph, Count).
 rdf_set_graph(+Graph, +Property) is det
Set properties of Graph. Defined properties are:
modified(false)
Set the modified state of Graph to false.
 2563rdf_set_graph(Graph, modified(Modified)) :-
 2564    must_be(oneof([false]), Modified),
 2565    rdf_graph_clear_modified_(Graph).
 save_cache(+DB, +Cache) is det
Save triples belonging to DB in the file Cache.
 2572save_cache(DB, Cache) :-
 2573    current_prolog_flag(rdf_triple_format, Version),
 2574    setup_call_cleanup(
 2575        catch(open(Cache, write, CacheStream, [type(binary)]), _, fail),
 2576        rdf_save_db_(CacheStream, DB, Version),
 2577        close(CacheStream)).
 assert_triples(+Triples, +Source)
Assert a list of triples into the database. Foir security reasons we check we aren't inserting anything but nice RDF triples.
 2585assert_triples([], _).
 2586assert_triples([rdf(S,P,O)|T], DB) :-
 2587    !,
 2588    rdf_assert(S, P, O, DB),
 2589    assert_triples(T, DB).
 2590assert_triples([H|_], _) :-
 2591    throw(error(type_error(rdf_triple, H), _)).
 2592
 2593
 2594                 /*******************************
 2595                 *             RESET            *
 2596                 *******************************/
 rdf_reset_db
Remove all triples from the RDF database and reset all its statistics.
bug
- This predicate checks for active queries, but this check is not properly synchronized and therefore the use of this predicate is unsafe in multi-threaded contexts. It is mainly used to run functionality tests that need to start with an empty database.
 2609rdf_reset_db :-
 2610    reset_gensym('_:genid'),
 2611    rdf_reset_db_.
 2612
 2613
 2614                 /*******************************
 2615                 *           SAVE RDF           *
 2616                 *******************************/
 rdf_save(+Out) is det
Same as rdf_save(Out, []). See rdf_save/2 for details.
 rdf_save(+Out, :Options) is det
Write RDF data as RDF/XML. Options is a list of one or more of the following options:
graph(+Graph)
Save only triples associated to the given named Graph.
anon(Bool)
If false (default true) do not save blank nodes that do not appear (indirectly) as object of a named resource.
base_uri(URI)
BaseURI used. If present, all URIs that can be represented relative to this base are written using their shorthand. See also write_xml_base option
convert_typed_literal(:Convertor)
Call Convertor(-Type, -Content, +RDFObject), providing the opposite for the convert_typed_literal option of the RDF parser.
document_language(+Lang)
Initial xml:lang saved with rdf:RDF element
encoding(Encoding)
Encoding for the output. Either utf8 or iso_latin_1
inline(+Bool)
If true (default false), inline resources when encountered for the first time. Normally, only bnodes are handled this way.
namespaces(+List)
Explicitely specify saved namespace declarations. See rdf_save_header/2 option namespaces for details.
sorted(+Boolean)
If true (default false), emit subjects sorted on the full URI. Useful to make file comparison easier.
write_xml_base(Bool)
If false, do not include the xml:base declaration that is written normally when using the base_uri option.
xml_attributes(+Bool)
If false (default true), never use xml attributes to save plain literal attributes, i.e., always used an XML element as in <name>Joe</name>.
Arguments:
Out- Location to save the data. This can also be a file-url (file://path) or a stream wrapped in a term stream(Out).
See also
- rdf_save_db/1
 2678:- thread_local
 2679    named_anon/2,                   % +Resource, -Id
 2680    inlined/1.                      % +Resource
 2681
 2682rdf_save(File) :-
 2683    rdf_save2(File, []).
 2684
 2685rdf_save(Spec, M:Options0) :-
 2686    is_list(Options0),
 2687    !,
 2688    meta_options(save_meta_option, M:Options0, Options),
 2689    to_file(Spec, File),
 2690    rdf_save2(File, Options).
 2691rdf_save(Spec, _:DB) :-
 2692    atom(DB),                      % backward compatibility
 2693    !,
 2694    to_file(Spec, File),
 2695    rdf_save2(File, [graph(DB)]).
 2696
 2697save_meta_option(convert_typed_literal).
 2698
 2699to_file(URL, File) :-
 2700    atom(URL),
 2701    uri_file_name(URL, File),
 2702    !.
 2703to_file(File, File).
 2704
 2705rdf_save2(File, Options) :-
 2706    option(encoding(Encoding), Options, utf8),
 2707    valid_encoding(Encoding),
 2708    open_output(File, Encoding, Out, Close),
 2709    flag(rdf_db_saved_subjects, OSavedSubjects, 0),
 2710    flag(rdf_db_saved_triples, OSavedTriples, 0),
 2711    call_cleanup(rdf_do_save(Out, Options),
 2712                 Reason,
 2713                 cleanup_save(Reason,
 2714                              File,
 2715                              OSavedSubjects,
 2716                              OSavedTriples,
 2717                              Close)).
 2718
 2719open_output(stream(Out), Encoding, Out,
 2720            set_stream(Out, encoding(Old))) :-
 2721    !,
 2722    stream_property(Out, encoding(Old)),
 2723    set_stream(Out, encoding(Encoding)).
 2724open_output(File, Encoding, Out,
 2725            close(Out)) :-
 2726    open(File, write, Out, [encoding(Encoding)]).
 2727
 2728valid_encoding(Enc) :-
 2729    (   xml_encoding_name(Enc, _)
 2730    ->  true
 2731    ;   throw(error(domain_error(encoding, Enc), _))
 2732    ).
 2733
 2734
 2735cleanup_save(Reason,
 2736             File,
 2737             OSavedSubjects,
 2738             OSavedTriples,
 2739             Close) :-
 2740    call(Close),
 2741    flag(rdf_db_saved_subjects, SavedSubjects, OSavedSubjects),
 2742    flag(rdf_db_saved_triples, SavedTriples, OSavedTriples),
 2743    retractall(named_anon(_, _)),
 2744    retractall(inlined(_)),
 2745    (   Reason == exit
 2746    ->  print_message(informational,
 2747                      rdf(saved(File, SavedSubjects, SavedTriples)))
 2748    ;   format(user_error, 'Reason = ~w~n', [Reason])
 2749    ).
 2750
 2751rdf_do_save(Out, Options0) :-
 2752    rdf_save_header(Out, Options0, Options),
 2753    (   option(sorted(true), Options, false)
 2754    ->  setof(Subject, rdf_subject(Subject, Options), Subjects),
 2755        forall(member(Subject, Subjects),
 2756               rdf_save_non_anon_subject(Out, Subject, Options))
 2757    ;   forall(rdf_subject(Subject, Options),
 2758               rdf_save_non_anon_subject(Out, Subject, Options))
 2759    ),
 2760    rdf_save_footer(Out),
 2761    !.        % dubious cut; without the
 2762                                        % cleanup handlers isn't called!?
 2763
 2764rdf_subject(Subject, Options) :-
 2765    graph(Options, DB),
 2766    var(DB),
 2767    !,
 2768    rdf_subject(Subject).
 2769rdf_subject(Subject, Options) :-
 2770    graph(Options, DB),
 2771    rdf_subject(Subject),
 2772    (   rdf(Subject, _, _, DB:_)
 2773    ->  true
 2774    ).
 2775
 2776graph(Options0, DB) :-
 2777    strip_module(Options0, _, Options),
 2778    (   memberchk(graph(DB0), Options)
 2779    ->  DB = DB0
 2780    ;   memberchk(db(DB0), Options)
 2781    ->  DB = DB0
 2782    ;   true                        % leave unbound
 2783    ).
 rdf_save_header(+Fd, +Options)
Save XML document header, doctype and open the RDF environment. This predicate also sets up the namespace notation.

Save an RDF header, with the XML header, DOCTYPE, ENTITY and opening the rdf:RDF element with appropriate namespace declarations. It uses the primitives from section 3.5 to generate the required namespaces and desired short-name. Options is one of:

graph(+URI)
Only search for namespaces used in triples that belong to the given named graph.
namespaces(+List)
Where List is a list of namespace abbreviations. With this option, the expensive search for all namespaces that may be used by your data is omitted. The namespaces rdf and rdfs are added to the provided List. If a namespace is not declared, the resource is emitted in non-abreviated form.
 2808rdf_save_header(Out, Options) :-
 2809    rdf_save_header(Out, Options, _).
 2810
 2811rdf_save_header(Out, Options, OptionsOut) :-
 2812    is_list(Options),
 2813    !,
 2814    stream_property(Out, encoding(Enc)),
 2815    xml_encoding(Enc, Encoding),
 2816    format(Out, '<?xml version=\'1.0\' encoding=\'~w\'?>~n', [Encoding]),
 2817    format(Out, '<!DOCTYPE rdf:RDF [', []),
 2818    header_namespaces(Options, NSIdList),
 2819    nsmap(NSIdList, NsMap),
 2820    append(Options, [nsmap(NsMap)], OptionsOut),
 2821    forall(member(Id=URI, NsMap),
 2822           (   xml_quote_attribute(URI, NSText0, Enc),
 2823               xml_escape_parameter_entity(NSText0, NSText),
 2824               format(Out, '~N    <!ENTITY ~w \'~w\'>', [Id, NSText])
 2825           )),
 2826    format(Out, '~N]>~n~n', []),
 2827    format(Out, '<rdf:RDF', []),
 2828    (   member(Id, NSIdList),
 2829        format(Out, '~N    xmlns:~w="&~w;"~n', [Id, Id]),
 2830        fail
 2831    ;   true
 2832    ),
 2833    (   option(base_uri(Base), Options),
 2834        option(write_xml_base(true), Options, true)
 2835    ->  xml_quote_attribute(Base, BaseText, Enc),
 2836        format(Out, '~N    xml:base="~w"~n', [BaseText])
 2837    ;   true
 2838    ),
 2839    (   memberchk(document_language(Lang), Options)
 2840    ->  format(Out, '~N    xml:lang="~w"', [Lang])
 2841    ;   true
 2842    ),
 2843    format(Out, '>~n', []).
 2844rdf_save_header(Out, FileRef, OptionsOut) :-    % compatibility
 2845    atom(FileRef),
 2846    rdf_save_header(Out, [graph(FileRef)], OptionsOut).
 2847
 2848xml_encoding(Enc, Encoding) :-
 2849    (   xml_encoding_name(Enc, Encoding)
 2850    ->  true
 2851    ;   throw(error(domain_error(rdf_encoding, Enc), _))
 2852    ).
 2853
 2854xml_encoding_name(ascii,       'US-ASCII').
 2855xml_encoding_name(iso_latin_1, 'ISO-8859-1').
 2856xml_encoding_name(utf8,        'UTF-8').
 nsmap(+NSIds, -Map:list(id=uri)) is det
Create a namespace-map that is compatible to xml_write/2 for dealing with XML-Literals
 2863nsmap([], []).
 2864nsmap([Id|T0], [Id=URI|T]) :-
 2865    ns(Id, URI),
 2866    nsmap(T0, T).
 xml_escape_parameter_entity(+In, -Out) is det
Escape % as &#37; for entity declarations.
 2872xml_escape_parameter_entity(In, Out) :-
 2873    sub_atom(In, _, _, _, '%'),
 2874    !,
 2875    atom_codes(In, Codes),
 2876    phrase(escape_parent(Codes), OutCodes),
 2877    atom_codes(Out, OutCodes).
 2878xml_escape_parameter_entity(In, In).
 2879
 2880escape_parent([]) --> [].
 2881escape_parent([H|T]) -->
 2882    (   { H == 37 }
 2883    ->  "&#37;"
 2884    ;   [H]
 2885    ),
 2886    escape_parent(T).
 header_namespaces(Options, -List)
Get namespaces we will define as entities
 2893header_namespaces(Options, List) :-
 2894    memberchk(namespaces(NSL0), Options),
 2895    !,
 2896    sort([rdf,rdfs|NSL0], List).
 2897header_namespaces(Options, List) :-
 2898    graph(Options, DB),
 2899    used_namespace_entities(List, DB).
 rdf_graph_prefixes(?Graph, -List:ord_set) is det
 rdf_graph_prefixes(?Graph, -List:ord_set, :Options) is det
List is a sorted list of prefixes (namepaces) in Graph. Options defined are:
filter(:Filter)
optional Filter argument is used to filter the results. It is called with 3 additional arguments:
call(Filter, Where, Prefix, URI)

The Where argument gives the location of the prefix ans is one of subject, predicate, object or type. The Prefix argument is the potentionally new prefix and URI is the full URI that is being processed.

expand(:Goal)
Hook to generate the graph. Called using
call(Goal,S,P,O,Graph)
min_count(+Count)
Only include prefixes that appear at least N times. Default is 1. Declared prefixes are always returned if found at least one time.
get_prefix(:GetPrefix)
Predicate to extract the candidate prefix from an IRI. Default is iri_xml_namespace/2.
 2937:- thread_local
 2938    graph_prefix/3. 2939:- meta_predicate
 2940    rdf_graph_prefixes(?, -, :). 2941
 2942rdf_graph_prefixes(Graph, List) :-
 2943    rdf_graph_prefixes(Graph, List, []).
 2944
 2945rdf_graph_prefixes(Graph, List, M:QOptions) :-
 2946    is_list(QOptions),
 2947    !,
 2948    meta_options(is_meta, M:QOptions, Options),
 2949    option(filter(Filter), Options, true),
 2950    option(expand(Expand), Options, rdf_db),
 2951    option(min_count(MinCount), Options, 1),
 2952    option(get_prefix(GetPrefix), Options, iri_xml_namespace),
 2953    call_cleanup(prefixes(Expand, Graph, Prefixes, Filter, MinCount, GetPrefix),
 2954                 retractall(graph_prefix(_,_,_))),
 2955    sort(Prefixes, List).
 2956rdf_graph_prefixes(Graph, List, M:Filter) :-
 2957    rdf_graph_prefixes(Graph, List, M:[filter(Filter)]).
 2958
 2959is_meta(filter).
 2960is_meta(expand).
 2961is_meta(get_prefix).
 2962
 2963
 2964prefixes(Expand, Graph, Prefixes, Filter, MinCount, GetPrefix) :-
 2965    (   call(Expand, S, P, O, Graph),
 2966        add_ns(subject, GetPrefix, Filter, S, MinCount, s(S)),
 2967        add_ns(predicate, GetPrefix, Filter, P, MinCount, sp(S,P)),
 2968        add_ns_obj(GetPrefix, Filter, O, MinCount, spo(S,P,O)),
 2969        fail
 2970    ;   true
 2971    ),
 2972    findall(Prefix, graph_prefix(Prefix, MinCount, _), Prefixes).
 2973
 2974add_ns(Where, GetPrefix, Filter, S, MinCount, Context) :-
 2975    \+ rdf_is_bnode(S),
 2976    call(GetPrefix, S, Full),
 2977    Full \== '',
 2978    !,
 2979    (   graph_prefix(Full, MinCount, _)
 2980    ->  true
 2981    ;   Filter == true
 2982    ->  add_ns(Full, Context)
 2983    ;   call(Filter, Where, Full, S)
 2984    ->  add_ns(Full, Context)
 2985    ;   true
 2986    ).
 2987add_ns(_, _, _, _, _, _).
 2988
 2989add_ns(Full, Context) :-
 2990    graph_prefix(Full, _, Contexts),
 2991    memberchk(Context, Contexts),
 2992    !.
 2993add_ns(Full, Context) :-
 2994    retract(graph_prefix(Full, C0, Contexts)),
 2995    !,
 2996    C1 is C0+1,
 2997    asserta(graph_prefix(Full, C1, [Context|Contexts])).
 2998add_ns(Full, _) :-
 2999    ns(_, Full),
 3000    !,
 3001    asserta(graph_prefix(Full, _, _)).
 3002add_ns(Full, Context) :-
 3003    asserta(graph_prefix(Full, 1, [Context])).
 3004
 3005
 3006add_ns_obj(GetPrefix, Filter, O, MinCount, Context) :-
 3007    atom(O),
 3008    !,
 3009    add_ns(object, GetPrefix, Filter, O, MinCount, Context).
 3010add_ns_obj(GetPrefix, Filter, literal(type(Type, _)), MinCount, _) :-
 3011    atom(Type),
 3012    !,
 3013    add_ns(type, GetPrefix, Filter, Type, MinCount, t(Type)).
 3014add_ns_obj(_, _, _, _, _).
 used_namespace_entities(-List, ?Graph) is det
Return the namespace aliases that are actually used in Graph. In addition, this predicate creates ns<N> aliases for namespaces used in predicates because RDF/XML cannot write predicates other than as an XML name.
 3024used_namespace_entities(List, Graph) :-
 3025    decl_used_predicate_ns(Graph),
 3026    used_namespaces(List, Graph).
 3027
 3028used_namespaces(List, DB) :-
 3029    rdf_graph_prefixes(DB, FullList),
 3030    ns_abbreviations(FullList, List0),
 3031    sort([rdf|List0], List).
 3032
 3033ns_abbreviations([], []).
 3034ns_abbreviations([H0|T0], [H|T]) :-
 3035    ns(H, H0),
 3036    !,
 3037    ns_abbreviations(T0, T).
 3038ns_abbreviations([_|T0], T) :-
 3039    ns_abbreviations(T0, T).
 3040
 3041
 3042/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 3043For every URL used as a predicate  we   *MUST*  define a namespace as we
 3044cannot use names holding /, :, etc. as XML identifiers.
 3045- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 3046
 3047:- thread_local
 3048    predicate_ns/2. 3049
 3050decl_used_predicate_ns(DB) :-
 3051    retractall(predicate_ns(_,_)),
 3052    (   rdf_current_predicate(P, DB),
 3053        decl_predicate_ns(P),
 3054        fail
 3055    ;   true
 3056    ).
 3057
 3058decl_predicate_ns(Pred) :-
 3059    predicate_ns(Pred, _),
 3060    !.
 3061decl_predicate_ns(Pred) :-
 3062    rdf_global_id(NS:Local, Pred),
 3063    xml_name(Local),
 3064    !,
 3065    assert(predicate_ns(Pred, NS)).
 3066decl_predicate_ns(Pred) :-
 3067    atom_codes(Pred, Codes),
 3068    append(NSCodes, LocalCodes, Codes),
 3069    xml_codes(LocalCodes),
 3070    !,
 3071    (   NSCodes \== []
 3072    ->  atom_codes(NS, NSCodes),
 3073        (   ns(Id, NS)
 3074        ->  assert(predicate_ns(Pred, Id))
 3075        ;   between(1, infinite, N),
 3076            atom_concat(ns, N, Id),
 3077            \+ ns(Id, _)
 3078        ->  rdf_register_ns(Id, NS),
 3079            print_message(informational,
 3080                          rdf(using_namespace(Id, NS)))
 3081        ),
 3082        assert(predicate_ns(Pred, Id))
 3083    ;   assert(predicate_ns(Pred, -)) % no namespace used
 3084    ).
 3085
 3086xml_codes([]).
 3087xml_codes([H|T]) :-
 3088    xml_code(H),
 3089    xml_codes(T).
 3090
 3091xml_code(X) :-
 3092    code_type(X, csym),
 3093    !.
 3094xml_code(0'-).                          % Match 0'-
 rdf_save_footer(Out:stream) is det
Finish XML generation and write the document footer.
See also
- rdf_save_header/2, rdf_save_subject/3.
 3103rdf_save_footer(Out) :-
 3104    retractall(named_anon(_, _)),
 3105    retractall(inlined(_)),
 3106    format(Out, '</rdf:RDF>~n', []).
 rdf_save_non_anon_subject(+Out, +Subject, +Options)
Save an object. Anonymous objects not saved if anon(false) is present in the Options list.
 3113rdf_save_non_anon_subject(_Out, Subject, Options) :-
 3114    rdf_is_bnode(Subject),
 3115    (   memberchk(anon(false), Options)
 3116    ;   graph(Options, DB),
 3117        rdf_db(_, _, Subject, DB)
 3118    ),
 3119    !.
 3120rdf_save_non_anon_subject(Out, Subject, Options) :-
 3121    rdf_save_subject(Out, Subject, Options),
 3122    flag(rdf_db_saved_subjects, X, X+1).
 rdf_save_subject(+Out, +Subject:resource, +Options) is det
Save the triples associated to Subject to Out. Options:
graph(+Graph)
Only save properties from Graph.
base_uri(+URI)
convert_typed_literal(:Goal)
document_language(+XMLLang)
See also
- rdf_save/2 for a description of these options.
 3137rdf_save_subject(Out, Subject, Options) :-
 3138    is_list(Options),
 3139    !,
 3140    option(base_uri(BaseURI), Options, '-'),
 3141    (   rdf_save_subject(Out, Subject, BaseURI, 0, Options)
 3142    ->  format(Out, '~n', [])
 3143    ;   throw(error(rdf_save_failed(Subject), 'Internal error'))
 3144    ).
 3145rdf_save_subject(Out, Subject, DB) :-
 3146    (   var(DB)
 3147    ->  rdf_save_subject(Out, Subject, [])
 3148    ;   rdf_save_subject(Out, Subject, [graph(DB)])
 3149    ).
 rdf_save_subject(+Out:stream, +Subject:resource, +BaseURI, +Indent:int, +Options) is det
Save properties of Subject.
Arguments:
Indent- Current indentation
 3159rdf_save_subject(_, Subject, _, _, _) :-
 3160    inlined(Subject),
 3161    !.
 3162rdf_save_subject(Out, Subject, BaseURI, Indent, Options) :-
 3163    do_save_subject(Out, Subject, BaseURI, Indent, Options).
 3164
 3165do_save_subject(Out, Subject, BaseURI, Indent, Options) :-
 3166    graph(Options, DB),
 3167    findall(Pred=Object, rdf_db(Subject, Pred, Object, DB), Atts0),
 3168    sort(Atts0, Atts),              % remove duplicates
 3169    length(Atts, L),
 3170    (   length(Atts0, L0),
 3171        Del is L0-L,
 3172        Del > 0
 3173    ->  print_message(informational,
 3174                      rdf(save_removed_duplicates(Del, Subject)))
 3175    ;   true
 3176    ),
 3177    rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options),
 3178    flag(rdf_db_saved_triples, X, X+L).
 3179
 3180rdf_db(Subject, Pred, Object, DB) :-
 3181    var(DB),
 3182    !,
 3183    rdf(Subject, Pred, Object).
 3184rdf_db(Subject, Pred, Object, DB) :-
 3185    rdf(Subject, Pred, Object, DB:_).
 rdf_save_subject(+Out:stream, +Subject:resource, +BaseURI, +Atts:list(Pred=Obj), +Indent:int, +Options) is det
Save triples defined by Atts on Subject.
 3192rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options) :-
 3193    rdf_equal(rdf:type, RdfType),
 3194    select(RdfType=Type, Atts, Atts1),
 3195    \+ rdf_is_bnode(Type),
 3196    rdf_id(Type, BaseURI, TypeId),
 3197    xml_is_name(TypeId),
 3198    !,
 3199    format(Out, '~*|<', [Indent]),
 3200    rdf_write_id(Out, TypeId),
 3201    save_about(Out, BaseURI, Subject),
 3202    save_attributes(Atts1, BaseURI, Out, TypeId, Indent, Options).
 3203rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options) :-
 3204    format(Out, '~*|<rdf:Description', [Indent]),
 3205    save_about(Out, BaseURI, Subject),
 3206    save_attributes(Atts, BaseURI, Out, rdf:'Description', Indent, Options).
 3207
 3208xml_is_name(_NS:Atom) :-
 3209    !,
 3210    xml_name(Atom).
 3211xml_is_name(Atom) :-
 3212    xml_name(Atom).
 save_about(+Out, +BaseURI, +Subject) is det
Save the rdf:about. If Subject is a blank node, save the nodeID if any.
 3219save_about(Out, _, Subject) :-
 3220    rdf_is_bnode(Subject),
 3221    !,
 3222    (   named_anon(Subject, NodeID)
 3223    ->  format(Out, ' rdf:nodeID="~w"', [NodeID])
 3224    ;   true
 3225    ).
 3226save_about(Out, BaseURI, Subject) :-
 3227    stream_property(Out, encoding(Encoding)),
 3228    rdf_value(Subject, BaseURI, QSubject, Encoding),
 3229    format(Out, ' rdf:about="~w"', [QSubject]).
 save_attributes(+List, +BaseURI, +Stream, +Element, +Indent, +Options)
Save the attributes. Short literal attributes are saved in the tag. Others as the content of the description element. The begin tag has already been filled.
 3237save_attributes(Atts, BaseURI, Out, Element, Indent, Options) :-
 3238    split_attributes(Atts, InTag, InBody, Options),
 3239    SubIndent is Indent + 2,
 3240    save_attributes2(InTag, BaseURI, tag, Out, SubIndent, Options),
 3241    (   InBody == []
 3242    ->  format(Out, '/>~n', [])
 3243    ;   format(Out, '>~n', []),
 3244        save_attributes2(InBody, BaseURI, body, Out, SubIndent, Options),
 3245        format(Out, '~N~*|</', [Indent]),
 3246        rdf_write_id(Out, Element),
 3247        format(Out, '>~n', [])
 3248    ).
 split_attributes(+Attributes, -HeadAttrs, -BodyAttr, Options)
Split attribute (Name=Value) list into attributes for the head and body. Attributes can only be in the head if they are literal and appear only one time in the attribute list.
 3256split_attributes(Atts, [], Atts, Options) :-
 3257    option(xml_attributes(false), Options),
 3258    !.
 3259split_attributes(Atts, HeadAttr, BodyAttr, _) :-
 3260    duplicate_attributes(Atts, Dupls, Singles),
 3261    simple_literal_attributes(Singles, HeadAttr, Rest),
 3262    append(Dupls, Rest, BodyAttr).
 duplicate_attributes(+Attrs, -Duplicates, -Singles)
Extract attributes that appear more than onces as we cannot dublicate an attribute in the head according to the XML rules.
 3269duplicate_attributes([], [], []).
 3270duplicate_attributes([H|T], Dupls, Singles) :-
 3271    H = (Name=_),
 3272    named_attributes(Name, T, D, R),
 3273    D \== [],
 3274    append([H|D], Dupls2, Dupls),
 3275    !,
 3276    duplicate_attributes(R, Dupls2, Singles).
 3277duplicate_attributes([H|T], Dupls2, [H|Singles]) :-
 3278    duplicate_attributes(T, Dupls2, Singles).
 3279
 3280named_attributes(_, [], [], []) :- !.
 3281named_attributes(Name, [H|T], D, R) :-
 3282    (   H = (Name=_)
 3283    ->  D = [H|DT],
 3284        named_attributes(Name, T, DT, R)
 3285    ;   R = [H|RT],
 3286        named_attributes(Name, T, D, RT)
 3287    ).
 simple_literal_attributes(+Attributes, -Inline, -Body)
Split attributes for (literal) attributes to be used in the begin-tag and ones that have to go into the body of the description.
 3294simple_literal_attributes([], [], []).
 3295simple_literal_attributes([H|TA], [H|TI], B) :-
 3296    in_tag_attribute(H),
 3297    !,
 3298    simple_literal_attributes(TA, TI, B).
 3299simple_literal_attributes([H|TA], I, [H|TB]) :-
 3300    simple_literal_attributes(TA, I, TB).
 3301
 3302in_tag_attribute(_=literal(Text)) :-
 3303    atom(Text),                     % may not have lang qualifier
 3304    atom_length(Text, Len),
 3305    Len < 60.
 save_attributes(+List, +BaseURI, +TagOrBody, +Stream)
Save a list of attributes.
 3311save_attributes2([], _, _, _, _, _).
 3312save_attributes2([H|T], BaseURI, Where, Out, Indent, Options) :-
 3313    save_attribute(Where, H, BaseURI, Out, Indent, Options),
 3314    save_attributes2(T, BaseURI, Where, Out, Indent, Options).
 3315
 3316save_attribute(tag, Name=literal(Value), BaseURI, Out, Indent, _DB) :-
 3317    AttIndent is Indent + 2,
 3318    rdf_id(Name, BaseURI, NameText),
 3319    stream_property(Out, encoding(Encoding)),
 3320    xml_quote_attribute(Value, QVal, Encoding),
 3321    format(Out, '~N~*|', [AttIndent]),
 3322    rdf_write_id(Out, NameText),
 3323    format(Out, '="~w"', [QVal]).
 3324save_attribute(body, Name=literal(Literal0), BaseURI, Out, Indent, Options) :-
 3325    !,
 3326    rdf_id(Name, BaseURI, NameText),
 3327    (   memberchk(convert_typed_literal(Converter), Options),
 3328        call(Converter, Type, Content, Literal0)
 3329    ->  Literal = type(Type, Content)
 3330    ;   Literal = Literal0
 3331    ),
 3332    save_body_literal(Literal, NameText, BaseURI, Out, Indent, Options).
 3333save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :-
 3334    rdf_is_bnode(Value),
 3335    !,
 3336    rdf_id(Name, BaseURI, NameText),
 3337    format(Out, '~N~*|<', [Indent]),
 3338    rdf_write_id(Out, NameText),
 3339    (   named_anon(Value, NodeID)
 3340    ->  format(Out, ' rdf:nodeID="~w"/>', [NodeID])
 3341    ;   (   rdf(S1, Name, Value),
 3342            rdf(S2, P2, Value),
 3343            (S1 \== S2 ; Name \== P2)
 3344        ->  predicate_property(named_anon(_,_), number_of_clauses(N)),
 3345            atom_concat('bn', N, NodeID),
 3346            assertz(named_anon(Value, NodeID))
 3347        ;   true
 3348        ),
 3349        SubIndent is Indent + 2,
 3350        (   rdf_collection(Value)
 3351        ->  save_about(Out, BaseURI, Value),
 3352            format(Out, ' rdf:parseType="Collection">~n', []),
 3353            rdf_save_list(Out, Value, BaseURI, SubIndent, Options)
 3354        ;   format(Out, '>~n', []),
 3355            rdf_save_subject(Out, Value, BaseURI, SubIndent, Options)
 3356        ),
 3357        format(Out, '~N~*|</', [Indent]),
 3358        rdf_write_id(Out, NameText),
 3359        format(Out, '>~n', [])
 3360    ).
 3361save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :-
 3362    option(inline(true), Options),
 3363    has_attributes(Value, Options),
 3364    \+ inlined(Value),
 3365    !,
 3366    assertz(inlined(Value)),
 3367    rdf_id(Name, BaseURI, NameText),
 3368    format(Out, '~N~*|<', [Indent]),
 3369    rdf_write_id(Out, NameText),
 3370    SubIndent is Indent + 2,
 3371    (   rdf_collection(Value)
 3372    ->  save_about(Out, BaseURI, Value),
 3373        format(Out, ' rdf:parseType="Collection">~n', []),
 3374        rdf_save_list(Out, Value, BaseURI, SubIndent, Options)
 3375    ;   format(Out, '>~n', []),
 3376        do_save_subject(Out, Value, BaseURI, SubIndent, Options)
 3377    ),
 3378    format(Out, '~N~*|</', [Indent]),
 3379    rdf_write_id(Out, NameText),
 3380    format(Out, '>~n', []).
 3381save_attribute(body, Name=Value, BaseURI, Out, Indent, _DB) :-
 3382    stream_property(Out, encoding(Encoding)),
 3383    rdf_value(Value, BaseURI, QVal, Encoding),
 3384    rdf_id(Name, BaseURI, NameText),
 3385    format(Out, '~N~*|<', [Indent]),
 3386    rdf_write_id(Out, NameText),
 3387    format(Out, ' rdf:resource="~w"/>', [QVal]).
 3388
 3389has_attributes(URI, Options) :-
 3390    graph(Options, DB),
 3391    rdf_db(URI, _, _, DB),
 3392    !.
 save_body_literal(+Literal, +NameText, +BaseURI, +Out, +Indent, +Options)
 3397save_body_literal(lang(Lang, Value),
 3398                  NameText, BaseURI, Out, Indent, Options) :-
 3399    !,
 3400    format(Out, '~N~*|<', [Indent]),
 3401    rdf_write_id(Out, NameText),
 3402    (   memberchk(document_language(Lang), Options)
 3403    ->  write(Out, '>')
 3404    ;   rdf_id(Lang, BaseURI, LangText),
 3405        format(Out, ' xml:lang="~w">', [LangText])
 3406    ),
 3407    save_attribute_value(Value, Out, Indent),
 3408    write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>').
 3409save_body_literal(type(Type, DOM),
 3410                  NameText, _BaseURI, Out, Indent, Options) :-
 3411    rdf_equal(Type, rdf:'XMLLiteral'),
 3412    !,
 3413    (   atom(DOM)
 3414    ->  format(Out, '~N~*|<', [Indent]),
 3415        rdf_write_id(Out, NameText),
 3416        format(Out, ' rdf:parseType="Literal">~w</', [DOM]),
 3417        rdf_write_id(Out, NameText), write(Out, '>')
 3418    ;   save_xml_literal(DOM, NameText, Out, Indent, Options)
 3419    ).
 3420save_body_literal(type(Type, Value),
 3421                  NameText, BaseURI, Out, Indent, _) :-
 3422    !,
 3423    format(Out, '~N~*|<', [Indent]),
 3424    rdf_write_id(Out, NameText),
 3425    stream_property(Out, encoding(Encoding)),
 3426    rdf_value(Type, BaseURI, QVal, Encoding),
 3427    format(Out, ' rdf:datatype="~w">', [QVal]),
 3428    save_attribute_value(Value, Out, Indent),
 3429    write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>').
 3430save_body_literal(Literal,
 3431                  NameText, _, Out, Indent, _) :-
 3432    atomic(Literal),
 3433    !,
 3434    format(Out, '~N~*|<', [Indent]),
 3435    rdf_write_id(Out, NameText),
 3436    write(Out, '>'),
 3437    save_attribute_value(Literal, Out, Indent),
 3438    write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>').
 3439save_body_literal(DOM,
 3440                  NameText, BaseURI, Out, Indent, Options) :-
 3441    rdf_equal(Type, rdf:'XMLLiteral'),
 3442    save_body_literal(type(Type, DOM),
 3443                      NameText, BaseURI, Out, Indent, Options).
 3444
 3445save_attribute_value(Value, Out, _) :-  % strings
 3446    atom(Value),
 3447    !,
 3448    stream_property(Out, encoding(Encoding)),
 3449    xml_quote_cdata(Value, QVal, Encoding),
 3450    write(Out, QVal).
 3451save_attribute_value(Value, Out, _) :-  % numbers
 3452    number(Value),
 3453    !,
 3454    writeq(Out, Value).             % quoted: preserve floats
 3455save_attribute_value(Value, _Out, _) :-
 3456    throw(error(save_attribute_value(Value), _)).
 save_xml_literal(+DOM, +Attr, +Out, +Indent, +Options) is det
Save an XMLLiteral value. We already emitted
<prop parseType="literal"

but not the terminating >. We need to establish the namespaces used in the DOM. The namespaces in the rdf document are in the nsmap-option of Options.

 3470save_xml_literal(DOM, Attr, Out, Indent, Options) :-
 3471    xml_is_dom(DOM),
 3472    !,
 3473    memberchk(nsmap(NsMap), Options),
 3474    id_to_atom(Attr, Atom),
 3475    xml_write(Out,
 3476              element(Atom, ['rdf:parseType'='Literal'], DOM),
 3477              [ header(false),
 3478                indent(Indent),
 3479                nsmap(NsMap)
 3480              ]).
 3481save_xml_literal(NoDOM, _, _, _, _) :-
 3482    must_be(xml_dom, NoDOM).
 3483
 3484id_to_atom(NS:Local, Atom) :-
 3485    !,
 3486    atomic_list_concat([NS,Local], :, Atom).
 3487id_to_atom(ID, ID).
 rdf_collection(+URI) is semidet
True if URI represents an RDF list that fits the RDF parseType=collection syntax. This means it is a linked list of bnode-cells with a rdf:first that is a resource, optionally a rdf:type that is an rdf:list and the list ends in an rdf:nil.
 3497:- rdf_meta
 3498    rdf_collection(r),
 3499    collection_p(r,r). 3500
 3501rdf_collection(rdf:nil) :- !.
 3502rdf_collection(Cell) :-
 3503    rdf_is_bnode(Cell),
 3504    findall(F, rdf(Cell, rdf:first, F), [_]),
 3505    findall(F, rdf(Cell, rdf:rest, F), [Rest]),
 3506    forall(rdf(Cell, P, V),
 3507           collection_p(P, V)),
 3508    rdf_collection(Rest).
 3509
 3510collection_p(rdf:first, V) :- atom(V).
 3511collection_p(rdf:rest, _).
 3512collection_p(rdf:type, rdf:'List').
 rdf_save_list(+Out, +List, +BaseURI, +Indent, +Options)
 3517rdf_save_list(_, List, _, _, _) :-
 3518    rdf_equal(List, rdf:nil),
 3519    !.
 3520rdf_save_list(Out, List, BaseURI, Indent, Options) :-
 3521    rdf_has(List, rdf:first, First),
 3522    (   rdf_is_bnode(First)
 3523    ->  nl(Out),
 3524        rdf_save_subject(Out, First, BaseURI, Indent, Options)
 3525    ;   stream_property(Out, encoding(Encoding)),
 3526        rdf_value(First, BaseURI, QVal, Encoding),
 3527        format(Out, '~N~*|<rdf:Description rdf:about="~w"/>',
 3528               [Indent, QVal])
 3529    ),
 3530    flag(rdf_db_saved_triples, X, X+3),
 3531    (   rdf_has(List, rdf:rest, List2),
 3532        \+ rdf_equal(List2, rdf:nil)
 3533    ->  rdf_save_list(Out, List2, BaseURI, Indent, Options)
 3534    ;   true
 3535    ).
 rdf_id(+Resource, +BaseURI, -NSLocal)
Generate a NS:Local name for Resource given the indicated default namespace. This call is used for elements.
 3543rdf_id(Id, BaseURI, Local) :-
 3544    assertion(atom(BaseURI)),
 3545    atom_concat(BaseURI, Local, Id),
 3546    sub_atom(Local, 0, 1, _, #),
 3547    !.
 3548rdf_id(Id, _, NS:Local) :-
 3549    iri_xml_namespace(Id, Full, Local),
 3550    ns(NS, Full),
 3551    !.
 3552rdf_id(Id, _, NS:Local) :-
 3553    ns(NS, Full),
 3554    Full \== '',
 3555    atom_concat(Full, Local, Id),
 3556    !.
 3557rdf_id(Id, _, Id).
 rdf_write_id(+Out, +NSLocal) is det
Write an identifier. We cannot use native write on it as both NS and Local can be operators.
 3565rdf_write_id(Out, NS:Local) :-
 3566    !,
 3567    format(Out, '~w:~w', [NS, Local]).
 3568rdf_write_id(Out, Atom) :-
 3569    write(Out, Atom).
 rdf_value(+Resource, +BaseURI, -Text, +Encoding)
According to "6.4 RDF URI References" of the RDF Syntax specification, a URI reference is UNICODE string not containing control sequences, represented as UTF-8 and then as escaped US-ASCII.
 3578rdf_value(Base, Base, '', _) :- !.
 3579rdf_value(V, Base, Text, Encoding) :-
 3580    atom_concat(Base, Local, V),
 3581    sub_atom(Local, 0, _, _, #),
 3582    !,
 3583    xml_quote_attribute(Local, Text, Encoding).
 3584rdf_value(V, _, Text, Encoding) :-
 3585    ns(NS, Full),
 3586    atom_concat(Full, Local, V),
 3587    xml_is_name(Local),
 3588    !,
 3589    xml_quote_attribute(Local, QLocal, Encoding),
 3590    atomic_list_concat(['&', NS, (';'), QLocal], Text).
 3591rdf_value(V, _, Q, Encoding) :-
 3592    xml_quote_attribute(V, Q, Encoding).
 3593
 3594
 3595                 /*******************************
 3596                 *       MATCH AND COMPARE      *
 3597                 *******************************/
 rdf_compare(-Dif, +Object1, +Object2) is det
Compare two object terms. Where SPARQL defines a partial ordering, we define a complete ordering of terms. The ordering is defines as:
 rdf_match_label(+How, +Pattern, +Label) is semidet
True if Label matches Pattern according to How. How is one of icase, substring, word, prefix or like. For backward compatibility, exact is a synonym for icase.
 3620                 /*******************************
 3621                 *      DEPRECATED MATERIAL     *
 3622                 *******************************/
 rdf_split_url(+Prefix, +Local, -URL) is det
rdf_split_url(-Prefix, -Local, +URL) is det
Split/join a URL. This functionality is moved to library(sgml).
deprecated
- Use iri_xml_namespace/3. Note that the argument order is iri_xml_namespace(+IRI, -Namespace, -Localname).
 3632rdf_split_url(Prefix, Local, URL) :-
 3633    atomic(URL),
 3634    !,
 3635    iri_xml_namespace(URL, Prefix, Local).
 3636rdf_split_url(Prefix, Local, URL) :-
 3637    atom_concat(Prefix, Local, URL).
 rdf_url_namespace(+URL, -Namespace)
Namespace is the namespace of URL.
deprecated
- Use iri_xml_namespace/2
 3645rdf_url_namespace(URL, Prefix) :-
 3646    iri_xml_namespace(URL, Prefix).
 3647
 3648
 3649                 /*******************************
 3650                 *            LITERALS          *
 3651                 *******************************/
 rdf_new_literal_map(-Map) is det
Create a new literal map, returning an opaque handle.
 rdf_destroy_literal_map(+Map) is det
Destroy a literal map. After this call, further use of the Map handle is illegal. Additional synchronisation is needed if maps that are shared between threads are destroyed to guarantee the handle is no longer used. In some scenarios rdf_reset_literal_map/1 provides a safe alternative.
 rdf_reset_literal_map(+Map) is det
Delete all content from the literal map.
 rdf_insert_literal_map(+Map, +Key, +Value) is det
Add a relation between Key and Value to the map. If this relation already exists no action is performed.
 rdf_insert_literal_map(+Map, +Key, +Value, -KeyCount) is det
As rdf_insert_literal_map/3. In addition, if Key is a new key in Map, unify KeyCount with the number of keys in Map. This serves two purposes. Derived maps, such as the stem and metaphone maps need to know about new keys and it avoids additional foreign calls for doing the progress in rdf_litindex.pl.
 rdf_delete_literal_map(+Map, +Key) is det
Delete Key and all associated values from the map.
 rdf_delete_literal_map(+Map, +Key, +Value) is det
Delete the association between Key and Value from the map.
 rdf_find_literal_map(+Map, +KeyList, -ValueList) is det
Unify ValueList with an ordered set of values associated to all keys from KeyList. Each key in KeyList is either an atom, an integer or a term not(Key). If not-terms are provided, there must be at least one positive keywords. The negations are tested after establishing the positive matches.
 rdf_keys_in_literal_map(+Map, +Spec, -Answer) is det
Realises various queries on the key-set:
 rdf_statistics_literal_map(+Map, -KeyValue)
Query some statistics of the map. Provides KeyValue are:
size(-Keys, -Relations)
Unify Keys with the total key-count of the index and Relation with the total Key-Value count.
 3739                 /*******************************
 3740                 *             MISC             *
 3741                 *******************************/
 rdf_version(-Version) is det
True when Version is the numerical version-id of this library. The version is computed as
Major*10000 + Minor*100 + Patch.
 rdf_set(+Term) is det
Set properties of the RDF store. Currently defines:
hash(+Hash, +Parameter, +Value)
Set properties for a triple index. Hash is one of s, p, sp, o, po, spo, g, sg or pg. Parameter is one of:
size
Value defines the number of entries in the hash-table. Value is rounded down to a power of 2. After setting the size explicitly, auto-sizing for this table is disabled. Setting the size smaller than the current size results in a permission_error exception.
average_chain_len
Set maximum average collision number for the hash.
optimize_threshold
Related to resizing hash-tables. If 0, all triples are moved to the new size by the garbage collector. If more then zero, those of the last Value resize steps remain at their current location. Leaving cells at their current location reduces memory fragmentation and slows down access.
 rdf_md5(+Graph, -MD5) is det
True when MD5 is the MD5 hash for all triples in graph. The MD5 digest itself is represented as an atom holding a 32-character hexadecimal string. The library maintains the digest incrementally on rdf_load/[1,2], rdf_load_db/1, rdf_assert/[3,4] and rdf_retractall/[3,4]. Checking whether the digest has changed since the last rdf_load/[1,2] call provides a practical means for checking whether the file needs to be saved.
deprecated
- New code should use rdf_graph_property(Graph, hash(Hash)).
 rdf_generation(-Generation) is det
True when Generation is the current generation of the database. Each modification to the database increments the generation. It can be used to check the validity of cached results deduced from the database. Committing a non-empty transaction increments the generation by one.

When inside a transaction, Generation is unified to a term TransactionStartGen + InsideTransactionGen. E.g., 4+3 means that the transaction was started at generation 4 of the global database and we have created 3 new generations inside the transaction. Note that this choice of representation allows for comparing generations using Prolog arithmetic. Comparing a generation in one transaction with a generation in another transaction is meaningless.

 rdf_estimate_complexity(?Subject, ?Predicate, ?Object, -Complexity)
Return the number of alternatives as indicated by the database internal hashed indexing. This is a rough measure for the number of alternatives we can expect for an rdf_has/3 call using the given three arguments. When called with three variables, the total number of triples is returned. This estimate is used in query optimisation. See also rdf_predicate_property/2 and rdf_statistics/1 for additional information to help optimizers.
 rdf_debug(+Level) is det
Set debugging to Level. Level is an integer 0..9. Default is 0 no debugging.
 rdf_atom_md5(+Text, +Times, -MD5) is det
Computes the MD5 hash from Text, which is an atom, string or list of character codes. Times is an integer >= 1. When > 0, the MD5 algorithm is repeated Times times on the generated hash. This can be used for password encryption algorithms to make generate-and-test loops slow.
deprecated
- . New code should use the library(crypt) library provided by the clib package for password encryption and library(md5) to compute MD5 hashes.
 3835                 /*******************************
 3836                 *             MESSAGES         *
 3837                 *******************************/
 3838
 3839:- multifile
 3840    prolog:message//1. 3841
 3842prolog:message(rdf(Term)) -->
 3843    message(Term).
 3844
 3845message(loaded(How, What, BaseURI, Triples, Time)) -->
 3846    how(How),
 3847    source(What),
 3848    into(What, BaseURI),
 3849    in_time(Triples, Time).
 3850message(save_removed_duplicates(N, Subject)) -->
 3851    [ 'Removed ~d duplicate triples about "~p"'-[N,Subject] ].
 3852message(saved(File, SavedSubjects, SavedTriples)) -->
 3853    [ 'Saved ~D triples about ~D subjects into ~p'-
 3854      [SavedTriples, SavedSubjects, File]
 3855    ].
 3856message(using_namespace(Id, NS)) -->
 3857    [ 'Using namespace id ~w for ~w'-[Id, NS] ].
 3858message(inconsistent_cache(DB, Graphs)) -->
 3859    [ 'RDF cache file for ~w contains the following graphs'-[DB], nl,
 3860      '~t~8|~p'-[Graphs]
 3861    ].
 3862message(guess_format(Ext)) -->
 3863    [ 'Unknown file-extension: ~w.  Assuming RDF/XML'-[Ext] ].
 3864message(meta(not_expanded(G))) -->
 3865    [ 'rdf_meta/1: ~p is not expanded'-[G] ].
 3866message(deprecated(rdf_unload(Graph))) -->
 3867    [ 'rdf_unload/1: Use ~q'-[rdf_unload_graph(Graph)] ].
 3868
 3869
 3870how(load)   --> [ 'Loaded' ].
 3871how(parsed) --> [ 'Parsed' ].
 3872
 3873source(SourceURL) -->
 3874    { uri_file_name(SourceURL, File),
 3875      !,
 3876      file_base_name(File, Base)    % TBD: relative file?
 3877    },
 3878    [ ' "~w"'-[Base] ].
 3879source(SourceURL) -->
 3880    [ ' "~w"'-[SourceURL] ].
 3881
 3882into(_, _) --> [].                      % TBD
 3883
 3884in_time(Triples, ParseTime) -->
 3885    [ ' in ~2f sec; ~D triples'-[ParseTime, Triples]
 3886    ]