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-2020, University of Amsterdam 7 VU University Amsterdam 8 CWI, Amsterdam 9 All rights reserved. 10 11 Redistribution and use in source and binary forms, with or without 12 modification, are permitted provided that the following conditions 13 are met: 14 15 1. Redistributions of source code must retain the above copyright 16 notice, this list of conditions and the following disclaimer. 17 18 2. Redistributions in binary form must reproduce the above copyright 19 notice, this list of conditions and the following disclaimer in 20 the documentation and/or other materials provided with the 21 distribution. 22 23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 POSSIBILITY OF SUCH DAMAGE. 35*/ 36 37:- module(rdf_db, 38 [ rdf_version/1, % -Version 39 40 rdf/3, % ?Subject, ?Predicate, ?Object 41 rdf/4, % ?Subject, ?Predicate, ?Object, ?DB 42 rdf_has/3, % ?Subject, +Pred, ?Obj 43 rdf_has/4, % ?Subject, +Pred, ?Obj, -RealPred 44 rdf_reachable/3, % ?Subject, +Pred, ?Object 45 rdf_reachable/5, % ?Subject, +Pred, ?Object, +MaxD, ?D 46 rdf_resource/1, % ?Resource 47 rdf_subject/1, % ?Subject 48 49 rdf_member_property/2, % ?Property, ?Index 50 51 rdf_assert/3, % +Subject, +Predicate, +Object 52 rdf_assert/4, % +Subject, +Predicate, +Object, +DB 53 rdf_retractall/3, % ?Subject, ?Predicate, ?Object 54 rdf_retractall/4, % ?Subject, ?Predicate, ?Object, +DB 55 rdf_update/4, % +Subject, +Predicate, +Object, +Act 56 rdf_update/5, % +Subject, +Predicate, +Object, +Src, +Act 57 rdf_set_predicate/2, % +Predicate, +Property 58 rdf_predicate_property/2, % +Predicate, ?Property 59 rdf_current_predicate/1, % -Predicate 60 rdf_current_literal/1, % -Literal 61 rdf_transaction/1, % :Goal 62 rdf_transaction/2, % :Goal, +Id 63 rdf_transaction/3, % :Goal, +Id, +Options 64 rdf_active_transaction/1, % ?Id 65 66 rdf_monitor/2, % :Goal, +Options 67 68 rdf_save_db/1, % +File 69 rdf_save_db/2, % +File, +DB 70 rdf_load_db/1, % +File 71 rdf_reset_db/0, 72 73 rdf_node/1, % -Id 74 rdf_bnode/1, % -Id 75 rdf_is_bnode/1, % +Id 76 77 rdf_is_resource/1, % +Term 78 rdf_is_literal/1, % +Term 79 rdf_literal_value/2, % +Term, -Value 80 81 rdf_load/1, % +File 82 rdf_load/2, % +File, +Options 83 rdf_save/1, % +File 84 rdf_save/2, % +File, +Options 85 rdf_unload/1, % +File 86 rdf_unload_graph/1, % +Graph 87 88 rdf_md5/2, % +DB, -MD5 89 rdf_atom_md5/3, % +Text, +Times, -MD5 90 91 rdf_create_graph/1, % ?Graph 92 rdf_graph_property/2, % ?Graph, ?Property 93 rdf_set_graph/2, % +Graph, +Property 94 rdf_graph/1, % ?Graph 95 rdf_source/1, % ?File 96 rdf_source/2, % ?DB, ?SourceURL 97 rdf_make/0, % Reload modified databases 98 rdf_gc/0, % Garbage collection 99 100 rdf_source_location/2, % +Subject, -Source 101 rdf_statistics/1, % -Key 102 rdf_set/1, % +Term 103 rdf_generation/1, % -Generation 104 rdf_snapshot/1, % -Snapshot 105 rdf_delete_snapshot/1, % +Snapshot 106 rdf_current_snapshot/1, % +Snapshot 107 rdf_estimate_complexity/4, % +S,+P,+O,-Count 108 109 rdf_save_subject/3, % +Stream, +Subject, +DB 110 rdf_save_header/2, % +Out, +Options 111 rdf_save_footer/1, % +Out 112 113 rdf_equal/2, % ?Resource, ?Resource 114 lang_equal/2, % +Lang1, +Lang2 115 lang_matches/2, % +Lang, +Pattern 116 117 rdf_prefix/2, % :Alias, +URI 118 rdf_current_prefix/2, % :Alias, ?URI 119 rdf_register_prefix/2, % +Alias, +URI 120 rdf_register_prefix/3, % +Alias, +URI, +Options 121 rdf_unregister_prefix/1, % +Alias 122 rdf_current_ns/2, % :Alias, ?URI 123 rdf_register_ns/2, % +Alias, +URI 124 rdf_register_ns/3, % +Alias, +URI, +Options 125 rdf_global_id/2, % ?NS:Name, :Global 126 rdf_global_object/2, % +Object, :NSExpandedObject 127 rdf_global_term/2, % +Term, :WithExpandedNS 128 129 rdf_compare/3, % -Dif, +Object1, +Object2 130 rdf_match_label/3, % +How, +String, +Label 131 rdf_split_url/3, % ?Base, ?Local, ?URL 132 rdf_url_namespace/2, % +URL, ?Base 133 134 rdf_warm_indexes/0, 135 rdf_warm_indexes/1, % +Indexed 136 rdf_update_duplicates/0, 137 138 rdf_debug/1, % Set verbosity 139 140 rdf_new_literal_map/1, % -Handle 141 rdf_destroy_literal_map/1, % +Handle 142 rdf_reset_literal_map/1, % +Handle 143 rdf_insert_literal_map/3, % +Handle, +Key, +Literal 144 rdf_insert_literal_map/4, % +Handle, +Key, +Literal, -NewKeys 145 rdf_delete_literal_map/3, % +Handle, +Key, +Literal 146 rdf_delete_literal_map/2, % +Handle, +Key 147 rdf_find_literal_map/3, % +Handle, +KeyList, -Literals 148 rdf_keys_in_literal_map/3, % +Handle, +Spec, -Keys 149 rdf_statistics_literal_map/2, % +Handle, +Name(-Arg...) 150 151 rdf_graph_prefixes/2, % ?Graph, -Prefixes 152 rdf_graph_prefixes/3, % ?Graph, -Prefixes, :Filter 153 154 (rdf_meta)/1, % +Heads 155 op(1150, fx, (rdf_meta)) 156 ]). 157:- use_module(library(semweb/rdf_prefixes), 158 [ (rdf_meta)/1, 159 register_file_prefixes/1, 160 rdf_global_id/2, 161 rdf_register_ns/2, 162 % re-exported predicates 163 rdf_global_object/2, 164 rdf_current_ns/2, 165 rdf_prefix/2, 166 rdf_global_term/2, 167 rdf_register_ns/3, 168 rdf_register_prefix/3, 169 rdf_register_prefix/2, 170 rdf_current_prefix/2, 171 rdf_unregister_prefix/1 172 ]). 173 174:- autoload(library(apply),[maplist/2,maplist/3]). 175:- autoload(library(debug),[debug/3,assertion/1]). 176:- autoload(library(error),[must_be/2,existence_error/2]). 177:- autoload(library(gensym),[gensym/2,reset_gensym/1]). 178:- autoload(library(lists), 179 [member/2,flatten/2,list_to_set/2,append/3,select/3]). 180:- autoload(library(memfile), 181 [atom_to_memory_file/2,open_memory_file/4]). 182:- autoload(library(option), 183 [option/2,option/3,merge_options/3,meta_options/3]). 184:- autoload(library(rdf),[process_rdf/3]). 185:- autoload(library(sgml), 186 [ load_structure/3, 187 xml_quote_attribute/3, 188 xml_name/1, 189 xml_quote_cdata/3, 190 xml_is_dom/1, 191 iri_xml_namespace/3, 192 iri_xml_namespace/2 193 ]). 194:- autoload(library(sgml_write),[xml_write/3]). 195:- autoload(library(uri), 196 [ uri_file_name/2, 197 uri_is_global/1, 198 uri_normalized/2, 199 uri_components/2, 200 uri_data/3, 201 uri_data/4 202 ]). 203:- autoload(library(xsdp_types),[xsdp_numeric_uri/2]). 204:- autoload(library(semweb/rdf_cache),[rdf_cache_file/3]). 205 206:- if(exists_source(library(thread))). 207:- autoload(library(thread), [concurrent/3]). 208:- endif. 209 210:- use_foreign_library(foreign(rdf_db)). 211:- public rdf_print_predicate_cloud/2. % print matrix of reachable predicates 212 213:- meta_predicate 214 rdf_transaction( ), 215 rdf_transaction( , ), 216 rdf_transaction( , , ), 217 rdf_monitor( , ), 218 rdf_save( , ), 219 rdf_load( , ). 220 221:- predicate_options(rdf_graph_prefixes/3, 3, 222 [expand(callable), filter(callable), min_count(nonneg)]). 223:- predicate_options(rdf_load/2, 2, 224 [ base_uri(atom), 225 blank_nodes(oneof([share,noshare])), 226 cache(boolean), 227 concurrent(positive_integer), 228 db(atom), 229 format(oneof([xml,triples,turtle,trig,nquads,ntriples])), 230 graph(atom), 231 multifile(boolean), 232 if(oneof([true,changed,not_loaded])), 233 modified(-float), 234 prefixes(-list), 235 silent(boolean), 236 register_namespaces(boolean) 237 ]). 238:- predicate_options(rdf_save/2, 2, 239 [ graph(atom), 240 db(atom), 241 anon(boolean), 242 base_uri(atom), 243 write_xml_base(boolean), 244 convert_typed_literal(callable), 245 encoding(encoding), 246 document_language(atom), 247 namespaces(list(atom)), 248 xml_attributes(boolean), 249 inline(boolean) 250 ]). 251:- predicate_options(rdf_save_header/2, 2, 252 [ graph(atom), 253 db(atom), 254 namespaces(list(atom)) 255 ]). 256:- predicate_options(rdf_save_subject/3, 3, 257 [ graph(atom), 258 base_uri(atom), 259 convert_typed_literal(callable), 260 document_language(atom) 261 ]). 262:- predicate_options(rdf_transaction/3, 3, 263 [ snapshot(any) 264 ]). 265 266:- discontiguous 267 term_expansion/2.
283 /******************************* 284 * PREFIXES * 285 *******************************/ 286 287% the ns/2 predicate is historically defined in this module. We'll keep 288% that for compatibility reasons. 289 290:- multifile ns/2. 291:- dynamic ns/2. % ID, URL 292 293:- multifile 294 rdf_prefixes:rdf_empty_prefix_cache/2. 295 296rdf_prefixesrdf_empty_prefix_cache(_Prefix, _IRI) :- 297 rdf_empty_prefix_cache. 298 299:- rdf_meta 300 rdf(r,r,o), 301 rdf_has(r,r,o,r), 302 rdf_has(r,r,o), 303 rdf_assert(r,r,o), 304 rdf_retractall(r,r,o), 305 rdf(r,r,o,?), 306 rdf_assert(r,r,o,+), 307 rdf_retractall(r,r,o,?), 308 rdf_reachable(r,r,o), 309 rdf_reachable(r,r,o,+,?), 310 rdf_update(r,r,o,t), 311 rdf_update(r,r,o,+,t), 312 rdf_equal(o,o), 313 rdf_source_location(r,-), 314 rdf_resource(r), 315 rdf_subject(r), 316 rdf_create_graph(r), 317 rdf_graph(r), 318 rdf_graph_property(r,?), 319 rdf_set_graph(r,+), 320 rdf_unload_graph(r), 321 rdf_set_predicate(r, t), 322 rdf_predicate_property(r, -), 323 rdf_estimate_complexity(r,r,r,-), 324 rdf_print_predicate_cloud(r,+).
330rdf_equal(Resource, Resource).
338lang_equal(Lang, Lang) :- !. 339lang_equal(Lang1, Lang2) :- 340 downcase_atom(Lang1, LangCannon), 341 downcase_atom(Lang2, LangCannon).
353 /******************************* 354 * BASIC TRIPLE QUERIES * 355 *******************************/
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.
521rdf_subject(Resource) :-
522 rdf_resource(Resource),
523 ( 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.
536 /******************************* 537 * TRIPLE MODIFICATIONS * 538 *******************************/
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)
.589 /******************************* 590 * COLLECTIONS * 591 *******************************/
597term_expansion(member_prefix(x), 598 member_prefix(Prefix)) :- 599 rdf_db:ns(rdf, NS), 600 atom_concat(NS, '_', Prefix). 601member_prefix(x). 602 603rdf_member_property(P, N) :- 604 integer(N), 605 !, 606 member_prefix(Prefix), 607 atom_concat(Prefix, N, P). 608rdf_member_property(P, N) :- 609 member_prefix(Prefix), 610 atom_concat(Prefix, Sub, P), 611 atom_number(Sub, N). 612 613 614 /******************************* 615 * ANONYMOUS SUBJECTS * 616 *******************************/
624rdf_node(Resource) :-
625 rdf_bnode(Resource).
631rdf_bnode(Value) :- 632 repeat, 633 gensym('_:genid', Value), 634 \+ rdf(Value, _, _), 635 \+ rdf(_, _, Value), 636 \+ rdf(_, Value, _), 637 !. 638 639 640 641 /******************************* 642 * TYPES * 643 *******************************/
_:
. For backward compatibility reason, __
is also
considered to be a blank node.
662rdf_is_resource(Term) :-
663 atom(Term).
670rdf_is_literal(literal(Value)) :- 671 ground(Value). 672 673 /******************************* 674 * LITERALS * 675 *******************************/
Plain literals | Atom |
Language tagged literal | Atom holding plain text |
xsd:string | Atom |
rdf:XMLLiteral | XML DOM Tree |
Numeric XSD type | Number |
700:- rdf_meta 701 rdf_literal_value(o, -), 702 typed_value(r, +, -), 703 numeric_value(r, +, -). 704 705rdf_literal_value(literal(String), Value) :- 706 atom(String), 707 !, 708 Value = String. 709rdf_literal_value(literal(lang(_Lang, String)), String). 710rdf_literal_value(literal(type(Type, String)), Value) :- 711 typed_value(Type, String, Value). 712 713typed_value(Numeric, String, Value) :- 714 xsdp_numeric_uri(Numeric, NumType), 715 !, 716 numeric_value(NumType, String, Value). 717typed_value(xsd:string, String, String). 718typed_value(rdf:'XMLLiteral', Value, DOM) :- 719 ( atom(Value) 720 -> setup_call_cleanup( 721 ( atom_to_memory_file(Value, MF), 722 open_memory_file(MF, read, In, [free_on_close(true)]) 723 ), 724 load_structure(stream(In), DOM, [dialect(xml)]), 725 close(In)) 726 ; DOM = Value 727 ). 728 729numeric_value(xsd:integer, String, Value) :- 730 atom_number(String, Value), 731 integer(Value). 732numeric_value(xsd:float, String, Value) :- 733 atom_number(String, Number), 734 Value is float(Number). 735numeric_value(xsd:double, String, Value) :- 736 atom_number(String, Number), 737 Value is float(Number). 738numeric_value(xsd:decimal, String, Value) :- 739 atom_number(String, Value). 740 741 742 /******************************* 743 * SOURCE * 744 *******************************/
752rdf_source_location(Subject, Source) :- 753 findall(Source, rdf(Subject, _, _, Source), Sources), 754 sort(Sources, Unique), 755 member(Source, Unique). 756 757 758 /******************************* 759 * GARBAGE COLLECT * 760 *******************************/
766:- public 767 rdf_create_gc_thread/0. 768 769rdf_create_gc_thread :- 770 thread_create(rdf_gc_loop, _, 771 [ alias('__rdf_GC') 772 ]).
779rdf_gc_loop :- 780 catch(rdf_gc_loop(0), E, recover_gc(E)). 781 782recover_gc('$aborted') :- 783 !, 784 thread_self(Me), 785 thread_detach(Me). 786recover_gc(Error) :- 787 print_message(error, Error), 788 rdf_gc_loop. 789 790rdf_gc_loop(CPU) :- 791 repeat, 792 ( consider_gc(CPU) 793 -> rdf_gc(CPU1), 794 sleep(CPU1) 795 ; sleep(0.1) 796 ), 797 fail.
805rdf_gc(CPU) :-
806 statistics(cputime, CPU0),
807 ( rdf_gc_
808 -> statistics(cputime, CPU1),
809 CPU is CPU1-CPU0,
810 rdf_add_gc_time(CPU)
811 ; CPU = 0.0
812 ).
__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.
824rdf_gc :- 825 has_garbage, 826 !, 827 rdf_gc(_), 828 rdf_gc. 829rdf_gc.
835has_garbage :- 836 rdf_gc_info_(Info), 837 has_garbage(Info), 838 !. 839 840has_garbage(Info) :- arg(2, Info, Garbage), Garbage > 0. 841has_garbage(Info) :- arg(3, Info, Reindexed), Reindexed > 0. 842has_garbage(Info) :- arg(4, Info, Optimizable), Optimizable > 0.
849consider_gc(_CPU) :- 850 ( rdf_gc_info_(gc_info(Triples, % Total #triples in DB 851 Garbage, % Garbage triples in DB 852 Reindexed, % Reindexed & not reclaimed 853 Optimizable, % Non-optimized tables 854 _KeepGen, % Oldest active generation 855 _LastGCGen, % Oldest active gen at last GC 856 _ReindexGen, 857 _LastGCReindexGen)) 858 -> ( (Garbage+Reindexed) * 5 > Triples 859 ; Optimizable > 4 860 ) 861 ; print_message(error, rdf(invalid_gc_info)), 862 sleep(10) 863 ), 864 !. 865 866 867 /******************************* 868 * STATISTICS * 869 *******************************/
triples
for the interpretation of this value.915rdf_statistics(graphs(Count)) :- 916 rdf_statistics_(graphs(Count)). 917rdf_statistics(triples(Count)) :- 918 rdf_statistics_(triples(Count)). 919rdf_statistics(duplicates(Count)) :- 920 rdf_statistics_(duplicates(Count)). 921rdf_statistics(lingering(Count)) :- 922 rdf_statistics_(lingering(Count)). 923rdf_statistics(resources(Count)) :- 924 rdf_statistics_(resources(Count)). 925rdf_statistics(properties(Count)) :- 926 rdf_statistics_(predicates(Count)). 927rdf_statistics(literals(Count)) :- 928 rdf_statistics_(literals(Count)). 929rdf_statistics(gc(Count, Reclaimed, Reindexed, Time)) :- 930 rdf_statistics_(gc(Count, Reclaimed, Reindexed, Time)). 931rdf_statistics(searched_nodes(Count)) :- 932 rdf_statistics_(searched_nodes(Count)). 933rdf_statistics(lookup(Index, Count)) :- 934 functor(Indexed, indexed, 16), 935 rdf_statistics_(Indexed), 936 index(Index, I), 937 Arg is I + 1, 938 arg(Arg, Indexed, Count), 939 Count \== 0. 940rdf_statistics(hash_quality(Index, Size, Quality,Optimize)) :- 941 rdf_statistics_(hash_quality(List)), 942 member(hash(Place,Size,Quality,Optimize), List), 943 index(Index, Place). 944rdf_statistics(triples_by_graph(Graph, Count)) :- 945 rdf_graph_(Graph, Count). 946 947index(rdf(-,-,-,-), 0). 948index(rdf(+,-,-,-), 1). 949index(rdf(-,+,-,-), 2). 950index(rdf(+,+,-,-), 3). 951index(rdf(-,-,+,-), 4). 952index(rdf(+,-,+,-), 5). 953index(rdf(-,+,+,-), 6). 954index(rdf(+,+,+,-), 7). 955 956index(rdf(-,-,-,+), 8). 957index(rdf(+,-,-,+), 9). 958index(rdf(-,+,-,+), 10). 959index(rdf(+,+,-,+), 11). 960index(rdf(-,-,+,+), 12). 961index(rdf(+,-,+,+), 13). 962index(rdf(-,+,+,+), 14). 963index(rdf(+,+,+,+), 15). 964 965 966 /******************************* 967 * PREDICATES * 968 *******************************/
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.
984rdf_current_predicate(P, DB) :-
985 rdf_current_predicate(P),
986 ( rdf(_,P,_,DB)
987 -> true
988 ).
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.1041rdf_predicate_property(P, Prop) :- 1042 var(P), 1043 !, 1044 rdf_current_predicate(P), 1045 rdf_predicate_property_(P, Prop). 1046rdf_predicate_property(P, Prop) :- 1047 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.
1072 /******************************* 1073 * SNAPSHOTS * 1074 *******************************/
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.1097rdf_current_snapshot(Term) :- 1098 current_blob(Term, rdf_snapshot). 1099 1100 1101 /******************************* 1102 * TRANSACTION * 1103 *******************************/
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.1139rdf_transaction(Goal) :- 1140 rdf_transaction(Goal, user, []). 1141rdf_transaction(Goal, Id) :- 1142 rdf_transaction(Goal, Id, []).
1153rdf_active_transaction(Id) :-
1154 rdf_active_transactions_(List),
1155 member(Id, List).
1161rdf_monitor(Goal, Options) :- 1162 monitor_mask(Options, 0xffff, Mask), 1163 rdf_monitor_(Goal, Mask). 1164 1165monitor_mask([], Mask, Mask). 1166monitor_mask([H|T], Mask0, Mask) :- 1167 update_mask(H, Mask0, Mask1), 1168 monitor_mask(T, Mask1, Mask). 1169 1170update_mask(-X, Mask0, Mask) :- 1171 !, 1172 monitor_mask(X, M), 1173 Mask is Mask0 /\ \M. 1174update_mask(+X, Mask0, Mask) :- 1175 !, 1176 monitor_mask(X, M), 1177 Mask is Mask0 \/ M. 1178update_mask(X, Mask0, Mask) :- 1179 monitor_mask(X, M), 1180 Mask is Mask0 \/ M.
1187 % C-defined broadcasts 1188monitor_mask(assert, 0x0001). 1189monitor_mask(assert(load), 0x0002). 1190monitor_mask(retract, 0x0004). 1191monitor_mask(update, 0x0008). 1192monitor_mask(new_literal, 0x0010). 1193monitor_mask(old_literal, 0x0020). 1194monitor_mask(transaction, 0x0040). 1195monitor_mask(load, 0x0080). 1196monitor_mask(create_graph, 0x0100). 1197monitor_mask(reset, 0x0200). 1198 % prolog defined broadcasts 1199monitor_mask(parse, 0x1000). 1200monitor_mask(unload, 0x1000). % FIXME: Duplicate 1201 % mask for all 1202monitor_mask(all, 0xffff). 1203 1204%rdf_broadcast(Term, MaskName) :- 1205%% monitor_mask(MaskName, Mask), 1206%% rdf_broadcast_(Term, Mask). 1207 1208 1209 /******************************* 1210 * WARM * 1211 *******************************/
1217rdf_warm_indexes :- 1218 findall(Index, rdf_index(Index), Indexes), 1219 rdf_warm_indexes(Indexes). 1220 1221rdf_index(s). 1222rdf_index(p). 1223rdf_index(o). 1224rdf_index(sp). 1225rdf_index(o). 1226rdf_index(po). 1227rdf_index(spo). 1228rdf_index(g). 1229rdf_index(sg). 1230rdf_index(pg).
1241 /******************************* 1242 * DUPLICATES * 1243 *******************************/
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.
1258:- public
1259 rdf_update_duplicates_thread/0.
1265rdf_update_duplicates_thread :-
1266 thread_create(rdf_update_duplicates, _,
1267 [ detached(true),
1268 alias('__rdf_duplicate_detecter')
1269 ]).
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.
1283 /******************************* 1284 * QUICK BINARY LOAD/SAVE * 1285 *******************************/
1295:- create_prolog_flag(rdf_triple_format, 3, [type(integer)]). 1296 1297rdf_save_db(File) :- 1298 current_prolog_flag(rdf_triple_format, Version), 1299 setup_call_cleanup( 1300 open(File, write, Out, [type(binary)]), 1301 ( set_stream(Out, record_position(false)), 1302 rdf_save_db_(Out, _, Version) 1303 ), 1304 close(Out)). 1305 1306 1307rdf_save_db(File, Graph) :- 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, Graph, Version) 1313 ), 1314 close(Out)).
1323rdf_load_db_no_admin(File, Id, Graphs) :-
1324 open(File, read, In, [type(binary)]),
1325 set_stream(In, record_position(false)),
1326 call_cleanup(rdf_load_db_(In, Id, Graphs), close(In)).
1337check_loaded_cache(DB, [DB], _Modified) :- !. 1338check_loaded_cache(DB, Graphs, _) :- 1339 print_message(warning, rdf(inconsistent_cache(DB, Graphs))).
1346rdf_load_db(File) :- 1347 uri_file_name(URL, File), 1348 rdf_load_db_no_admin(File, URL, _Graphs). 1349 1350 1351 /******************************* 1352 * LOADING RDF * 1353 *******************************/ 1354 1355:- multifile 1356 rdf_open_hook/8, 1357 rdf_open_decode/4, % +Encoding, +File, -Stream, -Cleanup 1358 rdf_load_stream/3, % +Format, +Stream, +Options 1359 rdf_file_type/2, % ?Extension, ?Format 1360 rdf_storage_encoding/2, % ?Extension, ?Encoding 1361 url_protocol/1. % ?Protocol
rdf_load(FileOrList, [])
. See rdf_load/2.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)).
1453:- dynamic 1454 rdf_loading/3. % Graph, Queue, Thread 1455 1456rdf_load(Spec) :- 1457 rdf_load(Spec, []). 1458 1459:- if(\+current_predicate(concurrent/3)). 1460concurrent(_, Goals, _) :- 1461 forall(member(G, Goals), call(G)). 1462:- endif. 1463 1464% Note that we kill atom garbage collection. This improves performance 1465% with about 15% loading the LUBM Univ_50 benchmark. 1466 1467rdf_load(Spec, M:Options) :- 1468 must_be(list, Options), 1469 current_prolog_flag(agc_margin, Old), 1470 setup_call_cleanup( 1471 set_prolog_flag(agc_margin, 0), 1472 rdf_load_noagc(Spec, M, Options), 1473 set_prolog_flag(agc_margin, Old)). 1474 1475rdf_load_noagc(List, M, Options) :- 1476 is_list(List), 1477 !, 1478 flatten(List, Inputs), % Compatibility: allow nested lists 1479 maplist(must_be(ground), Inputs), 1480 length(Inputs, Count), 1481 load_jobs(Count, Jobs, Options), 1482 ( Jobs =:= 1 1483 -> forall(member(Spec, Inputs), 1484 rdf_load_one(Spec, M, Options)) 1485 ; maplist(load_goal(Options, M), Inputs, Goals), 1486 concurrent(Jobs, Goals, []) 1487 ). 1488rdf_load_noagc(One, M, Options) :- 1489 must_be(ground, One), 1490 rdf_load_one(One, M, Options). 1491 1492load_goal(Options, M, Spec, rdf_load_one(Spec, M, Options)). 1493 1494load_jobs(_, Jobs, Options) :- 1495 option(concurrent(Jobs), Options), 1496 !, 1497 must_be(positive_integer, Jobs). 1498load_jobs(Count, Jobs, _) :- 1499 current_prolog_flag(cpu_count, CPUs), 1500 CPUs > 0, 1501 !, 1502 Jobs is max(1, min(CPUs, Count)). 1503load_jobs(_, 1, _). 1504 1505 1506rdf_load_one(Spec, M, Options) :- 1507 source_url(Spec, Protocol, SourceURL), 1508 load_graph(SourceURL, Graph, Options), 1509 setup_call_cleanup( 1510 with_mutex(rdf_load_file, 1511 rdf_start_load(SourceURL, Loading)), 1512 rdf_load_file(Loading, Spec, SourceURL, Protocol, 1513 Graph, M, Options), 1514 rdf_end_load(Loading)).
1531rdf_start_load(SourceURL, queue(Queue)) :- 1532 rdf_loading(SourceURL, Queue, LoadThread), 1533 \+ thread_self(LoadThread), 1534 !, 1535 debug(rdf(load), '~p is being loaded by thread ~w; waiting ...', 1536 [ SourceURL, LoadThread]). 1537rdf_start_load(SourceURL, Ref) :- 1538 thread_self(Me), 1539 message_queue_create(Queue), 1540 assertz(rdf_loading(SourceURL, Queue, Me), Ref). 1541 1542rdf_end_load(queue(_)) :- !. 1543rdf_end_load(Ref) :- 1544 clause(rdf_loading(_, Queue, _), _, Ref), 1545 erase(Ref), 1546 thread_send_message(Queue, done), 1547 message_queue_destroy(Queue). 1548 1549rdf_load_file(queue(Queue), _Spec, _SourceURL, _Protocol, _Graph, _M, _Options) :- 1550 !, 1551 catch(thread_get_message(Queue, _), _, true). 1552rdf_load_file(_Ref, _Spec, SourceURL, Protocol, Graph, M, Options) :- 1553 debug(rdf(load), 'RDF: Loading ~q into ~q', [SourceURL, Graph]), 1554 statistics(cputime, T0), 1555 rdf_open_input(SourceURL, Protocol, Graph, 1556 In, Cleanup, Modified, Format, Options), 1557 supported_format(Format, Cleanup), 1558 return_modified(Modified, Options), 1559 ( Modified == not_modified 1560 -> Action = none 1561 ; Modified = cached(CacheFile) 1562 -> do_unload(Graph), 1563 catch(rdf_load_db_no_admin(CacheFile, cache(Graph), Graphs), _, fail), 1564 check_loaded_cache(Graph, Graphs, Modified), 1565 Action = load 1566 ; option(base_uri(BaseURI), Options, Graph), 1567 ( var(BaseURI) 1568 -> BaseURI = SourceURL 1569 ; true 1570 ), 1571 once(phrase(derived_options(Options, NSList), Extra)), 1572 merge_options([ base_uri(BaseURI), 1573 graph(Graph), 1574 format(Format) 1575 | Extra 1576 ], Options, RDFOptions), 1577 ( option(multifile(true), Options) 1578 -> true 1579 ; do_unload(Graph) 1580 ), 1581 graph_modified(Modified, ModifiedStamp), 1582 rdf_set_graph_source(Graph, SourceURL, ModifiedStamp), 1583 call_cleanup(rdf_load_stream(Format, In, M:RDFOptions), 1584 Cleanup), 1585 save_cache(Graph, SourceURL, Options), 1586 register_file_prefixes(NSList), 1587 format_action(Format, Action) 1588 ), 1589 rdf_statistics_(triples(Graph, Triples)), 1590 report_loaded(Action, SourceURL, Graph, Triples, T0, Options). 1591 1592supported_format(Format, _Cleanup) :- 1593 rdf_file_type(_, Format), 1594 !. 1595supported_format(Format, Cleanup) :- 1596 call(Cleanup), 1597 existence_error(rdf_format_plugin, Format). 1598 1599format_action(triples, load) :- !. 1600format_action(_, parsed). 1601 1602save_cache(Graph, SourceURL, Options) :- 1603 option(cache(true), Options, true), 1604 rdf_cache_file(SourceURL, write, CacheFile), 1605 !, 1606 catch(save_cache(Graph, CacheFile), E, 1607 print_message(warning, E)). 1608save_cache(_, _, _). 1609 1610derived_options([], _) --> 1611 []. 1612derived_options([H|T], NSList) --> 1613 ( { H == register_namespaces(true) 1614 ; H == (register_namespaces = true) 1615 } 1616 -> [ namespaces(NSList) ] 1617 ; [] 1618 ), 1619 derived_options(T, NSList). 1620 1621graph_modified(last_modified(Stamp), Stamp). 1622graph_modified(unknown, Stamp) :- 1623 get_time(Stamp). 1624 1625return_modified(Modified, Options) :- 1626 option(modified(M0), Options), 1627 !, 1628 M0 = Modified. 1629return_modified(_, _). 1630 1631 1632 /******************************* 1633 * INPUT HANDLING * 1634 *******************************/ 1635 1636/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1637This section deals with pluggable input sources. The task of the input 1638layer is 1639 1640 * Decide on the graph-name 1641 * Decide on the source-location 1642 * Decide whether loading is needed (if-modified) 1643 * Decide on the serialization in the input 1644 1645The protocol must ensure minimal overhead, in particular for network 1646protocols. E.g. for HTTP we want to make a single call on the server and 1647use If-modified-since to verify that we need not reloading this file. 1648- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
Options processed:
graph(Graph)
db(Graph)
if(Condition)
cache(Cache)
format(Format)
1666rdf_open_input(SourceURL, Protocol, Graph,
1667 Stream, Cleanup, Modified, Format, Options) :-
1668 ( option(multifile(true), Options)
1669 -> true
1670 ; option(if(If), Options, changed),
1671 ( If == true
1672 -> true
1673 ; rdf_graph_source_(Graph, SourceURL, HaveModified)
1674 -> true
1675 ; option(cache(true), Options, true),
1676 rdf_cache_file(SourceURL, read, CacheFile)
1677 -> time_file(CacheFile, HaveModified)
1678 ; true
1679 )
1680 ),
1681 option(format(Format), Options, _),
1682 open_input_if_modified(Protocol, SourceURL, HaveModified,
1683 Stream, Cleanup, Modified0, Format, Options),
1684 ( Modified0 == not_modified
1685 -> ( nonvar(CacheFile)
1686 -> Modified = cached(CacheFile)
1687 ; Modified = not_modified
1688 )
1689 ; Modified = Modified0
1690 ).
stream(Stream)
http
)1701source_url(stream(In), stream(In), SourceURL) :- 1702 !, 1703 ( stream_property(In, file_name(File)) 1704 -> to_url(File, SourceURL) 1705 ; gensym('stream://', SourceURL) 1706 ). 1707source_url(Stream, Class, SourceURL) :- 1708 is_stream(Stream), 1709 !, 1710 source_url(stream(Stream), Class, SourceURL). 1711source_url(Spec, Protocol, SourceURL) :- 1712 compound(Spec), 1713 !, 1714 source_file(Spec, Protocol, SourceURL). 1715source_url(FileURL, Protocol, SourceURL) :- % or return FileURL? 1716 uri_file_name(FileURL, File), 1717 !, 1718 source_file(File, Protocol, SourceURL). 1719source_url(SourceURL0, Protocol, SourceURL) :- 1720 is_url(SourceURL0, Protocol, SourceURL), 1721 !. 1722source_url(File, Protocol, SourceURL) :- 1723 source_file(File, Protocol, SourceURL). 1724 1725source_file(Spec, file(SExt), SourceURL) :- 1726 findall(Ext, valid_extension(Ext), Exts), 1727 absolute_file_name(Spec, File, [access(read), extensions([''|Exts])]), 1728 storage_extension(_Plain, SExt, File), 1729 uri_file_name(SourceURL, File). 1730 1731to_url(URL, URL) :- 1732 uri_is_global(URL), 1733 !. 1734to_url(File, URL) :- 1735 absolute_file_name(File, Path), 1736 uri_file_name(URL, Path). 1737 1738storage_extension(Plain, SExt, File) :- 1739 file_name_extension(Plain, SExt, File), 1740 SExt \== '', 1741 rdf_storage_encoding(SExt, _), 1742 !. 1743storage_extension(File, '', File).
graph(Graph)
optiondb(Graph)
option (backward compatibility)base_uri(BaseURI)
option1755load_graph(_Source, Graph, Options) :- 1756 option(multifile(true), Options), 1757 !, 1758 ( ( option(graph(Graph), Options) 1759 -> true 1760 ; option(db(Graph), Options) 1761 ), 1762 ground(Graph) 1763 -> true 1764 ; throw(error(existence_error(option, graph), 1765 context(_, "rdf_load/2: using multifile requires graph"))) 1766 ). 1767load_graph(Source, Graph, Options) :- 1768 ( option(graph(Graph), Options) 1769 ; option(db(Graph), Options) 1770 ), 1771 !, 1772 load_graph2(Source, Graph, Options). 1773load_graph(Source, Graph, Options) :- 1774 load_graph2(Source, Graph, Options). 1775 1776load_graph2(_, Graph, _) :- 1777 ground(Graph), 1778 !. 1779load_graph2(_Source, Graph, Options) :- 1780 option(base_uri(Graph), Options), 1781 Graph \== [], 1782 ground(Graph), 1783 !. 1784load_graph2(Source, Graph, _) :- 1785 load_graph(Source, Graph). 1786 1787load_graph(SourceURL, BaseURI) :- 1788 file_name_extension(BaseURI, Ext, SourceURL), 1789 rdf_storage_encoding(Ext, _), 1790 !. 1791load_graph(SourceURL, SourceURL). 1792 1793 1794open_input_if_modified(stream(In), SourceURL, _, In, true, 1795 unknown, Format, _) :- 1796 !, 1797 ( var(Format) 1798 -> guess_format(SourceURL, Format) 1799 ; true 1800 ). 1801open_input_if_modified(file(SExt), SourceURL, HaveModified, Stream, Cleanup, 1802 Modified, Format, _) :- 1803 !, 1804 uri_file_name(SourceURL, File), 1805 ( SExt == '' -> Plain = File; file_name_extension(Plain, SExt, File)), 1806 time_file(File, LastModified), 1807 ( nonvar(HaveModified), 1808 HaveModified >= LastModified 1809 -> Modified = not_modified, 1810 Cleanup = true 1811 ; storage_open(SExt, File, Stream, Cleanup), 1812 Modified = last_modified(LastModified), 1813 ( var(Format) 1814 -> guess_format(Plain, Format) 1815 ; true 1816 ) 1817 ). 1818open_input_if_modified(file, SourceURL, HaveModified, Stream, Cleanup, 1819 Modified, Format, Options) :- 1820 !, 1821 open_input_if_modified(file(''), SourceURL, HaveModified, 1822 Stream, Cleanup, 1823 Modified, Format, Options). 1824open_input_if_modified(Protocol, SourceURL, HaveModified, Stream, Cleanup, 1825 Modified, Format, Options) :- 1826 rdf_open_hook(Protocol, SourceURL, HaveModified, Stream, Cleanup, 1827 Modified, Format, Options). 1828 1829guess_format(File, Format) :- 1830 file_name_extension(_, Ext, File), 1831 ( rdf_file_type(Ext, Format) 1832 -> true 1833 ; Format = xml, 1834 print_message(warning, rdf(guess_format(Ext))) 1835 ).
1843storage_open('', File, Stream, close(Stream)) :- 1844 !, 1845 open(File, read, Stream, [type(binary)]). 1846storage_open(Ext, File, Stream, Cleanup) :- 1847 rdf_storage_encoding(Ext, Encoding), 1848 rdf_open_decode(Encoding, File, Stream, Cleanup). 1849 1850valid_extension(Ext) :- 1851 rdf_file_type(Ext, _). 1852valid_extension(Ext) :- 1853 rdf_storage_encoding(Ext, _).
1863is_url(URL, Scheme, FetchURL) :- 1864 atom(URL), 1865 uri_is_global(URL), 1866 uri_normalized(URL, URL1), % case normalization 1867 uri_components(URL1, Components), 1868 uri_data(scheme, Components, Scheme0), 1869 url_protocol(Scheme0), 1870 !, 1871 Scheme = Scheme0, 1872 uri_data(fragment, Components, _, Components1), 1873 uri_components(FetchURL, Components1). 1874 1875url_protocol(file). % built-in
1883rdf_file_type(xml, xml). 1884rdf_file_type(rdf, xml). 1885rdf_file_type(rdfs, xml). 1886rdf_file_type(owl, xml). 1887rdf_file_type(htm, xhtml). 1888rdf_file_type(html, xhtml). 1889rdf_file_type(xhtml, xhtml). 1890rdf_file_type(trp, triples).
1897rdf_storage_encoding('', plain).
1906rdf_load_stream(xml, Stream, Options) :- 1907 !, 1908 graph(Options, Graph), 1909 rdf_transaction(load_stream(Stream, Options), 1910 parse(Graph)). 1911rdf_load_stream(xhtml, Stream, M:Options) :- 1912 !, 1913 graph(Options, Graph), 1914 rdf_transaction(load_stream(Stream, M:[embedded(true)|Options]), 1915 parse(Graph)). 1916rdf_load_stream(triples, Stream, Options) :- 1917 !, 1918 graph(Options, Graph), 1919 rdf_load_db_(Stream, Graph, _Graphs). 1920 1921load_stream(Stream, M:Options) :- 1922 process_rdf(Stream, assert_triples, M:Options), 1923 option(graph(Graph), Options), 1924 rdf_graph_clear_modified_(Graph).
1929report_loaded(none, _, _, _, _, _) :- !. 1930report_loaded(Action, Source, DB, Triples, T0, Options) :- 1931 statistics(cputime, T1), 1932 Time is T1 - T0, 1933 ( option(silent(true), Options) 1934 -> Level = silent 1935 ; Level = informational 1936 ), 1937 print_message(Level, 1938 rdf(loaded(Action, Source, DB, Triples, Time))).
1951rdf_unload(Spec) :- 1952 source_url(Spec, _Protocol, SourceURL), 1953 rdf_graph_source_(Graph, SourceURL, _), 1954 !, 1955 rdf_unload_graph(Graph). 1956rdf_unload(Graph) :- 1957 atom(Graph), 1958 rdf_graph(Graph), 1959 !, 1960 warn_deprecated_unload(Graph), 1961 rdf_unload_graph(Graph). 1962rdf_unload(_). 1963 1964:- dynamic 1965 warned/0. 1966 1967warn_deprecated_unload(_) :- 1968 warned, 1969 !. 1970warn_deprecated_unload(Graph) :- 1971 assertz(warned), 1972 print_message(warning, rdf(deprecated(rdf_unload(Graph)))).
1980rdf_unload_graph(Graph) :- 1981 must_be(atom, Graph), 1982 ( rdf_graph(Graph) 1983 -> rdf_transaction(do_unload(Graph), unload(Graph)) 1984 ; true 1985 ). 1986 1987do_unload(Graph) :- 1988 ( rdf_graph_(Graph, Triples), 1989 Triples > 0 1990 -> rdf_retractall(_,_,_,Graph) 1991 ; true 1992 ), 1993 rdf_destroy_graph(Graph). 1994 1995 /******************************* 1996 * GRAPH QUERIES * 1997 *******************************/
2009rdf_graph(Graph) :-
2010 rdf_graph_(Graph, _Triples).
2018rdf_source(Graph, SourceURL) :-
2019 rdf_graph(Graph),
2020 rdf_graph_source_(Graph, SourceURL, _Modified).
2028rdf_source(SourceURL) :-
2029 rdf_source(_Graph, SourceURL).
2036rdf_make :- 2037 findall(Source-Graph, modified_graph(Source, Graph), Modified), 2038 forall(member(Source-Graph, Modified), 2039 catch(rdf_load(Source, [graph(Graph), if(changed)]), E, 2040 print_message(error, E))). 2041 2042modified_graph(SourceURL, Graph) :- 2043 rdf_graph(Graph), 2044 rdf_graph_source_(Graph, SourceURL, Modified), 2045 \+ sub_atom(SourceURL, 0, _, _, 'stream://'), 2046 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.2074rdf_graph_property(Graph, Property) :- 2075 rdf_graph(Graph), 2076 property_of_graph(Property, Graph). 2077 2078:- multifile 2079 property_of_graph/2. 2080 2081property_of_graph(hash(Hash), Graph) :- 2082 rdf_md5(Graph, Hash). 2083property_of_graph(modified(Boolean), Graph) :- 2084 rdf_graph_modified_(Graph, Boolean, _). 2085property_of_graph(source(URL), Graph) :- 2086 rdf_graph_source_(Graph, URL, _). 2087property_of_graph(source_last_modified(Time), Graph) :- 2088 rdf_graph_source_(Graph, _, Time), 2089 Time > 0.0. 2090property_of_graph(triples(Count), Graph) :- 2091 rdf_graph_(Graph, Count).
2100rdf_set_graph(Graph, modified(Modified)) :-
2101 must_be(oneof([false]), Modified),
2102 rdf_graph_clear_modified_(Graph).
2109save_cache(DB, Cache) :-
2110 current_prolog_flag(rdf_triple_format, Version),
2111 setup_call_cleanup(
2112 catch(open(Cache, write, CacheStream, [type(binary)]), _, fail),
2113 rdf_save_db_(CacheStream, DB, Version),
2114 close(CacheStream)).
2122assert_triples([], _). 2123assert_triples([rdf(S,P,O)|T], DB) :- 2124 !, 2125 rdf_assert(S, P, O, DB), 2126 assert_triples(T, DB). 2127assert_triples([H|_], _) :- 2128 throw(error(type_error(rdf_triple, H), _)). 2129 2130 2131 /******************************* 2132 * RESET * 2133 *******************************/
2146rdf_reset_db :- 2147 reset_gensym('_:genid'), 2148 rdf_reset_db_. 2149 2150 2151 /******************************* 2152 * SAVE RDF * 2153 *******************************/
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>
.2215:- thread_local 2216 named_anon/2, % +Resource, -Id 2217 inlined/1. % +Resource 2218 2219rdf_save(File) :- 2220 rdf_save2(File, []). 2221 2222rdf_save(Spec, M:Options0) :- 2223 is_list(Options0), 2224 !, 2225 meta_options(save_meta_option, M:Options0, Options), 2226 to_file(Spec, File), 2227 rdf_save2(File, Options). 2228rdf_save(Spec, _:DB) :- 2229 atom(DB), % backward compatibility 2230 !, 2231 to_file(Spec, File), 2232 rdf_save2(File, [graph(DB)]). 2233 2234save_meta_option(convert_typed_literal). 2235 2236to_file(URL, File) :- 2237 atom(URL), 2238 uri_file_name(URL, File), 2239 !. 2240to_file(File, File). 2241 2242rdf_save2(File, Options) :- 2243 option(encoding(Encoding), Options, utf8), 2244 valid_encoding(Encoding), 2245 open_output(File, Encoding, Out, Close), 2246 flag(rdf_db_saved_subjects, OSavedSubjects, 0), 2247 flag(rdf_db_saved_triples, OSavedTriples, 0), 2248 call_cleanup(rdf_do_save(Out, Options), 2249 Reason, 2250 cleanup_save(Reason, 2251 File, 2252 OSavedSubjects, 2253 OSavedTriples, 2254 Close)). 2255 2256open_output(stream(Out), Encoding, Out, Cleanup) :- 2257 !, 2258 stream_property(Out, encoding(Old)), 2259 ( ( Old == Encoding 2260 ; Old == wchar_t % Internal encoding 2261 ) 2262 -> Cleanup = true 2263 ; set_stream(Out, encoding(Encoding)), 2264 Cleanup = set_stream(Out, encoding(Old)) 2265 ). 2266open_output(File, Encoding, Out, 2267 close(Out)) :- 2268 open(File, write, Out, [encoding(Encoding)]). 2269 2270valid_encoding(Enc) :- 2271 ( xml_encoding_name(Enc, _) 2272 -> true 2273 ; throw(error(domain_error(encoding, Enc), _)) 2274 ). 2275 2276 2277cleanup_save(Reason, 2278 File, 2279 OSavedSubjects, 2280 OSavedTriples, 2281 Close) :- 2282 call(Close), 2283 flag(rdf_db_saved_subjects, SavedSubjects, OSavedSubjects), 2284 flag(rdf_db_saved_triples, SavedTriples, OSavedTriples), 2285 retractall(named_anon(_, _)), 2286 retractall(inlined(_)), 2287 ( Reason == exit 2288 -> print_message(informational, 2289 rdf(saved(File, SavedSubjects, SavedTriples))) 2290 ; format(user_error, 'Reason = ~w~n', [Reason]) 2291 ). 2292 2293rdf_do_save(Out, Options0) :- 2294 rdf_save_header(Out, Options0, Options), 2295 graph(Options, DB), 2296 ( option(sorted(true), Options, false) 2297 -> ( var(DB) 2298 -> setof(Subject, rdf_subject(Subject), Subjects) 2299 ; findall(Subject, rdf(Subject, _, _, DB:_), SubjectList), 2300 sort(SubjectList, Subjects) 2301 ), 2302 forall(member(Subject, Subjects), 2303 rdf_save_non_anon_subject(Out, Subject, Options)) 2304 ; forall(rdf_subject_in_graph(Subject, DB), 2305 rdf_save_non_anon_subject(Out, Subject, Options)) 2306 ), 2307 rdf_save_footer(Out), 2308 !. % dubious cut; without the 2309 % cleanup handlers isn't called!?
2320rdf_subject_in_graph(Subject, DB) :- 2321 var(DB), 2322 !, 2323 rdf_subject(Subject). 2324rdf_subject_in_graph(Subject, DB) :- 2325 rdf_statistics(triples(AllTriples)), 2326 rdf_graph_property(DB, triples(DBTriples)), 2327 DBTriples > AllTriples // 10, 2328 !, 2329 rdf_resource(Subject), 2330 ( rdf(Subject, _, _, DB:_) 2331 -> true 2332 ). 2333rdf_subject_in_graph(Subject, DB) :- 2334 findall(Subject, rdf(Subject, _, _, DB:_), SubjectList), 2335 list_to_set(SubjectList, Subjects), 2336 member(Subject, Subjects). 2337 2338 2339graph(Options0, DB) :- 2340 strip_module(Options0, _, Options), 2341 ( memberchk(graph(DB0), Options) 2342 -> DB = DB0 2343 ; memberchk(db(DB0), Options) 2344 -> DB = DB0 2345 ; true % leave unbound 2346 ).
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.2371rdf_save_header(Out, Options) :- 2372 rdf_save_header(Out, Options, _). 2373 2374rdf_save_header(Out, Options, OptionsOut) :- 2375 is_list(Options), 2376 !, 2377 option(encoding(Enc), Options, utf8), 2378 xml_encoding(Enc, Encoding), 2379 format(Out, '<?xml version=\'1.0\' encoding=\'~w\'?>~n', [Encoding]), 2380 format(Out, '<!DOCTYPE rdf:RDF [', []), 2381 header_namespaces(Options, NSIdList), 2382 nsmap(NSIdList, NsMap), 2383 append(Options, [nsmap(NsMap)], OptionsOut), 2384 forall(member(Id=URI, NsMap), 2385 ( xml_quote_attribute(URI, NSText0, Enc), 2386 xml_escape_parameter_entity(NSText0, NSText), 2387 format(Out, '~N <!ENTITY ~w \'~w\'>', [Id, NSText]) 2388 )), 2389 format(Out, '~N]>~n~n', []), 2390 format(Out, '<rdf:RDF', []), 2391 ( member(Id, NSIdList), 2392 format(Out, '~N xmlns:~w="&~w;"~n', [Id, Id]), 2393 fail 2394 ; true 2395 ), 2396 ( option(base_uri(Base), Options), 2397 option(write_xml_base(true), Options, true) 2398 -> xml_quote_attribute(Base, BaseText, Enc), 2399 format(Out, '~N xml:base="~w"~n', [BaseText]) 2400 ; true 2401 ), 2402 ( memberchk(document_language(Lang), Options) 2403 -> format(Out, '~N xml:lang="~w"', [Lang]) 2404 ; true 2405 ), 2406 format(Out, '>~n', []). 2407rdf_save_header(Out, FileRef, OptionsOut) :- % compatibility 2408 atom(FileRef), 2409 rdf_save_header(Out, [graph(FileRef)], OptionsOut). 2410 2411xml_encoding(Enc, Encoding) :- 2412 ( xml_encoding_name(Enc, Encoding) 2413 -> true 2414 ; throw(error(domain_error(rdf_encoding, Enc), _)) 2415 ). 2416 2417xml_encoding_name(ascii, 'US-ASCII'). 2418xml_encoding_name(iso_latin_1, 'ISO-8859-1'). 2419xml_encoding_name(utf8, 'UTF-8').
2426nsmap([], []). 2427nsmap([Id|T0], [Id=URI|T]) :- 2428 ns(Id, URI), 2429 nsmap(T0, T).
2435xml_escape_parameter_entity(In, Out) :- 2436 sub_atom(In, _, _, _, '%'), 2437 !, 2438 atom_codes(In, Codes), 2439 phrase(escape_parent(Codes), OutCodes), 2440 atom_codes(Out, OutCodes). 2441xml_escape_parameter_entity(In, In). 2442 2443escape_parent([]) --> []. 2444escape_parent([H|T]) --> 2445 ( { H == 37 } 2446 -> "%" 2447 ; [H] 2448 ), 2449 escape_parent(T).
2456header_namespaces(Options, List) :- 2457 memberchk(namespaces(NSL0), Options), 2458 !, 2459 sort([rdf,rdfs|NSL0], List). 2460header_namespaces(Options, List) :- 2461 graph(Options, DB), 2462 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)
2500:- thread_local 2501 graph_prefix/3. 2502:- meta_predicate 2503 rdf_graph_prefixes( , , ). 2504 2505rdf_graph_prefixes(Graph, List) :- 2506 rdf_graph_prefixes(Graph, List, []). 2507 2508rdf_graph_prefixes(Graph, List, M:QOptions) :- 2509 is_list(QOptions), 2510 !, 2511 meta_options(is_meta, M:QOptions, Options), 2512 option(filter(Filter), Options, true), 2513 option(expand(Expand), Options, rdf_db), 2514 option(min_count(MinCount), Options, 1), 2515 option(get_prefix(GetPrefix), Options, iri_xml_namespace), 2516 call_cleanup(prefixes(Expand, Graph, Prefixes, Filter, MinCount, GetPrefix), 2517 retractall(graph_prefix(_,_,_))), 2518 sort(Prefixes, List). 2519rdf_graph_prefixes(Graph, List, M:Filter) :- 2520 rdf_graph_prefixes(Graph, List, M:[filter(Filter)]). 2521 2522is_meta(filter). 2523is_meta(expand). 2524is_meta(get_prefix). 2525 2526 2527prefixes(Expand, Graph, Prefixes, Filter, MinCount, GetPrefix) :- 2528 ( call(Expand, S, P, O, Graph), 2529 add_ns(subject, GetPrefix, Filter, S, MinCount, s(S)), 2530 add_ns(predicate, GetPrefix, Filter, P, MinCount, sp(S,P)), 2531 add_ns_obj(GetPrefix, Filter, O, MinCount, spo(S,P,O)), 2532 fail 2533 ; true 2534 ), 2535 findall(Prefix, graph_prefix(Prefix, MinCount, _), Prefixes). 2536 2537add_ns(Where, GetPrefix, Filter, S, MinCount, Context) :- 2538 \+ rdf_is_bnode(S), 2539 call(GetPrefix, S, Full), 2540 Full \== '', 2541 !, 2542 ( graph_prefix(Full, MinCount, _) 2543 -> true 2544 ; Filter == true 2545 -> add_ns(Full, Context) 2546 ; call(Filter, Where, Full, S) 2547 -> add_ns(Full, Context) 2548 ; true 2549 ). 2550add_ns(_, _, _, _, _, _). 2551 2552add_ns(Full, Context) :- 2553 graph_prefix(Full, _, Contexts), 2554 memberchk(Context, Contexts), 2555 !. 2556add_ns(Full, Context) :- 2557 retract(graph_prefix(Full, C0, Contexts)), 2558 !, 2559 C1 is C0+1, 2560 asserta(graph_prefix(Full, C1, [Context|Contexts])). 2561add_ns(Full, _) :- 2562 ns(_, Full), 2563 !, 2564 asserta(graph_prefix(Full, _, _)). 2565add_ns(Full, Context) :- 2566 asserta(graph_prefix(Full, 1, [Context])). 2567 2568 2569add_ns_obj(GetPrefix, Filter, O, MinCount, Context) :- 2570 atom(O), 2571 !, 2572 add_ns(object, GetPrefix, Filter, O, MinCount, Context). 2573add_ns_obj(GetPrefix, Filter, literal(type(Type, _)), MinCount, _) :- 2574 atom(Type), 2575 !, 2576 add_ns(type, GetPrefix, Filter, Type, MinCount, t(Type)). 2577add_ns_obj(_, _, _, _, _).
2587used_namespace_entities(List, Graph) :- 2588 decl_used_predicate_ns(Graph), 2589 used_namespaces(List, Graph). 2590 2591used_namespaces(List, DB) :- 2592 rdf_graph_prefixes(DB, FullList), 2593 ns_abbreviations(FullList, List0), 2594 sort([rdf|List0], List). 2595 2596ns_abbreviations([], []). 2597ns_abbreviations([H0|T0], [H|T]) :- 2598 ns(H, H0), 2599 !, 2600 ns_abbreviations(T0, T). 2601ns_abbreviations([_|T0], T) :- 2602 ns_abbreviations(T0, T). 2603 2604 2605/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2606For every URL used as a predicate we *MUST* define a namespace as we 2607cannot use names holding /, :, etc. as XML identifiers. 2608- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 2609 2610:- thread_local 2611 predicate_ns/2. 2612 2613decl_used_predicate_ns(DB) :- 2614 retractall(predicate_ns(_,_)), 2615 ( rdf_current_predicate(P, DB), 2616 decl_predicate_ns(P), 2617 fail 2618 ; true 2619 ). 2620 2621decl_predicate_ns(Pred) :- 2622 predicate_ns(Pred, _), 2623 !. 2624decl_predicate_ns(Pred) :- 2625 rdf_global_id(NS:Local, Pred), 2626 xml_name(Local), 2627 !, 2628 assert(predicate_ns(Pred, NS)). 2629decl_predicate_ns(Pred) :- 2630 atom_codes(Pred, Codes), 2631 append(NSCodes, LocalCodes, Codes), 2632 xml_codes(LocalCodes), 2633 !, 2634 ( NSCodes \== [] 2635 -> atom_codes(NS, NSCodes), 2636 ( ns(Id, NS) 2637 -> assert(predicate_ns(Pred, Id)) 2638 ; between(1, infinite, N), 2639 atom_concat(ns, N, Id), 2640 \+ ns(Id, _) 2641 -> rdf_register_ns(Id, NS), 2642 print_message(informational, 2643 rdf(using_namespace(Id, NS))) 2644 ), 2645 assert(predicate_ns(Pred, Id)) 2646 ; assert(predicate_ns(Pred, -)) % no namespace used 2647 ). 2648 2649xml_codes([]). 2650xml_codes([H|T]) :- 2651 xml_code(H), 2652 xml_codes(T). 2653 2654xml_code(X) :- 2655 code_type(X, csym), 2656 !. 2657xml_code(0'-). % Match 0'-
2666rdf_save_footer(Out) :-
2667 retractall(named_anon(_, _)),
2668 retractall(inlined(_)),
2669 format(Out, '</rdf:RDF>~n', []).
anon(false)
is present in the Options list.2676rdf_save_non_anon_subject(_Out, Subject, Options) :- 2677 rdf_is_bnode(Subject), 2678 ( memberchk(anon(false), Options) 2679 ; graph(Options, DB), 2680 rdf_db(_, _, Subject, DB) 2681 ), 2682 !. 2683rdf_save_non_anon_subject(Out, Subject, Options) :- 2684 rdf_save_subject(Out, Subject, Options), 2685 flag(rdf_db_saved_subjects, X, X+1).
2700rdf_save_subject(Out, Subject, Options) :- 2701 is_list(Options), 2702 !, 2703 option(base_uri(BaseURI), Options, '-'), 2704 ( rdf_save_subject(Out, Subject, BaseURI, 0, Options) 2705 -> format(Out, '~n', []) 2706 ; throw(error(rdf_save_failed(Subject), 'Internal error')) 2707 ). 2708rdf_save_subject(Out, Subject, DB) :- 2709 ( var(DB) 2710 -> rdf_save_subject(Out, Subject, []) 2711 ; rdf_save_subject(Out, Subject, [graph(DB)]) 2712 ).
2722rdf_save_subject(_, Subject, _, _, _) :- 2723 inlined(Subject), 2724 !. 2725rdf_save_subject(Out, Subject, BaseURI, Indent, Options) :- 2726 do_save_subject(Out, Subject, BaseURI, Indent, Options). 2727 2728do_save_subject(Out, Subject, BaseURI, Indent, Options) :- 2729 graph(Options, DB), 2730 findall(Pred=Object, rdf_db(Subject, Pred, Object, DB), Atts0), 2731 sort(Atts0, Atts), % remove duplicates 2732 length(Atts, L), 2733 ( length(Atts0, L0), 2734 Del is L0-L, 2735 Del > 0 2736 -> print_message(informational, 2737 rdf(save_removed_duplicates(Del, Subject))) 2738 ; true 2739 ), 2740 rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options), 2741 flag(rdf_db_saved_triples, X, X+L). 2742 2743rdf_db(Subject, Pred, Object, DB) :- 2744 var(DB), 2745 !, 2746 rdf(Subject, Pred, Object). 2747rdf_db(Subject, Pred, Object, DB) :- 2748 rdf(Subject, Pred, Object, DB:_).
2755rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options) :- 2756 rdf_equal(rdf:type, RdfType), 2757 select(RdfType=Type, Atts, Atts1), 2758 \+ rdf_is_bnode(Type), 2759 rdf_id(Type, BaseURI, TypeId), 2760 xml_is_name(TypeId), 2761 !, 2762 format(Out, '~*|<', [Indent]), 2763 rdf_write_id(Out, TypeId), 2764 save_about(Out, BaseURI, Subject, Options), 2765 save_attributes(Atts1, BaseURI, Out, TypeId, Indent, Options). 2766rdf_save_subject(Out, Subject, BaseURI, Atts, Indent, Options) :- 2767 format(Out, '~*|<rdf:Description', [Indent]), 2768 save_about(Out, BaseURI, Subject, Options), 2769 save_attributes(Atts, BaseURI, Out, rdf:'Description', Indent, Options). 2770 2771xml_is_name(_NS:Atom) :- 2772 !, 2773 xml_name(Atom). 2774xml_is_name(Atom) :- 2775 xml_name(Atom).
2782save_about(Out, _BaseURI, Subject, _Options) :- 2783 rdf_is_bnode(Subject), 2784 !, 2785 ( named_anon(Subject, NodeID) 2786 -> format(Out, ' rdf:nodeID="~w"', [NodeID]) 2787 ; true 2788 ). 2789save_about(Out, BaseURI, Subject, Options) :- 2790 option(encoding(Encoding), Options, utf8), 2791 rdf_value(Subject, BaseURI, QSubject, Encoding), 2792 format(Out, ' rdf:about="~w"', [QSubject]).
2800save_attributes(Atts, BaseURI, Out, Element, Indent, Options) :-
2801 split_attributes(Atts, InTag, InBody, Options),
2802 SubIndent is Indent + 2,
2803 save_attributes2(InTag, BaseURI, tag, Out, SubIndent, Options),
2804 ( InBody == []
2805 -> format(Out, '/>~n', [])
2806 ; format(Out, '>~n', []),
2807 save_attributes2(InBody, BaseURI, body, Out, SubIndent, Options),
2808 format(Out, '~N~*|</', [Indent]),
2809 rdf_write_id(Out, Element),
2810 format(Out, '>~n', [])
2811 ).
2819split_attributes(Atts, [], Atts, Options) :- 2820 option(xml_attributes(false), Options), 2821 !. 2822split_attributes(Atts, HeadAttr, BodyAttr, _) :- 2823 duplicate_attributes(Atts, Dupls, Singles), 2824 simple_literal_attributes(Singles, HeadAttr, Rest), 2825 append(Dupls, Rest, BodyAttr).
2832duplicate_attributes([], [], []). 2833duplicate_attributes([H|T], Dupls, Singles) :- 2834 H = (Name=_), 2835 named_attributes(Name, T, D, R), 2836 D \== [], 2837 append([H|D], Dupls2, Dupls), 2838 !, 2839 duplicate_attributes(R, Dupls2, Singles). 2840duplicate_attributes([H|T], Dupls2, [H|Singles]) :- 2841 duplicate_attributes(T, Dupls2, Singles). 2842 2843named_attributes(_, [], [], []) :- !. 2844named_attributes(Name, [H|T], D, R) :- 2845 ( H = (Name=_) 2846 -> D = [H|DT], 2847 named_attributes(Name, T, DT, R) 2848 ; R = [H|RT], 2849 named_attributes(Name, T, D, RT) 2850 ).
2857simple_literal_attributes([], [], []). 2858simple_literal_attributes([H|TA], [H|TI], B) :- 2859 in_tag_attribute(H), 2860 !, 2861 simple_literal_attributes(TA, TI, B). 2862simple_literal_attributes([H|TA], I, [H|TB]) :- 2863 simple_literal_attributes(TA, I, TB). 2864 2865in_tag_attribute(_=literal(Text)) :- 2866 atom(Text), % may not have lang qualifier 2867 atom_length(Text, Len), 2868 Len < 60.
2874save_attributes2([], _, _, _, _, _). 2875save_attributes2([H|T], BaseURI, Where, Out, Indent, Options) :- 2876 save_attribute(Where, H, BaseURI, Out, Indent, Options), 2877 save_attributes2(T, BaseURI, Where, Out, Indent, Options). 2878 2879save_attribute(tag, Name=literal(Value), BaseURI, Out, Indent, Options) :- 2880 AttIndent is Indent + 2, 2881 rdf_id(Name, BaseURI, NameText), 2882 option(encoding(Encoding), Options, utf8), 2883 xml_quote_attribute(Value, QVal, Encoding), 2884 format(Out, '~N~*|', [AttIndent]), 2885 rdf_write_id(Out, NameText), 2886 format(Out, '="~w"', [QVal]). 2887save_attribute(body, Name=literal(Literal0), BaseURI, Out, Indent, Options) :- 2888 !, 2889 rdf_id(Name, BaseURI, NameText), 2890 ( memberchk(convert_typed_literal(Converter), Options), 2891 call(Converter, Type, Content, Literal0) 2892 -> Literal = type(Type, Content) 2893 ; Literal = Literal0 2894 ), 2895 save_body_literal(Literal, NameText, BaseURI, Out, Indent, Options). 2896save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :- 2897 rdf_is_bnode(Value), 2898 !, 2899 rdf_id(Name, BaseURI, NameText), 2900 format(Out, '~N~*|<', [Indent]), 2901 rdf_write_id(Out, NameText), 2902 ( named_anon(Value, NodeID) 2903 -> format(Out, ' rdf:nodeID="~w"/>', [NodeID]) 2904 ; ( rdf(S1, Name, Value), 2905 rdf(S2, P2, Value), 2906 (S1 \== S2 ; Name \== P2) 2907 -> predicate_property(named_anon(_,_), number_of_clauses(N)), 2908 atom_concat('bn', N, NodeID), 2909 assertz(named_anon(Value, NodeID)) 2910 ; true 2911 ), 2912 SubIndent is Indent + 2, 2913 ( rdf_collection(Value) 2914 -> save_about(Out, BaseURI, Value, Options), 2915 format(Out, ' rdf:parseType="Collection">~n', []), 2916 rdf_save_list(Out, Value, BaseURI, SubIndent, Options) 2917 ; format(Out, '>~n', []), 2918 rdf_save_subject(Out, Value, BaseURI, SubIndent, Options) 2919 ), 2920 format(Out, '~N~*|</', [Indent]), 2921 rdf_write_id(Out, NameText), 2922 format(Out, '>~n', []) 2923 ). 2924save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :- 2925 option(inline(true), Options), 2926 has_attributes(Value, Options), 2927 \+ inlined(Value), 2928 !, 2929 assertz(inlined(Value)), 2930 rdf_id(Name, BaseURI, NameText), 2931 format(Out, '~N~*|<', [Indent]), 2932 rdf_write_id(Out, NameText), 2933 SubIndent is Indent + 2, 2934 ( rdf_collection(Value) 2935 -> save_about(Out, BaseURI, Value, Options), 2936 format(Out, ' rdf:parseType="Collection">~n', []), 2937 rdf_save_list(Out, Value, BaseURI, SubIndent, Options) 2938 ; format(Out, '>~n', []), 2939 do_save_subject(Out, Value, BaseURI, SubIndent, Options) 2940 ), 2941 format(Out, '~N~*|</', [Indent]), 2942 rdf_write_id(Out, NameText), 2943 format(Out, '>~n', []). 2944save_attribute(body, Name=Value, BaseURI, Out, Indent, Options) :- 2945 option(encoding(Encoding), Options, utf8), 2946 rdf_value(Value, BaseURI, QVal, Encoding), 2947 rdf_id(Name, BaseURI, NameText), 2948 format(Out, '~N~*|<', [Indent]), 2949 rdf_write_id(Out, NameText), 2950 format(Out, ' rdf:resource="~w"/>', [QVal]). 2951 2952has_attributes(URI, Options) :- 2953 graph(Options, DB), 2954 rdf_db(URI, _, _, DB), 2955 !.
2960save_body_literal(lang(Lang, Value), 2961 NameText, BaseURI, Out, Indent, Options) :- 2962 !, 2963 format(Out, '~N~*|<', [Indent]), 2964 rdf_write_id(Out, NameText), 2965 ( memberchk(document_language(Lang), Options) 2966 -> write(Out, '>') 2967 ; rdf_id(Lang, BaseURI, LangText), 2968 format(Out, ' xml:lang="~w">', [LangText]) 2969 ), 2970 save_attribute_value(Value, Out, Options), 2971 write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>'). 2972save_body_literal(type(Type, DOM), 2973 NameText, _BaseURI, Out, Indent, Options) :- 2974 rdf_equal(Type, rdf:'XMLLiteral'), 2975 !, 2976 ( atom(DOM) 2977 -> format(Out, '~N~*|<', [Indent]), 2978 rdf_write_id(Out, NameText), 2979 format(Out, ' rdf:parseType="Literal">~w</', [DOM]), 2980 rdf_write_id(Out, NameText), write(Out, '>') 2981 ; save_xml_literal(DOM, NameText, Out, Indent, Options) 2982 ). 2983save_body_literal(type(Type, Value), 2984 NameText, BaseURI, Out, Indent, Options) :- 2985 !, 2986 format(Out, '~N~*|<', [Indent]), 2987 rdf_write_id(Out, NameText), 2988 option(encoding(Encoding), Options, utf8), 2989 rdf_value(Type, BaseURI, QVal, Encoding), 2990 format(Out, ' rdf:datatype="~w">', [QVal]), 2991 save_attribute_value(Value, Out, Options), 2992 write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>'). 2993save_body_literal(Literal, 2994 NameText, _, Out, Indent, Options) :- 2995 atomic(Literal), 2996 !, 2997 format(Out, '~N~*|<', [Indent]), 2998 rdf_write_id(Out, NameText), 2999 write(Out, '>'), 3000 save_attribute_value(Literal, Out, Options), 3001 write(Out, '</'), rdf_write_id(Out, NameText), write(Out, '>'). 3002save_body_literal(DOM, 3003 NameText, BaseURI, Out, Indent, Options) :- 3004 rdf_equal(Type, rdf:'XMLLiteral'), 3005 save_body_literal(type(Type, DOM), 3006 NameText, BaseURI, Out, Indent, Options). 3007 3008save_attribute_value(Value, Out, Options) :- % strings 3009 ( atom(Value) 3010 ; string(Value) 3011 ), 3012 !, 3013 option(encoding(Encoding), Options, utf8), 3014 xml_quote_cdata(Value, QVal, Encoding), 3015 write(Out, QVal). 3016save_attribute_value(Value, Out, _Options) :- % numbers 3017 number(Value), 3018 !, 3019 writeq(Out, Value). % quoted: preserve floats 3020save_attribute_value(Value, _Out, _Options) :- 3021 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.
3035save_xml_literal(DOM, Attr, Out, Indent, Options) :- 3036 xml_is_dom(DOM), 3037 !, 3038 memberchk(nsmap(NsMap), Options), 3039 id_to_atom(Attr, Atom), 3040 xml_write(Out, 3041 element(Atom, ['rdf:parseType'='Literal'], DOM), 3042 [ header(false), 3043 indent(Indent), 3044 nsmap(NsMap) 3045 ]). 3046save_xml_literal(NoDOM, _, _, _, _) :- 3047 must_be(xml_dom, NoDOM). 3048 3049id_to_atom(NS:Local, Atom) :- 3050 !, 3051 atomic_list_concat([NS,Local], :, Atom). 3052id_to_atom(ID, ID).
3062:- rdf_meta 3063 rdf_collection(r), 3064 collection_p(r,r). 3065 3066rdf_collection(rdf:nil) :- !. 3067rdf_collection(Cell) :- 3068 rdf_is_bnode(Cell), 3069 findall(F, rdf(Cell, rdf:first, F), [_]), 3070 findall(F, rdf(Cell, rdf:rest, F), [Rest]), 3071 forall(rdf(Cell, P, V), 3072 collection_p(P, V)), 3073 rdf_collection(Rest). 3074 3075collection_p(rdf:first, V) :- atom(V). 3076collection_p(rdf:rest, _). 3077collection_p(rdf:type, rdf:'List').
3082rdf_save_list(_, List, _, _, _) :- 3083 rdf_equal(List, rdf:nil), 3084 !. 3085rdf_save_list(Out, List, BaseURI, Indent, Options) :- 3086 rdf_has(List, rdf:first, First), 3087 ( rdf_is_bnode(First) 3088 -> nl(Out), 3089 rdf_save_subject(Out, First, BaseURI, Indent, Options) 3090 ; option(encoding(Encoding), Options, utf8), 3091 rdf_value(First, BaseURI, QVal, Encoding), 3092 format(Out, '~N~*|<rdf:Description rdf:about="~w"/>', 3093 [Indent, QVal]) 3094 ), 3095 flag(rdf_db_saved_triples, X, X+3), 3096 ( rdf_has(List, rdf:rest, List2), 3097 \+ rdf_equal(List2, rdf:nil) 3098 -> rdf_save_list(Out, List2, BaseURI, Indent, Options) 3099 ; true 3100 ).
3108rdf_id(Id, BaseURI, Local) :- 3109 assertion(atom(BaseURI)), 3110 atom_concat(BaseURI, Local, Id), 3111 sub_atom(Local, 0, 1, _, #), 3112 !. 3113rdf_id(Id, _, NS:Local) :- 3114 iri_xml_namespace(Id, Full, Local), 3115 ns(NS, Full), 3116 !. 3117rdf_id(Id, _, NS:Local) :- 3118 ns(NS, Full), 3119 Full \== '', 3120 atom_concat(Full, Local, Id), 3121 !. 3122rdf_id(Id, _, Id).
3130rdf_write_id(Out, NS:Local) :- 3131 !, 3132 format(Out, '~w:~w', [NS, Local]). 3133rdf_write_id(Out, Atom) :- 3134 write(Out, Atom).
3143rdf_value(Base, Base, '', _) :- !. 3144rdf_value(V, Base, Text, Encoding) :- 3145 atom_concat(Base, Local, V), 3146 sub_atom(Local, 0, _, _, #), 3147 !, 3148 xml_quote_attribute(Local, Text, Encoding). 3149rdf_value(V, _, Text, Encoding) :- 3150 ns(NS, Full), 3151 atom_concat(Full, Local, V), 3152 xml_is_name(Local), 3153 !, 3154 xml_quote_attribute(Local, QLocal, Encoding), 3155 atomic_list_concat(['&', NS, (';'), QLocal], Text). 3156rdf_value(V, _, Q, Encoding) :- 3157 xml_quote_attribute(V, Q, Encoding). 3158 3159 3160 /******************************* 3161 * MATCH AND COMPARE * 3162 *******************************/
icase
, substring
, word
, prefix
or like
. For backward
compatibility, exact
is a synonym for icase
.3185 /******************************* 3186 * DEPRECATED MATERIAL * 3187 *******************************/
3197rdf_split_url(Prefix, Local, URL) :- 3198 atomic(URL), 3199 !, 3200 iri_xml_namespace(URL, Prefix, Local). 3201rdf_split_url(Prefix, Local, URL) :- 3202 atom_concat(Prefix, Local, URL).
3210rdf_url_namespace(URL, Prefix) :- 3211 iri_xml_namespace(URL, Prefix). 3212 3213 3214 /******************************* 3215 * LITERALS * 3216 *******************************/
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).3304 /******************************* 3305 * MISC * 3306 *******************************/
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.
3403 /******************************* 3404 * MESSAGES * 3405 *******************************/ 3406 3407:- multifile 3408 prolog:message//1. 3409 3410prologmessage(rdf(Term)) --> 3411 message(Term). 3412 3413message(loaded(How, What, BaseURI, Triples, Time)) --> 3414 how(How), 3415 source(What), 3416 into(What, BaseURI), 3417 in_time(Triples, Time). 3418message(save_removed_duplicates(N, Subject)) --> 3419 [ 'Removed ~d duplicate triples about "~p"'-[N,Subject] ]. 3420message(saved(File, SavedSubjects, SavedTriples)) --> 3421 [ 'Saved ~D triples about ~D subjects into ~p'- 3422 [SavedTriples, SavedSubjects, File] 3423 ]. 3424message(using_namespace(Id, NS)) --> 3425 [ 'Using namespace id ~w for ~w'-[Id, NS] ]. 3426message(inconsistent_cache(DB, Graphs)) --> 3427 [ 'RDF cache file for ~w contains the following graphs'-[DB], nl, 3428 '~t~8|~p'-[Graphs] 3429 ]. 3430message(guess_format(Ext)) --> 3431 [ 'Unknown file-extension: ~w. Assuming RDF/XML'-[Ext] ]. 3432message(meta(not_expanded(G))) --> 3433 [ 'rdf_meta/1: ~p is not expanded'-[G] ]. 3434message(deprecated(rdf_unload(Graph))) --> 3435 [ 'rdf_unload/1: Use ~q'-[rdf_unload_graph(Graph)] ]. 3436 3437 3438how(load) --> [ 'Loaded' ]. 3439how(parsed) --> [ 'Parsed' ]. 3440 3441source(SourceURL) --> 3442 { uri_file_name(SourceURL, File), 3443 !, 3444 file_base_name(File, Base) % TBD: relative file? 3445 }, 3446 [ ' "~w"'-[Base] ]. 3447source(SourceURL) --> 3448 [ ' "~w"'-[SourceURL] ]. 3449 3450into(_, _) --> []. % TBD 3451 3452in_time(Triples, ParseTime) --> 3453 [ ' in ~2f sec; ~D triples'-[ParseTime, Triples] 3454 ]
Core RDF database
The file library(semweb/rdf_db) provides the core of the SWI-Prolog RDF store.