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.
 236
 237/** <module> Core RDF database
 238
 239The file library(semweb/rdf_db) provides the core  of the SWI-Prolog RDF
 240store.
 241
 242@deprecated     New applications should use library(semweb/rdf11), which
 243                provides a much more intuitive API to the RDF store, notably
 244                for handling literals.  The library(semweb/rdf11) runs
 245                currently on top of this library and both can run side-by-side
 246                in the same application.  Terms retrieved from the database
 247                however have a different shape and can not be exchanged without
 248                precautions.
 249*/
 250
 251                 /*******************************
 252                 *           PREFIXES           *
 253                 *******************************/
 254
 255%!  rdf_current_prefix(:Alias, ?URI) is nondet.
 256%
 257%   Query   predefined   prefixes   and    prefixes   defined   with
 258%   rdf_register_prefix/2   and   local   prefixes    defined   with
 259%   rdf_prefix/2. If Alias is unbound and one   URI is the prefix of
 260%   another, the longest is returned first.   This  allows turning a
 261%   resource into a prefix/local couple using the simple enumeration
 262%   below. See rdf_global_id/2.
 263%
 264%     ==
 265%     rdf_current_prefix(Prefix, Expansion),
 266%     atom_concat(Expansion, Local, URI),
 267%     ==
 268
 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    ).
 287
 288%!  rdf_prefix(:Alias, +URI) is det.
 289%
 290%   Register a _local_ prefix.  This   declaration  takes precedence
 291%   over globally defined prefixes   using  rdf_register_prefix/2,3.
 292%   Module local prefixes are notably required   to deal with SWISH,
 293%   where users need to  be  able   to  have  independent  namespace
 294%   declarations.
 295
 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    ).
 310
 311%!  ns(?Alias, ?URI) is nondet.
 312%
 313%   Dynamic and multifile predicate that   maintains  the registered
 314%   namespace aliases.
 315%
 316%   @deprecated New code  must  modify   the  namespace  table using
 317%   rdf_register_ns/3 and query using rdf_current_ns/2.
 318
 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#').
 330
 331%!  rdf_register_prefix(+Prefix, +URI) is det.
 332%!  rdf_register_prefix(+Prefix, +URI, +Options) is det.
 333%
 334%   Register Prefix as an abbreviation for URI. Options:
 335%
 336%           * force(Boolean)
 337%           If =true=, Replace existing namespace alias. Please note
 338%           that replacing a namespace is dangerous as namespaces
 339%           affect preprocessing. Make sure all code that depends on
 340%           a namespace is compiled after changing the registration.
 341%
 342%           * keep(Boolean)
 343%           If =true= and Alias is already defined, keep the
 344%           original binding for Prefix and succeed silently.
 345%
 346%   Without options, an attempt  to  redefine   an  alias  raises  a
 347%   permission error.
 348%
 349%   Predefined prefixes are:
 350%
 351%   | **Alias** | **IRI prefix**                              |
 352%   | dc        | http://purl.org/dc/elements/1.1/            |
 353%   | dcterms   | http://purl.org/dc/terms/                   |
 354%   | eor       | http://dublincore.org/2000/03/13/eor#       |
 355%   | foaf      | http://xmlns.com/foaf/0.1/                  |
 356%   | owl       | http://www.w3.org/2002/07/owl#              |
 357%   | rdf       | http://www.w3.org/1999/02/22-rdf-syntax-ns# |
 358%   | rdfs      | http://www.w3.org/2000/01/rdf-schema#       |
 359%   | serql     | http://www.openrdf.org/schema/serql#        |
 360%   | skos      | http://www.w3.org/2004/02/skos/core#        |
 361%   | void      | http://rdfs.org/ns/void#                    |
 362%   | xsd       | http://www.w3.org/2001/XMLSchema#           |
 363
 364
 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    ).
 375
 376%!  register_global_prefix(+Alias, +URI, +Options)
 377%
 378%   Register a global prefix.
 379
 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).
 412
 413%!  rdf_current_ns(:Prefix, ?URI) is nondet.
 414%
 415%   @deprecated.  Use rdf_current_prefix/2.
 416
 417rdf_current_ns(Prefix, URI) :-
 418    rdf_current_prefix(Prefix, URI).
 419
 420%!  rdf_register_ns(:Prefix, ?URI) is det.
 421%!  rdf_register_ns(:Prefix, ?URI, +Options) is det.
 422%
 423%   Register an RDF prefix.
 424%
 425%   @deprecated. Use rdf_register_prefix/2 or rdf_register_prefix/3.
 426
 427rdf_register_ns(Prefix, URI) :-
 428    rdf_register_prefix(Prefix, URI).
 429rdf_register_ns(Prefix, URI, Options) :-
 430    rdf_register_prefix(Prefix, URI, Options).
 431
 432
 433%!  register_file_ns(+Map:list(pair)) is det.
 434%
 435%   Register a namespace as encounted in   the  namespace list of an
 436%   RDF document. We only register if  both the abbreviation and URL
 437%   are not already known. Is there a   better  way? This code could
 438%   also do checks on the consistency   of  RDF and other well-known
 439%   namespaces.
 440%
 441%   @tbd    Better error handling
 442
 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    ).
 461
 462
 463%!  rdf_global_id(?IRISpec, :IRI) is semidet.
 464%
 465%   Convert between Prefix:Local and full IRI   (an atom). If IRISpec is
 466%   an atom, it  is  simply  unified   with  IRI.  This  predicate fails
 467%   silently if IRI is an RDF literal.
 468%
 469%   Note that this predicate is a meta-predicate on its output argument.
 470%   This is necessary to get the module context while the first argument
 471%   may be of the form (:)/2. The above mode description is correct, but
 472%   should be interpreted as (?,?).
 473%
 474%   @error existence_error(rdf_prefix, Prefix)
 475%   @see   rdf_equal/2 provides a compile time alternative
 476%   @see   The rdf_meta/1 directive asks for compile time expansion
 477%          of arguments.
 478%   @bug   Error handling is incomplete.  In its current implementation
 479%	   the same code is used for compile-time expansion and to
 480%	   facilitate runtime conversion and checking.  These use cases
 481%	   have different requirements.
 482
 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, _).
 490
 491
 492%!  rdf_global_object(+Object, :GlobalObject) is semidet.
 493%!  rdf_global_object(-Object, :GlobalObject) is semidet.
 494%
 495%   Same as rdf_global_id/2,  but  intended   for  dealing  with the
 496%   object part of a  triple,  in   particular  the  type  for typed
 497%   literals. Note that the predicate  is   a  meta-predicate on the
 498%   output argument. This is necessary  to   get  the module context
 499%   while the first argument may be of the form (:)/2.
 500%
 501%   @error  existence_error(rdf_prefix, Prefix)
 502
 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    ).
 544
 545
 546%!  rdf_global_term(+TermIn, :GlobalTerm) is det.
 547%
 548%   Does  rdf_global_id/2  on  all  terms  NS:Local  by  recursively
 549%   analysing the term. Note that the  predicate is a meta-predicate
 550%   on the output argument. This  is   necessary  to  get the module
 551%   context while the first argument may be of the form (:)/2.
 552%
 553%   Terms of the form Prefix:Local that   appear in TermIn for which
 554%   Prefix is not defined are   not replaced. Unlike rdf_global_id/2
 555%   and rdf_global_object/2, no error is raised.
 556
 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, _).
 579
 580%!  rdf_global_graph(+TermIn, -GlobalTerm, +Module) is det.
 581%
 582%   Preforms rdf_global_id/2 on rdf/4, etc graph arguments
 583
 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), _)).
 651
 652%!  rdf_meta(+Heads)
 653%
 654%   This  directive  defines  the  argument    types  of  the  named
 655%   predicates, which will force compile   time  namespace expansion
 656%   for these predicates. Heads is a coma-separated list of callable
 657%   terms. Defined argument properties are:
 658%
 659%     $ : :
 660%     Argument is a goal. The goal is processed using expand_goal/2,
 661%     recursively applying goal transformation on the argument.
 662%
 663%     $ + :
 664%     The argument is instantiated at entry. Nothing is changed.
 665%
 666%     $ - :
 667%     The argument is not instantiated at entry. Nothing is changed.
 668%
 669%     $ ? :
 670%     The argument is unbound or instantiated at entry. Nothing is
 671%     changed.
 672%
 673%     $ @ :
 674%     The argument is not changed.
 675%
 676%     $ r :
 677%     The argument must be a resource. If it is a term
 678%     _prefix_:_local_ it is translated.
 679%
 680%     $ o :
 681%     The argument is an object or resource. See
 682%     rdf_global_object/2.
 683%
 684%     $ t :
 685%     The argument is a term that must be translated. Expansion will
 686%     translate all occurences of _prefix_:_local_ appearing
 687%     anywhere in the term. See rdf_global_term/2.
 688%
 689%   As it is subject to term_expansion/2, the rdf_meta/1 declaration
 690%   can only be used as a directive. The directive must be processed
 691%   before the definition of  the  predicates   as  well  as  before
 692%   compiling code that  uses  the   rdf  meta-predicates.  The atom
 693%   =rdf_meta=  is  declared   as   an    operator   exported   from
 694%   library(semweb/rdf_db). Files using rdf_meta/1  must explicitely
 695%   load this library.
 696%
 697%   Beginning with SWI-Prolog 7.3.17, the   low-level  RDF interface
 698%   (rdf/3,  rdf_assert/3,  etc.)  perform    runtime  expansion  of
 699%   `Prefix:Local` terms. This eliminates the   need  for rdf_meta/1
 700%   for  simple  cases.  However,  runtime   expansion  comes  at  a
 701%   significant overhead and having two  representations for IRIs (a
 702%   plain atom and  a  term   `Prefix:Local`)  implies  that  simple
 703%   operations such as comparison of IRIs   no  longer map to native
 704%   Prolog operations such as `IRI1 == IRI2`.
 705
 706rdf_meta(Heads) :-
 707    throw(error(context_error(nodirective, rdf_meta(Heads)), _)).
 708
 709%!  rdf_meta_specification(+General, +Module, -Spec) is semidet.
 710%
 711%   True when Spec is the RDF meta specification for Module:General.
 712%
 713%   @arg    General is the term Spec with all arguments replaced with
 714%           variables.
 715
 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).
 768
 769%!  mk_global(+Src, -Resource, +Module)
 770%
 771%   Realised rdf_global_id(+, -), but adds compiletime checking,
 772%   notably to see whether a namespace is not yet defined.
 773
 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,+).
 816
 817%!  rdf_equal(?Resource1, ?Resource2)
 818%
 819%   Simple equality test to exploit goal-expansion
 820
 821rdf_equal(Resource, Resource).
 822
 823%!  lang_equal(+Lang1, +Lang2) is semidet.
 824%
 825%   True if two RFC language specifiers denote the same language
 826%
 827%   @see lang_matches/2.
 828
 829lang_equal(Lang, Lang) :- !.
 830lang_equal(Lang1, Lang2) :-
 831    downcase_atom(Lang1, LangCannon),
 832    downcase_atom(Lang2, LangCannon).
 833
 834%!  lang_matches(+Lang, +Pattern) is semidet.
 835%
 836%   True if Lang  matches  Pattern.   This  implements  XML language
 837%   matching  conform  RFC  4647.   Both    Lang   and  Pattern  are
 838%   dash-separated strings of  identifiers  or   (for  Pattern)  the
 839%   wildcart *. Identifiers are  matched   case-insensitive  and a *
 840%   matches any number of identifiers. A   short pattern is the same
 841%   as *.
 842
 843
 844                 /*******************************
 845                 *     BASIC TRIPLE QUERIES     *
 846                 *******************************/
 847
 848%!  rdf(?Subject, ?Predicate, ?Object) is nondet.
 849%
 850%   Elementary query for triples. Subject   and  Predicate are atoms
 851%   representing the fully qualified URL of  the resource. Object is
 852%   either an atom representing a resource  or literal(Value) if the
 853%   object  is  a  literal  value.   If    a   value   of  the  form
 854%   NameSpaceID:LocalName is provided it  is   expanded  to a ground
 855%   atom  using  expand_goal/2.  This  implies   you  can  use  this
 856%   construct in compiled code without paying a performance penalty.
 857%   Literal values take one of the following forms:
 858%
 859%     * Atom
 860%     If the value is a simple atom it is the textual representation
 861%     of a string literal without explicit type or language
 862%     qualifier.
 863%
 864%     * lang(LangID, Atom)
 865%     Atom represents the text of a string literal qualified with
 866%     the given language.
 867%
 868%     * type(TypeID, Value)
 869%     Used for attributes qualified using the =|rdf:datatype|=
 870%     TypeID. The Value is either the textual representation or a
 871%     natural Prolog representation. See the option
 872%     convert_typed_literal(:Convertor) of the parser. The storage
 873%     layer provides efficient handling of atoms, integers (64-bit)
 874%     and floats (native C-doubles). All other data is represented
 875%     as a Prolog record.
 876%
 877%   For literal querying purposes, Object can be of the form
 878%   literal(+Query, -Value), where Query is one of the terms below.
 879%   If the Query takes a literal argument and the value has a
 880%   numeric type numerical comparison is performed.
 881%
 882%     * plain(+Text)
 883%     Perform exact match and demand the language or type qualifiers
 884%     to match. This query is fully indexed.
 885%
 886%     * icase(+Text)
 887%     Perform a full but case-insensitive match. This query is
 888%     fully indexed.
 889%
 890%     * exact(+Text)
 891%     Same as icase(Text).  Backward compatibility.
 892%
 893%     * substring(+Text)
 894%     Match any literal that contains Text as a case-insensitive
 895%     substring. The query is not indexed on Object.
 896%
 897%     * word(+Text)
 898%     Match any literal that contains Text delimited by a non
 899%     alpha-numeric character, the start or end of the string. The
 900%     query is not indexed on Object.
 901%
 902%     * prefix(+Text)
 903%     Match any literal that starts with Text. This call is intended
 904%     for completion. The query is indexed using the skip list of
 905%     literals.
 906%
 907%     * ge(+Literal)
 908%     Match any literal that is equal or larger then Literal in the
 909%     ordered set of literals.
 910%
 911%     * gt(+Literal)
 912%     Match any literal that is larger then Literal in the ordered set
 913%     of literals.
 914%
 915%     * eq(+Literal)
 916%     Match any literal that is equal to Literal in the ordered set
 917%     of literals.
 918%
 919%     * le(+Literal)
 920%     Match any literal that is equal or smaller then Literal in the
 921%     ordered set of literals.
 922%
 923%     * lt(+Literal)
 924%     Match any literal that is smaller then Literal in the ordered set
 925%     of literals.
 926%
 927%     * between(+Literal1, +Literal2)
 928%     Match any literal that is between Literal1 and Literal2 in the
 929%     ordered set of literals. This may include both Literal1 and
 930%     Literal2.
 931%
 932%     * like(+Pattern)
 933%     Match any literal that matches Pattern case insensitively,
 934%     where the `*' character in Pattern matches zero or more
 935%     characters.
 936%
 937%   Backtracking never returns duplicate triples.  Duplicates can be
 938%   retrieved using rdf/4. The predicate   rdf/3 raises a type-error
 939%   if called with improper arguments.  If   rdf/3  is called with a
 940%   term  literal(_)  as  Subject  or   Predicate  object  it  fails
 941%   silently.  This  allows   for   graph    matching   goals   like
 942%   rdf(S,P,O),rdf(O,P2,O2) to proceed without errors.
 943
 944%!  rdf(?Subject, ?Predicate, ?Object, ?Source) is nondet.
 945%
 946%   As rdf/3 but in addition query  the   graph  to which the triple
 947%   belongs. Unlike rdf/3, this predicate does not remove duplicates
 948%   from the result set.
 949%
 950%   @param Source is a term Graph:Line.  If Source is instatiated,
 951%   passing an atom is the same as passing Atom:_.
 952
 953
 954%!  rdf_has(?Subject, +Predicate, ?Object) is nondet.
 955%
 956%   Succeeds if the triple rdf(Subject,   Predicate, Object) is true
 957%   exploiting the rdfs:subPropertyOf predicate as   well as inverse
 958%   predicates   declared   using   rdf_set_predicate/2   with   the
 959%   =inverse_of= property.
 960
 961%!  rdf_has(?Subject, +Predicate, ?Object, -RealPredicate) is nondet.
 962%
 963%   Same as rdf_has/3, but RealPredicate is   unified  to the actual
 964%   predicate that makes this relation   true. RealPredicate must be
 965%   Predicate or an rdfs:subPropertyOf  Predicate.   If  an  inverse
 966%   match is found, RealPredicate is the term inverse_of(Pred).
 967
 968%!  rdf_reachable(?Subject, +Predicate, ?Object) is nondet.
 969%
 970%   Is true if Object can  be   reached  from  Subject following the
 971%   transitive predicate Predicate or a  sub-property thereof, while
 972%   repecting the symetric(true) or inverse_of(P2) properties.
 973%
 974%   If used with either Subject or  Object unbound, it first returns
 975%   the origin, followed by  the   reachable  nodes  in breath-first
 976%   search-order. The implementation internally   looks one solution
 977%   ahead and succeeds deterministically on  the last solution. This
 978%   predicate never generates the same  node   twice  and  is robust
 979%   against cycles in the transitive relation.
 980%
 981%   With all arguments instantiated,   it succeeds deterministically
 982%   if a path can be found from  Subject to Object. Searching starts
 983%   at Subject, assuming the branching factor   is normally lower. A
 984%   call  with  both  Subject   and    Object   unbound   raises  an
 985%   instantiation  error.  The  following    example  generates  all
 986%   subclasses of rdfs:Resource:
 987%
 988%     ==
 989%     ?- rdf_reachable(X, rdfs:subClassOf, rdfs:'Resource').
 990%     X = 'http://www.w3.org/2000/01/rdf-schema#Resource' ;
 991%     X = 'http://www.w3.org/2000/01/rdf-schema#Class' ;
 992%     X = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Property' ;
 993%     ...
 994%     ==
 995
 996
 997%!  rdf_reachable(?Subject, +Predicate, ?Object, +MaxD, -D) is nondet.
 998%
 999%   Same as rdf_reachable/3, but in addition, MaxD limits the number
1000%   of edges expanded and D is   unified with the `distance' between
1001%   Subject and Object. Distance 0 means  Subject and Object are the
1002%   same resource. MaxD can be the  constant =infinite= to impose no
1003%   distance-limit.
1004
1005%!  rdf_subject(?Resource) is nondet.
1006%
1007%   True if Resource appears as a   subject. This query respects the
1008%   visibility rules implied by the logical update view.
1009%
1010%   @see rdf_resource/1.
1011
1012rdf_subject(Resource) :-
1013    rdf_resource(Resource),
1014    ( rdf(Resource, _, _) -> true ).
1015
1016%!  rdf_resource(?Resource) is nondet.
1017%
1018%   True when Resource is a resource used as a subject or object in
1019%   a triple.
1020%
1021%   This predicate is primarily intended  as   a  way to process all
1022%   resources without processing resources twice.   The user must be
1023%   aware that some of the returned resources  may not appear in any
1024%   _visible_ triple.
1025
1026
1027                 /*******************************
1028                 *     TRIPLE MODIFICATIONS     *
1029                 *******************************/
1030
1031%!  rdf_assert(+Subject, +Predicate, +Object) is det.
1032%
1033%   Assert a new triple into  the   database.  This is equivalent to
1034%   rdf_assert/4 using Graph  =user=.  Subject   and  Predicate  are
1035%   resources. Object is either a resource or a term literal(Value).
1036%   See rdf/3 for an explanation  of   Value  for typed and language
1037%   qualified literals. All arguments  are   subject  to  name-space
1038%   expansion. Complete duplicates (including  the   same  graph and
1039%   `line' and with a compatible `lifespan')   are  not added to the
1040%   database.
1041
1042%!  rdf_assert(+Subject, +Predicate, +Object, +Graph) is det.
1043%
1044%   As rdf_assert/3, adding the  predicate   to  the indicated named
1045%   graph.
1046%
1047%   @param Graph is either the name of a   graph (an atom) or a term
1048%   Graph:Line, where Line is an integer that denotes a line number.
1049
1050%!  rdf_retractall(?Subject, ?Predicate, ?Object) is det.
1051%
1052%   Remove   all   matching   triples   from    the   database.   As
1053%   rdf_retractall/4 using an unbound graph.
1054
1055%!  rdf_retractall(?Subject, ?Predicate, ?Object, ?Graph) is det.
1056%
1057%   As rdf_retractall/3, also matching Graph.   This  is particulary
1058%   useful to remove all triples coming from a loaded file. See also
1059%   rdf_unload/1.
1060
1061%!  rdf_update(+Subject, +Predicate, +Object, +Action) is det.
1062%
1063%   Replaces one of  the  three  fields   on  the  matching  triples
1064%   depending on Action:
1065%
1066%     * subject(Resource)
1067%     Changes the first field of the triple.
1068%     * predicate(Resource)
1069%     Changes the second field of the triple.
1070%     * object(Object)
1071%     Changes the last field of the triple to the given resource or
1072%     literal(Value).
1073%     * graph(Graph)
1074%     Moves the triple from its current named graph to Graph.
1075
1076%!  rdf_update(+Subject, +Predicate, +Object, +Graph, +Action) is det
1077%
1078%   As rdf_update/4 but allows for specifying the graph.
1079
1080
1081                 /*******************************
1082                 *          COLLECTIONS         *
1083                 *******************************/
1084
1085%!  rdf_member_property(?Prop, ?Index)
1086%
1087%   Deal with the rdf:_1, ... properties.
1088
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                 *******************************/
1109
1110%!  rdf_node(-Id)
1111%
1112%   Generate a unique blank node identifier for a subject.
1113%
1114%   @deprecated     New code should use rdf_bnode/1.
1115
1116rdf_node(Resource) :-
1117    rdf_bnode(Resource).
1118
1119%!  rdf_bnode(-Id)
1120%
1121%   Generate a unique anonymous identifier for a subject.
1122
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                 *******************************/
1136
1137%!  rdf_is_bnode(+Id)
1138%
1139%   Tests if a resource is  a  blank   node  (i.e.  is  an anonymous
1140%   resource). A blank node is represented   as  an atom that starts
1141%   with =|_:|=. For backward compatibility   reason, =|__|= is also
1142%   considered to be a blank node.
1143%
1144%   @see rdf_bnode/1.
1145
1146%!  rdf_is_resource(@Term) is semidet.
1147%
1148%   True if Term is an RDF  resource.   Note  that  this is merely a
1149%   type-test; it does not mean  this   resource  is involved in any
1150%   triple.  Blank nodes are also considered resources.
1151%
1152%   @see rdf_is_bnode/1
1153
1154rdf_is_resource(Term) :-
1155    atom(Term).
1156
1157%!  rdf_is_literal(@Term) is semidet.
1158%
1159%   True if Term is an RDF literal object. Currently only checks for
1160%   groundness and the literal functor.
1161
1162rdf_is_literal(literal(Value)) :-
1163    ground(Value).
1164
1165                 /*******************************
1166                 *             LITERALS         *
1167                 *******************************/
1168
1169%!  rdf_current_literal(-Literal) is nondet.
1170%
1171%   True when Literal is a currently  known literal. Enumerates each
1172%   unique literal exactly once. Note that   it is possible that the
1173%   literal only appears in already deleted triples. Deleted triples
1174%   may be locked due to active   queries, transactions or snapshots
1175%   or may not yet be reclaimed by the garbage collector.
1176
1177
1178%!  rdf_literal_value(+Literal, -Value) is semidet.
1179%
1180%   True when value is  the   appropriate  Prolog  representation of
1181%   Literal in the RDF _|value space|_.  Current mapping:
1182%
1183%     | Plain literals              | Atom                    |
1184%     | Language tagged literal     | Atom holding plain text |
1185%     | xsd:string                  | Atom                    |
1186%     | rdf:XMLLiteral              | XML DOM Tree            |
1187%     | Numeric XSD type            | Number                  |
1188%
1189%   @tbd    Well, this is the long-term idea.
1190%   @tbd    Add mode (-,+)
1191
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                 *******************************/
1237
1238%!  rdf_source_location(+Subject, -Location) is nondet.
1239%
1240%   True when triples for Subject are loaded from Location.
1241%
1242%   @param Location is a term File:Line.
1243
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                 *******************************/
1253
1254%!  rdf_create_gc_thread
1255%
1256%   Create the garbage collection thread.
1257
1258:- public
1259    rdf_create_gc_thread/0.
1260
1261rdf_create_gc_thread :-
1262    thread_create(rdf_gc_loop, _,
1263                  [ alias('__rdf_GC')
1264                  ]).
1265
1266%!  rdf_gc_loop
1267%
1268%   Take care of running the RDF garbage collection.  This predicate
1269%   is called from a thread started by creating the RDF DB.
1270
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.
1290
1291%!  rdf_gc(-CPU) is det.
1292%
1293%   Run RDF GC one time. CPU is  the   amount  of CPU time spent. We
1294%   update this in Prolog because portable access to thread specific
1295%   CPU is really hard in C.
1296
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    ).
1305
1306%!  rdf_gc is det.
1307%
1308%   Run the RDF-DB garbage collector until   no  garbage is left and
1309%   all  tables  are  fully  optimized.  Under  normal  operation  a
1310%   seperate thread with  identifier   =__rdf_GC=  performs  garbage
1311%   collection as long as it is considered `useful'.
1312%
1313%   Using rdf_gc/0 should only be  needed   to  ensure a fully clean
1314%   database for analysis purposes such as leak detection.
1315
1316rdf_gc :-
1317    has_garbage,
1318    !,
1319    rdf_gc(_),
1320    rdf_gc.
1321rdf_gc.
1322
1323%!  has_garbage is semidet.
1324%
1325%   True if there is something to gain using GC.
1326
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.
1335
1336%!  consider_gc(+CPU) is semidet.
1337%
1338%   @param CPU is the amount of CPU time spent in the most recent
1339%   GC.
1340
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                 *******************************/
1362
1363%!  rdf_statistics(?KeyValue) is nondet.
1364%
1365%   Obtain statistics on the RDF database.  Defined statistics are:
1366%
1367%     * graphs(-Count)
1368%     Number of named graphs
1369%
1370%     * triples(-Count)
1371%     Total number of triples in the database.  This is the number
1372%     of asserted triples minus the number of retracted ones.  The
1373%     number of _visible_ triples in a particular context may be
1374%     different due to visibility rules defined by the logical
1375%     update view and transaction isolation.
1376%
1377%     * resources(-Count)
1378%     Number of resources that appear as subject or object in a
1379%     triple.  See rdf_resource/1.
1380%
1381%     * properties(-Count)
1382%     Number of current predicates.  See rdf_current_predicate/1.
1383%
1384%     * literals(-Count)
1385%     Number of current literals.  See rdf_current_literal/1.
1386%
1387%     * gc(GCCount, ReclaimedTriples, ReindexedTriples, Time)
1388%     Information about the garbage collector.
1389%
1390%     * searched_nodes(-Count)
1391%     Number of nodes expanded by rdf_reachable/3 and
1392%     rdf_reachable/5.
1393%
1394%     * lookup(rdf(S,P,O,G), Count)
1395%     Number of queries for this particular instantiation pattern.
1396%     Each of S,P,O,G is either + or -.
1397%
1398%     * hash_quality(rdf(S,P,O,G), Buckets, Quality, PendingResize)
1399%     Statistics on the index for this pattern.  Indices are created
1400%     lazily on the first relevant query.
1401%
1402%     * triples_by_graph(Graph, Count)
1403%     This statistics is produced for each named graph. See
1404%     =triples= for the interpretation of this value.
1405
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                 *******************************/
1460
1461%!  rdf_current_predicate(?Predicate) is nondet.
1462%
1463%   True when Predicate is a   currently known predicate. Predicates
1464%   are created if a triples is created  that uses this predicate or
1465%   a property of the predicate   is  set using rdf_set_predicate/2.
1466%   The predicate may (no longer) have triples associated with it.
1467%
1468%   Note that resources that have  =|rdf:type|= =|rdf:Property|= are
1469%   not automatically included in the  result-set of this predicate,
1470%   while _all_ resources that appear as   the  second argument of a
1471%   triple _are_ included.
1472%
1473%   @see rdf_predicate_property/2.
1474
1475rdf_current_predicate(P, DB) :-
1476    rdf_current_predicate(P),
1477    (   rdf(_,P,_,DB)
1478    ->  true
1479    ).
1480
1481%!  rdf_predicate_property(?Predicate, ?Property)
1482%
1483%   Query properties of  a  defined   predicate.  Currently  defined
1484%   properties are given below.
1485%
1486%     * symmetric(Bool)
1487%     True if the predicate is defined to be symetric. I.e., {A} P
1488%     {B} implies {B} P {A}. Setting symmetric is equivalent to
1489%     inverse_of(Self).
1490%
1491%     * inverse_of(Inverse)
1492%     True if this predicate is the inverse of Inverse. This
1493%     property is used by rdf_has/3, rdf_has/4, rdf_reachable/3 and
1494%     rdf_reachable/5.
1495%
1496%     * transitive(Bool)
1497%     True if this predicate is transitive. This predicate is
1498%     currently not used. It might be used to make rdf_has/3 imply
1499%     rdf_reachable/3 for transitive predicates.
1500%
1501%     * triples(Triples)
1502%     Unify Triples with the number of existing triples using this
1503%     predicate as second argument. Reporting the number of triples
1504%     is intended to support query optimization.
1505%
1506%     * rdf_subject_branch_factor(-Float)
1507%     Unify Float with the average number of triples associated with
1508%     each unique value for the subject-side of this relation. If
1509%     there are no triples the value 0.0 is returned. This value is
1510%     cached with the predicate and recomputed only after
1511%     substantial changes to the triple set associated to this
1512%     relation. This property is intended for path optimalisation
1513%     when solving conjunctions of rdf/3 goals.
1514%
1515%     * rdf_object_branch_factor(-Float)
1516%     Unify Float with the average number of triples associated with
1517%     each unique value for the object-side of this relation. In
1518%     addition to the comments with the subject_branch_factor
1519%     property, uniqueness of the object value is computed from the
1520%     hash key rather than the actual values.
1521%
1522%     * rdfs_subject_branch_factor(-Float)
1523%     Same as =rdf_subject_branch_factor=, but also considering
1524%     triples of `subPropertyOf' this relation. See also rdf_has/3.
1525%
1526%     * rdfs_object_branch_factor(-Float)
1527%     Same as =rdf_object_branch_factor=, but also considering
1528%     triples of `subPropertyOf' this relation. See also rdf_has/3.
1529%
1530%   @see rdf_set_predicate/2.
1531
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).
1539
1540%!  rdf_set_predicate(+Predicate, +Property) is det.
1541%
1542%   Define a property of  the   predicate.  This predicate currently
1543%   supports the following properties:
1544%
1545%       - symmetric(+Boolean)
1546%       Set/unset the predicate as being symmetric.  Using
1547%       symmetric(true) is the same as inverse_of(Predicate),
1548%       i.e., creating a predicate that is the inverse of
1549%       itself.
1550%       - transitive(+Boolean)
1551%       Sets the transitive property.
1552%       - inverse_of(+Predicate2)
1553%       Define Predicate as the inverse of Predicate2. An inverse
1554%       relation is deleted using inverse_of([]).
1555%
1556%   The `transitive` property is currently not used. The `symmetric`
1557%   and `inverse_of` properties are considered   by  rdf_has/3,4 and
1558%   rdf_reachable/3.
1559%
1560%   @tbd    Maintain these properties based on OWL triples.
1561
1562
1563                 /*******************************
1564                 *            SNAPSHOTS         *
1565                 *******************************/
1566
1567%!  rdf_snapshot(-Snapshot) is det.
1568%
1569%   Take a snapshot of the current state   of  the RDF store. Later,
1570%   goals may be executed in the  context   of  the database at this
1571%   moment using rdf_transaction/3 with  the   =snapshot=  option. A
1572%   snapshot created outside  a  transaction   exists  until  it  is
1573%   deleted. Snapshots taken inside a transaction   can only be used
1574%   inside this transaction.
1575
1576%!  rdf_delete_snapshot(+Snapshot) is det.
1577%
1578%   Delete a snapshot as obtained   from  rdf_snapshot/1. After this
1579%   call, resources used for maintaining the snapshot become subject
1580%   to garbage collection.
1581
1582%!  rdf_current_snapshot(?Term) is nondet.
1583%
1584%   True when Term is a currently known snapshot.
1585%
1586%   @bug    Enumeration of snapshots is slow.
1587
1588rdf_current_snapshot(Term) :-
1589    current_blob(Term, rdf_snapshot).
1590
1591
1592                 /*******************************
1593                 *          TRANSACTION         *
1594                 *******************************/
1595
1596%!  rdf_transaction(:Goal) is semidet.
1597%
1598%   Same as rdf_transaction(Goal, user, []).  See rdf_transaction/3.
1599
1600%!  rdf_transaction(:Goal, +Id) is semidet.
1601%
1602%   Same as rdf_transaction(Goal, Id, []).  See rdf_transaction/3.
1603
1604%!  rdf_transaction(:Goal, +Id, +Options) is semidet.
1605%
1606%   Run Goal in an RDF  transaction.   Compared to the ACID model,
1607%   RDF transactions have the following properties:
1608%
1609%     1. Modifications inside the transactions become all atomically
1610%        visible to the outside world if Goal succeeds or remain
1611%        invisible if Goal fails or throws an exception.  I.e.,
1612%        the _atomicy_ property is fully supported.
1613%     2. _Consistency_ is not guaranteed. Later versions may
1614%        implement consistency constraints that will be checked
1615%        serialized just before the actual commit of a transaction.
1616%     3. Concurrently executing transactions do not infuence each
1617%        other.  I.e., the _isolation_ property is fully supported.
1618%     4. _Durability_ can be activated by loading
1619%        library(semweb/rdf_persistency).
1620%
1621%   Processed options are:
1622%
1623%     * snapshot(+Snapshot)
1624%     Execute Goal using the state of the RDF store as stored in
1625%     Snapshot.  See rdf_snapshot/1.  Snapshot can also be the
1626%     atom =true=, which implies that an anonymous snapshot is
1627%     created at the current state of the store.  Modifications
1628%     due to executing Goal are only visible to Goal.
1629
1630rdf_transaction(Goal) :-
1631    rdf_transaction(Goal, user, []).
1632rdf_transaction(Goal, Id) :-
1633    rdf_transaction(Goal, Id, []).
1634
1635%!  rdf_active_transaction(?Id) is nondet.
1636%
1637%   True if Id is the identifier of  a transaction in the context of
1638%   which  this  call  is  executed.  If  Id  is  not  instantiated,
1639%   backtracking yields transaction identifiers   starting  with the
1640%   innermost nested transaction. Transaction   identifier terms are
1641%   not copied, need not be ground   and  can be instantiated during
1642%   the transaction.
1643
1644rdf_active_transaction(Id) :-
1645    rdf_active_transactions_(List),
1646    member(Id, List).
1647
1648%!  rdf_monitor(:Goal, +Options)
1649%
1650%   Call Goal if specified actions occur on the database.
1651
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.
1672
1673%!  monitor_mask(Name, Mask)
1674%
1675%   Mask bit for the monitor events.  Note that this must be kept
1676%   consistent with the enum broadcast_id defined in rdf_db.c
1677
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                 *******************************/
1703
1704%!  rdf_warm_indexes
1705%
1706%   Warm all indexes.  See rdf_warm_indexes/1.
1707
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).
1722
1723%!  rdf_warm_indexes(+Indexes) is det.
1724%
1725%   Create the named indexes.  Normally,   the  RDF database creates
1726%   indexes on lazily the first time they are needed. This predicate
1727%   serves two purposes: it provides an   explicit  way to make sure
1728%   that the required indexes  are   present  and  creating multiple
1729%   indexes at the same time is more efficient.
1730
1731
1732                 /*******************************
1733                 *          DUPLICATES          *
1734                 *******************************/
1735
1736%!  rdf_update_duplicates is det.
1737%
1738%   Update the duplicate administration of the RDF store. This marks
1739%   every triple that is potentionally  a   duplicate  of another as
1740%   duplicate. Being potentially a  duplicate   means  that subject,
1741%   predicate and object are equivalent and   the  life-times of the
1742%   two triples overlap.
1743%
1744%   The duplicates marks are used to  reduce the administrative load
1745%   of avoiding duplicate answers.  Normally,   the  duplicates  are
1746%   marked using a background thread that   is  started on the first
1747%   query that produces a substantial amount of duplicates.
1748
1749:- public
1750    rdf_update_duplicates_thread/0.
1751
1752%!  rdf_update_duplicates_thread
1753%
1754%   Start a thread to initialize the duplicate administration.
1755
1756rdf_update_duplicates_thread :-
1757    thread_create(rdf_update_duplicates, _,
1758                  [ detached(true),
1759                    alias('__rdf_duplicate_detecter')
1760                  ]).
1761
1762%!  rdf_update_duplicates is det.
1763%
1764%   Update the duplicate administration. If   this  adminstration is
1765%   up-to-date, each triples that _may_ have a duplicate is flagged.
1766%   The predicate rdf/3 uses this administration to speedup checking
1767%   for duplicate answers.
1768%
1769%   This predicate is normally  executed   from  a background thread
1770%   named =__rdf_duplicate_detecter= which is created   when a query
1771%   discovers that checking for duplicates becomes too expensive.
1772
1773
1774                 /*******************************
1775                 *    QUICK BINARY LOAD/SAVE    *
1776                 *******************************/
1777
1778%!  rdf_save_db(+File) is det.
1779%!  rdf_save_db(+File, +Graph) is det.
1780%
1781%   Save triples into File in a   quick-to-load binary format. If Graph
1782%   is supplied only triples flagged to originate from that database
1783%   are  added.  Files  created  this  way    can  be  loaded  using
1784%   rdf_load_db/1.
1785
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)).
1806
1807
1808%!  rdf_load_db_no_admin(+File, +Id, -Graphs) is det.
1809%
1810%   Load triples from a  .trp  file   without  updating  the  source
1811%   administration. Id is  handled  to   monitor  action.  Graphs is
1812%   a list of graph-names encountered in File.
1813
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)).
1818
1819
1820%!  check_loaded_cache(+Graph, +Graphs, +Modified) is det.
1821%
1822%   Verify the loaded cache file and optionally fix the modification
1823%   time (new versions save this along with the snapshot).
1824%
1825%   @tbd    What to do if there is a cache mismatch? Delete the loaded
1826%           graphs and fail?
1827
1828check_loaded_cache(DB, [DB], _Modified) :- !.
1829check_loaded_cache(DB, Graphs, _) :-
1830    print_message(warning, rdf(inconsistent_cache(DB, Graphs))).
1831
1832
1833%!  rdf_load_db(+File) is det.
1834%
1835%   Load triples from a file created using rdf_save_db/2.
1836
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
1853
1854%!  rdf_load(+FileOrList) is det.
1855%
1856%   Same as rdf_load(FileOrList, []).  See rdf_load/2.
1857
1858%!  rdf_load(+FileOrList, :Options) is det.
1859%
1860%   Load RDF data. Options provides   additional processing options.
1861%   Defined options are:
1862%
1863%       * blank_nodes(+ShareMode)
1864%       How to handle equivalent blank nodes.  If =share= (default),
1865%       equivalent blank nodes are shared in the same resource.
1866%
1867%       * base_uri(+URI)
1868%       URI that is used for rdf:about="" and other RDF constructs
1869%       that are relative to the base uri.  Default is the source
1870%       URL.
1871%
1872%       * concurrent(+Jobs)
1873%       If FileOrList is a list of files, process the input files
1874%       using Jobs threads concurrently.  Default is the mininum
1875%       of the number of cores and the number of inputs.  Higher
1876%       values can be useful when loading inputs from (slow)
1877%       network connections.  Using 1 (one) does not use
1878%       separate worker threads.
1879%
1880%       * format(+Format)
1881%       Specify the source format explicitly. Normally this is
1882%       deduced from the filename extension or the mime-type. The
1883%       core library understands the formats xml (RDF/XML) and
1884%       triples (internal quick load and cache format).  Plugins,
1885%       such as library(semweb/turtle) extend the set of recognised
1886%       extensions.
1887%
1888%       * graph(?Graph)
1889%       Named graph in which to load the data.  It is *not* allowed
1890%       to load two sources into the same named graph.  If Graph is
1891%       unbound, it is unified to the graph into which the data is
1892%       loaded.  The default graph is a =file://= URL when loading
1893%       a file or, if the specification is a URL, its normalized
1894%       version without the optional _|#fragment|_.
1895%
1896%       * if(Condition)
1897%       When to load the file. One of =true=, =changed= (default) or
1898%       =not_loaded=.
1899%
1900%       * modified(-Modified)
1901%       Unify Modified with one of =not_modified=, cached(File),
1902%       last_modified(Stamp) or =unknown=.
1903%
1904%       * cache(Bool)
1905%       If =false=, do not use or create a cache file.
1906%
1907%       * register_namespaces(Bool)
1908%       If =true= (default =false=), register =xmlns= namespace
1909%       declarations or Turtle =|@prefix|= prefixes using
1910%       rdf_register_prefix/3 if there is no conflict.
1911%
1912%       * silent(+Bool)
1913%       If =true=, the message reporting completion is printed using
1914%       level =silent=. Otherwise the level is =informational=. See
1915%       also print_message/2.
1916%
1917%   Other  options  are  forwarded  to  process_rdf/3.  By  default,
1918%   rdf_load/2 only loads RDF/XML from files.  It can be extended to
1919%   load data from other formats and   locations  using plugins. The
1920%   full set of plugins relevant to   support  different formats and
1921%   locations is below:
1922%
1923%     ==
1924%     :- use_module(library(semweb/turtle)).        % Turtle and TRiG
1925%     :- use_module(library(semweb/rdf_ntriples)).
1926%     :- use_module(library(semweb/rdf_zlib_plugin)).
1927%     :- use_module(library(semweb/rdf_http_plugin)).
1928%     :- use_module(library(http/http_ssl_plugin)).
1929%     ==
1930%
1931%   @see    rdf_db:rdf_open_hook/3, library(semweb/rdf_persistency) and
1932%           library(semweb/rdf_cache)
1933
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)).
1996
1997%!  rdf_start_load(+SourceURL, -WhatToDo) is det.
1998%!  rdf_end_load(+WhatToDo) is det.
1999%!  rdf_load_file(+WhatToDo, +Spec, +SourceURL, +Protocol, +Graph,
2000%!                +Module, +Options) is det.
2001%
2002%   Of these three predicates, rdf_load_file/7   does the real work.
2003%   The others deal with the  possibility   that  the graph is being
2004%   loaded by another thread. In that case,   we  wait for the other
2005%   thread to complete the work.
2006%
2007%   @tbd    What if both threads disagree on what is loaded into the
2008%           graph?
2009%   @see    Code is modelled closely after how concurrent loading
2010%           is handled in SWI-Prolog's boot/init.pl
2011
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- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2127
2128%!  rdf_open_input(+SourceURL, +Protocol, +Graph,
2129%!                 -Stream, -Cleanup, -Modified, -Format, +Options)
2130%
2131%   Open an input source.
2132%
2133%   Options processed:
2134%
2135%       * graph(Graph)
2136%       * db(Graph)
2137%       * if(Condition)
2138%       * cache(Cache)
2139%       * format(Format)
2140%
2141%   @param  Modified is one of =not_modified=, last_modified(Time),
2142%           cached(CacheFile) or =unknown=
2143
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    ).
2166
2167
2168%!  source_url(+Spec, -Class, -SourceURL) is det.
2169%
2170%   Determine class and url of the source.  Class is one of
2171%
2172%       * stream(Stream)
2173%       * file
2174%       * a url-protocol (e.g., =http=)
2175
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, Plain).
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).
2219
2220%!  load_graph(+SourceURL, -Graph, +Options) is det.
2221%
2222%   Graph is the graph into which  we   load  the  data. Tries these
2223%   options:
2224%
2225%     1. The graph(Graph) option
2226%     2. The db(Graph) option (backward compatibility)
2227%     3. The base_uri(BaseURI) option
2228%     4. The source URL
2229
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, File0),
2268    file_name_extension(File0, 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(File0, 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    ).
2299
2300%!  storage_open(+Extension, +File, -Stream, -Cleanup)
2301%
2302%   Open the low-level storage. Note  that   the  file  is opened as
2303%   binary. This is the same  as   for  HTTP  resources. The correct
2304%   encoding will be set by the XML parser or the Turtle parser.
2305
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, _).
2317
2318%!  is_url(@Term, -Scheme, -URL) is semidet.
2319%
2320%   True if Term is an atom denoting URL of the given Scheme. URL is
2321%   normalized  (see  uri_normalized/2)  and   a  possible  fragment
2322%   identifier (#fragment) is removed. This  predicate only succeeds
2323%   if  the  scheme  is   registered    using   the  multifile  hook
2324%   url_protocol/1.
2325
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
2339
2340%!  rdf_file_type(+Extension, -Format) is semidet.
2341%
2342%   True if Format  is  the  format   belonging  to  the  given file
2343%   extension.  This predicate is multifile and can thus be extended
2344%   by plugins.
2345
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).
2354
2355
2356%!  rdf_file_encoding(+Extension, -Format) is semidet.
2357%
2358%   True if Format describes the storage encoding of file.
2359
2360rdf_storage_encoding('', plain).
2361
2362
2363%!  rdf_load_stream(+Format, +Stream, :Options)
2364%
2365%   Load RDF data from Stream.
2366%
2367%   @tbd    Handle mime-types?
2368
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).
2388
2389
2390%!  report_loaded(+Action, +Source, +DB, +Triples, +StartCPU, +Options)
2391
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))).
2402
2403
2404%!  rdf_unload(+Source) is det.
2405%
2406%   Identify the graph loaded from Source and use rdf_unload_graph/1
2407%   to erase this graph.
2408%
2409%   @deprecated     For compatibility, this predicate also accepts a
2410%                   graph name instead of a source specification.
2411%                   Please update your code to use
2412%                   rdf_unload_graph/1.
2413
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)))).
2436
2437
2438%!  rdf_unload_graph(+Graph) is det.
2439%
2440%   Remove Graph from the RDF store.  Succeeds silently if the named
2441%   graph does not exist.
2442
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                 *******************************/
2461
2462%!  rdf_create_graph(+Graph) is det.
2463%
2464%   Create an RDF graph without triples.   Succeeds  silently if the
2465%   graph already exists.
2466
2467
2468%!  rdf_graph(?Graph) is nondet.
2469%
2470%   True when Graph is an existing graph.
2471
2472rdf_graph(Graph) :-
2473    rdf_graph_(Graph, _Triples).
2474
2475%!  rdf_source(?Graph, ?SourceURL) is nondet.
2476%
2477%   True if named Graph is loaded from SourceURL.
2478%
2479%   @deprecated Use rdf_graph_property(Graph, source(SourceURL)).
2480
2481rdf_source(Graph, SourceURL) :-
2482    rdf_graph(Graph),
2483    rdf_graph_source_(Graph, SourceURL, _Modified).
2484
2485%!  rdf_source(?Source)
2486%
2487%   True if Source is a loaded source.
2488%
2489%   @deprecated     Use rdf_graph/1 or rdf_source/2.
2490
2491rdf_source(SourceURL) :-
2492    rdf_source(_Graph, SourceURL).
2493
2494%!  rdf_make
2495%
2496%   Reload all loaded files that have been modified since the last
2497%   time they were loaded.
2498
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.
2510
2511%!  rdf_graph_property(?Graph, ?Property) is nondet.
2512%
2513%   True when Property is a property of Graph.  Defined properties
2514%   are:
2515%
2516%       * hash(Hash)
2517%       Hash is the (MD5-)hash for the content of Graph.
2518%       * modified(Boolean)
2519%       True if the graph is modified since it was loaded or
2520%       rdf_set_graph/2 was called with modified(false).
2521%       * source(Source)
2522%       The graph is loaded from the Source (a URL)
2523%       * source_last_modified(?Time)
2524%       Time is the last-modified timestamp of Source at the moment
2525%       that the graph was loaded from Source.
2526%       * triples(Count)
2527%       True when Count is the number of triples in Graph.
2528%
2529%    Additional graph properties can be added  by defining rules for
2530%    the multifile predicate  property_of_graph/2.   Currently,  the
2531%    following extensions are defined:
2532%
2533%       - library(semweb/rdf_persistency)
2534%         - persistent(Boolean)
2535%           Boolean is =true= if the graph is persistent.
2536
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).
2555
2556%!  rdf_set_graph(+Graph, +Property) is det.
2557%
2558%   Set properties of Graph.  Defined properties are:
2559%
2560%       * modified(false)
2561%       Set the modified state of Graph to false.
2562
2563rdf_set_graph(Graph, modified(Modified)) :-
2564    must_be(oneof([false]), Modified),
2565    rdf_graph_clear_modified_(Graph).
2566
2567
2568%!  save_cache(+DB, +Cache) is det.
2569%
2570%   Save triples belonging to DB in the file Cache.
2571
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)).
2578
2579%!  assert_triples(+Triples, +Source)
2580%
2581%   Assert a list of triples into the database. Foir security
2582%   reasons we check we aren't inserting anything but nice RDF
2583%   triples.
2584
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                 *******************************/
2597
2598%!  rdf_reset_db
2599%
2600%   Remove all triples from the RDF database and reset all its
2601%   statistics.
2602%
2603%   @bug    This predicate checks for active queries, but this check is
2604%           not properly synchronized and therefore the use of this
2605%           predicate is unsafe in multi-threaded contexts. It is
2606%           mainly used to run functionality tests that need to
2607%           start with an empty database.
2608
2609rdf_reset_db :-
2610    reset_gensym('_:genid'),
2611    rdf_reset_db_.
2612
2613
2614                 /*******************************
2615                 *           SAVE RDF           *
2616                 *******************************/
2617
2618%!  rdf_save(+Out) is det.
2619%
2620%   Same as rdf_save(Out, []).  See rdf_save/2 for details.
2621
2622%!  rdf_save(+Out, :Options) is det.
2623%
2624%   Write RDF data as RDF/XML. Options is a list of one or more of
2625%   the following options:
2626%
2627%           * graph(+Graph)
2628%           Save only triples associated to the given named Graph.
2629%
2630%           * anon(Bool)
2631%           If false (default true) do not save blank nodes that do
2632%           not appear (indirectly) as object of a named resource.
2633%
2634%           * base_uri(URI)
2635%           BaseURI used. If present, all URIs that can be
2636%           represented relative to this base are written using
2637%           their shorthand.  See also =write_xml_base= option
2638%
2639%           * convert_typed_literal(:Convertor)
2640%           Call Convertor(-Type, -Content, +RDFObject), providing
2641%           the opposite for the convert_typed_literal option of
2642%           the RDF parser.
2643%
2644%           * document_language(+Lang)
2645%           Initial xml:lang saved with rdf:RDF element
2646%
2647%           * encoding(Encoding)
2648%           Encoding for the output.  Either utf8 or iso_latin_1
2649%
2650%           * inline(+Bool)
2651%           If =true= (default =false=), inline resources when
2652%           encountered for the first time. Normally, only bnodes
2653%           are handled this way.
2654%
2655%           * namespaces(+List)
2656%           Explicitely specify saved namespace declarations. See
2657%           rdf_save_header/2 option namespaces for details.
2658%
2659%           * sorted(+Boolean)
2660%           If =true= (default =false=), emit subjects sorted on
2661%           the full URI.  Useful to make file comparison easier.
2662%
2663%           * write_xml_base(Bool)
2664%           If =false=, do _not_ include the =|xml:base|=
2665%           declaration that is written normally when using the
2666%           =base_uri= option.
2667%
2668%           * xml_attributes(+Bool)
2669%           If =false= (default =true=), never use xml attributes to
2670%           save plain literal attributes, i.e., always used an XML
2671%           element as in =|<name>Joe</name>|=.
2672%
2673%   @param Out      Location to save the data.  This can also be a
2674%                   file-url (=|file://path|=) or a stream wrapped
2675%                   in a term stream(Out).
2676%   @see rdf_save_db/1
2677
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    ).
2784
2785
2786%!  rdf_save_header(+Fd, +Options)
2787%
2788%   Save XML document header, doctype and open the RDF environment.
2789%   This predicate also sets up the namespace notation.
2790%
2791%   Save an RDF header, with the XML header, DOCTYPE, ENTITY and
2792%   opening the rdf:RDF element with appropriate namespace
2793%   declarations. It uses the primitives from section 3.5 to
2794%   generate the required namespaces and desired short-name. Options
2795%   is one of:
2796%
2797%     * graph(+URI)
2798%     Only search for namespaces used in triples that belong to the
2799%     given named graph.
2800%
2801%     * namespaces(+List)
2802%     Where List is a list of namespace abbreviations. With this
2803%     option, the expensive search for all namespaces that may be
2804%     used by your data is omitted. The namespaces =rdf= and =rdfs=
2805%     are added to the provided List. If a namespace is not
2806%     declared, the resource is emitted in non-abreviated form.
2807
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').
2857
2858%!  nsmap(+NSIds, -Map:list(id=uri)) is det.
2859%
2860%   Create a namespace-map that is compatible to xml_write/2
2861%   for dealing with XML-Literals
2862
2863nsmap([], []).
2864nsmap([Id|T0], [Id=URI|T]) :-
2865    ns(Id, URI),
2866    nsmap(T0, T).
2867
2868%!  xml_escape_parameter_entity(+In, -Out) is det.
2869%
2870%   Escape % as &#37; for entity declarations.
2871
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).
2887
2888
2889%!  header_namespaces(Options, -List)
2890%
2891%   Get namespaces we will define as entities
2892
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).
2900
2901%!  rdf_graph_prefixes(?Graph, -List:ord_set) is det.
2902%!  rdf_graph_prefixes(?Graph, -List:ord_set, :Options) is det.
2903%
2904%   List is a sorted list of  prefixes (namepaces) in Graph. Options
2905%   defined are:
2906%
2907%       * filter(:Filter)
2908%       optional Filter argument is used to filter the results. It
2909%       is called with 3 additional arguments:
2910%
2911%           ==
2912%           call(Filter, Where, Prefix, URI)
2913%           ==
2914%
2915%       The Where argument gives the location of the prefix ans is
2916%       one of =subject=, =predicate=, =object= or =type=. The
2917%       Prefix argument is the potentionally new prefix and URI is
2918%       the full URI that is being processed.
2919%
2920%       * expand(:Goal)
2921%       Hook to generate the graph.  Called using
2922%
2923%           ==
2924%           call(Goal,S,P,O,Graph)
2925%           ==
2926%
2927%       * min_count(+Count)
2928%       Only include prefixes that appear at least N times.  Default
2929%       is 1. Declared prefixes are always returned if found at
2930%       least one time.
2931%
2932%       * get_prefix(:GetPrefix)
2933%       Predicate to extract the candidate prefix from an IRI.  Default
2934%       is iri_xml_namespace/2.
2935
2936
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(_, _, _, _, _).
3015
3016
3017%!  used_namespace_entities(-List, ?Graph) is det.
3018%
3019%   Return the namespace aliases that are actually used in Graph. In
3020%   addition, this predicate creates ns<N>   aliases  for namespaces
3021%   used in predicates because RDF/XML cannot write predicates other
3022%   than as an XML name.
3023
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'-
3095
3096
3097%!  rdf_save_footer(Out:stream) is det.
3098%
3099%   Finish XML generation and write the document footer.
3100%
3101%   @see rdf_save_header/2, rdf_save_subject/3.
3102
3103rdf_save_footer(Out) :-
3104    retractall(named_anon(_, _)),
3105    retractall(inlined(_)),
3106    format(Out, '</rdf:RDF>~n', []).
3107
3108%!  rdf_save_non_anon_subject(+Out, +Subject, +Options)
3109%
3110%   Save an object.  Anonymous objects not saved if anon(false)
3111%   is present in the Options list.
3112
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).
3123
3124
3125%!  rdf_save_subject(+Out, +Subject:resource, +Options) is det.
3126%
3127%   Save the triples associated to Subject to Out. Options:
3128%
3129%     * graph(+Graph)
3130%     Only save properties from Graph.
3131%     * base_uri(+URI)
3132%     * convert_typed_literal(:Goal)
3133%     * document_language(+XMLLang)
3134%
3135%   @see rdf_save/2 for a description of these options.
3136
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    ).
3150
3151
3152%!  rdf_save_subject(+Out:stream, +Subject:resource, +BaseURI,
3153%!                   +Indent:int, +Options) is det.
3154%
3155%   Save properties of Subject.
3156%
3157%   @param Indent   Current indentation
3158
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:_).
3186
3187%!  rdf_save_subject(+Out:stream, +Subject:resource, +BaseURI,
3188%!                   +Atts:list(Pred=Obj), +Indent:int, +Options) is det.
3189%
3190%   Save triples defined by Atts on Subject.
3191
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).
3213
3214%!  save_about(+Out, +BaseURI, +Subject) is det.
3215%
3216%   Save the rdf:about. If Subject is a  blank node, save the nodeID
3217%   if any.
3218
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]).
3230
3231%!  save_attributes(+List, +BaseURI, +Stream, +Element, +Indent, +Options)
3232%
3233%   Save the attributes.  Short literal attributes are saved in the
3234%   tag.  Others as the content of the description element.  The
3235%   begin tag has already been filled.
3236
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    ).
3249
3250%!  split_attributes(+Attributes, -HeadAttrs, -BodyAttr, Options)
3251%
3252%   Split attribute (Name=Value) list into attributes for the head
3253%   and body. Attributes can only be in the head if they are literal
3254%   and appear only one time in the attribute list.
3255
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).
3263
3264%!  duplicate_attributes(+Attrs, -Duplicates, -Singles)
3265%
3266%   Extract attributes that appear more than onces as we cannot
3267%   dublicate an attribute in the head according to the XML rules.
3268
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    ).
3288
3289%!  simple_literal_attributes(+Attributes, -Inline, -Body)
3290%
3291%   Split attributes for (literal) attributes to be used in the
3292%   begin-tag and ones that have to go into the body of the description.
3293
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.
3306
3307%!  save_attributes(+List, +BaseURI, +TagOrBody, +Stream)
3308%
3309%   Save a list of attributes.
3310
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    !.
3393
3394%!  save_body_literal(+Literal, +NameText, +BaseURI,
3395%!                    +Out, +Indent, +Options).
3396
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), _)).
3457
3458%!  save_xml_literal(+DOM, +Attr, +Out, +Indent, +Options) is det.
3459%
3460%   Save an XMLLiteral value. We already emitted
3461%
3462%           ==
3463%           <prop parseType="literal"
3464%           ==
3465%
3466%   but  not  the  terminating  =|>|=.  We  need  to  establish  the
3467%   namespaces used in the DOM. The   namespaces in the rdf document
3468%   are in the nsmap-option of Options.
3469
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).
3488
3489
3490%!  rdf_collection(+URI) is semidet.
3491%
3492%   True  if  URI  represents  an  RDF    list  that  fits  the  RDF
3493%   parseType=collection syntax. This means it is   a linked list of
3494%   bnode-cells with a rdf:first that is   a  resource, optionally a
3495%   rdf:type that is an rdf:list and the list ends in an rdf:nil.
3496
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').
3513
3514
3515%!  rdf_save_list(+Out, +List, +BaseURI, +Indent, +Options)
3516
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    ).
3536
3537
3538%!  rdf_id(+Resource, +BaseURI, -NSLocal)
3539%
3540%   Generate a NS:Local  name  for   Resource  given  the  indicated
3541%   default namespace. This call is used for elements.
3542
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).
3558
3559
3560%!  rdf_write_id(+Out, +NSLocal) is det.
3561%
3562%   Write an identifier. We cannot use native write on it as both NS
3563%   and Local can be operators.
3564
3565rdf_write_id(Out, NS:Local) :-
3566    !,
3567    format(Out, '~w:~w', [NS, Local]).
3568rdf_write_id(Out, Atom) :-
3569    write(Out, Atom).
3570
3571%!  rdf_value(+Resource, +BaseURI, -Text, +Encoding)
3572%
3573%   According  to  "6.4  RDF  URI  References"  of  the  RDF  Syntax
3574%   specification, a URI reference is  UNICODE string not containing
3575%   control sequences, represented as  UTF-8   and  then  as escaped
3576%   US-ASCII.
3577
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                 *******************************/
3598
3599%!  rdf_compare(-Dif, +Object1, +Object2) is det.
3600%
3601%   Compare  two  object  terms.  Where  SPARQL  defines  a  partial
3602%   ordering, we define a complete ordering   of terms. The ordering
3603%   is defines as:
3604%
3605%     - Blank nodes < IRIs < Literals
3606%     - Numeric literals < other literals
3607%     - Numeric literals are compared by value and then by type,
3608%       where Integer < Decimal < Double
3609%     - Other literals are compare lexically, case insensitive.
3610%       If equal, uppercase preceeds lowercase.  If still equal,
3611%       the types are compared lexically.
3612
3613%!  rdf_match_label(+How, +Pattern, +Label) is semidet.
3614%
3615%   True if Label matches Pattern according to   How.  How is one of
3616%   `icase`, `substring`, `word`, `prefix` or   `like`. For backward
3617%   compatibility, `exact` is a synonym for `icase`.
3618
3619
3620                 /*******************************
3621                 *      DEPRECATED MATERIAL     *
3622                 *******************************/
3623
3624%!  rdf_split_url(+Prefix, +Local, -URL) is det.
3625%!  rdf_split_url(-Prefix, -Local, +URL) is det.
3626%
3627%   Split/join a URL.  This functionality is moved to library(sgml).
3628%
3629%   @deprecated Use iri_xml_namespace/3. Note that the argument
3630%   order is iri_xml_namespace(+IRI, -Namespace, -Localname).
3631
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).
3638
3639%!  rdf_url_namespace(+URL, -Namespace)
3640%
3641%   Namespace is the namespace of URL.
3642%
3643%   @deprecated Use iri_xml_namespace/2
3644
3645rdf_url_namespace(URL, Prefix) :-
3646    iri_xml_namespace(URL, Prefix).
3647
3648
3649                 /*******************************
3650                 *            LITERALS          *
3651                 *******************************/
3652
3653%!  rdf_new_literal_map(-Map) is det.
3654%
3655%   Create a new literal map, returning an opaque handle.
3656
3657%!  rdf_destroy_literal_map(+Map) is det.
3658%
3659%   Destroy a literal map. After this call,   further use of the Map
3660%   handle is illegal. Additional synchronisation  is needed if maps
3661%   that are shared between threads are   destroyed to guarantee the
3662%   handle    is    no    longer    used.    In    some    scenarios
3663%   rdf_reset_literal_map/1 provides a safe alternative.
3664
3665%!  rdf_reset_literal_map(+Map) is det.
3666%
3667%   Delete all content from the literal map.
3668
3669%!  rdf_insert_literal_map(+Map, +Key, +Value) is det.
3670%
3671%   Add a relation between  Key  and  Value   to  the  map.  If this
3672%   relation already exists no action is performed.
3673
3674%!  rdf_insert_literal_map(+Map, +Key, +Value, -KeyCount) is det.
3675%
3676%   As rdf_insert_literal_map/3. In addition, if Key is a new key in
3677%   Map, unify KeyCount with the number of  keys in Map. This serves
3678%   two purposes. Derived maps, such as  the stem and metaphone maps
3679%   need to know about new  keys   and  it avoids additional foreign
3680%   calls for doing the progress in rdf_litindex.pl.
3681
3682%!  rdf_delete_literal_map(+Map, +Key) is det.
3683%
3684%   Delete Key and all associated values from the map.
3685
3686%!  rdf_delete_literal_map(+Map, +Key, +Value) is det.
3687%
3688%   Delete the association between Key and Value from the map.
3689
3690%!  rdf_find_literal_map(+Map, +KeyList, -ValueList) is det.
3691%
3692%   Unify ValueList with an ordered set  of values associated to all
3693%   keys from KeyList. Each key in  KeyList   is  either an atom, an
3694%   integer or a term not(Key).  If   not-terms  are provided, there
3695%   must be at least one positive keywords. The negations are tested
3696%   after establishing the positive matches.
3697
3698%!  rdf_keys_in_literal_map(+Map, +Spec, -Answer) is det.
3699%
3700%   Realises various queries on the key-set:
3701%
3702%     * all
3703%
3704%     Unify Answer with an ordered list of all keys.
3705%     * key(+Key)
3706%
3707%     Succeeds if Key is a key in the map and unify Answer with the
3708%     number of values associated with the key. This provides a fast
3709%     test of existence without fetching the possibly large
3710%     associated value set as with rdf_find_literal_map/3.
3711%
3712%     * prefix(+Prefix)
3713%     Unify Answer with an ordered set of all keys that have the
3714%     given prefix. See section 3.1 for details on prefix matching.
3715%     Prefix must be an atom. This call is intended for
3716%     auto-completion in user interfaces.
3717%
3718%     * ge(+Min)
3719%     Unify Answer with all keys that are larger or equal to the
3720%     integer Min.
3721%
3722%     * le(+Max)
3723%     Unify Answer with all keys that are smaller or equal to the integer
3724%     Max.
3725%
3726%     * between(+Min, +Max) Unify
3727%     Answer with all keys between Min and Max (including).
3728
3729%!  rdf_statistics_literal_map(+Map, -KeyValue)
3730%
3731%   Query some statistics of the map. Provides KeyValue are:
3732%
3733%     * size(-Keys, -Relations)
3734%     Unify Keys with the total key-count of the index and Relation
3735%     with the total Key-Value count.
3736
3737
3738
3739                 /*******************************
3740                 *             MISC             *
3741                 *******************************/
3742
3743%!  rdf_version(-Version) is det.
3744%
3745%   True when Version is the numerical version-id of this library.
3746%   The version is computed as
3747%
3748%           Major*10000 + Minor*100 + Patch.
3749
3750%!  rdf_set(+Term) is det.
3751%
3752%   Set properties of the RDF store.  Currently defines:
3753%
3754%     * hash(+Hash, +Parameter, +Value)
3755%     Set properties for a triple index.  Hash is one of =s=,
3756%     =p=, =sp=, =o=, =po=, =spo=, =g=, =sg= or =pg=.  Parameter
3757%     is one of:
3758%
3759%       - size
3760%       Value defines the number of entries in the hash-table.
3761%       Value is rounded _down_ to a power of 2.  After setting
3762%       the size explicitly, auto-sizing for this table is
3763%       disabled.  Setting the size smaller than the current
3764%       size results in a =permission_error= exception.
3765%
3766%       - average_chain_len
3767%       Set maximum average collision number for the hash.
3768%
3769%       - optimize_threshold
3770%       Related to resizing hash-tables.  If 0, all triples are
3771%       moved to the new size by the garbage collector.  If more
3772%       then zero, those of the last Value resize steps remain at
3773%       their current location.  Leaving cells at their current
3774%       location reduces memory fragmentation and slows down
3775%       access.
3776
3777%!  rdf_md5(+Graph, -MD5) is det.
3778%
3779%   True when MD5 is the MD5 hash for  all triples in graph. The MD5
3780%   digest itself is represented as an   atom holding a 32-character
3781%   hexadecimal   string.   The   library   maintains   the   digest
3782%   incrementally on rdf_load/[1,2], rdf_load_db/1, rdf_assert/[3,4]
3783%   and  rdf_retractall/[3,4].  Checking  whether   the  digest  has
3784%   changed since the last rdf_load/[1,2]  call provides a practical
3785%   means for checking whether the file needs to be saved.
3786%
3787%   @deprecated New code should use rdf_graph_property(Graph,
3788%   hash(Hash)).
3789
3790%!  rdf_generation(-Generation) is det.
3791%
3792%   True when Generation is the current  generation of the database.
3793%   Each modification to the database  increments the generation. It
3794%   can be used to check the validity of cached results deduced from
3795%   the database. Committing a non-empty  transaction increments the
3796%   generation by one.
3797%
3798%   When inside a transaction,  Generation  is   unified  to  a term
3799%   _TransactionStartGen_ + _InsideTransactionGen_. E.g.,  4+3 means
3800%   that the transaction was started at   generation 4 of the global
3801%   database and we have  created  3   new  generations  inside  the
3802%   transaction. Note that this choice  of representation allows for
3803%   comparing  generations  using  Prolog  arithmetic.  Comparing  a
3804%   generation in one  transaction  with   a  generation  in another
3805%   transaction is meaningless.
3806
3807%!  rdf_estimate_complexity(?Subject, ?Predicate, ?Object, -Complexity)
3808%
3809%   Return the number of alternatives as   indicated by the database
3810%   internal hashed indexing. This is a rough measure for the number
3811%   of alternatives we can expect for   an  rdf_has/3 call using the
3812%   given three arguments. When  called   with  three variables, the
3813%   total number of triples is returned.   This  estimate is used in
3814%   query  optimisation.  See  also    rdf_predicate_property/2  and
3815%   rdf_statistics/1 for additional information to help optimizers.
3816
3817%!  rdf_debug(+Level) is det.
3818%
3819%   Set debugging to Level.  Level is an integer 0..9.  Default is
3820%   0 no debugging.
3821
3822%!  rdf_atom_md5(+Text, +Times, -MD5) is det.
3823%
3824%   Computes the MD5 hash from Text,  which   is  an atom, string or
3825%   list of character codes. Times is an integer >= 1. When > 0, the
3826%   MD5 algorithm is repeated Times  times   on  the generated hash.
3827%   This can be used for  password   encryption  algorithms  to make
3828%   generate-and-test loops slow.
3829%
3830%   @deprecated. New code should  use   the  library(crypt)  library
3831%   provided  by  the  clib  package  for  password  encryption  and
3832%   library(md5) to compute MD5 hashes.
3833
3834
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    ].