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) 2010-2013, University of Amsterdam 7 All rights reserved. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions 11 are met: 12 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in 18 the documentation and/or other materials provided with the 19 distribution. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 POSSIBILITY OF SUCH DAMAGE. 33*/ 34 35:- module(rdf_triple, 36 [ rdf_triples/2, % +Parsed, -Tripples 37 rdf_triples/3, % +Parsed, -Tripples, +Tail 38 rdf_reset_ids/0, % Reset gensym id's 39 rdf_start_file/2, % +Options, -Cleanup 40 rdf_end_file/1, % +Cleanup 41 anon_prefix/1 % Prefix for anonynmous resources 42 ]). 43:- autoload(library(gensym),[gensym/2,reset_gensym/1]). 44:- autoload(library(option),[option/3,option/2]). 45:- autoload(library(rdf_parser),[rdf_name_space/1]). 46:- autoload(library(uri),[iri_normalized/2]). 47 48 49:- predicate_options(rdf_start_file/2, 1, 50 [ base_uri(atom), 51 blank_nodes(oneof([share,noshare])) 52 ]).
rdf.pl
into a list of rdf/3
triples. The identifier of the main object created is returned
by rdf_triples/3.
Input is the `content' of the RDF element in the format as
generated by load_structure(File, Term, [dialect(xmlns)])
.
rdf_triples/3 can process both individual descriptions as
well as the entire content-list of an RDF element. The first
mode is suitable when using library(sgml) in `call-back' mode.
100rdf_triples(RDF, Tripples) :- 101 rdf_triples(RDF, Tripples, []). 102 103rdf_triples([]) --> 104 !, 105 []. 106rdf_triples([H|T]) --> 107 !, 108 rdf_triples(H), 109 rdf_triples(T). 110rdf_triples(Term) --> 111 triples(Term, _).
118triples(description(Type, About, Props), Subject) --> 119 { var(About), 120 share_blank_nodes(true) 121 }, 122 !, 123 ( { shared_description(description(Type, Props), Subject) 124 } 125 -> [] 126 ; { make_id('_:Description', Id) 127 }, 128 triples(description(Type, about(Id), Props), Subject), 129 { assert_shared_description(description(Type, Props), Subject) 130 } 131 ). 132triples(description(description, IdAbout, Props), Subject) --> 133 !, 134 { description_id(IdAbout, Subject) 135 }, 136 properties(Props, Subject). 137triples(description(TypeURI, IdAbout, Props), Subject) --> 138 { description_id(IdAbout, Subject) 139 }, 140 properties([ rdf:type = TypeURI 141 | Props 142 ], Subject). 143triples(unparsed(Data), Id) --> 144 { make_id('_:Error', Id), 145 print_message(error, rdf(unparsed(Data))) 146 }, 147 []. 148 149 150 /******************************* 151 * DESCRIPTIONS * 152 *******************************/ 153 154:- thread_local 155 node_id/2, % nodeID --> ID 156 unique_id/1. % known rdf:ID 157 158rdf_reset_node_ids :- 159 retractall(node_id(_,_)), 160 retractall(unique_id(_)). 161 162description_id(Id, Id) :- 163 var(Id), 164 !, 165 make_id('_:Description', Id). 166description_id(about(Id), Id). 167description_id(id(Id), Id) :- 168 ( unique_id(Id) 169 -> print_message(error, rdf(redefined_id(Id))) 170 ; assert(unique_id(Id)) 171 ). 172description_id(each(Id), each(Id)). 173description_id(prefix(Id), prefix(Id)). 174description_id(node(NodeID), Id) :- 175 ( node_id(NodeID, Id) 176 -> true 177 ; make_id('_:Node', Id), 178 assert(node_id(NodeID, Id)) 179 ). 180 181properties(PlRDF, Subject) --> 182 properties(PlRDF, 1, [], [], Subject). 183 184properties([], _, Bag, Bag, _) --> 185 []. 186properties([H0|T0], N, Bag0, Bag, Subject) --> 187 property(H0, N, NN, Bag0, Bag1, Subject), 188 properties(T0, NN, Bag1, Bag, Subject).
202property(Pred0 = Object, N, NN, BagH, BagT, Subject) --> % inlined object 203 triples(Object, Id), 204 !, 205 { li_pred(Pred0, Pred, N, NN) 206 }, 207 statement(Subject, Pred, Id, _, BagH, BagT). 208property(Pred0 = collection(Elems), N, NN, BagH, BagT, Subject) --> 209 !, 210 { li_pred(Pred0, Pred, N, NN) 211 }, 212 statement(Subject, Pred, Object, _Id, BagH, BagT), 213 collection(Elems, Object). 214property(Pred0 = Object, N, NN, BagH, BagT, Subject) --> 215 !, 216 { li_pred(Pred0, Pred, N, NN) 217 }, 218 statement(Subject, Pred, Object, _Id, BagH, BagT). 219property(id(Id, Pred0 = Object), N, NN, BagH, BagT, Subject) --> 220 triples(Object, ObjectId), 221 !, 222 { li_pred(Pred0, Pred, N, NN) 223 }, 224 statement(Subject, Pred, ObjectId, Id, BagH, BagT). 225property(id(Id, Pred0 = collection(Elems)), N, NN, BagH, BagT, Subject) --> 226 !, 227 { li_pred(Pred0, Pred, N, NN) 228 }, 229 statement(Subject, Pred, Object, Id, BagH, BagT), 230 collection(Elems, Object). 231property(id(Id, Pred0 = Object), N, NN, BagH, BagT, Subject) --> 232 { li_pred(Pred0, Pred, N, NN) 233 }, 234 statement(Subject, Pred, Object, Id, BagH, BagT).
nonvar(Id)
, we reinify the
statement using the given Id.241statement(Subject, Pred, Object, Id, BagH, BagT) --> 242 rdf(Subject, Pred, Object), 243 { BagH = [Id|BagT] 244 -> statement_id(Id) 245 ; BagT = BagH 246 }, 247 ( { nonvar(Id) 248 } 249 -> rdf(Id, rdf:type, rdf:'Statement'), 250 rdf(Id, rdf:subject, Subject), 251 rdf(Id, rdf:predicate, Pred), 252 rdf(Id, rdf:object, Object) 253 ; [] 254 ). 255 256 257statement_id(Id) :- 258 nonvar(Id), 259 !. 260statement_id(Id) :- 261 make_id('_:Statement', Id).
267li_pred(rdf:li, rdf:Pred, N, NN) :- 268 !, 269 NN is N + 1, 270 atom_concat('_', N, Pred). 271li_pred(Pred, Pred, N, N).
278collection([], Nil) --> 279 { global_ref(rdf:nil, Nil) 280 }. 281collection([H|T], Id) --> 282 triples(H, HId), 283 { make_id('_:List', Id) 284 }, 285 rdf(Id, rdf:type, rdf:'List'), 286 rdf(Id, rdf:first, HId), 287 rdf(Id, rdf:rest, TId), 288 collection(T, TId). 289 290 291rdf(S0, P0, O0) --> 292 { global_ref(S0, S), 293 global_ref(P0, P), 294 global_obj(O0, O) 295 }, 296 [ rdf(S, P, O) ]. 297 298 299global_ref(In, Out) :- 300 ( nonvar(In), 301 In = NS:Local 302 -> ( NS == rdf, 303 rdf_name_space(RDF) 304 -> atom_concat(RDF, Local, Out) 305 ; atom_concat(NS, Local, Out0), 306 iri_normalized(Out0, Out) 307 ) 308 ; Out = In 309 ). 310 311global_obj(V, V) :- 312 var(V), 313 !. 314global_obj(literal(type(Local, X)), literal(type(Global, X))) :- 315 !, 316 global_ref(Local, Global). 317global_obj(literal(X), literal(X)) :- !. 318global_obj(Local, Global) :- 319 global_ref(Local, Global). 320 321 322 /******************************* 323 * SHARING * 324 *******************************/ 325 326:- thread_local 327 shared_description/3, % +Hash, +Term, -Subject 328 share_blank_nodes/1, % Boolean 329 shared_nodes/1. % counter 330 :- 332 retractall(shared_description(_,_,_)), 333 retractall(shared_nodes(_)). 334 Term, Subject) (:- 336 term_hash(Term, Hash), 337 shared_description(Hash, Term, Subject), 338 ( retract(shared_nodes(N)) 339 -> N1 is N + 1 340 ; N1 = 1 341 ), 342 assert(shared_nodes(N1)). 343 344 Term, Subject) (:- 346 term_hash(Term, Hash), 347 assert(shared_description(Hash, Term, Subject)). 348 349 350 /******************************* 351 * START/END * 352 *******************************/
358rdf_start_file(Options, Cleanup) :-
359 rdf_reset_node_ids, % play safe
360 reset_shared_descriptions,
361 set_bnode_sharing(Options, C1),
362 set_anon_prefix(Options, C2),
363 add_cleanup(C1, C2, Cleanup).
369rdf_end_file(Cleanup) :- 370 rdf_reset_node_ids, 371 ( shared_nodes(N) 372 -> print_message(informational, rdf(shared_blank_nodes(N))) 373 ; true 374 ), 375 reset_shared_descriptions, 376 . 377 378set_bnode_sharing(Options, erase(Ref)) :- 379 option(blank_nodes(Share), Options, noshare), 380 ( Share == share 381 -> assert(share_blank_nodes(true), Ref), ! 382 ; Share == noshare 383 -> fail % next clause 384 ; throw(error(domain_error(share, Share), _)) 385 ). 386set_bnode_sharing(_, true). 387 388set_anon_prefix(Options, erase(Ref)) :- 389 option(base_uri(BaseURI), Options), 390 nonvar(BaseURI), 391 !, 392 ( BaseURI == [] 393 -> AnonBase = '_:' 394 ; atomic_list_concat(['_:', BaseURI, '#'], AnonBase) 395 ), 396 asserta(anon_prefix(AnonBase), Ref). 397set_anon_prefix(_, true). 398 399add_cleanup(true, X, X) :- !. 400add_cleanup(X, true, X) :- !. 401add_cleanup(X, Y, (X, Y)). 402 403 404 /******************************* 405 * UTIL * 406 *******************************/
412:- thread_local 413 anon_prefix/1. 414 415make_id(For, ID) :- 416 anon_prefix(Prefix), 417 !, 418 atom_concat(Prefix, For, Base), 419 gensym(Base, ID). 420make_id(For, ID) :- 421 gensym(For, ID). 422 423anon_base('_:Description'). 424anon_base('_:Statement'). 425anon_base('_:List'). 426anon_base('_:Node').
rdf_test.pl
).434rdf_reset_ids :- 435 anon_prefix(Prefix), 436 !, 437 ( anon_base(Base), 438 atom_concat(Prefix, Base, X), 439 reset_gensym(X), 440 fail 441 ; true 442 ). 443rdf_reset_ids :- 444 ( anon_base(Base), 445 reset_gensym(Base), 446 fail 447 ; true 448 )
Create triples from intermediate representation
Convert the output of xml_to_rdf/3 from library(rdf) into a list of triples of the format described below. The intermediate representation should be regarded a proprietary representation.
Where `Subject' is
And `Predicate' is
And `Object' is