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-2023, University of Amsterdam 7 VU University Amsterdam 8 CWI, Amsterdam 9 SWI-Prolog Solutions b.v. 10 All rights reserved. 11 12 Redistribution and use in source and binary forms, with or without 13 modification, are permitted provided that the following conditions 14 are met: 15 16 1. Redistributions of source code must retain the above copyright 17 notice, this list of conditions and the following disclaimer. 18 19 2. Redistributions in binary form must reproduce the above copyright 20 notice, this list of conditions and the following disclaimer in 21 the documentation and/or other materials provided with the 22 distribution. 23 24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 POSSIBILITY OF SUCH DAMAGE. 36*/ 37 38:- module(rdf_db, 39 [ rdf_version/1, % -Version 40 41 rdf/3, % ?Subject, ?Predicate, ?Object 42 rdf/4, % ?Subject, ?Predicate, ?Object, ?DB 43 rdf_has/3, % ?Subject, +Pred, ?Obj 44 rdf_has/4, % ?Subject, +Pred, ?Obj, -RealPred 45 rdf_reachable/3, % ?Subject, +Pred, ?Object 46 rdf_reachable/5, % ?Subject, +Pred, ?Object, +MaxD, ?D 47 rdf_resource/1, % ?Resource 48 rdf_subject/1, % ?Subject 49 50 rdf_member_property/2, % ?Property, ?Index 51 52 rdf_assert/3, % +Subject, +Predicate, +Object 53 rdf_assert/4, % +Subject, +Predicate, +Object, +DB 54 rdf_retractall/3, % ?Subject, ?Predicate, ?Object 55 rdf_retractall/4, % ?Subject, ?Predicate, ?Object, +DB 56 rdf_update/4, % +Subject, +Predicate, +Object, +Act 57 rdf_update/5, % +Subject, +Predicate, +Object, +Src, +Act 58 rdf_set_predicate/2, % +Predicate, +Property 59 rdf_predicate_property/2, % +Predicate, ?Property 60 rdf_current_predicate/1, % -Predicate 61 rdf_current_literal/1, % -Literal 62 rdf_transaction/1, % :Goal 63 rdf_transaction/2, % :Goal, +Id 64 rdf_transaction/3, % :Goal, +Id, +Options 65 rdf_active_transaction/1, % ?Id 66 67 rdf_monitor/2, % :Goal, +Options 68 69 rdf_save_db/1, % +File 70 rdf_save_db/2, % +File, +DB 71 rdf_load_db/1, % +File 72 rdf_reset_db/0, 73 74 rdf_node/1, % -Id 75 rdf_bnode/1, % -Id 76 rdf_is_bnode/1, % +Id 77 78 rdf_is_resource/1, % +Term 79 rdf_is_literal/1, % +Term 80 rdf_literal_value/2, % +Term, -Value 81 82 rdf_load/1, % +File 83 rdf_load/2, % +File, +Options 84 rdf_save/1, % +File 85 rdf_save/2, % +File, +Options 86 rdf_unload/1, % +File 87 rdf_unload_graph/1, % +Graph 88 89 rdf_md5/2, % +DB, -MD5 90 rdf_atom_md5/3, % +Text, +Times, -MD5 91 92 rdf_create_graph/1, % ?Graph 93 rdf_graph_property/2, % ?Graph, ?Property 94 rdf_set_graph/2, % +Graph, +Property 95 rdf_graph/1, % ?Graph 96 rdf_source/1, % ?File 97 rdf_source/2, % ?DB, ?SourceURL 98 rdf_make/0, % Reload modified databases 99 rdf_gc/0, % Garbage collection 100 101 rdf_source_location/2, % +Subject, -Source 102 rdf_statistics/1, % -Key 103 rdf_set/1, % +Term 104 rdf_generation/1, % -Generation 105 rdf_snapshot/1, % -Snapshot 106 rdf_delete_snapshot/1, % +Snapshot 107 rdf_current_snapshot/1, % +Snapshot 108 rdf_estimate_complexity/4, % +S,+P,+O,-Count 109 110 rdf_save_subject/3, % +Stream, +Subject, +DB 111 rdf_save_header/2, % +Out, +Options 112 rdf_save_footer/1, % +Out 113 114 rdf_equal/2, % ?Resource, ?Resource 115 lang_equal/2, % +Lang1, +Lang2 116 lang_matches/2, % +Lang, +Pattern 117 118 rdf_prefix/2, % :Alias, +URI 119 rdf_current_prefix/2, % :Alias, ?URI 120 rdf_register_prefix/2, % +Alias, +URI 121 rdf_register_prefix/3, % +Alias, +URI, +Options 122 rdf_unregister_prefix/1, % +Alias 123 rdf_current_ns/2, % :Alias, ?URI 124 rdf_register_ns/2, % +Alias, +URI 125 rdf_register_ns/3, % +Alias, +URI, +Options 126 rdf_global_id/2, % ?NS:Name, :Global 127 rdf_global_object/2, % +Object, :NSExpandedObject 128 rdf_global_term/2, % +Term, :WithExpandedNS 129 130 rdf_compare/3, % -Dif, +Object1, +Object2 131 rdf_match_label/3, % +How, +String, +Label 132 rdf_split_url/3, % ?Base, ?Local, ?URL 133 rdf_url_namespace/2, % +URL, ?Base 134 135 rdf_warm_indexes/0, 136 rdf_warm_indexes/1, % +Indexed 137 rdf_update_duplicates/0, 138 139 rdf_debug/1, % Set verbosity 140 141 rdf_new_literal_map/1, % -Handle 142 rdf_destroy_literal_map/1, % +Handle 143 rdf_reset_literal_map/1, % +Handle 144 rdf_insert_literal_map/3, % +Handle, +Key, +Literal 145 rdf_insert_literal_map/4, % +Handle, +Key, +Literal, -NewKeys 146 rdf_delete_literal_map/3, % +Handle, +Key, +Literal 147 rdf_delete_literal_map/2, % +Handle, +Key 148 rdf_find_literal_map/3, % +Handle, +KeyList, -Literals 149 rdf_keys_in_literal_map/3, % +Handle, +Spec, -Keys 150 rdf_statistics_literal_map/2, % +Handle, +Name(-Arg...) 151 152 rdf_graph_prefixes/2, % ?Graph, -Prefixes 153 rdf_graph_prefixes/3, % ?Graph, -Prefixes, :Filter 154 155 (rdf_meta)/1, % +Heads 156 op(1150, fx, (rdf_meta)) 157 ]). 158:- use_module(library(semweb/rdf_prefixes), 159 [ (rdf_meta)/1, 160 register_file_prefixes/1, 161 rdf_global_id/2, 162 rdf_register_ns/2, 163 % re-exported predicates 164 rdf_global_object/2, 165 rdf_current_ns/2, 166 rdf_prefix/2, 167 rdf_global_term/2, 168 rdf_register_ns/3, 169 rdf_register_prefix/3, 170 rdf_register_prefix/2, 171 rdf_current_prefix/2, 172 rdf_unregister_prefix/1 173 ]). 174 175:- autoload(library(apply),[maplist/2,maplist/3]). 176:- use_module(library(debug),[debug/3,assertion/1]). 177:- autoload(library(error),[must_be/2,existence_error/2]). 178:- autoload(library(gensym),[gensym/2,reset_gensym/1]). 179:- autoload(library(lists), 180 [member/2,flatten/2,list_to_set/2,append/3,select/3]). 181:- autoload(library(memfile), 182 [atom_to_memory_file/2,open_memory_file/4]). 183:- autoload(library(option), 184 [option/2,option/3,merge_options/3,meta_options/3]). 185:- autoload(library(rdf),[process_rdf/3]). 186:- autoload(library(sgml), 187 [ load_structure/3, 188 xml_quote_attribute/3, 189 xml_name/1, 190 xml_quote_cdata/3, 191 xml_is_dom/1, 192 iri_xml_namespace/3, 193 iri_xml_namespace/2 194 ]). 195:- autoload(library(sgml_write),[xml_write/3]). 196:- autoload(library(uri), 197 [ uri_file_name/2, 198 uri_is_global/1, 199 uri_normalized/2, 200 uri_components/2, 201 uri_data/3, 202 uri_data/4 203 ]). 204:- autoload(library(xsdp_types),[xsdp_numeric_uri/2]). 205:- autoload(library(semweb/rdf_cache),[rdf_cache_file/3]). 206 207:- if(exists_source(library(thread))). 208:- autoload(library(thread), [concurrent/3]). 209:- endif. 210 211:- use_foreign_library(foreign(rdf_db)). 212:- public rdf_print_predicate_cloud/2. % print matrix of reachable predicates 213 214:- meta_predicate 215 rdf_transaction( ), 216 rdf_transaction( , ), 217 rdf_transaction( , , ), 218 rdf_monitor( , ), 219 rdf_save( , ), 220 rdf_load( , ). 221 222:- predicate_options(rdf_graph_prefixes/3, 3, 223 [ expand(callable+4), 224 filter(callable+3), 225 get_prefix(callable+2), 226 min_count(nonneg) 227 ]). 228:- predicate_options(rdf_load/2, 2, 229 [ base_uri(atom), 230 blank_nodes(oneof([share,noshare])), 231 cache(boolean), 232 concurrent(positive_integer), 233 db(atom), 234 format(oneof([xml,triples,turtle,trig,nquads,ntriples])), 235 graph(atom), 236 multifile(boolean), 237 if(oneof([true,changed,not_loaded])), 238 modified(-float), 239 prefixes(-list), 240 silent(boolean), 241 register_namespaces(boolean) 242 ]). 243:- predicate_options(rdf_save/2, 2, 244 [ graph(atom), 245 db(atom), 246 anon(boolean), 247 base_uri(atom), 248 write_xml_base(boolean), 249 convert_typed_literal(callable), 250 encoding(encoding), 251 document_language(atom), 252 namespaces(list(atom)), 253 xml_attributes(boolean), 254 inline(boolean) 255 ]). 256:- predicate_options(rdf_save_header/2, 2, 257 [ graph(atom), 258 db(atom), 259 namespaces(list(atom)) 260 ]). 261:- predicate_options(rdf_save_subject/3, 3, 262 [ graph(atom), 263 base_uri(atom), 264 convert_typed_literal(callable), 265 document_language(atom) 266 ]). 267:- predicate_options(rdf_transaction/3, 3, 268 [ snapshot(any) 269 ]). 270 271:- discontiguous 272 term_expansion/2.
288 /******************************* 289 * PREFIXES * 290 *******************************/ 291 292% the ns/2 predicate is historically defined in this module. We'll keep 293% that for compatibility reasons. 294 295:- multifile ns/2. 296:- dynamic ns/2. % ID, URL 297 298:- multifile 299 rdf_prefixes:rdf_empty_prefix_cache/2. 300 301rdf_prefixesrdf_empty_prefix_cache(_Prefix, _IRI) :- 302 rdf_empty_prefix_cache. 303 304:- rdf_meta 305 rdf(r,r,o), 306 rdf_has(r,r,o,r), 307 rdf_has(r,r,o), 308 rdf_assert(r,r,o), 309 rdf_retractall(r,r,o), 310 rdf(r,r,o,?), 311 rdf_assert(r,r,o,+), 312 rdf_retractall(r,r,o,?), 313 rdf_reachable(r,r,o), 314 rdf_reachable(r,r,o,+,?), 315 rdf_update(r,r,o,t), 316 rdf_update(r,r,o,+,t), 317 rdf_equal(o,o), 318 rdf_source_location(r,-), 319 rdf_resource(r), 320 rdf_subject(r), 321 rdf_create_graph(r), 322 rdf_graph(r), 323 rdf_graph_property(r,?), 324 rdf_set_graph(r,+), 325 rdf_unload_graph(r), 326 rdf_set_predicate(r, t), 327 rdf_predicate_property(r, -), 328 rdf_estimate_complexity(r,r,r,-), 329 rdf_print_predicate_cloud(r,+).
335rdf_equal(Resource, Resource).
343lang_equal(Lang, Lang) :- !. 344lang_equal(Lang1, Lang2) :- 345 downcase_atom(Lang1, LangCannon), 346 downcase_atom(Lang2, LangCannon).
358 /******************************* 359 * BASIC TRIPLE QUERIES * 360 *******************************/
literal(Value)
if the
object is a literal value. If a value of the form
NameSpaceID:LocalName is provided it is expanded to a ground
atom using expand_goal/2. This implies you can use this
construct in compiled code without paying a performance penalty.
Literal values take one of the following forms:
rdf:datatype
TypeID. The Value is either the textual representation or a
natural Prolog representation. See the option
convert_typed_literal(:Convertor) of the parser. The storage
layer provides efficient handling of atoms, integers (64-bit)
and floats (native C-doubles). All other data is represented
as a Prolog record.
For literal querying purposes, Object can be of the form
literal(+Query, -Value)
, where Query is one of the terms below.
If the Query takes a literal argument and the value has a
numeric type numerical comparison is performed.
icase(Text)
. Backward compatibility.
Backtracking never returns duplicate triples. Duplicates can be
retrieved using rdf/4. The predicate rdf/3 raises a type-error
if called with improper arguments. If rdf/3 is called with a
term literal(_)
as Subject or Predicate object it fails
silently. This allows for graph matching goals like
rdf(S,P,O)
,rdf(O,P2,O2)
to proceed without errors.
rdf(Subject, Predicate, Object)
is true
exploiting the rdfs:subPropertyOf predicate as well as inverse
predicates declared using rdf_set_predicate/2 with the
inverse_of
property.inverse_of(Pred)
.symetric(true)
or inverse_of(P2)
properties.
If used with either Subject or Object unbound, it first returns the origin, followed by the reachable nodes in breadth-first search-order. The implementation internally looks one solution ahead and succeeds deterministically on the last solution. This predicate never generates the same node twice and is robust against cycles in the transitive relation.
With all arguments instantiated, it succeeds deterministically if a path can be found from Subject to Object. Searching starts at Subject, assuming the branching factor is normally lower. A call with both Subject and Object unbound raises an instantiation error. The following example generates all subclasses of rdfs:Resource:
?- rdf_reachable(X, rdfs:subClassOf, rdfs:'Resource'). X = 'http://www.w3.org/2000/01/rdf-schema#Resource' ; X = 'http://www.w3.org/2000/01/rdf-schema#Class' ; X = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Property' ; ...
infinite
to impose no
distance-limit.
526rdf_subject(Resource) :-
527 rdf_resource(Resource),
528 ( rdf(Resource, _, _) -> true ).
This predicate is primarily intended as a way to process all resources without processing resources twice. The user must be aware that some of the returned resources may not appear in any visible triple.
541 /******************************* 542 * TRIPLE MODIFICATIONS * 543 *******************************/
user
. Subject and Predicate are
resources. Object is either a resource or a term literal(Value)
.
See rdf/3 for an explanation of Value for typed and language
qualified literals. All arguments are subject to name-space
expansion. Complete duplicates (including the same graph and
`line' and with a compatible `lifespan') are not added to the
database.literal(Value)
.595 /******************************* 596 * COLLECTIONS * 597 *******************************/
603term_expansion(member_prefix(x), 604 member_prefix(Prefix)) :- 605 rdf_db:ns(rdf, NS), 606 atom_concat(NS, '_', Prefix). 607member_prefix(x). 608 609rdf_member_property(P, N) :- 610 integer(N), 611 !, 612 member_prefix(Prefix), 613 atom_concat(Prefix, N, P). 614rdf_member_property(P, N) :- 615 member_prefix(Prefix), 616 atom_concat(Prefix, Sub, P), 617 atom_number(Sub, N). 618 619 620 /******************************* 621 * ANONYMOUS SUBJECTS * 622 *******************************/
630rdf_node(Resource) :-
631 rdf_bnode(Resource).
637rdf_bnode(Value) :- 638 repeat, 639 gensym('_:genid', Value), 640 \+ rdf(Value, _, _), 641 \+ rdf(_, _, Value), 642 \+ rdf(_, Value, _), 643 !. 644 645 646 647 /******************************* 648 * TYPES * 649 *******************************/
_:
. For backward compatibility reason, __
is also
considered to be a blank node.
668rdf_is_resource(Term) :-
669 atom(Term).
676rdf_is_literal(literal(Value)) :- 677 ground(Value). 678 679 /******************************* 680 * LITERALS * 681 *******************************/
Plain literals | Atom |
Language tagged literal | Atom holding plain text |
xsd:string | Atom |
rdf:XMLLiteral | XML DOM Tree |
Numeric XSD type | Number |
706:- rdf_meta 707 rdf_literal_value(o, -), 708 typed_value(r, +, -), 709 numeric_value(r, +, -). 710 711rdf_literal_value(literal(String), Value) :- 712 atom(String), 713 !, 714 Value = String. 715rdf_literal_value(literal(lang(_Lang, String)), String). 716rdf_literal_value(literal(type(Type, String)), Value) :- 717 typed_value(Type, String, Value). 718 719typed_value(Numeric, String, Value) :- 720 xsdp_numeric_uri(Numeric, NumType), 721 !, 722 numeric_value(NumType, String, Value). 723typed_value(xsd:string, String, String). 724typed_value(rdf:'XMLLiteral', Value, DOM) :- 725 ( atom(Value) 726 -> setup_call_cleanup( 727 ( atom_to_memory_file(Value, MF), 728 open_memory_file(MF, read, In, [free_on_close(true)]) 729 ), 730 load_structure(stream(In), DOM, [dialect(xml)]), 731 close(In)) 732 ; DOM = Value 733 ). 734 735numeric_value(xsd:integer, String, Value) :- 736 atom_number(String, Value), 737 integer(Value). 738numeric_value(xsd:float, String, Value) :- 739 atom_number(String, Number), 740 Value is float(Number). 741numeric_value(xsd:double, String, Value) :- 742 atom_number(String, Number), 743 Value is float(Number). 744numeric_value(xsd:decimal, String, Value) :- 745 atom_number(String, Value). 746 747 748 /******************************* 749 * SOURCE * 750 *******************************/
758rdf_source_location(Subject, Source) :- 759 findall(Source, rdf(Subject, _, _, Source), Sources), 760 sort(Sources, Unique), 761 member(Source, Unique). 762 763 764 /******************************* 765 * GARBAGE COLLECT * 766 *******************************/
772:- public 773 rdf_create_gc_thread/0. 774 775rdf_create_gc_thread :- 776 thread_create(rdf_gc_loop, _, 777 [ alias('__rdf_GC') 778 ]).
785rdf_gc_loop :- 786 catch(rdf_gc_loop(0), E, recover_gc(E)). 787 788recover_gc('$aborted') :- 789 !, 790 thread_self(Me), 791 thread_detach(Me). 792recover_gc(Error) :- 793 print_message(error, Error), 794 rdf_gc_loop. 795 796rdf_gc_loop(CPU) :- 797 repeat, 798 ( consider_gc(CPU) 799 -> rdf_gc(CPU1), 800 sleep(CPU1) 801 ; sleep(0.1) 802 ), 803 fail.
811rdf_gc(CPU) :-
812 statistics(cputime, CPU0),
813 ( rdf_gc_
814 -> statistics(cputime, CPU1),
815 CPU is CPU1-CPU0,
816 rdf_add_gc_time(CPU)
817 ; CPU = 0.0
818 ).
__rdf_GC
performs garbage collection as long as
it is considered `useful'.
Using rdf_gc/0 should only be needed to ensure a fully clean database for analysis purposes such as leak detection.
830rdf_gc :- 831 has_garbage, 832 !, 833 rdf_gc(_), 834 rdf_gc. 835rdf_gc.
841has_garbage :- 842 rdf_gc_info_(Info), 843 has_garbage(Info), 844 !. 845 846has_garbage(Info) :- arg(2, Info, Garbage), Garbage > 0. 847has_garbage(Info) :- arg(3, Info, Reindexed), Reindexed > 0. 848has_garbage(Info) :- arg(4, Info, Optimizable), Optimizable > 0.
855consider_gc(_CPU) :- 856 ( rdf_gc_info_(gc_info(Triples, % Total #triples in DB 857 Garbage, % Garbage triples in DB 858 Reindexed, % Reindexed & not reclaimed 859 Optimizable, % Non-optimized tables 860 _KeepGen, % Oldest active generation 861 _LastGCGen, % Oldest active gen at last GC 862 _ReindexGen, 863 _LastGCReindexGen)) 864 -> ( (Garbage+Reindexed) * 5 > Triples 865 ; Optimizable > 4 866 ) 867 ; print_message(error, rdf(invalid_gc_info)), 868 sleep(10) 869 ), 870 !. 871 872 873 /******************************* 874 * STATISTICS * 875 *******************************/
triples
for the interpretation of this value.921rdf_statistics(graphs(Count)) :- 922 rdf_statistics_(graphs(Count)). 923rdf_statistics(triples(Count)) :- 924 rdf_statistics_(triples(Count)). 925rdf_statistics(duplicates(Count)) :- 926 rdf_statistics_(duplicates(Count)). 927rdf_statistics(lingering(Count)) :- 928 rdf_statistics_(lingering(Count)). 929rdf_statistics(resources(Count)) :- 930 rdf_statistics_(resources(Count)). 931rdf_statistics(properties(Count)) :- 932 rdf_statistics_(predicates(Count)). 933rdf_statistics(literals(Count)) :- 934 rdf_statistics_(literals(Count)). 935rdf_statistics(gc(Count, Reclaimed, Reindexed, Time)) :- 936 rdf_statistics_(gc(Count, Reclaimed, Reindexed, Time)). 937rdf_statistics(searched_nodes(Count)) :- 938 rdf_statistics_(searched_nodes(Count)). 939rdf_statistics(lookup(Index, Count)) :- 940 functor(Indexed, indexed, 16), 941 rdf_statistics_(Indexed), 942 index(Index, I), 943 Arg is I + 1, 944 arg(Arg, Indexed, Count), 945 Count \== 0. 946rdf_statistics(hash_quality(Index, Size, Quality,Optimize)) :- 947 rdf_statistics_(hash_quality(List)), 948 member(hash(Place,Size,Quality,Optimize), List), 949 index(Index, Place). 950rdf_statistics(triples_by_graph(Graph, Count)) :- 951 rdf_graph_(Graph, Count). 952 953index(rdf(-,-,-,-), 0). 954index(rdf(+,-,-,-), 1). 955index(rdf(-,+,-,-), 2). 956index(rdf(+,+,-,-), 3). 957index(rdf(-,-,+,-), 4). 958index(rdf(+,-,+,-), 5). 959index(rdf(-,+,+,-), 6). 960index(rdf(+,+,+,-), 7). 961 962index(rdf(-,-,-,+), 8). 963index(rdf(+,-,-,+), 9). 964index(rdf(-,+,-,+), 10). 965index(rdf(+,+,-,+), 11). 966index(rdf(-,-,+,+), 12). 967index(rdf(+,-,+,+), 13). 968index(rdf(-,+,+,+), 14). 969index(rdf(+,+,+,+), 15). 970 971 972 /******************************* 973 * PREDICATES * 974 *******************************/
Note that resources that have rdf:type
rdf:Property
are
not automatically included in the result-set of this predicate,
while all resources that appear as the second argument of a
triple are included.
990rdf_current_predicate(P, DB) :-
991 rdf_current_predicate(P),
992 ( rdf(_,P,_,DB)
993 -> true
994 ).
inverse_of(Self)
.rdf_subject_branch_factor
property, uniqueness of the object value is computed from the
hash key rather than the actual values.rdf_subject_branch_factor
, but also considering
triples of `subPropertyOf' this relation. See also rdf_has/3.rdf_object_branch_factor
, but also considering
triples of `subPropertyOf' this relation. See also rdf_has/3.1047rdf_predicate_property(P, Prop) :- 1048 var(P), 1049 !, 1050 rdf_current_predicate(P), 1051 rdf_predicate_property_(P, Prop). 1052rdf_predicate_property(P, Prop) :- 1053 rdf_predicate_property_(P, Prop).
symmetric(true)
is the same as inverse_of(Predicate)
,
i.e., creating a predicate that is the inverse of
itself.inverse_of([])
.
The transitive
property is currently not used. The symmetric
and inverse_of
properties are considered by rdf_has/3,4 and
rdf_reachable/3.
1078 /******************************* 1079 * SNAPSHOTS * 1080 *******************************/
snapshot
option. A
snapshot created outside a transaction exists until it is
deleted. Snapshots taken inside a transaction can only be used
inside this transaction.1103rdf_current_snapshot(Term) :- 1104 current_blob(Term, rdf_snapshot). 1105 1106 1107 /******************************* 1108 * TRANSACTION * 1109 *******************************/
rdf_transaction(Goal, user, [])
. See rdf_transaction/3.rdf_transaction(Goal, Id, [])
. See rdf_transaction/3.Processed options are:
true
, which implies that an anonymous snapshot is
created at the current state of the store. Modifications
due to executing Goal are only visible to Goal.1145rdf_transaction(Goal) :- 1146 rdf_transaction(Goal, user, []). 1147rdf_transaction(Goal, Id) :- 1148 rdf_transaction(Goal, Id, []).
1159rdf_active_transaction(Id) :-
1160 rdf_active_transactions_(List),
1161 member(Id, List).
1167rdf_monitor(Goal, Options) :- 1168 monitor_mask(Options, 0xffff, Mask), 1169 rdf_monitor_(Goal, Mask). 1170 1171monitor_mask([], Mask, Mask). 1172monitor_mask([H|T], Mask0, Mask) :- 1173 update_mask(H, Mask0, Mask1), 1174 monitor_mask(T, Mask1, Mask). 1175 1176update_mask(-X, Mask0, Mask) :- 1177 !, 1178 monitor_mask(X, M), 1179 Mask is Mask0 /\ \M. 1180update_mask(+X, Mask0, Mask) :- 1181 !, 1182 monitor_mask(X, M), 1183 Mask is Mask0 \/ M. 1184update_mask(X, Mask0, Mask) :- 1185 monitor_mask(X, M), 1186 Mask is Mask0 \/ M.
1193 % C-defined broadcasts 1194monitor_mask(assert, 0x0001). 1195monitor_mask(assert(load), 0x0002). 1196monitor_mask(retract, 0x0004). 1197monitor_mask(update, 0x0008). 1198monitor_mask(new_literal, 0x0010). 1199monitor_mask(old_literal, 0x0020). 1200monitor_mask(transaction, 0x0040). 1201monitor_mask(load, 0x0080). 1202monitor_mask(create_graph, 0x0100). 1203monitor_mask(reset, 0x0200). 1204 % prolog defined broadcasts 1205monitor_mask(parse, 0x1000). 1206monitor_mask(unload, 0x1000). % FIXME: Duplicate 1207 % mask for all 1208monitor_mask(all, 0xffff). 1209 1210%rdf_broadcast(Term, MaskName) :- 1211%% monitor_mask(MaskName, Mask), 1212%% rdf_broadcast_(Term, Mask). 1213 1214 1215 /******************************* 1216 * WARM * 1217 *******************************/
1223rdf_warm_indexes :- 1224 findall(Index, rdf_index(Index), Indexes), 1225 rdf_warm_indexes(Indexes). 1226 1227rdf_index(s). 1228rdf_index(p). 1229rdf_index(o). 1230rdf_index(sp). 1231rdf_index(o). 1232rdf_index(po). 1233rdf_index(spo). 1234rdf_index(g). 1235rdf_index(sg). 1236rdf_index(pg).
1247 /******************************* 1248 * DUPLICATES * 1249 *******************************/
The duplicates marks are used to reduce the administrative load of avoiding duplicate answers. Normally, the duplicates are marked using a background thread that is started on the first query that produces a substantial amount of duplicates.
1264:- public
1265 rdf_update_duplicates_thread/0.
1271rdf_update_duplicates_thread :-
1272 thread_create(rdf_update_duplicates, _,
1273 [ detached(true),
1274 alias('__rdf_duplicate_detecter')
1275 ]).
This predicate is normally executed from a background thread named =__rdf_duplicate_detecter= which is created when a query discovers that checking for duplicates becomes too expensive.
1289 /******************************* 1290 * QUICK BINARY LOAD/SAVE * 1291 *******************************/
1301:- create_prolog_flag(rdf_triple_format, 3, [type(integer)]). 1302 1303rdf_save_db(File) :- 1304 current_prolog_flag(rdf_triple_format, Version), 1305 setup_call_cleanup( 1306 open(File, write, Out, [type(binary)]), 1307 ( set_stream(Out, record_position(false)), 1308 rdf_save_db_(Out, _, Version) 1309 ), 1310 close(Out)). 1311 1312 1313rdf_save_db(File, Graph) :- 1314 current_prolog_flag(rdf_triple_format, Version), 1315 setup_call_cleanup( 1316 open(File, write, Out, [type(binary)]), 1317 ( set_stream(Out, record_position(false)), 1318 rdf_save_db_(Out, Graph, Version) 1319 ), 1320 close(Out)).
1329rdf_load_db_no_admin(File, Id, Graphs) :-
1330 open(File, read, In, [type(binary)]),
1331 set_stream(In, record_position(false)),
1332 call_cleanup(rdf_load_db_(In, Id, Graphs), close(In)).
1343check_loaded_cache(DB, [DB], _Modified) :- !. 1344check_loaded_cache(DB, Graphs, _) :- 1345 print_message(warning, rdf(inconsistent_cache(DB, Graphs))).
1352rdf_load_db(File) :- 1353 uri_file_name(URL, File), 1354 rdf_load_db_no_admin(File, URL, _Graphs). 1355 1356 1357 /******************************* 1358 * LOADING RDF * 1359 *******************************/ 1360 1361:- multifile 1362 rdf_open_hook/8, 1363 rdf_open_decode/4, % +Encoding, +File, -Stream, -Cleanup 1364 rdf_load_stream/3, % +Format, +Stream, +Options 1365 rdf_file_type/2, % ?Extension, ?Format 1366 rdf_storage_encoding/2, % ?Extension, ?Encoding 1367 url_protocol/1. % ?Protocol
rdf_load(FileOrList, [])
. See rdf_load/2.if(changed)
=.
Options provides additional processing options. Defined options are:
share
(default),
equivalent blank nodes are shared in the same resource.file://
URL when loading
a file or, if the specification is a URL, its normalized
version without the optional #fragment.true
, changed
(default) or
not_loaded
.not_modified
, cached(File)
,
last_modified(Stamp)
or unknown
.false
, do not use or create a cache file.true
(default false
), register xmlns
namespace
declarations or Turtle @prefix
prefixes using
rdf_register_prefix/3 if there is no conflict.true
, the message reporting completion is printed using
level silent
. Otherwise the level is informational
. See
also print_message/2.Other options are forwarded to process_rdf/3. By default, rdf_load/2 only loads RDF/XML from files. It can be extended to load data from other formats and locations using plugins. The full set of plugins relevant to support different formats and locations is below:
:- use_module(library(semweb/turtle)). % Turtle and TriG :- use_module(library(semweb/rdf_ntriples)). :- use_module(library(semweb/rdf_zlib_plugin)). :- use_module(library(semweb/rdf_http_plugin)). :- use_module(library(http/http_ssl_plugin)).
1463:- dynamic 1464 rdf_loading/3. % Graph, Queue, Thread 1465 1466rdf_load(Spec) :- 1467 rdf_load(Spec, []). 1468 1469:- if(\+current_predicate(concurrent/3)). 1470concurrent(_, Goals, _) :- 1471 forall(member(G, Goals), call(G)). 1472:- endif. 1473 1474% Note that we kill atom garbage collection. This improves performance 1475% with about 15% loading the LUBM Univ_50 benchmark. 1476 1477rdf_load(Spec, M:Options) :- 1478 must_be(list, Options), 1479 current_prolog_flag(agc_margin, Old), 1480 setup_call_cleanup( 1481 set_prolog_flag(agc_margin, 0), 1482 rdf_load_noagc(Spec, M, Options), 1483 set_prolog_flag(agc_margin, Old)). 1484 1485rdf_load_noagc(List, M, Options) :- 1486 is_list(List), 1487 !, 1488 flatten(List, Inputs), % Compatibility: allow nested lists 1489 maplist(must_be(ground), Inputs), 1490 length(Inputs, Count), 1491 load_jobs(Count, Jobs, Options), 1492 ( Jobs =:= 1 1493 -> forall(member(Spec, Inputs), 1494 rdf_load_one(Spec, M, Options)) 1495 ; maplist(load_goal(Options, M), Inputs, Goals), 1496 concurrent(Jobs, Goals, []) 1497 ). 1498rdf_load_noagc(One, M, Options) :- 1499 must_be(ground, One), 1500 rdf_load_one(One, M, Options). 1501 1502load_goal(Options, M, Spec, rdf_load_one(Spec, M, Options)). 1503 1504load_jobs(_, Jobs, Options) :- 1505 option(concurrent(Jobs), Options), 1506 !, 1507 must_be(positive_integer, Jobs). 1508load_jobs(Count, Jobs, _) :- 1509 current_prolog_flag(cpu_count, CPUs), 1510 CPUs > 0, 1511 !, 1512 Jobs is max(1, min(CPUs, Count)). 1513load_jobs(_, 1, _). 1514 1515 1516rdf_load_one(Spec, M, Options) :- 1517 source_url(Spec, Protocol, SourceURL), 1518 load_graph(SourceURL, Graph, Options), 1519 setup_call_cleanup( 1520 with_mutex(rdf_load_file, 1521 rdf_start_load(SourceURL, Loading)), 1522 rdf_load_file(Loading, Spec, SourceURL, Protocol, 1523 Graph, M, Options), 1524 rdf_end_load(Loading)).
1541rdf_start_load(SourceURL, queue(Queue)) :- 1542 rdf_loading(SourceURL, Queue, LoadThread), 1543 \+ thread_self(LoadThread), 1544 !, 1545 debug(rdf(load), '~p is being loaded by thread ~w; waiting ...', 1546 [ SourceURL, LoadThread]). 1547rdf_start_load(SourceURL, Ref) :- 1548 thread_self(Me), 1549 message_queue_create(Queue), 1550 assertz(rdf_loading(SourceURL, Queue, Me), Ref). 1551 1552rdf_end_load(queue(_)) :- !. 1553rdf_end_load(Ref) :- 1554 clause(rdf_loading(_, Queue, _), _, Ref), 1555 erase(Ref), 1556 thread_send_message(Queue, done), 1557 message_queue_destroy(Queue). 1558 1559rdf_load_file(queue(Queue), _Spec, _SourceURL, _Protocol, _Graph, _M, _Options) :- 1560 !, 1561 catch(thread_get_message(Queue, _), _, true). 1562rdf_load_file(_Ref, _Spec, SourceURL, Protocol, Graph, M, Options) :- 1563 debug(rdf(load), 'RDF: Loading ~q into ~q', [SourceURL, Graph]), 1564 statistics(cputime, T0), 1565 rdf_open_input(SourceURL, Protocol, Graph, 1566 In, Cleanup, Modified, Format, Options), 1567 supported_format(Format, Cleanup), 1568 return_modified(Modified, Options), 1569 ( Modified == not_modified 1570 -> Action = none 1571 ; Modified = cached(CacheFile) 1572 -> do_unload(Graph), 1573 catch(rdf_load_db_no_admin(CacheFile, cache(Graph), Graphs), _, fail), 1574 check_loaded_cache(Graph, Graphs, Modified), 1575 Action = load 1576 ; option(base_uri(BaseURI), Options, Graph), 1577 ( var(BaseURI) 1578 -> BaseURI = SourceURL 1579 ; true 1580 ), 1581 once(phrase(derived_options(Options, NSList), Extra)), 1582 merge_options([ base_uri(BaseURI), 1583 graph(Graph), 1584 format(Format) 1585 | Extra 1586 ], Options, RDFOptions), 1587 ( option(multifile(true), Options) 1588 -> true 1589 ; do_unload(Graph) 1590 ), 1591 graph_modified(Modified, ModifiedStamp), 1592 rdf_set_graph_source(Graph, SourceURL, ModifiedStamp), 1593 call_cleanup(rdf_load_stream(Format, In, M:RDFOptions), 1594 Cleanup), 1595 save_cache(Graph, SourceURL, Options), 1596 register_file_prefixes(NSList), 1597 format_action(Format, Action) 1598 ), 1599 rdf_statistics_(triples(Graph, Triples)), 1600 report_loaded(Action, SourceURL, Graph, Triples, T0, Options). 1601 1602supported_format(Format, _Cleanup) :- 1603 rdf_file_type(_, Format), 1604 !. 1605supported_format(Format, Cleanup) :- 1606 call(Cleanup), 1607 existence_error(rdf_format_plugin, Format). 1608 1609format_action(triples, load) :- !. 1610format_action(_, parsed). 1611 1612save_cache(Graph, SourceURL, Options) :- 1613 option(cache(true), Options, true), 1614 rdf_cache_file(SourceURL, write, CacheFile), 1615 !, 1616 catch(save_cache(Graph, CacheFile), E, 1617 print_message(warning, E)). 1618save_cache(_, _, _). 1619 1620derived_options([], _) --> 1621 []. 1622derived_options([H|T], NSList) --> 1623 ( { H == register_namespaces(true) 1624 ; H == (register_namespaces = true) 1625 } 1626 -> [ namespaces(NSList) ] 1627 ; [] 1628 ), 1629 derived_options(T, NSList). 1630 1631graph_modified(last_modified(Stamp), Stamp). 1632graph_modified(unknown, Stamp) :- 1633 get_time(Stamp). 1634 1635return_modified(Modified, Options) :- 1636 option(modified(M0), Options), 1637 !, 1638 M0 = Modified. 1639return_modified(_, _). 1640 1641 1642 /******************************* 1643 * INPUT HANDLING * 1644 *******************************/ 1645 1646/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1647This section deals with pluggable input sources. The task of the input 1648layer is 1649 1650 * Decide on the graph-name 1651 * Decide on the source-location 1652 * Decide whether loading is needed (if-modified) 1653 * Decide on the serialization in the input 1654 1655The protocol must ensure minimal overhead, in particular for network 1656protocols. E.g. for HTTP we want to make a single call on the server and 1657use If-modified-since to verify that we need not reloading this file. 1658- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Options processed:
graph(Graph)
db(Graph)
if(Condition)
cache(Cache)
format(Format)
1676rdf_open_input(SourceURL, Protocol, Graph,
1677 Stream, Cleanup, Modified, Format, Options) :-
1678 ( option(multifile(true), Options)
1679 -> true
1680 ; option(if(If), Options, changed),
1681 ( If == true
1682 -> true
1683 ; rdf_graph_source_(Graph, SourceURL, HaveModified)
1684 -> true
1685 ; option(cache(true), Options, true),
1686 rdf_cache_file(SourceURL, read, CacheFile)
1687 -> time_file(CacheFile, HaveModified)
1688 ; true
1689 )
1690 ),
1691 option(format(Format), Options, _),
1692 open_input_if_modified(Protocol, SourceURL, HaveModified,
1693 Stream, Cleanup, Modified0, Format, Options),
1694 ( Modified0 == not_modified
1695 -> ( nonvar(CacheFile)
1696 -> Modified = cached(CacheFile)
1697 ; Modified = not_modified
1698 )
1699 ; Modified = Modified0
1700 ).
stream(Stream)
http
)1711source_url(stream(In), stream(In), SourceURL) :- 1712 !, 1713 ( stream_property(In, file_name(File)) 1714 -> to_url(File, SourceURL) 1715 ; gensym('stream://', SourceURL) 1716 ). 1717source_url(Stream, Class, SourceURL) :- 1718 is_stream(Stream), 1719 !, 1720 source_url(stream(Stream), Class, SourceURL). 1721source_url(Spec, Protocol, SourceURL) :- 1722 compound(Spec), 1723 !, 1724 source_file(Spec, Protocol, SourceURL). 1725source_url(FileURL, Protocol, SourceURL) :- % or return FileURL? 1726 uri_file_name(FileURL, File), 1727 !, 1728 source_file(File, Protocol, SourceURL). 1729source_url(SourceURL0, Protocol, SourceURL) :- 1730 is_url(SourceURL0, Protocol, SourceURL), 1731 !. 1732source_url(File, Protocol, SourceURL) :- 1733 source_file(File, Protocol, SourceURL). 1734 1735source_file(Spec, file(SExt), SourceURL) :- 1736 findall(Ext, valid_extension(Ext), Exts), 1737 absolute_file_name(Spec, File, [access(read), extensions([''|Exts])]), 1738 storage_extension(_Plain, SExt, File), 1739 uri_file_name(SourceURL, File). 1740 1741to_url(URL, URL) :- 1742 uri_is_global(URL), 1743 !. 1744to_url(File, URL) :- 1745 absolute_file_name(File, Path), 1746 uri_file_name(URL, Path). 1747 1748storage_extension(Plain, SExt, File) :- 1749 file_name_extension(Plain, SExt, File), 1750 SExt \== '', 1751 rdf_storage_encoding(SExt, _), 1752 !. 1753storage_extension(File, '', File).
graph(Graph)
optiondb(Graph)
option (backward compatibility)base_uri(BaseURI)
option1765load_graph(_Source, Graph, Options) :- 1766 option(multifile(true), Options), 1767 !, 1768 ( ( option(graph(Graph), Options) 1769 -> true 1770 ; option(db(Graph), Options) 1771 ), 1772 ground(Graph) 1773 -> true 1774 ; throw(error(existence_error(option, graph), 1775 context(_, "rdf_load/2: using multifile requires graph"))) 1776 ). 1777load_graph(Source, Graph, Options) :- 1778 ( option(graph(Graph), Options) 1779 ; option(db(Graph), Options) 1780 ), 1781 !, 1782 load_graph2(Source, Graph, Options). 1783load_graph(Source, Graph, Options) :- 1784 load_graph2(Source, Graph, Options). 1785 1786load_graph2(_, Graph, _) :- 1787 ground(Graph), 1788 !. 1789load_graph2(_Source, Graph, Options) :- 1790 option(base_uri(Graph), Options), 1791 Graph \== [], 1792 ground(Graph), 1793 !. 1794load_graph2(Source, Graph, _) :- 1795 load_graph(Source, Graph). 1796 1797load_graph(SourceURL, BaseURI) :- 1798 file_name_extension(BaseURI, Ext, SourceURL), 1799 rdf_storage_encoding(Ext, _), 1800 !. 1801load_graph(SourceURL, SourceURL). 1802 1803 1804open_input_if_modified(stream(In), SourceURL, _, In, true, 1805 unknown, Format, _) :- 1806 !, 1807 ( var(Format) 1808 -> guess_format(SourceURL, Format) 1809 ; true 1810 ). 1811open_input_if_modified(file(SExt), SourceURL, HaveModified, Stream, Cleanup, 1812 Modified, Format, _) :- 1813 !, 1814 uri_file_name(SourceURL, File), 1815 ( SExt == '' -> Plain = File; file_name_extension(Plain, SExt, File)), 1816 time_file(File, LastModified), 1817 ( nonvar(HaveModified), 1818 HaveModified >= LastModified 1819 -> Modified = not_modified, 1820 Cleanup = true 1821 ; storage_open(SExt, File, Stream, Cleanup), 1822 Modified = last_modified(LastModified), 1823 ( var(Format) 1824 -> guess_format(Plain, Format) 1825 ; true 1826 ) 1827 ). 1828open_input_if_modified(file, SourceURL, HaveModified, Stream, Cleanup, 1829 Modified, Format, Options) :- 1830 !, 1831 open_input_if_modified(file(''), SourceURL, HaveModified, 1832 Stream, Cleanup, 1833 Modified, Format, Options). 1834open_input_if_modified(Protocol, SourceURL, HaveModified, Stream, Cleanup, 1835 Modified, Format, Options) :- 1836 rdf_open_hook(Protocol, SourceURL, HaveModified, Stream, Cleanup, 1837 Modified, Format, Options). 1838 1839guess_format(File, Format) :- 1840 file_name_extension(_, Ext, File), 1841 ( rdf_file_type(Ext, Format) 1842 -> true 1843 ; Format = xml, 1844 print_message(warning, rdf(guess_format(Ext))) 1845 ).
1853storage_open('', File, Stream, close(Stream)) :- 1854 !, 1855 open(File, read, Stream, [type(binary)]). 1856storage_open(Ext, File, Stream, Cleanup) :- 1857 rdf_storage_encoding(Ext, Encoding), 1858 rdf_open_decode(Encoding, File, Stream, Cleanup). 1859 1860valid_extension(Ext) :- 1861 rdf_file_type(Ext, _). 1862valid_extension(Ext) :- 1863 rdf_storage_encoding(Ext, _).
1873is_url(URL, Scheme, FetchURL) :- 1874 atom(URL), 1875 uri_is_global(URL), 1876 uri_normalized(URL, URL1), % case normalization 1877 uri_components(URL1, Components), 1878 uri_data(scheme, Components, Scheme0), 1879 url_protocol(Scheme0), 1880 !, 1881 Scheme = Scheme0, 1882 uri_data(fragment, Components, _, Components1), 1883 uri_components(FetchURL, Components1). 1884 1885url_protocol(file). % built-in
1893rdf_file_type(xml, xml). 1894rdf_file_type(rdf, xml). 1895rdf_file_type(rdfs, xml). 1896rdf_file_type(owl, xml). 1897rdf_file_type(htm, xhtml). 1898rdf_file_type(html, xhtml). 1899rdf_file_type(xhtml, xhtml). 1900rdf_file_type(trp, triples).
1907rdf_storage_encoding('', plain).
1916rdf_load_stream(xml, Stream, Options) :- 1917 !, 1918 graph(Options, Graph), 1919 rdf_transaction(load_stream(Stream, Options), 1920 parse(Graph)). 1921rdf_load_stream(xhtml, Stream, M:Options) :- 1922 !, 1923 graph(Options, Graph), 1924 rdf_transaction(load_stream(Stream, M:[embedded(true)|Options]), 1925 parse(Graph)). 1926rdf_load_stream(triples, Stream, Options) :- 1927 !, 1928 graph(Options, Graph), 1929 rdf_load_db_(Stream, Graph, _Graphs). 1930 1931load_stream(Stream, M:Options) :- 1932 process_rdf(Stream, assert_triples, M:Options), 1933 option(graph(Graph), Options), 1934 rdf_graph_clear_modified_(Graph).
1939report_loaded(none, _, _, _, _, _) :- !. 1940report_loaded(Action, Source, DB, Triples, T0, Options) :- 1941 statistics(cputime, T1), 1942 Time is T1 - T0, 1943 ( option(silent(true), Options) 1944 -> Level = silent 1945 ; Level = informational 1946 ), 1947 print_message(Level, 1948 rdf(loaded(Action, Source, DB, Triples, Time))).
1961rdf_unload(Spec) :- 1962 source_url(Spec, _Protocol, SourceURL), 1963 rdf_graph_source_(Graph, SourceURL, _), 1964 !, 1965 rdf_unload_graph(Graph). 1966rdf_unload(Graph) :- 1967 atom(Graph), 1968 rdf_graph(Graph), 1969 !, 1970 warn_deprecated_unload(Graph), 1971 rdf_unload_graph(Graph). 1972rdf_unload(_). 1973 1974:- dynamic 1975 warned/0. 1976 1977warn_deprecated_unload(_) :- 1978 warned, 1979 !. 1980warn_deprecated_unload(Graph) :- 1981 assertz(warned), 1982 print_message(warning, rdf(deprecated(rdf_unload(Graph)))).
1990rdf_unload_graph(Graph) :- 1991 must_be(atom, Graph), 1992 ( rdf_graph(Graph) 1993 -> rdf_transaction(do_unload(Graph), unload(Graph)) 1994 ; true 1995 ). 1996 1997do_unload(Graph) :- 1998 ( rdf_graph_(Graph, Triples), 1999 Triples > 0 2000 -> rdf_retractall(_,_,_,Graph) 2001 ; true 2002 ), 2003 rdf_destroy_graph(Graph). 2004 2005 /******************************* 2006 * GRAPH QUERIES * 2007 *******************************/
2019rdf_graph(Graph) :-
2020 rdf_graph_(Graph, _Triples).
2028rdf_source(Graph, SourceURL) :-
2029 rdf_graph(Graph),
2030 rdf_graph_source_(Graph, SourceURL, _Modified).
2038rdf_source(SourceURL) :-
2039 rdf_source(_Graph, SourceURL).
2046rdf_make :- 2047 findall(Source-Graph, modified_graph(Source, Graph), Modified), 2048 forall(member(Source-Graph, Modified), 2049 catch(rdf_load(Source, [graph(Graph), if(changed)]), E, 2050 print_message(error, E))). 2051 2052modified_graph(SourceURL, Graph) :- 2053 rdf_graph(Graph), 2054 rdf_graph_source_(Graph, SourceURL, Modified), 2055 \+ sub_atom(SourceURL, 0, _, _, 'stream://'), 2056 Modified > 0.
modified(false)
.Additional graph properties can be added by defining rules for the multifile predicate property_of_graph/2. Currently, the following extensions are defined:
true
if the graph is persistent.2084rdf_graph_property(Graph, Property) :- 2085 rdf_graph(Graph), 2086 property_of_graph(Property, Graph). 2087 2088:- multifile 2089 property_of_graph/2. 2090 2091property_of_graph(hash(Hash), Graph) :- 2092 rdf_md5(Graph, Hash). 2093property_of_graph(modified(Boolean), Graph) :- 2094 rdf_graph_modified_(Graph, Boolean, _). 2095property_of_graph(source(URL), Graph) :- 2096 rdf_graph_source_(Graph, URL, _). 2097property_of_graph(source_last_modified(Time), Graph) :- 2098 rdf_graph_source_(Graph, _, Time), 2099 Time > 0.0. 2100property_of_graph(triples(Count), Graph) :- 2101 rdf_graph_(Graph, Count).
2110rdf_set_graph(Graph, modified(Modified)) :-
2111 must_be(oneof([false]), Modified),
2112 rdf_graph_clear_modified_(Graph).
2119save_cache(DB, Cache) :-
2120 current_prolog_flag(rdf_triple_format, Version),
2121 setup_call_cleanup(
2122 catch(open(Cache, write, CacheStream, [type(binary)]), _, fail),
2123 rdf_save_db_(CacheStream, DB, Version),
2124 close(CacheStream)).
2132assert_triples([], _). 2133assert_triples([rdf(S,P,O)|T], DB) :- 2134 !, 2135 rdf_assert(S, P, O, DB), 2136 assert_triples(T, DB). 2137assert_triples([H|_], _) :- 2138 throw(error(type_error(rdf_triple, H), _)). 2139 2140 2141 /******************************* 2142 * RESET * 2143 *******************************/
2156rdf_reset_db :- 2157 reset_gensym('_:genid'), 2158 rdf_reset_db_. 2159 2160 2161 /******************************* 2162 * SAVE RDF * 2163 *******************************/
rdf_save(Out, [])
. See rdf_save/2 for details.false
(default true
) do not save blank nodes that do
not appear (indirectly) as object of a named resource.write_xml_base
option.xml:lang
saved with rdf:RDF element.true
(default false
), inline resources when
encountered for the first time. Normally, only bnodes
are handled this way.true
(default false
), emit subjects sorted on
the full URI. Useful to make file comparison easier.false
, do not include the xml:base
declaration that is written normally when using the
base_uri
option.false
(default true
), never use xml attributes to
save plain literal attributes, i.e., always used an XML
element as in <name>Joe</name>
.2225:- thread_local 2226 named_anon/2, % +Resource, -Id 2227 inlined/1. % +Resource 2228 2229rdf_save(File) :- 2230 rdf_save2(File, []). 2231 2232rdf_save(Spec, M:Options0) :- 2233 is_list(Options0), 2234 !, 2235 meta_options(save_meta_option, M:Options0, Options), 2236 to_file(Spec, File), 2237 rdf_save2(File, Options). 2238rdf_save(Spec, _:DB) :- 2239 atom(DB), % backward compatibility 2240 !, 2241 to_file(Spec, File), 2242 rdf_save2(File, [graph(DB)]). 2243 2244save_meta_option(convert_typed_literal). 2245 2246to_file(URL, File) :- 2247 atom(URL), 2248 uri_file_name(URL, File), 2249 !. 2250to_file(File, File). 2251 2252rdf_save2(File, Options) :- 2253 option(encoding(Encoding), Options, utf8), 2254 valid_encoding(Encoding), 2255 open_output(File, Encoding, Out, Close), 2256 flag(rdf_db_saved_subjects, OSavedSubjects, 0), 2257 flag(rdf_db_saved_triples, OSavedTriples, 0), 2258 call_cleanup(rdf_do_save(Out, Options), 2259 Reason, 2260 cleanup_save(Reason, 2261 File, 2262 OSavedSubjects, 2263 OSavedTriples, 2264 Close)). 2265 2266open_output(stream(Out), Encoding, Out, Cleanup) :- 2267 !, 2268 stream_property(Out, encoding(Old)), 2269 ( ( Old == Encoding 2270 ; Old == wchar_t % Internal encoding 2271 ) 2272 -> Cleanup = true 2273 ; set_stream(Out, encoding(Encoding)), 2274 Cleanup = set_stream(Out, encoding(Old)) 2275 ). 2276open_output(File, Encoding, Out, 2277 close(Out)) :- 2278 open(File, write, Out, [encoding(Encoding)]). 2279 2280valid_encoding(Enc) :- 2281 ( xml_encoding_name(Enc, _) 2282 -> true 2283 ; throw(error(domain_error(encoding, Enc), _)) 2284 ). 2285 2286 2287cleanup_save(Reason, 2288 File, 2289 OSavedSubjects, 2290 OSavedTriples, 2291 Close) :- 2292 call(Close), 2293 flag(rdf_db_saved_subjects, SavedSubjects, OSavedSubjects), 2294 flag(rdf_db_saved_triples, SavedTriples, OSavedTriples), 2295 retractall(named_anon(_, _)), 2296 retractall(inlined(_)), 2297 ( Reason == exit 2298 -> print_message(informational, 2299 rdf(saved(File, SavedSubjects, SavedTriples))) 2300 ; format(user_error, 'Reason = ~w~n', [Reason]) 2301 ). 2302 2303rdf_do_save(Out, Options0) :- 2304 rdf_save_header(Out, Options0, Options), 2305 graph(Options, DB), 2306 ( option(sorted(true), Options, false) 2307 -> ( var(DB) 2308 -> setof(Subject, rdf_subject(Subject), Subjects) 2309 ; findall(Subject, rdf(Subject, _, _, DB:_), SubjectList), 2310 sort(SubjectList, Subjects) 2311 ), 2312 forall(member(Subject, Subjects), 2313 rdf_save_non_anon_subject(Out, Subject, Options)) 2314 ; forall(rdf_subject_in_graph(Subject, DB), 2315 rdf_save_non_anon_subject(Out, Subject, Options)) 2316 ), 2317 rdf_save_footer(Out), 2318 !. % dubious cut; without the 2319 % cleanup handlers isn't called!?
2330rdf_subject_in_graph(Subject, DB) :- 2331 var(DB), 2332 !, 2333 rdf_subject(Subject). 2334rdf_subject_in_graph(Subject, DB) :- 2335 rdf_statistics(triples(AllTriples)), 2336 rdf_graph_property(DB, triples(DBTriples)), 2337 DBTriples > AllTriples // 10, 2338 !, 2339 rdf_resource(Subject), 2340 ( rdf(Subject, _, _, DB:_) 2341 -> true 2342 ). 2343rdf_subject_in_graph(Subject, DB) :- 2344 findall(Subject, rdf(Subject, _, _, DB:_), SubjectList), 2345 list_to_set(SubjectList, Subjects), 2346 member(Subject, Subjects). 2347 2348 2349graph(Options0, DB) :- 2350 strip_module(Options0, _, Options), 2351 ( memberchk(graph(DB0), Options) 2352 -> DB = DB0 2353 ; memberchk(db(DB0), Options) 2354 -> DB = DB0 2355 ; true % leave unbound 2356 ).
Save an RDF header, with the XML header, DOCTYPE, ENTITY and opening the rdf:RDF element with appropriate namespace declarations. It uses the primitives from section 3.5 to generate the required namespaces and desired short-name. Options is one of:
rdf
and rdfs
are added to the provided List. If a namespace is not
declared, the resource is emitted in non-abreviated form.2381rdf_save_header(Out, Options) :- 2382 rdf_save_header(Out, Options, _). 2383 2384rdf_save_header(Out, Options, OptionsOut) :- 2385 is_list(Options), 2386 !, 2387 option(encoding(Enc), Options, utf8), 2388 xml_encoding(Enc, Encoding), 2389 format(Out, '<?xml version=\'1.0\' encoding=\'~w\'?>~n', [Encoding]), 2390 format(Out, '<!DOCTYPE rdf:RDF [', []), 2391 header_namespaces(Options, NSIdList), 2392 nsmap(NSIdList, NsMap), 2393 append(Options, [nsmap(NsMap)], OptionsOut), 2394 forall(member(Id=URI, NsMap), 2395 ( xml_quote_attribute(URI, NSText0, Enc), 2396 xml_escape_parameter_entity(NSText0, NSText), 2397 format(Out, '~N <!ENTITY ~w \'~w\'>', [Id, NSText]) 2398 )), 2399 format(Out, '~N]>~n~n', []), 2400 format(Out, '<rdf:RDF', []), 2401 ( member(Id, NSIdList), 2402 format(Out, '~N xmlns:~w="&~w;"~n', [Id, Id]), 2403 fail 2404 ; true 2405 ), 2406 ( option(base_uri(Base), Options), 2407 option(write_xml_base(true), Options, true) 2408 -> xml_quote_attribute(Base, BaseText, Enc), 2409 format(Out, '~N xml:base="~w"~n', [BaseText]) 2410 ; true 2411 ), 2412 ( memberchk(document_language(Lang), Options) 2413 -> format(Out, '~N xml:lang="~w"', [Lang]) 2414 ; true 2415 ), 2416 format(Out, '>~n', []). 2417rdf_save_header(Out, FileRef, OptionsOut) :- % compatibility 2418 atom(FileRef), 2419 rdf_save_header(Out, [graph(FileRef)], OptionsOut). 2420 2421xml_encoding(Enc, Encoding) :- 2422 ( xml_encoding_name(Enc, Encoding) 2423 -> true 2424 ; throw(error(domain_error(rdf_encoding, Enc), _)) 2425 ). 2426 2427xml_encoding_name(ascii, 'US-ASCII'). 2428xml_encoding_name(iso_latin_1, 'ISO-8859-1'). 2429xml_encoding_name(utf8, 'UTF-8').
2436nsmap([], []). 2437nsmap([Id|T0], [Id=URI|T]) :- 2438 ns(Id, URI), 2439 nsmap(T0, T).
2445xml_escape_parameter_entity(In, Out) :- 2446 sub_atom(In, _, _, _, '%'), 2447 !, 2448 atom_codes(In, Codes), 2449 phrase(escape_parent(Codes), OutCodes), 2450 atom_codes(Out, OutCodes). 2451xml_escape_parameter_entity(In, In). 2452 2453escape_parent([]) --> []. 2454escape_parent([H|T]) --> 2455 ( { H == 37 } 2456 -> "%" 2457 ; [H] 2458 ), 2459 escape_parent(T).
2466header_namespaces(Options, List) :- 2467 memberchk(namespaces(NSL0), Options), 2468 !, 2469 sort([rdf,rdfs|NSL0], List). 2470header_namespaces(Options, List) :- 2471 graph(Options, DB), 2472 used_namespace_entities(List, DB).
call(Filter, Where, Prefix, URI)
The Where argument gives the location of the prefix ans is
one of subject
, predicate
, object
or type
. The
Prefix argument is the potentionally new prefix and URI is
the full URI that is being processed.
call(Goal,S,P,O,Graph)
2510:- thread_local 2511 graph_prefix/3. 2512:- meta_predicate 2513 rdf_graph_prefixes( , , ). 2514 2515rdf_graph_prefixes(Graph, List) :- 2516 rdf_graph_prefixes(Graph, List, []). 2517 2518rdf_graph_prefixes(Graph, List, M:QOptions) :- 2519 is_list(QOptions), 2520 !, 2521 meta_options(is_meta, M:QOptions, Options), 2522 option(filter(Filter), Options, true), 2523 option(expand(Expand), Options, rdf_db), 2524 option(min_count(MinCount), Options, 1), 2525 option(get_prefix(GetPrefix), Options, iri_xml_namespace), 2526 call_cleanup(prefixes(Expand, Graph, Prefixes, Filter, MinCount, GetPrefix), 2527 retractall(graph_prefix(_,_,_))), 2528 sort(Prefixes, List). 2529rdf_graph_prefixes(Graph, List, M:Filter) :- 2530 rdf_graph_prefixes(Graph, List, M:[filter(Filter)]). 2531 2532is_meta(filter). 2533is_meta(expand). 2534is_meta(get_prefix). 2535 2536 2537prefixes(Expand, Graph, Prefixes, Filter, MinCount, GetPrefix) :- 2538 ( call(Expand, S, P, O, Graph), 2539 add_ns(subject, GetPrefix, Filter, S, MinCount, s(S)), 2540 add_ns(predicate, GetPrefix, Filter, P, MinCount, sp(S,P)), 2541 add_ns_obj(GetPrefix, Filter, O, MinCount, spo(S,P,O)), 2542 fail 2543 ; true 2544 ), 2545 findall(Prefix, graph_prefix(Prefix, MinCount, _), Prefixes). 2546 2547add_ns(Where, GetPrefix, Filter, S, MinCount, Context) :- 2548 \+ rdf_is_bnode(S), 2549 call(GetPrefix, S, Full), 2550 Full \== '', 2551 !, 2552 ( graph_prefix(Full, MinCount, _) 2553 -> true 2554 ; Filter == true 2555 -> add_ns(Full, Context) 2556 ; call(Filter, Where, Full, S) 2557 -> add_ns(Full, Context) 2558 ; true 2559 ). 2560add_ns(_, _, _, _, _, _). 2561 2562add_ns(Full, Context) :- 2563 graph_prefix(Full, _, Contexts), 2564 memberchk(Context, Contexts), 2565 !. 2566add_ns(Full, Context) :- 2567 retract(graph_prefix(Full, C0, Contexts)), 2568 !, 2569 C1 is C0+1, 2570 asserta(graph_prefix(Full, C1, [Context|Contexts])). 2571add_ns(Full, _) :- 2572 ns(_, Full), 2573 !, 2574 asserta(graph_prefix(Full, _, _)). 2575add_ns(Full, Context) :- 2576 asserta(graph_prefix(Full, 1, [Context])). 2577 2578 2579add_ns_obj(GetPrefix, Filter, O, MinCount, Context) :- 2580 atom(O), 2581 !, 2582 add_ns(object, GetPrefix, Filter, O, MinCount, Context). 2583add_ns_obj(GetPrefix, Filter, literal(type(Type, _)), MinCount, _) :- 2584 atom(Type), 2585 !, 2586 add_ns(type, GetPrefix, Filter, Type, MinCount, t(Type)). 2587add_ns_obj(_, _, _, _, _).
2597used_namespace_entities(List, Graph) :- 2598 decl_used_predicate_ns(Graph), 2599 used_namespaces(List, Graph). 2600 2601used_namespaces(List, DB) :- 2602 rdf_graph_prefixes(DB, FullList), 2603 ns_abbreviations(FullList, List0), 2604 sort([rdf|List0], List). 2605 2606ns_abbreviations([], []). 2607ns_abbreviations([H0|T0], [H|T]) :- 2608 ns(H, H0), 2609 !, 2610 ns_abbreviations(T0, T). 2611ns_abbreviations([_|T0], T) :- 2612 ns_abbreviations(T0, T). 2613 2614 2615/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2616For every URL used as a predicate we *MUST* define a namespace as we 2617cannot use names holding /, :, etc. as XML identifiers. 2618- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 2619 2620:- thread_local 2621 predicate_ns/2. 2622 2623decl_used_predicate_ns(DB) :- 2624 retractall(predicate_ns(_,_)), 2625 ( rdf_current_predicate(P, DB), 2626 decl_predicate_ns(P), 2627 fail 2628 ; true 2629 ). 2630 2631decl_predicate_ns(Pred) :- 2632 predicate_ns(Pred, _), 2633 !. 2634decl_predicate_ns(Pred) :- 2635 rdf_global_id(NS:Local, Pred), 2636 xml_name(Local), 2637 !, 2638 assert(predicate_ns(Pred, NS)). 2639decl_predicate_ns(Pred) :- 2640 atom_codes(Pred, Codes), 2641 append(NSCodes, LocalCodes, Codes), 2642 xml_codes(LocalCodes), 2643 !, 2644 ( NSCodes \== [] 2645 -> atom_codes(NS, NSCodes), 2646 ( ns(Id, NS) 2647 -> assert(predicate_ns(Pred, Id)) 2648 ; between(1, infinite, N), 2649 atom_concat(ns, N, Id), 2650 \+ ns(Id, _) 2651 -> rdf_register_ns(Id, NS), 2652 print_message(informational, 2653 rdf(using_namespace(Id, NS))) 2654 ), 2655 assert(predicate_ns(Pred, Id)) 2656 ; assert(predicate_ns(Pred, -)) % no namespace used 2657 ). 2658 2659xml_codes([]). 2660xml_codes([H|T]) :- 2661 xml_code(H), 2662 xml_codes(T). 2663 2664xml_code(X) :- 2665 code_type(X, csym), 2666 !. 2667xml_code(0'-). % Match 0'-
2676rdf_save_footer(Out) :-
2677 retractall(named_anon(_, _)),
2678 retractall(inlined(_)),
2679 format(Out, '</rdf:RDF>~n', []).
anon(false)
is present in the Options list.2686rdf_save_non_anon_subject(_Out, Subject, Options) :- 2687 rdf_is_bnode(Subject), 2688 ( memberchk(anon(false), Options) 2689 ; graph(Options, DB), 2690 rdf_db(_, _, Subject, DB) 2691 ), 2692 !. 2693rdf_save_non_anon_subject(Out, Subject, Options) :- 2694 rdf_save_subject(Out, Subject, Options), 2695 flag(rdf_db_saved_subjects, X, X+1).
2710rdf_save_subject(Out, Subject, Options) :- 2711 is_list(Options), 2712 !, 2713 option(base_uri(BaseURI), Options, '-'), 2714 ( rdf_save_subject(Out, Subject, BaseURI, 0, Options) 2715 -> format(Out, '~n', []) 2716 ; throw(error(rdf_save_failed(Subject), 'Internal error')) 2717 ). 2718rdf_save_subject(Out, Subject, DB) :- 2719 ( var(DB) 2720 -> rdf_save_subject(Out, Subject, []) 2721 ; rdf_save_subject(Out, Subject, [graph(DB)]) 2722 ).
2732rdf_save_subject(_, Subject, _, _, _) :- 2733 inlined(Subject), 2734 !. 2735rdf_save_subject(Out, Subject, BaseURI, Indent, Options) :- 2736 do_save_subject(Out, Subject, BaseURI, Indent, Options). 2737 2738do_save_subject(Out, Subject, BaseURI, Indent, Options) :- 2739 graph(Options, DB), 2740 findall(Pred=Object, rdf_db(Subject, Pred, Object, DB), Atts0), 2741 sort(Atts0, Atts), % remove duplicates 2742 length(Atts, L), 2743 ( length(Atts0, L0), 2744 Del is L0-L, 2745 Del > 0 2746 -> print_message(informational, 2747 rdf(save_removed_duplicates(Del, Subject))) 2748 ; true 2749 ), 2750 rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options), 2751 flag(rdf_db_saved_triples, X, X+L). 2752 2753rdf_db(Subject, Pred, Object, DB) :- 2754 var(DB), 2755 !, 2756 rdf(Subject, Pred, Object). 2757rdf_db(Subject, Pred, Object, DB) :- 2758 rdf(Subject, Pred, Object, DB:_).
2765rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options) :- 2766 rdf_equal(rdf:type, RdfType), 2767 select(RdfType=Type, Atts, Atts1), 2768 \+ rdf_is_bnode(Type), 2769 rdf_id(Type, BaseURI, TypeId), 2770 xml_is_name(TypeId), 2771 !, 2772 format(Out, '~*|<', [Indent]), 2773 rdf_write_id(Out, TypeId), 2774 save_about(Out, BaseURI, Subject, Options), 2775 save_attributes(Atts1, BaseURI, Out, TypeId, Indent, Options). 2776rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options) :- 2777 format(Out, '~*|<rdf:Description', [Indent]), 2778 save_about(Out, BaseURI, Subject, Options), 2779 save_attributes(Atts, BaseURI, Out, rdf:'Description', Indent, Options). 2780 2781xml_is_name(_NS:Atom) :- 2782 !, 2783 xml_name(Atom). 2784xml_is_name(Atom) :- 2785 xml_name(Atom).
2792save_about(Out, _BaseURI, Subject, _Options) :- 2793 rdf_is_bnode(Subject), 2794 !, 2795 ( named_anon(Subject, NodeID) 2796 -> format(Out, ' rdf:nodeID="~w"', [NodeID]) 2797 ; true 2798 ). 2799save_about(Out, BaseURI, Subject, Options) :- 2800 option(encoding(Encoding), Options, utf8), 2801 rdf_value(Subject, BaseURI, QSubject, Encoding), 2802 format(Out, ' rdf:about="~w"', [QSubject]).
2810save_attributes(Atts, BaseURI, Out, Element, Indent, Options) :-
2811 split_attributes(Atts, InTag, InBody, Options),
2812 SubIndent is Indent + 2,
2813 save_attributes2(InTag, BaseURI, tag, Out, SubIndent, Options),
2814 ( InBody == []
2815 -> format(Out, '/>~n', [])
2816 ; format(Out, '>~n', []),
2817 save_attributes2(InBody, BaseURI, body, Out, SubIndent, Options),
2818 format(Out, '~N~*|</', [Indent]),
2819 rdf_write_id(Out, Element),
2820 format(Out, '>~n', [])
2821 ).
2829split_attributes(Atts, [], Atts, Options) :- 2830 option(xml_attributes(false), Options), 2831 !. 2832split_attributes(Atts, HeadAttr, BodyAttr, _) :- 2833 duplicate_attributes(Atts, Dupls, Singles), 2834 simple_literal_attributes(Singles, HeadAttr, Rest), 2835 append(Dupls, Rest, BodyAttr).
2842duplicate_attributes([], [], []). 2843duplicate_attributes([H|T], Dupls, Singles) :- 2844 H = (Name=_), 2845 named_attributes(Name, T, D, R), 2846 D \== [], 2847 append([H|D], Dupls2, Dupls), 2848 !, 2849 duplicate_attributes(R, Dupls2, Singles). 2850duplicate_attributes([H|T], Dupls2, [H|Singles]) :- 2851 duplicate_attributes(T, Dupls2, Singles). 2852 2853named_attributes(_, [], [], []) :- !. 2854named_attributes(Name, [H|T], D, R) :- 2855 ( H = (Name=_) 2856 -> D = [H|DT], 2857 named_attributes(Name, T, DT, R) 2858 ; R = [H|RT], 2859 named_attributes(Name, T, D, RT) 2860 ).
2867simple_literal_attributes([], [], []). 2868simple_literal_attributes([H|TA], [H|TI], B) :- 2869 in_tag_attribute(H), 2870 !, 2871 simple_literal_attributes(TA, TI, B). 2872simple_literal_attributes([H|TA], I, [H|TB]) :- 2873 simple_literal_attributes(TA, I, TB). 2874 2875in_tag_attribute(_=literal(Text)) :- 2876 atom(Text), % may not have lang qualifier 2877 atom_length(Text, Len), 2878 Len < 60.
2884save_attributes2([], _, _, _, _, _). 2885save_attributes2([H|T], BaseURI, Where, Out, Indent, Options) :- 2886 save_attribute(Where, H, BaseURI, Out, Indent, Options), 2887 save_attributes2(T, BaseURI, Where, Out, Indent, Options). 2888 2889save_attribute(tag, Name=literal(Value), BaseURI, Out, Indent, Options) :- 2890 AttIndent is Indent + 2, 2891 rdf_id(Name, BaseURI, NameText), 2892 option(encoding(Encoding), Options, utf8), 2893 xml_quote_attribute(Value, QVal, Encoding), 2894 format(Out, '~N~*|', [AttIndent]), 2895 rdf_write_id(Out, NameText), 2896 format(Out, '="~w"', [QVal]). 2897save_attribute(body, Name=literal(Literal0), BaseURI, Out, Indent, Options) :- 2898 !, 2899 rdf_id(Name, BaseURI, NameText), 2900 ( memberchk(convert_typed_literal(Converter), Options), 2901 call(Converter, Type, Content, Literal0) 2902 -> Literal = type(Type, Content) 2903 ; Literal = Literal0 2904 ), 2905 save_body_literal(Literal, NameText, BaseURI, Out, Indent, Options). 2906save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :- 2907 rdf_is_bnode(Value), 2908 !, 2909 rdf_id(Name, BaseURI, NameText), 2910 format(Out, '~N~*|<', [Indent]), 2911 rdf_write_id(Out, NameText), 2912 ( named_anon(Value, NodeID) 2913 -> format(Out, ' rdf:nodeID="~w"/>', [NodeID]) 2914 ; ( rdf(S1, Name, Value), 2915 rdf(S2, P2, Value), 2916 (S1 \== S2 ; Name \== P2) 2917 -> predicate_property(named_anon(_,_), number_of_clauses(N)), 2918 atom_concat('bn', N, NodeID), 2919 assertz(named_anon(Value, NodeID)) 2920 ; true 2921 ), 2922 SubIndent is Indent + 2, 2923 ( rdf_collection(Value) 2924 -> save_about(Out, BaseURI, Value, Options), 2925 format(Out, ' rdf:parseType="Collection">~n', []), 2926 rdf_save_list(Out, Value, BaseURI, SubIndent, Options) 2927 ; format(Out, '>~n', []), 2928 rdf_save_subject(Out, Value, BaseURI, SubIndent, Options) 2929 ), 2930 format(Out, '~N~*|</', [Indent]), 2931 rdf_write_id(Out, NameText), 2932 format(Out, '>~n', []) 2933 ). 2934save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :- 2935 option(inline(true), Options), 2936 has_attributes(Value, Options), 2937 \+ inlined(Value), 2938 !, 2939 assertz(inlined(Value)), 2940 rdf_id(Name, BaseURI, NameText), 2941 format(Out, '~N~*|<', [Indent]), 2942 rdf_write_id(Out, NameText), 2943 SubIndent is Indent + 2, 2944 ( rdf_collection(Value) 2945 -> save_about(Out, BaseURI, Value, Options), 2946 format(Out, ' rdf:parseType="Collection">~n', []), 2947 rdf_save_list(Out, Value, BaseURI, SubIndent, Options) 2948 ; format(Out, '>~n', []), 2949 do_save_subject(Out, Value, BaseURI, SubIndent, Options) 2950 ), 2951 format(Out, '~N~*|</', [Indent]), 2952 rdf_write_id(Out, NameText), 2953 format(Out, '>~n', []). 2954save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :- 2955 option(encoding(Encoding), Options, utf8), 2956 rdf_value(Value, BaseURI, QVal, Encoding), 2957 rdf_id(Name, BaseURI, NameText), 2958 format(Out, '~N~*|<', [Indent]), 2959 rdf_write_id(Out, NameText), 2960 format(Out, ' rdf:resource="~w"/>', [QVal]). 2961 2962has_attributes(URI, Options) :- 2963 graph(Options, DB), 2964 rdf_db(URI, _, _, DB), 2965 !.
2970save_body_literal(lang(Lang, Value), 2971 NameText, BaseURI, Out, Indent, Options) :- 2972 !, 2973 format(Out, '~N~*|<', [Indent]), 2974 rdf_write_id(Out, NameText), 2975 ( memberchk(document_language(Lang), Options) 2976 -> write(Out, '>') 2977 ; rdf_id(Lang, BaseURI, LangText), 2978 format(Out, ' xml:lang="~w">', [LangText]) 2979 ), 2980 save_attribute_value(Value, Out, Options), 2981 write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>'). 2982save_body_literal(type(Type, DOM), 2983 NameText, _BaseURI, Out, Indent, Options) :- 2984 rdf_equal(Type, rdf:'XMLLiteral'), 2985 !, 2986 ( atom(DOM) 2987 -> format(Out, '~N~*|<', [Indent]), 2988 rdf_write_id(Out, NameText), 2989 format(Out, ' rdf:parseType="Literal">~w</', [DOM]), 2990 rdf_write_id(Out, NameText), write(Out, '>') 2991 ; save_xml_literal(DOM, NameText, Out, Indent, Options) 2992 ). 2993save_body_literal(type(Type, Value), 2994 NameText, BaseURI, Out, Indent, Options) :- 2995 !, 2996 format(Out, '~N~*|<', [Indent]), 2997 rdf_write_id(Out, NameText), 2998 option(encoding(Encoding), Options, utf8), 2999 rdf_value(Type, BaseURI, QVal, Encoding), 3000 format(Out, ' rdf:datatype="~w">', [QVal]), 3001 save_attribute_value(Value, Out, Options), 3002 write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>'). 3003save_body_literal(Literal, 3004 NameText, _, Out, Indent, Options) :- 3005 atomic(Literal), 3006 !, 3007 format(Out, '~N~*|<', [Indent]), 3008 rdf_write_id(Out, NameText), 3009 write(Out, '>'), 3010 save_attribute_value(Literal, Out, Options), 3011 write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>'). 3012save_body_literal(DOM, 3013 NameText, BaseURI, Out, Indent, Options) :- 3014 rdf_equal(Type, rdf:'XMLLiteral'), 3015 save_body_literal(type(Type, DOM), 3016 NameText, BaseURI, Out, Indent, Options). 3017 3018save_attribute_value(Value, Out, Options) :- % strings 3019 ( atom(Value) 3020 ; string(Value) 3021 ), 3022 !, 3023 option(encoding(Encoding), Options, utf8), 3024 xml_quote_cdata(Value, QVal, Encoding), 3025 write(Out, QVal). 3026save_attribute_value(Value, Out, _Options) :- % numbers 3027 number(Value), 3028 !, 3029 writeq(Out, Value). % quoted: preserve floats 3030save_attribute_value(Value, _Out, _Options) :- 3031 throw(error(save_attribute_value(Value), _)).
<prop parseType="literal"
but not the terminating >
. We need to establish the
namespaces used in the DOM. The namespaces in the rdf document
are in the nsmap-option of Options.
3045save_xml_literal(DOM, Attr, Out, Indent, Options) :- 3046 xml_is_dom(DOM), 3047 !, 3048 memberchk(nsmap(NsMap), Options), 3049 id_to_atom(Attr, Atom), 3050 xml_write(Out, 3051 element(Atom, ['rdf:parseType'='Literal'], DOM), 3052 [ header(false), 3053 indent(Indent), 3054 nsmap(NsMap) 3055 ]). 3056save_xml_literal(NoDOM, _, _, _, _) :- 3057 must_be(xml_dom, NoDOM). 3058 3059id_to_atom(NS:Local, Atom) :- 3060 !, 3061 atomic_list_concat([NS,Local], :, Atom). 3062id_to_atom(ID, ID).
3072:- rdf_meta 3073 rdf_collection(r), 3074 collection_p(r,r). 3075 3076rdf_collection(rdf:nil) :- !. 3077rdf_collection(Cell) :- 3078 rdf_is_bnode(Cell), 3079 findall(F, rdf(Cell, rdf:first, F), [_]), 3080 findall(F, rdf(Cell, rdf:rest, F), [Rest]), 3081 forall(rdf(Cell, P, V), 3082 collection_p(P, V)), 3083 rdf_collection(Rest). 3084 3085collection_p(rdf:first, V) :- atom(V). 3086collection_p(rdf:rest, _). 3087collection_p(rdf:type, rdf:'List').
3092rdf_save_list(_, List, _, _, _) :- 3093 rdf_equal(List, rdf:nil), 3094 !. 3095rdf_save_list(Out, List, BaseURI, Indent, Options) :- 3096 rdf_has(List, rdf:first, First), 3097 ( rdf_is_bnode(First) 3098 -> nl(Out), 3099 rdf_save_subject(Out, First, BaseURI, Indent, Options) 3100 ; option(encoding(Encoding), Options, utf8), 3101 rdf_value(First, BaseURI, QVal, Encoding), 3102 format(Out, '~N~*|<rdf:Description rdf:about="~w"/>', 3103 [Indent, QVal]) 3104 ), 3105 flag(rdf_db_saved_triples, X, X+3), 3106 ( rdf_has(List, rdf:rest, List2), 3107 \+ rdf_equal(List2, rdf:nil) 3108 -> rdf_save_list(Out, List2, BaseURI, Indent, Options) 3109 ; true 3110 ).
3118rdf_id(Id, BaseURI, Local) :- 3119 assertion(atom(BaseURI)), 3120 atom_concat(BaseURI, Local, Id), 3121 sub_atom(Local, 0, 1, _, #), 3122 !. 3123rdf_id(Id, _, NS:Local) :- 3124 iri_xml_namespace(Id, Full, Local), 3125 ns(NS, Full), 3126 !. 3127rdf_id(Id, _, NS:Local) :- 3128 ns(NS, Full), 3129 Full \== '', 3130 atom_concat(Full, Local, Id), 3131 !. 3132rdf_id(Id, _, Id).
3140rdf_write_id(Out, NS:Local) :- 3141 !, 3142 format(Out, '~w:~w', [NS, Local]). 3143rdf_write_id(Out, Atom) :- 3144 write(Out, Atom).
3153rdf_value(Base, Base, '', _) :- !. 3154rdf_value(V, Base, Text, Encoding) :- 3155 atom_concat(Base, Local, V), 3156 sub_atom(Local, 0, _, _, #), 3157 !, 3158 xml_quote_attribute(Local, Text, Encoding). 3159rdf_value(V, _, Text, Encoding) :- 3160 ns(NS, Full), 3161 atom_concat(Full, Local, V), 3162 xml_is_name(Local), 3163 !, 3164 xml_quote_attribute(Local, QLocal, Encoding), 3165 atomic_list_concat(['&', NS, (';'), QLocal], Text). 3166rdf_value(V, _, Q, Encoding) :- 3167 xml_quote_attribute(V, Q, Encoding). 3168 3169 3170 /******************************* 3171 * MATCH AND COMPARE * 3172 *******************************/
icase
, substring
, word
, prefix
or like
. For backward
compatibility, exact
is a synonym for icase
.3195 /******************************* 3196 * DEPRECATED MATERIAL * 3197 *******************************/
3207rdf_split_url(Prefix, Local, URL) :- 3208 atomic(URL), 3209 !, 3210 iri_xml_namespace(URL, Prefix, Local). 3211rdf_split_url(Prefix, Local, URL) :- 3212 atom_concat(Prefix, Local, URL).
3220rdf_url_namespace(URL, Prefix) :- 3221 iri_xml_namespace(URL, Prefix). 3222 3223 3224 /******************************* 3225 * LITERALS * 3226 *******************************/
rdf_litindex.pl
.not(Key)
. If not-terms are provided, there
must be at least one positive keywords. The negations are tested
after establishing the positive matches.key(+Key)
Succeeds if Key is a key in the map and unify Answer with the
number of values associated with the key. This provides a fast
test of existence without fetching the possibly large
associated value set as with rdf_find_literal_map/3.prefix(+Prefix)
Unify Answer with an ordered set of all keys that have the
given prefix. See section 3.1 for details on prefix matching.
Prefix must be an atom. This call is intended for
auto-completion in user interfaces.ge(+Min)
Unify Answer with all keys that are larger or equal to the
integer Min.le(+Max)
Unify Answer with all keys that are smaller or equal to the integer
Max.between(+Min, +Max)
Unify
Answer with all keys between Min and Max (including).3314 /******************************* 3315 * MISC * 3316 *******************************/
Major*10000 + Minor*100 + Patch.
s
,
p
, sp
, o
, po
, spo
, g
, sg
or pg
. Parameter
is one of:
permission_error
exception.When inside a transaction, Generation is unified to a term TransactionStartGen + InsideTransactionGen. E.g., 4+3 means that the transaction was started at generation 4 of the global database and we have created 3 new generations inside the transaction. Note that this choice of representation allows for comparing generations using Prolog arithmetic. Comparing a generation in one transaction with a generation in another transaction is meaningless.
3413 /******************************* 3414 * MESSAGES * 3415 *******************************/ 3416 3417:- multifile 3418 prolog:message//1. 3419 3420prologmessage(rdf(Term)) --> 3421 message(Term). 3422 3423message(loaded(How, What, BaseURI, Triples, Time)) --> 3424 how(How), 3425 source(What), 3426 into(What, BaseURI), 3427 in_time(Triples, Time). 3428message(save_removed_duplicates(N, Subject)) --> 3429 [ 'Removed ~d duplicate triples about "~p"'-[N,Subject] ]. 3430message(saved(File, SavedSubjects, SavedTriples)) --> 3431 [ 'Saved ~D triples about ~D subjects into ~p'- 3432 [SavedTriples, SavedSubjects, File] 3433 ]. 3434message(using_namespace(Id, NS)) --> 3435 [ 'Using namespace id ~w for ~w'-[Id, NS] ]. 3436message(inconsistent_cache(DB, Graphs)) --> 3437 [ 'RDF cache file for ~w contains the following graphs'-[DB], nl, 3438 '~t~8|~p'-[Graphs] 3439 ]. 3440message(guess_format(Ext)) --> 3441 [ 'Unknown file-extension: ~w. Assuming RDF/XML'-[Ext] ]. 3442message(meta(not_expanded(G))) --> 3443 [ 'rdf_meta/1: ~p is not expanded'-[G] ]. 3444message(deprecated(rdf_unload(Graph))) --> 3445 [ 'rdf_unload/1: Use ~q'-[rdf_unload_graph(Graph)] ]. 3446 3447 3448how(load) --> [ 'Loaded' ]. 3449how(parsed) --> [ 'Parsed' ]. 3450 3451source(SourceURL) --> 3452 { uri_file_name(SourceURL, File), 3453 !, 3454 file_base_name(File, Base) % TBD: relative file? 3455 }, 3456 [ ' "~w"'-[Base] ]. 3457source(SourceURL) --> 3458 [ ' "~w"'-[SourceURL] ]. 3459 3460into(_, _) --> []. % TBD 3461 3462in_time(Triples, ParseTime) --> 3463 [ ' in ~2f sec; ~D triples'-[ParseTime, Triples] 3464 ]
Core RDF database
The file library(semweb/rdf_db) provides the core of the SWI-Prolog RDF store.