1:- encoding(utf8).
2:- module(
3 rdf_print,
4 [
5 rdf_dcg_node//1, 6 rdf_dcg_node//2, 7 rdf_dcg_predicate//1, 8 rdf_dcg_predicate//2, 9 rdf_dcg_triples//1, 10 rdf_dcg_triples//2 11 ]
12).
29:- use_module(library(aggregate)). 30:- use_module(library(apply)). 31:- use_module(library(clpfd)). 32:- use_module(library(error)). 33:- use_module(library(lists)). 34:- use_module(library(solution_sequences)). 35
36:- use_module(library(abnf)). 37:- use_module(library(atom_ext)). 38:- use_module(library(call_ext)). 39:- use_module(library(dcg)). 40:- use_module(library(dict)). 41:- use_module(library(rdf_prefix)). 42:- use_module(library(rdf_term)). 43
44:- rdf_meta
45 rdf_dcg_literal(t, +, ?, ?), rdf_dcg_node(o, ?, ?), rdf_dcg_node(o, +, ?, ?), rdf_dcg_predicate(r, ?, ?), rdf_dcg_predicate(r, +, ?, ?), rdf_dcg_triples(t, ?, ?), rdf_dcg_triples(t, +, ?, ?).
61rdf_dcg_bnode(BNode, Options) -->
62 {dict_get(max_length, Options, inf, Max)},
63 "_:",
64 ellipsis(BNode, Max).
65
66
67
68%! rdf_dcg_iri(+Iri:iri, +Options:options)// is det.
69%
70% @param Options The following options are supported:
71%
72% * max_length(+or([positive_integer,oneof([inf])]))
73%
74% * prefix2alias(+assoc(iri,atom))
75
76% Abbreviated IRI notation.
77rdf_dcg_iri(Iri, Options) -->
78 {
79 ( dict_get(prefix2alias, Options, Prefix2Alias)
80 -> % Abbreviated based on the prefix map specified in options.
81 ( gen_assoc(Prefix, Prefix2Alias, Alias),
82 atom_prefix(Iri, Prefix)
83 -> atom_concat(Prefix, Local, Iri)
84 )
85 ; % Abbreviated based on the global prefix declarations.
86 rdf_prefix_iri(Alias:Local, Iri),
87 \+ sub_atom(Local, /)
88 )
89 }, !,
90 {
91 atom_length(Alias, AliasLength),
92 Minus #= AliasLength + 1,
93 dict_get(max_length, Options, inf, Length),
94 ( Length == inf
95 -> Max = inf
96 ; Length =< Minus
97 -> Max = Length
98 ; Max = Length - Minus
99 )
100 },
101 atom(Alias),
102 ":",
103 ellipsis(Local, Max).
105rdf_dcg_iri(Iri, Options) -->
106 {dict_get(max_length, Options, inf, Max)},
107 "<",
108 ellipsis(Iri, Max),
109 ">".
119rdf_dcg_lexical_form(Lex, Options) -->
120 {
121 dict_get(max_length, Options, inf, Length),
122 extra_quotes_(Lex, ExtraQuotes)
123 },
124 ({ExtraQuotes == true} -> "\"\"\"" ; "\""),
125 ellipsis(Lex, Length),
126 ({ExtraQuotes == true} -> "\"\"\"" ; "\"").
127
128lex_([0'\\|T]) --> !,
129 "\\\\",
130 lex_(T).
131lex_([H|T]) --> !,
132 [H],
133 lex_(T).
134lex_([]) --> "".
135
(Atom, true) :-
137 atom_codes(Atom, Codes),
138 member(Code, [0'",0'\n]), 139 memberchk(Code, Codes), !.
140extra_quotes_(_, false).
150rdf_dcg_literal(literal(lang(LTag,Lex)), Options) --> !,
151 rdf_dcg_lexical_form(Lex, Options),
152 "@",
153 atom(LTag).
155rdf_dcg_literal(literal(type(D,Lex)), _) -->
156 {
157 rdf_prefix_memberchk(
158 D,
159 [xsd:boolean,xsd:decimal,xsd:float,xsd:integer]
160 )
161 }, !,
162 atom(Lex).
164rdf_dcg_literal(literal(type(D,Lex)), Options) -->
165 {
166 rdf_equal(D, xsd:string), !,
167 rdf_canonical_lexical_form(D, Lex, CanonicalLex)
168 },
169 rdf_dcg_lexical_form(CanonicalLex, Options).
171rdf_dcg_literal(literal(type(D,Lex)), Options) -->
172 rdf_dcg_lexical_form(Lex, Options),
173 "^^",
174 rdf_dcg_iri(D, Options).
184rdf_dcg_node(Node) -->
185 rdf_dcg_node(Node, options{}).
186
187
188rdf_dcg_node(Var, _) -->
189 {var(Var)}, !,
190 {instantiation_error(Var)}.
192rdf_dcg_node(BNode, Options) -->
193 {rdf_is_bnode(BNode)}, !,
194 rdf_dcg_bnode(BNode, Options).
196rdf_dcg_node(Literal, Options) -->
197 {rdf_is_literal(Literal)}, !,
198 rdf_dcg_literal(Literal, Options).
200rdf_dcg_node(Iri, Options) -->
201 {rdf_is_iri(Iri)}, !,
202 rdf_dcg_iri(Iri, Options).
204rdf_dcg_node(Term, _) -->
205 {syntax_error(rdf_term(Term))}.
214rdf_dcg_predicate(P) -->
215 rdf_dcg_predicate(P, options{}).
216
217
218rdf_dcg_predicate(P, _) -->
219 {rdf_equal(P, rdf:type)}, !,
220 "a".
221rdf_dcg_predicate(Iri, Options) -->
222 rdf_dcg_iri(Iri, Options).
234rdf_dcg_triples(Triples) -->
235 rdf_dcg_triples(Triples, options{}).
236
237
238rdf_dcg_triples(Triples, Options) -->
239 {dict_get(graph, Options, _NoGraphName, GraphName)},
240 rdf_dcg_prefixes(Triples),
241 rdf_dcg_groups0([GraphName-Triples], Options).
242
243rdf_dcg_prefixes(Triples) -->
244 {
245 aggregate_all(
246 set(Alias-Prefix),
247 (
248 member(tp(S,P,O), Triples),
249 member(Term, [S,P,O]),
250 term_iri_(Term, Iri),
251 rdf_prefix_iri(Alias, _, Iri),
252 rdf_prefix(Alias, Prefix)
253 ),
254 Pairs
255 )
256 },
257 '*'(rdf_dcg_prefix, Pairs), !,
258 ({Pairs == []} -> "" ; "\n").
259
260term_iri_(Iri, Iri) :-
261 rdf_is_iri(Iri), !.
262term_iri_(Literal, Iri) :-
263 rdf_literal_datatype_iri(Literal, Iri).
264
265rdf_dcg_prefix(Alias-Prefix) -->
266 "prefix ",
267 atom(Alias),
268 ": <",
269 atom(Prefix),
270 ">\n".
271
272rdf_dcg_groups0([], _) --> !, "".
273rdf_dcg_groups0([G-Triples|Groups], Options) -->
274 {dict_get(indent, Options, 0, I1)},
275 ( {var(G)}
276 -> {I2 = I1}
277 ; tab(I1),
278 rdf_dcg_node(G, Options),
279 " {\n",
280 {I2 = I1 + 2}
281 ),
282 rdf_dcg_triples0(I2, Triples, Options),
283 ({var(G)} -> "" ; "}\n"),
284 rdf_dcg_groups0(Groups, Options).
285
286rdf_dcg_triples0(I, Triples, Options) -->
287 {
288 partition(is_skip_tp_(Triples), Triples, SkipTriples, NonSkipTriples),
289 triples_to_groups0(NonSkipTriples, Groups)
290 },
291 rdf_dcg_subjects0(I, Groups, SkipTriples, Options).
297is_skip_tp_(Triples, tp(S,_,_)) :-
298 ( 299 rdf_is_bnode(S)
300 ; 301 rdf_is_bnode_iri(S)
302 ), !,
303 memberchk(tp(_,_,S), Triples), !.
305is_skip_tp_(_, tp(_,P,_)) :-
306 rdf_prefix_memberchk(P, [rdf:first,rdf:rest]), !.
308is_skip_tp_(_, tp(_,_,O)) :-
309 rdf_is_bnode(O).
314triples_to_groups0(Triples, Groups) :-
315 aggregate_all(
316 set(S-SGroups),
317 (
318 distinct(S, member(tp(S,_,_), Triples)),
319 triples_to_groups1(S, Triples, SGroups)
320 ),
321 Groups
322 ).
323
324triples_to_groups1(S, Triples, SGroups) :-
325 aggregate_all(
326 set(P-Os),
327 (
328 distinct(P, member(tp(S,P,_), Triples)),
329 triples_to_groups2(S, P, Triples, Os)
330 ),
331 SGroups
332 ).
333
334triples_to_groups2(S, P, Triples, Os) :-
335 aggregate_all(set(O), member(tp(S,P,O), Triples), Os).
342rdf_dcg_subjects0(_, [], _, _) --> !, "".
343rdf_dcg_subjects0(I1, [S-SGroups|Groups], SkipTriples1, Options) -->
344 tab(I1),
345 rdf_dcg_node(S, Options),
346 {I2 is I1 + 2},
347 rdf_dcg_predicates1(I2, SGroups, SkipTriples1, SkipTriples2, Options),
348 nl,
349 ({Groups == []} -> "" ; nl),
350 rdf_dcg_subjects0(I1, Groups, SkipTriples2, Options).
351
354rdf_dcg_predicates1(I, [P-[O]], SkipTriples1, SkipTriples2, Options) --> !,
355 " ",
356 rdf_dcg_predicate(P, Options),
357 rdf_dcg_complex_object_(I, true, O, SkipTriples1, SkipTriples2, Options),
358 ".".
360rdf_dcg_predicates1(I, SGroups1, SkipTriples1, SkipTriples2, Options) -->
361 362 363 {types_to_the_front(SGroups1, SGroups2)},
364 rdf_dcg_predicates2(I, false, false, SGroups2, SkipTriples1, SkipTriples2, Options).
365
366types_to_the_front(SGroups1, [P-Os|SGroups2]) :-
367 rdf_prefix_iri(rdf, type, P),
368 selectchk(P-Os, SGroups1, SGroups2), !.
369types_to_the_front(SGroups, SGroups).
370
372rdf_dcg_predicates2(_, _, _, [], SkipTriples, SkipTriples, _) --> !, "".
374rdf_dcg_predicates2(I1, StartOfBlock, InBlock, [P-Os|Groups], SkipTriples1, SkipTriples3, Options) -->
375 start_of_block(I1, StartOfBlock),
376 rdf_dcg_predicate(P, Options),
377 {I2 is I1 + 2},
378 rdf_dcg_objects1(I2, Os, SkipTriples1, SkipTriples2, Options),
379 ({Groups == []} -> ({InBlock == true} -> " " ; ".") ; ";"),
380 rdf_dcg_predicates2(I1, false, InBlock, Groups, SkipTriples2, SkipTriples3, Options).
381
382start_of_block(I, false) --> !,
383 nl,
384 tab(I).
385start_of_block(_, true) --> " ".
386
388rdf_dcg_objects1(I, [O], SkipTriples1, SkipTriples2, Options) --> !,
389 rdf_dcg_complex_object_(I, true, O, SkipTriples1, SkipTriples2, Options).
391rdf_dcg_objects1(I, Os, SkipTriples1, SkipTriples2, Options) -->
392 rdf_dcg_objects2(I, Os, SkipTriples1, SkipTriples2, Options).
393
395rdf_dcg_objects2(_, [], SkipTriples, SkipTriples, _) --> !, "".
397rdf_dcg_objects2(I, [O|Os], SkipTriples1, SkipTriples3, Options) -->
398 rdf_dcg_complex_object_(I, false, O, SkipTriples1, SkipTriples2, Options),
399 ({Os == []} -> "" ; ","),
400 rdf_dcg_objects2(I, Os, SkipTriples2, SkipTriples3, Options).
410rdf_dcg_complex_object_(I, InLine, RdfList, SkipTriples1, SkipTriples2, Options) -->
411 {
412 linear_list_(RdfList, SkipTriples1, SkipTriples2, Terms),
413 Terms = [_|_]
414 }, !,
415 ({InLine == true} -> " " ; nl, tab(I)),
416 rdf_dcg_list_(Terms, Options).
418rdf_dcg_complex_object_(I1, _, Node, SkipTriples1, SkipTriples3, Options) -->
419 {
420 turtle_object_(Node, SkipTriples1, SkipTriples2, Pairs),
421 Pairs = [_|_], !,
422 group_pairs_by_key(Pairs, Groups),
423 I2 is I1 + 2
424 },
425 nl,
426 tab(I1),
427 "[",
428 rdf_dcg_predicates2(I2, true, true, Groups, SkipTriples2, SkipTriples3, Options),
429 "]".
431rdf_dcg_complex_object_(I, InLine, Term, SkipTriples, SkipTriples, Options) -->
432 ({InLine == true} -> " " ; nl, tab(I)),
433 rdf_dcg_node(Term, Options).
439turtle_object_(S, SkipTriples1, SkipTriples3, [P-O|T]) :-
440 rdf_prefix_selectchk(tp(S,P,O), SkipTriples1, SkipTriples2), !,
441 turtle_object_(S, SkipTriples2, SkipTriples3, T).
442turtle_object_(_, SkipTriples, SkipTriples, []).
449linear_list_(S1, SkipTriples1, SkipTriples4, [H|T]) :-
450 rdf_prefix_selectchk(tp(S1,rdf:first,H), SkipTriples1, SkipTriples2),
451 rdf_prefix_selectchk(tp(S1,rdf:rest,S2), SkipTriples2, SkipTriples3), !,
452 linear_list_(S2, SkipTriples3, SkipTriples4, T).
453linear_list_(_, SkipTriples, SkipTriples, []).
457rdf_dcg_list_(Terms, Options) -->
458 "(",
459 ( {Terms = [H|T]}
460 -> " ",
461 rdf_dcg_node(H, Options),
462 rdf_dcg_list_tail_(T, Options),
463 " "
464 ; ""
465 ),
466 ")".
470rdf_dcg_list_tail_([H|T], Options) --> !,
471 " ",
472 rdf_dcg_node(H, Options),
473 rdf_dcg_list_tail_(T, Options).
474rdf_dcg_list_tail_([], _) --> ""
RDF printing
indent
max_length
inf
prefix2alias
assoc(iri,atom)
)@note RDF prefix expansion does not work in DCGs.
*/