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).symmetric(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, Cont)), 787 ( Cont == true 788 -> rdf_gc_loop 789 ; thread_self(Me), 790 thread_detach(Me) 791 ). 792 793recover_gc('$aborted', false) :- 794 !. 795recover_gc(unwind(_), false) :- 796 !. 797recover_gc(Error, true) :- 798 print_message(error, Error). 799 800rdf_gc_loop(CPU) :- 801 repeat, 802 ( consider_gc(CPU) 803 -> rdf_gc(CPU1), 804 sleep(CPU1) 805 ; sleep(0.1) 806 ), 807 fail.
815rdf_gc(CPU) :-
816 statistics(cputime, CPU0),
817 ( rdf_gc_
818 -> statistics(cputime, CPU1),
819 CPU is CPU1-CPU0,
820 rdf_add_gc_time(CPU)
821 ; CPU = 0.0
822 ).__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.
834rdf_gc :- 835 has_garbage, 836 !, 837 rdf_gc(_), 838 rdf_gc. 839rdf_gc.
845has_garbage :- 846 rdf_gc_info_(Info), 847 has_garbage(Info), 848 !. 849 850has_garbage(Info) :- arg(2, Info, Garbage), Garbage > 0. 851has_garbage(Info) :- arg(3, Info, Reindexed), Reindexed > 0. 852has_garbage(Info) :- arg(4, Info, Optimizable), Optimizable > 0.
859consider_gc(_CPU) :- 860 ( rdf_gc_info_(gc_info(Triples, % Total #triples in DB 861 Garbage, % Garbage triples in DB 862 Reindexed, % Reindexed & not reclaimed 863 Optimizable, % Non-optimized tables 864 _KeepGen, % Oldest active generation 865 _LastGCGen, % Oldest active gen at last GC 866 _ReindexGen, 867 _LastGCReindexGen)) 868 -> ( (Garbage+Reindexed) * 5 > Triples 869 ; Optimizable > 4 870 ) 871 ; print_message(error, rdf(invalid_gc_info)), 872 sleep(10) 873 ), 874 !. 875 876 877 /******************************* 878 * STATISTICS * 879 *******************************/
triples for the interpretation of this value.925rdf_statistics(graphs(Count)) :- 926 rdf_statistics_(graphs(Count)). 927rdf_statistics(triples(Count)) :- 928 rdf_statistics_(triples(Count)). 929rdf_statistics(duplicates(Count)) :- 930 rdf_statistics_(duplicates(Count)). 931rdf_statistics(lingering(Count)) :- 932 rdf_statistics_(lingering(Count)). 933rdf_statistics(resources(Count)) :- 934 rdf_statistics_(resources(Count)). 935rdf_statistics(properties(Count)) :- 936 rdf_statistics_(predicates(Count)). 937rdf_statistics(literals(Count)) :- 938 rdf_statistics_(literals(Count)). 939rdf_statistics(gc(Count, Reclaimed, Reindexed, Time)) :- 940 rdf_statistics_(gc(Count, Reclaimed, Reindexed, Time)). 941rdf_statistics(searched_nodes(Count)) :- 942 rdf_statistics_(searched_nodes(Count)). 943rdf_statistics(lookup(Index, Count)) :- 944 functor(Indexed, indexed, 16), 945 rdf_statistics_(Indexed), 946 index(Index, I), 947 Arg is I + 1, 948 arg(Arg, Indexed, Count), 949 Count \== 0. 950rdf_statistics(hash_quality(Index, Size, Quality,Optimize)) :- 951 rdf_statistics_(hash_quality(List)), 952 member(hash(Place,Size,Quality,Optimize), List), 953 index(Index, Place). 954rdf_statistics(triples_by_graph(Graph, Count)) :- 955 rdf_graph_(Graph, Count). 956 957index(rdf(-,-,-,-), 0). 958index(rdf(+,-,-,-), 1). 959index(rdf(-,+,-,-), 2). 960index(rdf(+,+,-,-), 3). 961index(rdf(-,-,+,-), 4). 962index(rdf(+,-,+,-), 5). 963index(rdf(-,+,+,-), 6). 964index(rdf(+,+,+,-), 7). 965 966index(rdf(-,-,-,+), 8). 967index(rdf(+,-,-,+), 9). 968index(rdf(-,+,-,+), 10). 969index(rdf(+,+,-,+), 11). 970index(rdf(-,-,+,+), 12). 971index(rdf(+,-,+,+), 13). 972index(rdf(-,+,+,+), 14). 973index(rdf(+,+,+,+), 15). 974 975 976 /******************************* 977 * PREDICATES * 978 *******************************/
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.
994rdf_current_predicate(P, DB) :-
995 rdf_current_predicate(P),
996 ( rdf(_,P,_,DB)
997 -> true
998 ).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.1051rdf_predicate_property(P, Prop) :- 1052 var(P), 1053 !, 1054 rdf_current_predicate(P), 1055 rdf_predicate_property_(P, Prop). 1056rdf_predicate_property(P, Prop) :- 1057 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.
1082 /******************************* 1083 * SNAPSHOTS * 1084 *******************************/
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.1107rdf_current_snapshot(Term) :- 1108 current_blob(Term, rdf_snapshot). 1109 1110 1111 /******************************* 1112 * TRANSACTION * 1113 *******************************/
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.1149rdf_transaction(Goal) :- 1150 rdf_transaction(Goal, user, []). 1151rdf_transaction(Goal, Id) :- 1152 rdf_transaction(Goal, Id, []).
1163rdf_active_transaction(Id) :-
1164 rdf_active_transactions_(List),
1165 member(Id, List).1171rdf_monitor(Goal, Options) :- 1172 monitor_mask(Options, 0xffff, Mask), 1173 rdf_monitor_(Goal, Mask). 1174 1175monitor_mask([], Mask, Mask). 1176monitor_mask([H|T], Mask0, Mask) :- 1177 update_mask(H, Mask0, Mask1), 1178 monitor_mask(T, Mask1, Mask). 1179 1180update_mask(-X, Mask0, Mask) :- 1181 !, 1182 monitor_mask(X, M), 1183 Mask is Mask0 /\ \M. 1184update_mask(+X, Mask0, Mask) :- 1185 !, 1186 monitor_mask(X, M), 1187 Mask is Mask0 \/ M. 1188update_mask(X, Mask0, Mask) :- 1189 monitor_mask(X, M), 1190 Mask is Mask0 \/ M.
1197 % C-defined broadcasts 1198monitor_mask(assert, 0x0001). 1199monitor_mask(assert(load), 0x0002). 1200monitor_mask(retract, 0x0004). 1201monitor_mask(update, 0x0008). 1202monitor_mask(new_literal, 0x0010). 1203monitor_mask(old_literal, 0x0020). 1204monitor_mask(transaction, 0x0040). 1205monitor_mask(load, 0x0080). 1206monitor_mask(create_graph, 0x0100). 1207monitor_mask(reset, 0x0200). 1208 % prolog defined broadcasts 1209monitor_mask(parse, 0x1000). 1210monitor_mask(unload, 0x1000). % FIXME: Duplicate 1211 % mask for all 1212monitor_mask(all, 0xffff). 1213 1214%rdf_broadcast(Term, MaskName) :- 1215%% monitor_mask(MaskName, Mask), 1216%% rdf_broadcast_(Term, Mask). 1217 1218 1219 /******************************* 1220 * WARM * 1221 *******************************/
1227rdf_warm_indexes :- 1228 findall(Index, rdf_index(Index), Indexes), 1229 rdf_warm_indexes(Indexes). 1230 1231rdf_index(s). 1232rdf_index(p). 1233rdf_index(o). 1234rdf_index(sp). 1235rdf_index(o). 1236rdf_index(po). 1237rdf_index(spo). 1238rdf_index(g). 1239rdf_index(sg). 1240rdf_index(pg).
1251 /******************************* 1252 * DUPLICATES * 1253 *******************************/
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.
1268:- public
1269 rdf_update_duplicates_thread/0.
1275rdf_update_duplicates_thread :-
1276 thread_create(rdf_update_duplicates, _,
1277 [ detached(true),
1278 alias('__rdf_duplicate_detecter')
1279 ]).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.
1293 /******************************* 1294 * QUICK BINARY LOAD/SAVE * 1295 *******************************/
1305:- create_prolog_flag(rdf_triple_format, 3, [type(integer)]). 1306 1307rdf_save_db(File) :- 1308 current_prolog_flag(rdf_triple_format, Version), 1309 setup_call_cleanup( 1310 open(File, write, Out, [type(binary)]), 1311 ( set_stream(Out, record_position(false)), 1312 rdf_save_db_(Out, _, Version) 1313 ), 1314 close(Out)). 1315 1316 1317rdf_save_db(File, Graph) :- 1318 current_prolog_flag(rdf_triple_format, Version), 1319 setup_call_cleanup( 1320 open(File, write, Out, [type(binary)]), 1321 ( set_stream(Out, record_position(false)), 1322 rdf_save_db_(Out, Graph, Version) 1323 ), 1324 close(Out)).
1333rdf_load_db_no_admin(File, Id, Graphs) :-
1334 open(File, read, In, [type(binary)]),
1335 set_stream(In, record_position(false)),
1336 call_cleanup(rdf_load_db_(In, Id, Graphs), close(In)).1347check_loaded_cache(DB, [DB], _Modified) :- !. 1348check_loaded_cache(DB, Graphs, _) :- 1349 print_message(warning, rdf(inconsistent_cache(DB, Graphs))).
1356rdf_load_db(File) :- 1357 uri_file_name(URL, File), 1358 rdf_load_db_no_admin(File, URL, _Graphs). 1359 1360 1361 /******************************* 1362 * LOADING RDF * 1363 *******************************/ 1364 1365:- multifile 1366 rdf_open_hook/8, 1367 rdf_open_decode/4, % +Encoding, +File, -Stream, -Cleanup 1368 rdf_load_stream/3, % +Format, +Stream, +Options 1369 rdf_file_type/2, % ?Extension, ?Format 1370 rdf_storage_encoding/2, % ?Extension, ?Encoding 1371 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)).
1467:- dynamic 1468 rdf_loading/3. % Graph, Queue, Thread 1469 1470rdf_load(Spec) :- 1471 rdf_load(Spec, []). 1472 1473:- if(\+current_predicate(concurrent/3)). 1474concurrent(_, Goals, _) :- 1475 forall(member(G, Goals), call(G)). 1476:- endif. 1477 1478% Note that we kill atom garbage collection. This improves performance 1479% with about 15% loading the LUBM Univ_50 benchmark. 1480 1481rdf_load(Spec, M:Options) :- 1482 must_be(list, Options), 1483 setup_call_cleanup( 1484 push_prolog_flag(agc_margin, 0), 1485 rdf_load_noagc(Spec, M, Options), 1486 pop_prolog_flag(agc_margin)). 1487 1488rdf_load_noagc(List, M, Options) :- 1489 is_list(List), 1490 !, 1491 flatten(List, Inputs), % Compatibility: allow nested lists 1492 maplist(must_be(ground), Inputs), 1493 length(Inputs, Count), 1494 load_jobs(Count, Jobs, Options), 1495 ( Jobs =:= 1 1496 -> forall(member(Spec, Inputs), 1497 rdf_load_one(Spec, M, Options)) 1498 ; maplist(load_goal(Options, M), Inputs, Goals), 1499 concurrent(Jobs, Goals, []) 1500 ). 1501rdf_load_noagc(One, M, Options) :- 1502 must_be(ground, One), 1503 rdf_load_one(One, M, Options). 1504 1505load_goal(Options, M, Spec, rdf_load_one(Spec, M, Options)). 1506 1507load_jobs(_, Jobs, Options) :- 1508 option(concurrent(Jobs), Options), 1509 !, 1510 must_be(positive_integer, Jobs). 1511load_jobs(Count, Jobs, _) :- 1512 current_prolog_flag(cpu_count, CPUs), 1513 CPUs > 0, 1514 !, 1515 Jobs is max(1, min(CPUs, Count)). 1516load_jobs(_, 1, _). 1517 1518 1519rdf_load_one(Spec, M, Options) :- 1520 source_url(Spec, Protocol, SourceURL), 1521 load_graph(SourceURL, Graph, Options), 1522 setup_call_cleanup( 1523 with_mutex(rdf_load_file, 1524 rdf_start_load(SourceURL, Loading)), 1525 rdf_load_file(Loading, Spec, SourceURL, Protocol, 1526 Graph, M, Options), 1527 rdf_end_load(Loading)).
1544rdf_start_load(SourceURL, queue(Queue)) :- 1545 rdf_loading(SourceURL, Queue, LoadThread), 1546 \+ thread_self(LoadThread), 1547 !, 1548 debug(rdf(load), '~p is being loaded by thread ~w; waiting ...', 1549 [ SourceURL, LoadThread]). 1550rdf_start_load(SourceURL, Ref) :- 1551 thread_self(Me), 1552 message_queue_create(Queue), 1553 assertz(rdf_loading(SourceURL, Queue, Me), Ref). 1554 1555rdf_end_load(queue(_)) :- !. 1556rdf_end_load(Ref) :- 1557 clause(rdf_loading(_, Queue, _), _, Ref), 1558 erase(Ref), 1559 thread_send_message(Queue, done), 1560 message_queue_destroy(Queue). 1561 1562rdf_load_file(queue(Queue), _Spec, _SourceURL, _Protocol, _Graph, _M, _Options) :- 1563 !, 1564 catch(thread_get_message(Queue, _), _, true). 1565rdf_load_file(_Ref, _Spec, SourceURL, Protocol, Graph, M, Options) :- 1566 debug(rdf(load), 'RDF: Loading ~q into ~q', [SourceURL, Graph]), 1567 statistics(cputime, T0), 1568 rdf_open_input(SourceURL, Protocol, Graph, 1569 In, Cleanup, Modified, Format, Options), 1570 supported_format(Format, Cleanup), 1571 return_modified(Modified, Options), 1572 ( Modified == not_modified 1573 -> Action = none 1574 ; Modified = cached(CacheFile) 1575 -> do_unload(Graph), 1576 catch(rdf_load_db_no_admin(CacheFile, cache(Graph), Graphs), _, fail), 1577 check_loaded_cache(Graph, Graphs, Modified), 1578 Action = load 1579 ; option(base_uri(BaseURI), Options, Graph), 1580 ( var(BaseURI) 1581 -> BaseURI = SourceURL 1582 ; true 1583 ), 1584 once(phrase(derived_options(Options, NSList), Extra)), 1585 merge_options([ base_uri(BaseURI), 1586 graph(Graph), 1587 format(Format) 1588 | Extra 1589 ], Options, RDFOptions), 1590 ( option(multifile(true), Options) 1591 -> true 1592 ; do_unload(Graph) 1593 ), 1594 graph_modified(Modified, ModifiedStamp), 1595 rdf_set_graph_source(Graph, SourceURL, ModifiedStamp), 1596 call_cleanup(rdf_load_stream(Format, In, M:RDFOptions), 1597 Cleanup), 1598 save_cache(Graph, SourceURL, Options), 1599 register_file_prefixes(NSList), 1600 format_action(Format, Action) 1601 ), 1602 rdf_statistics_(triples(Graph, Triples)), 1603 report_loaded(Action, SourceURL, Graph, Triples, T0, Options). 1604 1605supported_format(Format, _Cleanup) :- 1606 rdf_file_type(_, Format), 1607 !. 1608supported_format(Format, Cleanup) :- 1609 call(Cleanup), 1610 existence_error(rdf_format_plugin, Format). 1611 1612format_action(triples, load) :- !. 1613format_action(_, parsed). 1614 1615save_cache(Graph, SourceURL, Options) :- 1616 option(cache(true), Options, true), 1617 rdf_cache_file(SourceURL, write, CacheFile), 1618 !, 1619 catch(save_cache(Graph, CacheFile), E, 1620 print_message(warning, E)). 1621save_cache(_, _, _). 1622 1623derived_options([], _) --> 1624 []. 1625derived_options([H|T], NSList) --> 1626 ( { H == register_namespaces(true) 1627 ; H == (register_namespaces = true) 1628 } 1629 -> [ namespaces(NSList) ] 1630 ; [] 1631 ), 1632 derived_options(T, NSList). 1633 1634graph_modified(last_modified(Stamp), Stamp). 1635graph_modified(unknown, Stamp) :- 1636 get_time(Stamp). 1637 1638return_modified(Modified, Options) :- 1639 option(modified(M0), Options), 1640 !, 1641 M0 = Modified. 1642return_modified(_, _). 1643 1644 1645 /******************************* 1646 * INPUT HANDLING * 1647 *******************************/ 1648 1649/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1650This section deals with pluggable input sources. The task of the input 1651layer is 1652 1653 * Decide on the graph-name 1654 * Decide on the source-location 1655 * Decide whether loading is needed (if-modified) 1656 * Decide on the serialization in the input 1657 1658The protocol must ensure minimal overhead, in particular for network 1659protocols. E.g. for HTTP we want to make a single call on the server and 1660use If-modified-since to verify that we need not reloading this file. 1661- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Options processed:
graph(Graph)db(Graph)if(Condition)cache(Cache)format(Format)
1679rdf_open_input(SourceURL, Protocol, Graph,
1680 Stream, Cleanup, Modified, Format, Options) :-
1681 ( option(multifile(true), Options)
1682 -> true
1683 ; option(if(If), Options, changed),
1684 ( If == true
1685 -> true
1686 ; rdf_graph_source_(Graph, SourceURL, HaveModified)
1687 -> true
1688 ; option(cache(true), Options, true),
1689 rdf_cache_file(SourceURL, read, CacheFile)
1690 -> time_file(CacheFile, HaveModified)
1691 ; true
1692 )
1693 ),
1694 option(format(Format), Options, _),
1695 open_input_if_modified(Protocol, SourceURL, HaveModified,
1696 Stream, Cleanup, Modified0, Format, Options),
1697 ( Modified0 == not_modified
1698 -> ( nonvar(CacheFile)
1699 -> Modified = cached(CacheFile)
1700 ; Modified = not_modified
1701 )
1702 ; Modified = Modified0
1703 ).stream(Stream)http)1714source_url(stream(In), stream(In), SourceURL) :- 1715 !, 1716 ( stream_property(In, file_name(File)) 1717 -> to_url(File, SourceURL) 1718 ; gensym('stream://', SourceURL) 1719 ). 1720source_url(Stream, Class, SourceURL) :- 1721 is_stream(Stream), 1722 !, 1723 source_url(stream(Stream), Class, SourceURL). 1724source_url(Spec, Protocol, SourceURL) :- 1725 compound(Spec), 1726 !, 1727 source_file(Spec, Protocol, SourceURL). 1728source_url(FileURL, Protocol, SourceURL) :- % or return FileURL? 1729 uri_file_name(FileURL, File), 1730 !, 1731 source_file(File, Protocol, SourceURL). 1732source_url(SourceURL0, Protocol, SourceURL) :- 1733 is_url(SourceURL0, Protocol, SourceURL), 1734 !. 1735source_url(File, Protocol, SourceURL) :- 1736 source_file(File, Protocol, SourceURL). 1737 1738source_file(Spec, file(SExt), SourceURL) :- 1739 findall(Ext, valid_extension(Ext), Exts), 1740 absolute_file_name(Spec, File, [access(read), extensions([''|Exts])]), 1741 storage_extension(_Plain, SExt, File), 1742 uri_file_name(SourceURL, File). 1743 1744to_url(URL, URL) :- 1745 uri_is_global(URL), 1746 !. 1747to_url(File, URL) :- 1748 absolute_file_name(File, Path), 1749 uri_file_name(URL, Path). 1750 1751storage_extension(Plain, SExt, File) :- 1752 file_name_extension(Plain, SExt, File), 1753 SExt \== '', 1754 rdf_storage_encoding(SExt, _), 1755 !. 1756storage_extension(File, '', File).
graph(Graph) optiondb(Graph) option (backward compatibility)base_uri(BaseURI) option1768load_graph(_Source, Graph, Options) :- 1769 option(multifile(true), Options), 1770 !, 1771 ( ( option(graph(Graph), Options) 1772 -> true 1773 ; option(db(Graph), Options) 1774 ), 1775 ground(Graph) 1776 -> true 1777 ; throw(error(existence_error(option, graph), 1778 context(_, "rdf_load/2: using multifile requires graph"))) 1779 ). 1780load_graph(Source, Graph, Options) :- 1781 ( option(graph(Graph), Options) 1782 ; option(db(Graph), Options) 1783 ), 1784 !, 1785 load_graph2(Source, Graph, Options). 1786load_graph(Source, Graph, Options) :- 1787 load_graph2(Source, Graph, Options). 1788 1789load_graph2(_, Graph, _) :- 1790 ground(Graph), 1791 !. 1792load_graph2(_Source, Graph, Options) :- 1793 option(base_uri(Graph), Options), 1794 Graph \== [], 1795 ground(Graph), 1796 !. 1797load_graph2(Source, Graph, _) :- 1798 load_graph(Source, Graph). 1799 1800load_graph(SourceURL, BaseURI) :- 1801 file_name_extension(BaseURI, Ext, SourceURL), 1802 rdf_storage_encoding(Ext, _), 1803 !. 1804load_graph(SourceURL, SourceURL). 1805 1806 1807open_input_if_modified(stream(In), SourceURL, _, In, true, 1808 unknown, Format, _) :- 1809 !, 1810 ( var(Format) 1811 -> guess_format(SourceURL, Format) 1812 ; true 1813 ). 1814open_input_if_modified(file(SExt), SourceURL, HaveModified, Stream, Cleanup, 1815 Modified, Format, _) :- 1816 !, 1817 uri_file_name(SourceURL, File), 1818 ( SExt == '' -> Plain = File; file_name_extension(Plain, SExt, File)), 1819 time_file(File, LastModified), 1820 ( nonvar(HaveModified), 1821 HaveModified >= LastModified 1822 -> Modified = not_modified, 1823 Cleanup = true 1824 ; storage_open(SExt, File, Stream, Cleanup), 1825 Modified = last_modified(LastModified), 1826 ( var(Format) 1827 -> guess_format(Plain, Format) 1828 ; true 1829 ) 1830 ). 1831open_input_if_modified(file, SourceURL, HaveModified, Stream, Cleanup, 1832 Modified, Format, Options) :- 1833 !, 1834 open_input_if_modified(file(''), SourceURL, HaveModified, 1835 Stream, Cleanup, 1836 Modified, Format, Options). 1837open_input_if_modified(Protocol, SourceURL, HaveModified, Stream, Cleanup, 1838 Modified, Format, Options) :- 1839 rdf_open_hook(Protocol, SourceURL, HaveModified, Stream, Cleanup, 1840 Modified, Format, Options). 1841 1842guess_format(File, Format) :- 1843 file_name_extension(_, Ext, File), 1844 ( rdf_file_type(Ext, Format) 1845 -> true 1846 ; Format = xml, 1847 print_message(warning, rdf(guess_format(Ext))) 1848 ).
1856storage_open('', File, Stream, close(Stream)) :- 1857 !, 1858 open(File, read, Stream, [type(binary)]). 1859storage_open(Ext, File, Stream, Cleanup) :- 1860 rdf_storage_encoding(Ext, Encoding), 1861 rdf_open_decode(Encoding, File, Stream, Cleanup). 1862 1863valid_extension(Ext) :- 1864 rdf_file_type(Ext, _). 1865valid_extension(Ext) :- 1866 rdf_storage_encoding(Ext, _).
1876is_url(URL, Scheme, FetchURL) :- 1877 atom(URL), 1878 uri_is_global(URL), 1879 uri_normalized(URL, URL1), % case normalization 1880 uri_components(URL1, Components), 1881 uri_data(scheme, Components, Scheme0), 1882 url_protocol(Scheme0), 1883 !, 1884 Scheme = Scheme0, 1885 uri_data(fragment, Components, _, Components1), 1886 uri_components(FetchURL, Components1). 1887 1888url_protocol(file). % built-in
1896rdf_file_type(xml, xml). 1897rdf_file_type(rdf, xml). 1898rdf_file_type(rdfs, xml). 1899rdf_file_type(owl, xml). 1900rdf_file_type(htm, xhtml). 1901rdf_file_type(html, xhtml). 1902rdf_file_type(xhtml, xhtml). 1903rdf_file_type(trp, triples).
1910rdf_storage_encoding('', plain).1919rdf_load_stream(xml, Stream, Options) :- 1920 !, 1921 graph(Options, Graph), 1922 rdf_transaction(load_stream(Stream, Options), 1923 parse(Graph)). 1924rdf_load_stream(xhtml, Stream, M:Options) :- 1925 !, 1926 graph(Options, Graph), 1927 rdf_transaction(load_stream(Stream, M:[embedded(true)|Options]), 1928 parse(Graph)). 1929rdf_load_stream(triples, Stream, Options) :- 1930 !, 1931 graph(Options, Graph), 1932 rdf_load_db_(Stream, Graph, _Graphs). 1933 1934load_stream(Stream, M:Options) :- 1935 process_rdf(Stream, assert_triples, M:Options), 1936 option(graph(Graph), Options), 1937 rdf_graph_clear_modified_(Graph).
1942report_loaded(none, _, _, _, _, _) :- !. 1943report_loaded(Action, Source, DB, Triples, T0, Options) :- 1944 statistics(cputime, T1), 1945 Time is T1 - T0, 1946 ( option(silent(true), Options) 1947 -> Level = silent 1948 ; Level = informational 1949 ), 1950 print_message(Level, 1951 rdf(loaded(Action, Source, DB, Triples, Time))).
1964rdf_unload(Spec) :- 1965 source_url(Spec, _Protocol, SourceURL), 1966 rdf_graph_source_(Graph, SourceURL, _), 1967 !, 1968 rdf_unload_graph(Graph). 1969rdf_unload(Graph) :- 1970 atom(Graph), 1971 rdf_graph(Graph), 1972 !, 1973 warn_deprecated_unload(Graph), 1974 rdf_unload_graph(Graph). 1975rdf_unload(_). 1976 1977:- dynamic 1978 warned/0. 1979 1980warn_deprecated_unload(_) :- 1981 warned, 1982 !. 1983warn_deprecated_unload(Graph) :- 1984 assertz(warned), 1985 print_message(warning, rdf(deprecated(rdf_unload(Graph)))).
1993rdf_unload_graph(Graph) :- 1994 must_be(atom, Graph), 1995 ( rdf_graph(Graph) 1996 -> rdf_transaction(do_unload(Graph), unload(Graph)) 1997 ; true 1998 ). 1999 2000do_unload(Graph) :- 2001 ( rdf_graph_(Graph, Triples), 2002 Triples > 0 2003 -> rdf_retractall(_,_,_,Graph) 2004 ; true 2005 ), 2006 rdf_destroy_graph(Graph). 2007 2008 /******************************* 2009 * GRAPH QUERIES * 2010 *******************************/
2022rdf_graph(Graph) :-
2023 rdf_graph_(Graph, _Triples).
2031rdf_source(Graph, SourceURL) :-
2032 rdf_graph(Graph),
2033 rdf_graph_source_(Graph, SourceURL, _Modified).
2041rdf_source(SourceURL) :-
2042 rdf_source(_Graph, SourceURL).2049rdf_make :- 2050 findall(Source-Graph, modified_graph(Source, Graph), Modified), 2051 forall(member(Source-Graph, Modified), 2052 catch(rdf_load(Source, [graph(Graph), if(changed)]), E, 2053 print_message(error, E))). 2054 2055modified_graph(SourceURL, Graph) :- 2056 rdf_graph(Graph), 2057 rdf_graph_source_(Graph, SourceURL, Modified), 2058 \+ sub_atom(SourceURL, 0, _, _, 'stream://'), 2059 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.2087rdf_graph_property(Graph, Property) :- 2088 rdf_graph(Graph), 2089 property_of_graph(Property, Graph). 2090 2091:- multifile 2092 property_of_graph/2. 2093 2094property_of_graph(hash(Hash), Graph) :- 2095 rdf_md5(Graph, Hash). 2096property_of_graph(modified(Boolean), Graph) :- 2097 rdf_graph_modified_(Graph, Boolean, _). 2098property_of_graph(source(URL), Graph) :- 2099 rdf_graph_source_(Graph, URL, _). 2100property_of_graph(source_last_modified(Time), Graph) :- 2101 rdf_graph_source_(Graph, _, Time), 2102 Time > 0.0. 2103property_of_graph(triples(Count), Graph) :- 2104 rdf_graph_(Graph, Count).
2113rdf_set_graph(Graph, modified(Modified)) :-
2114 must_be(oneof([false]), Modified),
2115 rdf_graph_clear_modified_(Graph).
2122save_cache(DB, Cache) :-
2123 current_prolog_flag(rdf_triple_format, Version),
2124 setup_call_cleanup(
2125 catch(open(Cache, write, CacheStream, [type(binary)]), _, fail),
2126 rdf_save_db_(CacheStream, DB, Version),
2127 close(CacheStream)).2135assert_triples([], _). 2136assert_triples([rdf(S,P,O)|T], DB) :- 2137 !, 2138 rdf_assert(S, P, O, DB), 2139 assert_triples(T, DB). 2140assert_triples([H|_], _) :- 2141 throw(error(type_error(rdf_triple, H), _)). 2142 2143 2144 /******************************* 2145 * RESET * 2146 *******************************/
2159rdf_reset_db :- 2160 reset_gensym('_:genid'), 2161 rdf_reset_db_. 2162 2163 2164 /******************************* 2165 * SAVE RDF * 2166 *******************************/
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>.2228:- thread_local 2229 named_anon/2, % +Resource, -Id 2230 inlined/1. % +Resource 2231 2232rdf_save(File) :- 2233 rdf_save2(File, []). 2234 2235rdf_save(Spec, M:Options0) :- 2236 is_list(Options0), 2237 !, 2238 meta_options(save_meta_option, M:Options0, Options), 2239 to_file(Spec, File), 2240 rdf_save2(File, Options). 2241rdf_save(Spec, _:DB) :- 2242 atom(DB), % backward compatibility 2243 !, 2244 to_file(Spec, File), 2245 rdf_save2(File, [graph(DB)]). 2246 2247save_meta_option(convert_typed_literal). 2248 2249to_file(URL, File) :- 2250 atom(URL), 2251 uri_file_name(URL, File), 2252 !. 2253to_file(File, File). 2254 2255rdf_save2(File, Options) :- 2256 option(encoding(Encoding), Options, utf8), 2257 valid_encoding(Encoding), 2258 open_output(File, Encoding, Out, Close), 2259 flag(rdf_db_saved_subjects, OSavedSubjects, 0), 2260 flag(rdf_db_saved_triples, OSavedTriples, 0), 2261 call_cleanup(rdf_do_save(Out, Options), 2262 Reason, 2263 cleanup_save(Reason, 2264 File, 2265 OSavedSubjects, 2266 OSavedTriples, 2267 Close)). 2268 2269open_output(stream(Out), Encoding, Out, Cleanup) :- 2270 !, 2271 stream_property(Out, encoding(Old)), 2272 ( ( Old == Encoding 2273 ; Old == wchar_t % Internal encoding 2274 ) 2275 -> Cleanup = true 2276 ; set_stream(Out, encoding(Encoding)), 2277 Cleanup = set_stream(Out, encoding(Old)) 2278 ). 2279open_output(File, Encoding, Out, 2280 close(Out)) :- 2281 open(File, write, Out, [encoding(Encoding)]). 2282 2283valid_encoding(Enc) :- 2284 ( xml_encoding_name(Enc, _) 2285 -> true 2286 ; throw(error(domain_error(encoding, Enc), _)) 2287 ). 2288 2289 2290cleanup_save(Reason, 2291 File, 2292 OSavedSubjects, 2293 OSavedTriples, 2294 Close) :- 2295 call(Close), 2296 flag(rdf_db_saved_subjects, SavedSubjects, OSavedSubjects), 2297 flag(rdf_db_saved_triples, SavedTriples, OSavedTriples), 2298 retractall(named_anon(_, _)), 2299 retractall(inlined(_)), 2300 ( Reason == exit 2301 -> print_message(informational, 2302 rdf(saved(File, SavedSubjects, SavedTriples))) 2303 ; format(user_error, 'Reason = ~w~n', [Reason]) 2304 ). 2305 2306rdf_do_save(Out, Options0) :- 2307 rdf_save_header(Out, Options0, Options), 2308 graph(Options, DB), 2309 ( option(sorted(true), Options, false) 2310 -> ( var(DB) 2311 -> setof(Subject, rdf_subject(Subject), Subjects) 2312 ; findall(Subject, rdf(Subject, _, _, DB:_), SubjectList), 2313 sort(SubjectList, Subjects) 2314 ), 2315 forall(member(Subject, Subjects), 2316 rdf_save_non_anon_subject(Out, Subject, Options)) 2317 ; forall(rdf_subject_in_graph(Subject, DB), 2318 rdf_save_non_anon_subject(Out, Subject, Options)) 2319 ), 2320 rdf_save_footer(Out), 2321 !. % dubious cut; without the 2322 % cleanup handlers isn't called!?
2333rdf_subject_in_graph(Subject, DB) :- 2334 var(DB), 2335 !, 2336 rdf_subject(Subject). 2337rdf_subject_in_graph(Subject, DB) :- 2338 rdf_statistics(triples(AllTriples)), 2339 rdf_graph_property(DB, triples(DBTriples)), 2340 DBTriples > AllTriples // 10, 2341 !, 2342 rdf_resource(Subject), 2343 ( rdf(Subject, _, _, DB:_) 2344 -> true 2345 ). 2346rdf_subject_in_graph(Subject, DB) :- 2347 findall(Subject, rdf(Subject, _, _, DB:_), SubjectList), 2348 list_to_set(SubjectList, Subjects), 2349 member(Subject, Subjects). 2350 2351 2352graph(Options0, DB) :- 2353 strip_module(Options0, _, Options), 2354 ( option(graph(DB0), Options) 2355 -> DB = DB0 2356 ; option(db(DB0), Options) 2357 -> DB = DB0 2358 ; true % leave unbound 2359 ).
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-abbreviated form.2384rdf_save_header(Out, Options) :- 2385 rdf_save_header(Out, Options, _). 2386 2387rdf_save_header(Out, Options, OptionsOut) :- 2388 is_list(Options), 2389 !, 2390 option(encoding(Enc), Options, utf8), 2391 xml_encoding(Enc, Encoding), 2392 format(Out, '<?xml version=\'1.0\' encoding=\'~w\'?>~n', [Encoding]), 2393 format(Out, '<!DOCTYPE rdf:RDF [', []), 2394 header_namespaces(Options, NSIdList), 2395 nsmap(NSIdList, NsMap), 2396 append(Options, [nsmap(NsMap)], OptionsOut), 2397 forall(member(Id=URI, NsMap), 2398 ( xml_quote_attribute(URI, NSText0, Enc), 2399 xml_escape_parameter_entity(NSText0, NSText), 2400 format(Out, '~N <!ENTITY ~w \'~w\'>', [Id, NSText]) 2401 )), 2402 format(Out, '~N]>~n~n', []), 2403 format(Out, '<rdf:RDF', []), 2404 ( member(Id, NSIdList), 2405 format(Out, '~N xmlns:~w="&~w;"~n', [Id, Id]), 2406 fail 2407 ; true 2408 ), 2409 ( option(base_uri(Base), Options), 2410 option(write_xml_base(true), Options, true) 2411 -> xml_quote_attribute(Base, BaseText, Enc), 2412 format(Out, '~N xml:base="~w"~n', [BaseText]) 2413 ; true 2414 ), 2415 ( option(document_language(Lang), Options) 2416 -> format(Out, '~N xml:lang="~w"', [Lang]) 2417 ; true 2418 ), 2419 format(Out, '>~n', []). 2420rdf_save_header(Out, FileRef, OptionsOut) :- % compatibility 2421 atom(FileRef), 2422 rdf_save_header(Out, [graph(FileRef)], OptionsOut). 2423 2424xml_encoding(Enc, Encoding) :- 2425 ( xml_encoding_name(Enc, Encoding) 2426 -> true 2427 ; throw(error(domain_error(rdf_encoding, Enc), _)) 2428 ). 2429 2430xml_encoding_name(ascii, 'US-ASCII'). 2431xml_encoding_name(iso_latin_1, 'ISO-8859-1'). 2432xml_encoding_name(utf8, 'UTF-8').
2439nsmap([], []). 2440nsmap([Id|T0], [Id=URI|T]) :- 2441 ns(Id, URI), 2442 nsmap(T0, T).
2448xml_escape_parameter_entity(In, Out) :- 2449 sub_atom(In, _, _, _, '%'), 2450 !, 2451 atom_codes(In, Codes), 2452 phrase(escape_parent(Codes), OutCodes), 2453 atom_codes(Out, OutCodes). 2454xml_escape_parameter_entity(In, In). 2455 2456escape_parent([]) --> []. 2457escape_parent([H|T]) --> 2458 ( { H == 37 } 2459 -> "%" 2460 ; [H] 2461 ), 2462 escape_parent(T).
2469header_namespaces(Options, List) :- 2470 memberchk(namespaces(NSL0), Options), 2471 !, 2472 sort([rdf,rdfs|NSL0], List). 2473header_namespaces(Options, List) :- 2474 graph(Options, DB), 2475 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 potentially new prefix and URI is
the full URI that is being processed.
call(Goal,S,P,O,Graph)
2513:- thread_local 2514 graph_prefix/3. 2515:- meta_predicate 2516 rdf_graph_prefixes(, , ). 2517 2518rdf_graph_prefixes(Graph, List) :- 2519 rdf_graph_prefixes(Graph, List, []). 2520 2521rdf_graph_prefixes(Graph, List, M:QOptions) :- 2522 is_list(QOptions), 2523 !, 2524 meta_options(is_meta, M:QOptions, Options), 2525 option(filter(Filter), Options, true), 2526 option(expand(Expand), Options, rdf_db), 2527 option(min_count(MinCount), Options, 1), 2528 option(get_prefix(GetPrefix), Options, iri_xml_namespace), 2529 call_cleanup(prefixes(Expand, Graph, Prefixes, Filter, MinCount, GetPrefix), 2530 retractall(graph_prefix(_,_,_))), 2531 sort(Prefixes, List). 2532rdf_graph_prefixes(Graph, List, M:Filter) :- 2533 rdf_graph_prefixes(Graph, List, M:[filter(Filter)]). 2534 2535is_meta(filter). 2536is_meta(expand). 2537is_meta(get_prefix). 2538 2539 2540prefixes(Expand, Graph, Prefixes, Filter, MinCount, GetPrefix) :- 2541 ( call(Expand, S, P, O, Graph), 2542 add_ns(subject, GetPrefix, Filter, S, MinCount, s(S)), 2543 add_ns(predicate, GetPrefix, Filter, P, MinCount, sp(S,P)), 2544 add_ns_obj(GetPrefix, Filter, O, MinCount, spo(S,P,O)), 2545 fail 2546 ; true 2547 ), 2548 findall(Prefix, graph_prefix(Prefix, MinCount, _), Prefixes). 2549 2550add_ns(Where, GetPrefix, Filter, S, MinCount, Context) :- 2551 \+ rdf_is_bnode(S), 2552 call(GetPrefix, S, Full), 2553 Full \== '', 2554 !, 2555 ( graph_prefix(Full, MinCount, _) 2556 -> true 2557 ; Filter == true 2558 -> add_ns(Full, Context) 2559 ; call(Filter, Where, Full, S) 2560 -> add_ns(Full, Context) 2561 ; true 2562 ). 2563add_ns(_, _, _, _, _, _). 2564 2565add_ns(Full, Context) :- 2566 graph_prefix(Full, _, Contexts), 2567 memberchk(Context, Contexts), 2568 !. 2569add_ns(Full, Context) :- 2570 retract(graph_prefix(Full, C0, Contexts)), 2571 !, 2572 C1 is C0+1, 2573 asserta(graph_prefix(Full, C1, [Context|Contexts])). 2574add_ns(Full, _) :- 2575 ns(_, Full), 2576 !, 2577 asserta(graph_prefix(Full, _, _)). 2578add_ns(Full, Context) :- 2579 asserta(graph_prefix(Full, 1, [Context])). 2580 2581 2582add_ns_obj(GetPrefix, Filter, O, MinCount, Context) :- 2583 atom(O), 2584 !, 2585 add_ns(object, GetPrefix, Filter, O, MinCount, Context). 2586add_ns_obj(GetPrefix, Filter, literal(type(Type, _)), MinCount, _) :- 2587 atom(Type), 2588 !, 2589 add_ns(type, GetPrefix, Filter, Type, MinCount, t(Type)). 2590add_ns_obj(_, _, _, _, _).
2600used_namespace_entities(List, Graph) :- 2601 decl_used_predicate_ns(Graph), 2602 used_namespaces(List, Graph). 2603 2604used_namespaces(List, DB) :- 2605 rdf_graph_prefixes(DB, FullList), 2606 ns_abbreviations(FullList, List0), 2607 sort([rdf|List0], List). 2608 2609ns_abbreviations([], []). 2610ns_abbreviations([H0|T0], [H|T]) :- 2611 ns(H, H0), 2612 !, 2613 ns_abbreviations(T0, T). 2614ns_abbreviations([_|T0], T) :- 2615 ns_abbreviations(T0, T). 2616 2617 2618/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2619For every URL used as a predicate we *MUST* define a namespace as we 2620cannot use names holding /, :, etc. as XML identifiers. 2621- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 2622 2623:- thread_local 2624 predicate_ns/2. 2625 2626decl_used_predicate_ns(DB) :- 2627 retractall(predicate_ns(_,_)), 2628 ( rdf_current_predicate(P, DB), 2629 decl_predicate_ns(P), 2630 fail 2631 ; true 2632 ). 2633 2634decl_predicate_ns(Pred) :- 2635 predicate_ns(Pred, _), 2636 !. 2637decl_predicate_ns(Pred) :- 2638 rdf_global_id(NS:Local, Pred), 2639 xml_name(Local), 2640 !, 2641 assert(predicate_ns(Pred, NS)). 2642decl_predicate_ns(Pred) :- 2643 atom_codes(Pred, Codes), 2644 append(NSCodes, LocalCodes, Codes), 2645 xml_codes(LocalCodes), 2646 !, 2647 ( NSCodes \== [] 2648 -> atom_codes(NS, NSCodes), 2649 ( ns(Id, NS) 2650 -> assert(predicate_ns(Pred, Id)) 2651 ; between(1, infinite, N), 2652 atom_concat(ns, N, Id), 2653 \+ ns(Id, _) 2654 -> rdf_register_ns(Id, NS), 2655 print_message(informational, 2656 rdf(using_namespace(Id, NS))) 2657 ), 2658 assert(predicate_ns(Pred, Id)) 2659 ; assert(predicate_ns(Pred, -)) % no namespace used 2660 ). 2661 2662xml_codes([]). 2663xml_codes([H|T]) :- 2664 xml_code(H), 2665 xml_codes(T). 2666 2667xml_code(X) :- 2668 code_type(X, csym), 2669 !. 2670xml_code(0'-). % Match 0'-
2679rdf_save_footer(Out) :-
2680 retractall(named_anon(_, _)),
2681 retractall(inlined(_)),
2682 format(Out, '</rdf:RDF>~n', []).anon(false)
is present in the Options list.2689rdf_save_non_anon_subject(_Out, Subject, Options) :- 2690 rdf_is_bnode(Subject), 2691 ( memberchk(anon(false), Options) 2692 ; graph(Options, DB), 2693 rdf_db(_, _, Subject, DB) 2694 ), 2695 !. 2696rdf_save_non_anon_subject(Out, Subject, Options) :- 2697 rdf_save_subject(Out, Subject, Options), 2698 flag(rdf_db_saved_subjects, X, X+1).
2713rdf_save_subject(Out, Subject, Options) :- 2714 is_list(Options), 2715 !, 2716 option(base_uri(BaseURI), Options, '-'), 2717 ( rdf_save_subject(Out, Subject, BaseURI, 0, Options) 2718 -> format(Out, '~n', []) 2719 ; throw(error(rdf_save_failed(Subject), 'Internal error')) 2720 ). 2721rdf_save_subject(Out, Subject, DB) :- 2722 ( var(DB) 2723 -> rdf_save_subject(Out, Subject, []) 2724 ; rdf_save_subject(Out, Subject, [graph(DB)]) 2725 ).
2735rdf_save_subject(_, Subject, _, _, _) :- 2736 inlined(Subject), 2737 !. 2738rdf_save_subject(Out, Subject, BaseURI, Indent, Options) :- 2739 do_save_subject(Out, Subject, BaseURI, Indent, Options). 2740 2741do_save_subject(Out, Subject, BaseURI, Indent, Options) :- 2742 graph(Options, DB), 2743 findall(Pred=Object, rdf_db(Subject, Pred, Object, DB), Atts0), 2744 sort(Atts0, Atts), % remove duplicates 2745 length(Atts, L), 2746 ( length(Atts0, L0), 2747 Del is L0-L, 2748 Del > 0 2749 -> print_message(informational, 2750 rdf(save_removed_duplicates(Del, Subject))) 2751 ; true 2752 ), 2753 rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options), 2754 flag(rdf_db_saved_triples, X, X+L). 2755 2756rdf_db(Subject, Pred, Object, DB) :- 2757 var(DB), 2758 !, 2759 rdf(Subject, Pred, Object). 2760rdf_db(Subject, Pred, Object, DB) :- 2761 rdf(Subject, Pred, Object, DB:_).
2768rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options) :- 2769 rdf_equal(rdf:type, RdfType), 2770 select(RdfType=Type, Atts, Atts1), 2771 \+ rdf_is_bnode(Type), 2772 rdf_id(Type, BaseURI, TypeId), 2773 xml_is_name(TypeId), 2774 !, 2775 format(Out, '~*|<', [Indent]), 2776 rdf_write_id(Out, TypeId), 2777 save_about(Out, BaseURI, Subject, Options), 2778 save_attributes(Atts1, BaseURI, Out, TypeId, Indent, Options). 2779rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options) :- 2780 format(Out, '~*|<rdf:Description', [Indent]), 2781 save_about(Out, BaseURI, Subject, Options), 2782 save_attributes(Atts, BaseURI, Out, rdf:'Description', Indent, Options). 2783 2784xml_is_name(_NS:Atom) :- 2785 !, 2786 xml_name(Atom). 2787xml_is_name(Atom) :- 2788 xml_name(Atom).
2795save_about(Out, _BaseURI, Subject, _Options) :- 2796 rdf_is_bnode(Subject), 2797 !, 2798 ( named_anon(Subject, NodeID) 2799 -> format(Out, ' rdf:nodeID="~w"', [NodeID]) 2800 ; true 2801 ). 2802save_about(Out, BaseURI, Subject, Options) :- 2803 option(encoding(Encoding), Options, utf8), 2804 rdf_value(Subject, BaseURI, QSubject, Encoding), 2805 format(Out, ' rdf:about="~w"', [QSubject]).
2813save_attributes(Atts, BaseURI, Out, Element, Indent, Options) :-
2814 split_attributes(Atts, InTag, InBody, Options),
2815 SubIndent is Indent + 2,
2816 save_attributes2(InTag, BaseURI, tag, Out, SubIndent, Options),
2817 ( InBody == []
2818 -> format(Out, '/>~n', [])
2819 ; format(Out, '>~n', []),
2820 save_attributes2(InBody, BaseURI, body, Out, SubIndent, Options),
2821 format(Out, '~N~*|</', [Indent]),
2822 rdf_write_id(Out, Element),
2823 format(Out, '>~n', [])
2824 ).2832split_attributes(Atts, [], Atts, Options) :- 2833 option(xml_attributes(false), Options), 2834 !. 2835split_attributes(Atts, HeadAttr, BodyAttr, _) :- 2836 duplicate_attributes(Atts, Dupls, Singles), 2837 simple_literal_attributes(Singles, HeadAttr, Rest), 2838 append(Dupls, Rest, BodyAttr).
2845duplicate_attributes([], [], []). 2846duplicate_attributes([H|T], Dupls, Singles) :- 2847 H = (Name=_), 2848 named_attributes(Name, T, D, R), 2849 D \== [], 2850 append([H|D], Dupls2, Dupls), 2851 !, 2852 duplicate_attributes(R, Dupls2, Singles). 2853duplicate_attributes([H|T], Dupls2, [H|Singles]) :- 2854 duplicate_attributes(T, Dupls2, Singles). 2855 2856named_attributes(_, [], [], []) :- !. 2857named_attributes(Name, [H|T], D, R) :- 2858 ( H = (Name=_) 2859 -> D = [H|DT], 2860 named_attributes(Name, T, DT, R) 2861 ; R = [H|RT], 2862 named_attributes(Name, T, D, RT) 2863 ).
2870simple_literal_attributes([], [], []). 2871simple_literal_attributes([H|TA], [H|TI], B) :- 2872 in_tag_attribute(H), 2873 !, 2874 simple_literal_attributes(TA, TI, B). 2875simple_literal_attributes([H|TA], I, [H|TB]) :- 2876 simple_literal_attributes(TA, I, TB). 2877 2878in_tag_attribute(_=literal(Text)) :- 2879 atom(Text), % may not have lang qualifier 2880 atom_length(Text, Len), 2881 Len < 60.
2887save_attributes2([], _, _, _, _, _). 2888save_attributes2([H|T], BaseURI, Where, Out, Indent, Options) :- 2889 save_attribute(Where, H, BaseURI, Out, Indent, Options), 2890 save_attributes2(T, BaseURI, Where, Out, Indent, Options). 2891 2892save_attribute(tag, Name=literal(Value), BaseURI, Out, Indent, Options) :- 2893 AttIndent is Indent + 2, 2894 rdf_id(Name, BaseURI, NameText), 2895 option(encoding(Encoding), Options, utf8), 2896 xml_quote_attribute(Value, QVal, Encoding), 2897 format(Out, '~N~*|', [AttIndent]), 2898 rdf_write_id(Out, NameText), 2899 format(Out, '="~w"', [QVal]). 2900save_attribute(body, Name=literal(Literal0), BaseURI, Out, Indent, Options) :- 2901 !, 2902 rdf_id(Name, BaseURI, NameText), 2903 ( option(convert_typed_literal(Converter), Options), 2904 call(Converter, Type, Content, Literal0) 2905 -> Literal = type(Type, Content) 2906 ; Literal = Literal0 2907 ), 2908 save_body_literal(Literal, NameText, BaseURI, Out, Indent, Options). 2909save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :- 2910 rdf_is_bnode(Value), 2911 !, 2912 rdf_id(Name, BaseURI, NameText), 2913 format(Out, '~N~*|<', [Indent]), 2914 rdf_write_id(Out, NameText), 2915 ( named_anon(Value, NodeID) 2916 -> format(Out, ' rdf:nodeID="~w"/>', [NodeID]) 2917 ; ( rdf(S1, Name, Value), 2918 rdf(S2, P2, Value), 2919 (S1 \== S2 ; Name \== P2) 2920 -> predicate_property(named_anon(_,_), number_of_clauses(N)), 2921 atom_concat('bn', N, NodeID), 2922 assertz(named_anon(Value, NodeID)) 2923 ; true 2924 ), 2925 SubIndent is Indent + 2, 2926 ( rdf_collection(Value) 2927 -> save_about(Out, BaseURI, Value, Options), 2928 format(Out, ' rdf:parseType="Collection">~n', []), 2929 rdf_save_list(Out, Value, BaseURI, SubIndent, Options) 2930 ; format(Out, '>~n', []), 2931 rdf_save_subject(Out, Value, BaseURI, SubIndent, Options) 2932 ), 2933 format(Out, '~N~*|</', [Indent]), 2934 rdf_write_id(Out, NameText), 2935 format(Out, '>~n', []) 2936 ). 2937save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :- 2938 option(inline(true), Options), 2939 has_attributes(Value, Options), 2940 \+ inlined(Value), 2941 !, 2942 assertz(inlined(Value)), 2943 rdf_id(Name, BaseURI, NameText), 2944 format(Out, '~N~*|<', [Indent]), 2945 rdf_write_id(Out, NameText), 2946 SubIndent is Indent + 2, 2947 ( rdf_collection(Value) 2948 -> save_about(Out, BaseURI, Value, Options), 2949 format(Out, ' rdf:parseType="Collection">~n', []), 2950 rdf_save_list(Out, Value, BaseURI, SubIndent, Options) 2951 ; format(Out, '>~n', []), 2952 do_save_subject(Out, Value, BaseURI, SubIndent, Options) 2953 ), 2954 format(Out, '~N~*|</', [Indent]), 2955 rdf_write_id(Out, NameText), 2956 format(Out, '>~n', []). 2957save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :- 2958 option(encoding(Encoding), Options, utf8), 2959 rdf_value(Value, BaseURI, QVal, Encoding), 2960 rdf_id(Name, BaseURI, NameText), 2961 format(Out, '~N~*|<', [Indent]), 2962 rdf_write_id(Out, NameText), 2963 format(Out, ' rdf:resource="~w"/>', [QVal]). 2964 2965has_attributes(URI, Options) :- 2966 graph(Options, DB), 2967 rdf_db(URI, _, _, DB), 2968 !.
2973save_body_literal(lang(Lang, Value), 2974 NameText, BaseURI, Out, Indent, Options) :- 2975 !, 2976 format(Out, '~N~*|<', [Indent]), 2977 rdf_write_id(Out, NameText), 2978 ( memberchk(document_language(Lang), Options) 2979 -> write(Out, '>') 2980 ; rdf_id(Lang, BaseURI, LangText), 2981 format(Out, ' xml:lang="~w">', [LangText]) 2982 ), 2983 save_attribute_value(Value, Out, Options), 2984 write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>'). 2985save_body_literal(type(Type, DOM), 2986 NameText, _BaseURI, Out, Indent, Options) :- 2987 rdf_equal(Type, rdf:'XMLLiteral'), 2988 !, 2989 ( atom(DOM) 2990 -> format(Out, '~N~*|<', [Indent]), 2991 rdf_write_id(Out, NameText), 2992 format(Out, ' rdf:parseType="Literal">~w</', [DOM]), 2993 rdf_write_id(Out, NameText), write(Out, '>') 2994 ; save_xml_literal(DOM, NameText, Out, Indent, Options) 2995 ). 2996save_body_literal(type(Type, Value), 2997 NameText, BaseURI, Out, Indent, Options) :- 2998 !, 2999 format(Out, '~N~*|<', [Indent]), 3000 rdf_write_id(Out, NameText), 3001 option(encoding(Encoding), Options, utf8), 3002 rdf_value(Type, BaseURI, QVal, Encoding), 3003 format(Out, ' rdf:datatype="~w">', [QVal]), 3004 save_attribute_value(Value, Out, Options), 3005 write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>'). 3006save_body_literal(Literal, 3007 NameText, _, Out, Indent, Options) :- 3008 atomic(Literal), 3009 !, 3010 format(Out, '~N~*|<', [Indent]), 3011 rdf_write_id(Out, NameText), 3012 write(Out, '>'), 3013 save_attribute_value(Literal, Out, Options), 3014 write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>'). 3015save_body_literal(DOM, 3016 NameText, BaseURI, Out, Indent, Options) :- 3017 rdf_equal(Type, rdf:'XMLLiteral'), 3018 save_body_literal(type(Type, DOM), 3019 NameText, BaseURI, Out, Indent, Options). 3020 3021save_attribute_value(Value, Out, Options) :- % strings 3022 ( atom(Value) 3023 ; string(Value) 3024 ), 3025 !, 3026 option(encoding(Encoding), Options, utf8), 3027 xml_quote_cdata(Value, QVal, Encoding), 3028 write(Out, QVal). 3029save_attribute_value(Value, Out, _Options) :- % numbers 3030 number(Value), 3031 !, 3032 writeq(Out, Value). % quoted: preserve floats 3033save_attribute_value(Value, _Out, _Options) :- 3034 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.
3048save_xml_literal(DOM, Attr, Out, Indent, Options) :- 3049 xml_is_dom(DOM), 3050 !, 3051 memberchk(nsmap(NsMap), Options), 3052 id_to_atom(Attr, Atom), 3053 xml_write(Out, 3054 element(Atom, ['rdf:parseType'='Literal'], DOM), 3055 [ header(false), 3056 indent(Indent), 3057 nsmap(NsMap) 3058 ]). 3059save_xml_literal(NoDOM, _, _, _, _) :- 3060 must_be(xml_dom, NoDOM). 3061 3062id_to_atom(NS:Local, Atom) :- 3063 !, 3064 atomic_list_concat([NS,Local], :, Atom). 3065id_to_atom(ID, ID).
3075:- rdf_meta 3076 rdf_collection(r), 3077 collection_p(r,r). 3078 3079rdf_collection(rdf:nil) :- !. 3080rdf_collection(Cell) :- 3081 rdf_is_bnode(Cell), 3082 findall(F, rdf(Cell, rdf:first, F), [_]), 3083 findall(F, rdf(Cell, rdf:rest, F), [Rest]), 3084 forall(rdf(Cell, P, V), 3085 collection_p(P, V)), 3086 rdf_collection(Rest). 3087 3088collection_p(rdf:first, V) :- atom(V). 3089collection_p(rdf:rest, _). 3090collection_p(rdf:type, rdf:'List').
3095rdf_save_list(_, List, _, _, _) :- 3096 rdf_equal(List, rdf:nil), 3097 !. 3098rdf_save_list(Out, List, BaseURI, Indent, Options) :- 3099 rdf_has(List, rdf:first, First), 3100 ( rdf_is_bnode(First) 3101 -> nl(Out), 3102 rdf_save_subject(Out, First, BaseURI, Indent, Options) 3103 ; option(encoding(Encoding), Options, utf8), 3104 rdf_value(First, BaseURI, QVal, Encoding), 3105 format(Out, '~N~*|<rdf:Description rdf:about="~w"/>', 3106 [Indent, QVal]) 3107 ), 3108 flag(rdf_db_saved_triples, X, X+3), 3109 ( rdf_has(List, rdf:rest, List2), 3110 \+ rdf_equal(List2, rdf:nil) 3111 -> rdf_save_list(Out, List2, BaseURI, Indent, Options) 3112 ; true 3113 ).
3121rdf_id(Id, BaseURI, Local) :- 3122 assertion(atom(BaseURI)), 3123 atom_concat(BaseURI, Local, Id), 3124 sub_atom(Local, 0, 1, _, #), 3125 !. 3126rdf_id(Id, _, NS:Local) :- 3127 iri_xml_namespace(Id, Full, Local), 3128 ns(NS, Full), 3129 !. 3130rdf_id(Id, _, NS:Local) :- 3131 ns(NS, Full), 3132 Full \== '', 3133 atom_concat(Full, Local, Id), 3134 !. 3135rdf_id(Id, _, Id).
3143rdf_write_id(Out, NS:Local) :- 3144 !, 3145 format(Out, '~w:~w', [NS, Local]). 3146rdf_write_id(Out, Atom) :- 3147 write(Out, Atom).
3156rdf_value(Base, Base, '', _) :- !. 3157rdf_value(V, Base, Text, Encoding) :- 3158 atom_concat(Base, Local, V), 3159 sub_atom(Local, 0, _, _, #), 3160 !, 3161 xml_quote_attribute(Local, Text, Encoding). 3162rdf_value(V, _, Text, Encoding) :- 3163 ns(NS, Full), 3164 atom_concat(Full, Local, V), 3165 xml_is_name(Local), 3166 !, 3167 xml_quote_attribute(Local, QLocal, Encoding), 3168 atomic_list_concat(['&', NS, (';'), QLocal], Text). 3169rdf_value(V, _, Q, Encoding) :- 3170 xml_quote_attribute(V, Q, Encoding). 3171 3172 3173 /******************************* 3174 * MATCH AND COMPARE * 3175 *******************************/
icase, substring, word, prefix or like. For backward
compatibility, exact is a synonym for icase.3198 /******************************* 3199 * DEPRECATED MATERIAL * 3200 *******************************/
3210rdf_split_url(Prefix, Local, URL) :- 3211 atomic(URL), 3212 !, 3213 iri_xml_namespace(URL, Prefix, Local). 3214rdf_split_url(Prefix, Local, URL) :- 3215 atom_concat(Prefix, Local, URL).
3223rdf_url_namespace(URL, Prefix) :- 3224 iri_xml_namespace(URL, Prefix). 3225 3226 3227 /******************************* 3228 * LITERALS * 3229 *******************************/
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).3317 /******************************* 3318 * MISC * 3319 *******************************/
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.
3416 /******************************* 3417 * MESSAGES * 3418 *******************************/ 3419 3420:- multifile 3421 prolog:message//1. 3422 3423prologmessage(rdf(Term)) --> 3424 message(Term). 3425 3426message(loaded(How, What, BaseURI, Triples, Time)) --> 3427 how(How), 3428 source(What), 3429 into(What, BaseURI), 3430 in_time(Triples, Time). 3431message(save_removed_duplicates(N, Subject)) --> 3432 [ 'Removed ~d duplicate triples about "~p"'-[N,Subject] ]. 3433message(saved(File, SavedSubjects, SavedTriples)) --> 3434 [ 'Saved ~D triples about ~D subjects into ~p'- 3435 [SavedTriples, SavedSubjects, File] 3436 ]. 3437message(using_namespace(Id, NS)) --> 3438 [ 'Using namespace id ~w for ~w'-[Id, NS] ]. 3439message(inconsistent_cache(DB, Graphs)) --> 3440 [ 'RDF cache file for ~w contains the following graphs'-[DB], nl, 3441 '~t~8|~p'-[Graphs] 3442 ]. 3443message(guess_format(Ext)) --> 3444 [ 'Unknown file-extension: ~w. Assuming RDF/XML'-[Ext] ]. 3445message(meta(not_expanded(G))) --> 3446 [ 'rdf_meta/1: ~p is not expanded'-[G] ]. 3447message(deprecated(rdf_unload(Graph))) --> 3448 [ 'rdf_unload/1: Use ~q'-[rdf_unload_graph(Graph)] ]. 3449 3450 3451how(load) --> [ 'Loaded' ]. 3452how(parsed) --> [ 'Parsed' ]. 3453 3454source(SourceURL) --> 3455 { uri_file_name(SourceURL, File), 3456 !, 3457 file_base_name(File, Base) % TBD: relative file? 3458 }, 3459 [ ' "~w"'-[Base] ]. 3460source(SourceURL) --> 3461 [ ' "~w"'-[SourceURL] ]. 3462 3463into(_, _) --> []. % TBD 3464 3465in_time(Triples, ParseTime) --> 3466 [ ' in ~2f sec; ~D triples'-[ParseTime, Triples] 3467 ]
Core RDF database
The file library(semweb/rdf_db) provides the core of the SWI-Prolog RDF store.