35
36:- module(sparql_client,
37 [ sparql_query/3, 38 sparql_set_server/1, 39 sparql_read_xml_result/2, 40 sparql_read_json_result/2 41 ]). 42:- use_module(library(http/http_open)). 43:- use_module(library(http/json)). 44:- use_module(library(lists)). 45:- use_module(library(rdf)). 46:- use_module(library(semweb/turtle)). 47:- use_module(library(option)). 48
80
81
115
116sparql_query(Query, Row, Options) :-
117 sparql_param(scheme(Scheme), Options, Options1),
118 sparql_port(Scheme, Port, Options1, Options2),
119 sparql_param(host(Host), Options2, Options3),
120 sparql_param(path(Path), Options3, Options4),
121 select_option(search(Extra), Options4, Options5, []),
122 select_option(variable_names(VarNames), Options5, Options6, _),
123 sparql_extra_headers(HTTPOptions),
124 http_open([ scheme(Scheme),
125 host(Host),
126 port(Port),
127 path(Path),
128 search([ query = Query
129 | Extra
130 ])
131 | Options6
132 ], In,
133 [ header(content_type, ContentType),
134 status_code(Status)
135 | HTTPOptions
136 ]),
137 plain_content_type(ContentType, CleanType),
138 read_reply(Status, CleanType, In, VarNames, Row).
139
146
(
148 [ request_header('Accept' = 'application/sparql-results+xml, \c
149 application/n-triples, \c
150 application/x-turtle; q=0.9, \c
151 application/turtle; q=0.9, \c
152 text/turtle, \c
153 application/sparql-results+json, \c
154 application/rdf+xml, \c
155 text/rdf+xml; q=0.8, \c
156 */*; q=0.1'),
157 cert_verify_hook(ssl_verify)
158 ]).
159
160:- public ssl_verify/5. 161
165
166ssl_verify(_SSL,
167 _ProblemCertificate, _AllCertificates, _FirstCertificate,
168 _Error).
169
171
172read_reply(200, ContentType, In, Close, Row) :-
173 !,
174 read_reply(ContentType, In, Close, Row).
175read_reply(Status, _ContentType, In, _Close, _Row) :-
176 call_cleanup(read_string(In, _, Reply),
177 close(In, [force(true)])),
178 throw(error(sparql_error(Status, Reply), _)).
179
180read_reply('application/rdf+xml', In, _, Row) :-
181 !,
182 call_cleanup(load_rdf(stream(In), RDF), close(In)),
183 member(Row, RDF).
184read_reply(MIME, In, _, Row) :-
185 turtle_media_type(MIME),
186 !,
187 call_cleanup(rdf_read_turtle(stream(In), RDF, []), close(In)),
188 member(Row, RDF).
189read_reply(MIME, In, VarNames, Row) :-
190 sparql_result_mime(MIME),
191 !,
192 call_cleanup(sparql_read_xml_result(stream(In), Result),
193 close(In)),
194 varnames(Result, VarNames),
195 xml_result(Result, Row).
196read_reply(MIME, In, VarNames, Row) :-
197 json_result_mime(MIME),
198 !,
199 call_cleanup(sparql_read_json_result(stream(In), Result),
200 close(In)),
201 ( Result = select(VarNames, Rows)
202 -> member(Row, Rows)
203 ; Result = ask(True)
204 -> Row = True,
205 VarNames = []
206 ).
207read_reply(Type, In, _, _) :-
208 read_stream_to_codes(In, Codes),
209 string_codes(Reply, Codes),
210 close(In),
211 throw(error(domain_error(sparql_result_document, Type),
212 context(_, Reply))).
213
214turtle_media_type('application/x-turtle').
215turtle_media_type('application/turtle').
216turtle_media_type('application/n-triples').
217turtle_media_type('text/rdf+n3').
218turtle_media_type('text/turtle').
219
220sparql_result_mime('application/sparql-results+xml'). 221sparql_result_mime('application/sparql-result+xml').
222
223json_result_mime('application/sparql-results+json').
224
225
226plain_content_type(Type, Plain) :-
227 sub_atom(Type, B, _, _, (;)),
228 !,
229 sub_string(Type, 0, B, _, Main),
230 normalize_space(atom(Plain), Main).
231plain_content_type(Type, Type).
232
233xml_result(ask(Bool), Result) :-
234 !,
235 Result = Bool.
236xml_result(select(_VarNames, Rows), Result) :-
237 member(Result, Rows).
238
239varnames(ask(_), _).
240varnames(select(VarTerm, _Rows), VarNames) :-
241 VarTerm =.. [_|VarNames].
242
243
244 247
248:- dynamic
249 sparql_setting/1. 250
251sparql_setting(scheme(http)).
252sparql_setting(path('/sparql/')).
253
254sparql_param(Param, Options0, Options) :-
255 select_option(Param, Options0, Options),
256 !.
257sparql_param(Param, Options, Options) :-
258 sparql_setting(Param),
259 !.
260sparql_param(Param, Options, Options) :-
261 functor(Param, Name, _),
262 throw(error(existence_error(option, Name), _)).
263
264sparql_port(_Scheme, Port, Options0, Options) :-
265 select_option(port(Port), Options0, Options),
266 !.
267sparql_port(_Scheme, Port, Options, Options) :-
268 sparql_setting(port(Port)),
269 !.
270sparql_port(http, 80, Options, Options) :-
271 !.
272sparql_port(https, 443, Options, Options) :-
273 !.
274
275
289
290sparql_set_server([]) :- !.
291sparql_set_server([H|T]) :-
292 !,
293 sparql_set_server(H),
294 sparql_set_server(T).
295sparql_set_server(Term) :-
296 functor(Term, Name, Arity),
297 functor(Unbound, Name, Arity),
298 retractall(sparql_setting(Unbound)),
299 assert(sparql_setting(Term)).
300
301
302 305
306ns(sparql, 'http://www.w3.org/2005/sparql-results#').
307
312
313 316
319
320term_subst(V, _, _, V) :-
321 var(V),
322 !.
323term_subst(F, F, T, T) :- !.
324term_subst(C, F, T, C2) :-
325 compound(C),
326 !,
327 functor(C, Name, Arity),
328 functor(C2, Name, Arity),
329 term_subst(0, Arity, C, F, T, C2).
330term_subst(T, _, _, T).
331
332term_subst(A, A, _, _, _, _) :- !.
333term_subst(I0, Arity, C0, F, T, C) :-
334 I is I0 + 1,
335 arg(I, C0, A0),
336 term_subst(A0, F, T, A),
337 arg(I, C, A),
338 term_subst(I, Arity, C0, F, T, C).
339
340term_expansion(T0, T) :-
341 ns(sparql, NS),
342 term_subst(T0, sparql, NS, T).
343
344
345 348
361
362:- thread_local
363 bnode_map/2. 364
365sparql_read_xml_result(Input, Result) :-
366 load_structure(Input, DOM,
367 [ dialect(xmlns),
368 space(remove)
369 ]),
370 call_cleanup(dom_to_result(DOM, Result),
371 retractall(bnode_map(_,_))).
372
373dom_to_result(DOM, Result) :-
374 ( sub_element(DOM, sparql:head, _HAtt, Content)
375 -> variables(Content, Vars)
376 ; Vars = []
377 ),
378 ( Vars == [],
379 sub_element(DOM, sparql:boolean, _, [TrueFalse])
380 -> Result = ask(TrueFalse)
381 ; VarTerm =.. [v|Vars],
382 Result = select(VarTerm, Rows),
383 sub_element(DOM, sparql:results, _RAtt, RContent)
384 -> rows(RContent, Vars, Rows)
385 ),
386 !. 387
393
394variables([], []).
395variables([element(sparql:variable, Att, [])|T0], [Name|T]) :-
396 !,
397 memberchk(name=Name, Att),
398 variables(T0, T).
399variables([element(sparql:link, _, _)|T0], T) :-
400 variables(T0, T).
401
402
403rows([], _, []).
404rows([R|T0], Vars, [Row|T]) :-
405 row_values(Vars, R, Values),
406 Row =.. [row|Values],
407 rows(T0, Vars, T).
408
409row_values([], _, []).
410row_values([Var|VarT], DOM, [Value|ValueT]) :-
411 ( sub_element(DOM, sparql:binding, Att, Content),
412 memberchk(name=Var, Att)
413 -> value(Content, Value)
414 ; Value = '$null$'
415 ),
416 row_values(VarT, DOM, ValueT).
417
418value([element(sparql:literal, Att, Content)], literal(Lit)) :-
419 !,
420 lit_value(Content, Value),
421 ( memberchk(datatype=Type, Att)
422 -> Lit = type(Type, Value)
423 ; memberchk(xml:lang=Lang, Att)
424 -> Lit = lang(Lang, Value)
425 ; Lit = Value
426 ).
427value([element(sparql:uri, [], [URI])], URI) :- !.
428value([element(sparql:bnode, [], [NodeID])], URI) :-
429 !,
430 bnode(NodeID, URI).
431value([element(sparql:unbound, [], [])], '$null$').
432
433
434lit_value([], '').
435lit_value([Value], Value).
436
437
439
440sub_element(element(Name, Att, Content), Name, Att, Content).
441sub_element(element(_, _, List), Name, Att, Content) :-
442 sub_element(List, Name, Att, Content).
443sub_element([H|T], Name, Att, Content) :-
444 ( sub_element(H, Name, Att, Content)
445 ; sub_element(T, Name, Att, Content)
446 ).
447
448
449bnode(Name, URI) :-
450 bnode_map(Name, URI),
451 !.
452bnode(Name, URI) :-
453 gensym('__bnode', URI0),
454 assertz(bnode_map(Name, URI0)),
455 URI = URI0.
456
457
471
472sparql_read_json_result(Input, Result) :-
473 setup_call_cleanup(
474 open_input(Input, In, Close),
475 read_json_result(In, Result),
476 close_input(Close)).
477
478open_input(stream(In), In, Close) :-
479 !,
480 encoding(In, utf8, Close).
481open_input(In, In, Close) :-
482 is_stream(In),
483 !,
484 encoding(In, utf8, Close).
485open_input(File, In, close(In)) :-
486 open(File, read, In, [encoding(utf8)]).
487
488encoding(In, Encoding, Close) :-
489 stream_property(In, encoding(Old)),
490 ( Encoding == Old
491 -> Close = true
492 ; set_stream(In, encoding(Encoding)),
493 Close = set_stream(In, Encoding, Old)
494 ).
495
496close_input(close(In)) :-
497 !,
498 retractall(bnode_map(_,_)),
499 close(In).
500close_input(_) :-
501 retractall(bnode_map(_,_)).
502
503read_json_result(In, Result) :-
504 json_read(In, JSON),
505 json_to_result(JSON, Result).
506
507json_to_result(json([ head = json(Head),
508 results = json(Body)
509 ]),
510 select(Vars, Rows)) :-
511 memberchk(vars=VarList, Head),
512 Vars =.. [v|VarList],
513 memberchk(bindings=Bindings, Body),
514 !,
515 maplist(json_row(VarList), Bindings, Rows).
516json_to_result(json(JSon), ask(Boolean)) :-
517 memberchk(boolean = @(Boolean), JSon).
518
519
520json_row(Vars, json(Columns), Row) :-
521 maplist(json_cell, Vars, Columns, Values),
522 !,
523 Row =.. [row|Values].
524json_row(Vars, json(Columns), Row) :-
525 maplist(json_cell_or_null(Columns), Vars, Values),
526 Row =.. [row|Values].
527
528json_cell(Var, Var=json(JValue), Value) :-
529 memberchk(type=Type, JValue),
530 jvalue(Type, JValue, Value).
531
532json_cell_or_null(Columns, Var, Value) :-
533 memberchk(Var=json(JValue), Columns),
534 !,
535 memberchk(type=Type, JValue),
536 jvalue(Type, JValue, Value).
537json_cell_or_null(_, _, '$null$').
538
539jvalue(uri, JValue, URI) :-
540 memberchk(value=URI, JValue).
541jvalue(literal, JValue, literal(Literal)) :-
542 memberchk(value=Value, JValue),
543 ( memberchk('xml:lang'=Lang, JValue)
544 -> Literal = lang(Lang, Value)
545 ; memberchk('datatype'=Type, JValue)
546 -> Literal = type(Type, Value)
547 ; Literal = Value
548 ).
549jvalue('typed-literal', JValue, literal(type(Type, Value))) :-
550 memberchk(value=Value, JValue),
551 memberchk('datatype'=Type, JValue).
552jvalue(bnode, JValue, URI) :-
553 memberchk(value=NodeID, JValue),
554 bnode(NodeID, URI)