View source with raw comments or as raw
   1/*  Part of ClioPatria SeRQL and SPARQL server
   2
   3    Author:        Jan Wielemaker
   4    E-mail:        J.Wielemaker@cs.vu.nl
   5    WWW:           http://www.swi-prolog.org
   6    Copyright (C): 2010-2016, University of Amsterdam,
   7			      VU University Amsterdam
   8
   9    This program is free software; you can redistribute it and/or
  10    modify it under the terms of the GNU General Public License
  11    as published by the Free Software Foundation; either version 2
  12    of the License, or (at your option) any later version.
  13
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18
  19    You should have received a copy of the GNU General Public
  20    License along with this library; if not, write to the Free Software
  21    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  22
  23    As a special exception, if you link this library with other files,
  24    compiled with a Free Software compiler, to produce an executable, this
  25    library does not by itself cause the resulting executable to be covered
  26    by the GNU General Public License. This exception does not however
  27    invalidate any other reasons why the executable file might be covered by
  28    the GNU General Public License.
  29*/
  30
  31:- module(rdf_describe,
  32	  [ rdf_bounded_description/4,	% :Expand, +Type, +URI, -Graph
  33	    rdf_bounded_description/5,	% :Expand, +Type, +Pattern, +URI, -Graph
  34	    resource_CBD/3,		% :Expand, +URI, -Graph
  35	    graph_CBD/3,		% :Expand, +Graph0, -Graph
  36	    rdf_include_reifications/3,	% :Expand, +Graph0, -Graph
  37	    rdf_include_labels/3,	% :Expand, +Graph0, -Graph
  38	    lcbd_label/3		% +Subject, -Pred, -Label
  39	  ]).
  40:- use_module(library(semweb/rdf_db)).
  41:- use_module(library(assoc)).
  42:- use_module(library(lists)).
  43
  44
  45/** <module> RDF Bounded descriptions
  46
  47The predicates in this module deal   with  `RDF bounded descriptions'. A
  48bounded description is a  subgraph  that   describes  a  single resource
  49(URI). Unfortunately, such  an  isolated   description  is  not possible
  50without the possibility of loosing semantics. We provide some meaningful
  51approximations described in the literature.
  52
  53Scanning the definitions given in  the   link  below, we distinguish two
  54ortogonal expansions: one expanding the graph  and another adding either
  55reifications    or    labels.    Expansion      is     implemented    by
  56rdf_bounded_description/4, while the  returned  graph   can  be  further
  57expanded using rdf_include_reifications/3 and/or rdf_include_labels/3.
  58
  59
  60@tbd	Also implement the variations on CBD
  61@see	http://n2.talis.com/wiki/Bounded_Descriptions_in_RDF
  62*/
  63
  64:- meta_predicate
  65	rdf_bounded_description(3, +, +, -),
  66	resource_CBD(3, +, -),
  67	graph_CBD(3, +, -),
  68	rdf_include_reifications(3, +, -).
  69
  70
  71		 /*******************************
  72		 *     RESOURCE OPERATIONS	*
  73		 *******************************/
  74
  75%%	rdf_bounded_description(:Expand, +Type, +URI, -Graph) is det.
  76%%	rdf_bounded_description(:Expand, +Type, +Filter, +URI, -Graph)	is det.
  77%
  78%	Graph is a Bounded Description of   URI.  The literature defines
  79%	various types of  bounding   descriptions.  Currently  supported
  80%	types are:
  81%
  82%	    * cbd
  83%	    Concise Bounded Description of URI. This notion is also
  84%	    known as "the bnode-closure of a resource"
  85%	    * scbd
  86%	    Symmetric Concise Bounded Description is similar to
  87%	    =cbd=, but includes triples with both URI as subject and
  88%	    object.
  89
  90rdf_bounded_description(Expand, Type, S, Graph) :-
  91	rdf_bounded_description(Expand, Type, [], S, Graph).
  92
  93rdf_bounded_description(Expand, Type, Filter, S, Graph) :-
  94	empty_assoc(Map0),
  95	compile_pattern(Filter, Triple, Expand, Filter1),
  96	expansion(Type, Expand, S, Triple, Filter1, Graph, BNG),
  97	phrase(new_bnodes(Graph, Map0), BN),
  98	phrase(r_bnodes(BN, Type, Expand, Map0, _Map), BNG).
  99
 100compile_pattern([], _, _, true).
 101compile_pattern([rdf(S,P,O)], rdf(S,P,O), Expand,
 102		call(Expand, S,P,O)) :- !.
 103compile_pattern([rdf(S,P,O)|T], rdf(S,P,O), Expand,
 104		( call(Expand, S,P,O) ; More )) :-
 105	compile_pattern(T, rdf(S,P,O), Expand, More).
 106
 107
 108
 109:- meta_predicate
 110	expansion(+, 3, +, +, +, -, ?),
 111	r_bnodes(+, +, 3, +, -, ?, ?).
 112
 113expansion(cbd, Expand, S, rdf(S,P,O), Filter, RDF, Tail) :-
 114	findall(rdf(S,P,O), (call(Expand, S,P,O),Filter), RDF, Tail).
 115expansion(scbd, Expand, S, rdf(S,P,O), Filter, RDF, Tail) :-
 116	findall(rdf(S,P,O), (call(Expand, S,P,O),Filter), RDF, T0),
 117	findall(rdf(O,P,S), (call(Expand, O,P,S),Filter), T0, Tail).
 118
 119r_bnodes([], _, _, Map, Map) -->
 120	[].
 121r_bnodes([H|T], Type, Expand, Map0, Map, Graph, Tail) :-
 122	rdf_is_bnode(H), !,
 123	put_assoc(H, Map0, true, Map1),
 124	expansion(Type, Expand, H, _, true, Graph, Tail0),
 125	phrase(new_bnodes(Graph, Map1), BN, T),
 126	r_bnodes(BN, Type, Expand, Map1, Map, Tail0, Tail).
 127r_bnodes([_|T], Type, Expand, Map0, Map) -->
 128	r_bnodes(T, Type, Expand, Map0, Map).
 129
 130new_bnodes(Var, _) -->
 131	{ var(Var) }, !.
 132new_bnodes([rdf(S,_,O)|RDF], Map) -->
 133	new_bnode(S, Map),
 134	new_bnode(O, Map),
 135	new_bnodes(RDF, Map).
 136
 137new_bnode(S, Map) --> { rdf_is_bnode(S), \+ get_assoc(S, Map, _) }, !, [S].
 138new_bnode(_, _) --> [].
 139
 140
 141%%	resource_CBD(:Expand, +URI, -Graph) is det.
 142%
 143%	Graph is the Concise Bounded Description  of URI. This notion is
 144%	also known as "the bnode-closure  of   a  resource".  Note that,
 145%	according to the definition on the  Talis wiki, the CBD includes
 146%	reified  statements.  This  predicate  does  not  do  this.  Use
 147%	rdf_include_reifications/3 to add reifications to the graph.
 148%
 149%	@param	Expand is called to enumerate the PO pairs for a subject.
 150%		This will often be =rdf= to use rdf/3.
 151%	@see	http://n2.talis.com/wiki/Bounded_Descriptions_in_RDF
 152
 153resource_CBD(Expand, S, Graph) :-
 154	rdf_bounded_description(Expand, cbd, S, Graph).
 155
 156
 157		 /*******************************
 158		 *	GRAPH OPERATIONS	*
 159		 *******************************/
 160
 161%%	graph_CBD(:Expand, +Graph0, -Graph) is det.
 162%
 163%	Add concise bounded descriptions for bnodes in a graph, creating
 164%	an expanded graph.
 165
 166graph_CBD(Expand, Graph0, Graph) :-
 167	empty_assoc(Map0),
 168	must_be(list, Graph0),
 169	phrase(gr_cbd(Graph0, Expand, Map0, _Map), Graph).
 170
 171:- meta_predicate
 172	gr_cbd(+, 3, +, -, ?, ?).
 173
 174gr_cbd([], _, Map, Map) -->
 175	[].
 176gr_cbd([rdf(S,P,O)|T], Expand, Map0, Map) -->
 177	{   rdf_is_bnode(S)
 178	;   rdf_is_bnode(O)
 179	}, !,
 180	[ rdf(S,P,O) ],
 181	r_bnodes([S,O], cbd, Expand, Map0, Map1),
 182	gr_cbd(T, Expand, Map1, Map).
 183gr_cbd([Triple|T], Expand, Map0, Map) -->
 184	[Triple],
 185	gr_cbd(T, Expand, Map0, Map).
 186
 187%%	rdf_include_reifications(:Expand, +Graph0, -Graph) is det.
 188%
 189%	Include the reification of any reified statements in Graph0.
 190
 191rdf_include_reifications(Expand, Graph0, Graph) :-
 192	phrase(reified_triples(Graph0, Expand), Statements),
 193	(   Statements == []
 194	->  Graph = Graph0
 195	;   graph_CBD(Expand, Statements, Statements1),
 196	    rdf_include_reifications(Expand, Statements1, Graph1),
 197	    append(Graph0, Graph1, Graph)
 198	).
 199
 200:- meta_predicate
 201	reified_triples(+, 3, ?, ?),
 202	reification(?,?,?,3,-).
 203
 204reified_triples([], _) --> [].
 205reified_triples([rdf(S,P,O)|T], Expand) -->
 206	findall(T, reification(S,P,O,Expand,T)),
 207	reified_triples(T, Expand).
 208
 209reification(S,P,O, Expand, Triple) :-
 210	rdf_equal(SP, rdf:subject),
 211	rdf_equal(PP, rdf:predicate),
 212	rdf_equal(OP, rdf:object),
 213	call(Expand, Stmt, SP, S),
 214	call(Expand, Stmt, OP, O),
 215	call(Expand, Stmt, PP, P),
 216	(   Triple = rdf(Stmt, SP, S)
 217	;   Triple = rdf(Stmt, PP, P)
 218	;   Triple = rdf(Stmt, OP, O)
 219	).
 220
 221%%	rdf_include_labels(:Expand, +Graph0, -Graph) is det.
 222%
 223%	Include missing `label' statements in   Graph0.  Expand must
 224%	provide label triples on
 225%
 226%	    call(Expand, S, P, O)
 227%
 228%	The  predicate  lcbd_label/3  does   this    for   the  standard
 229%	definition, considering the properties  rdfs:label, rdfs:comment
 230%	and rdfs:seeAlso.
 231
 232rdf_include_labels(Expand, Graph0, Graph) :-
 233	phrase(label_triples(Graph0, Expand), LabelRDF),
 234	(   LabelRDF == []
 235	->  Graph = Graph0
 236	;   append(Graph0, LabelRDF, Graph)
 237	).
 238
 239:- meta_predicate
 240	label_triples(+, 3, ?, ?),
 241	label_triple(+, 3, -).
 242
 243label_triples([], _) --> [].
 244label_triples([rdf(_,_,O)|T], Expand) -->
 245	findall(T, label_triple(O,Expand,T)),
 246	label_triples(T, Expand).
 247
 248label_triple(O, Expand, Triple) :-
 249	call(Expand, O, LP, Label),
 250	Triple = rdf(O, LP, Label).
 251
 252:- rdf_meta
 253	lcbd_property(r).
 254
 255%%	lcbd_label(+S, -P, -Label) is nondet.
 256%
 257%	Standard conforming `Expand' for rdf_include_labels/3.
 258
 259lcbd_label(S, P, Label) :-
 260	lcbd_property(P),
 261	rdf_has(S, P, Label).
 262
 263lcbd_property(rdfs:label).
 264lcbd_property(rdfs:comment).
 265lcbd_property(rdfs:seeAlso).