1/* -*- Mode: Prolog -*- */
    2
    3:- module(rdfs2pl,
    4          [assert_schema/2,
    5           assert_schema/1,
    6           write_schema/3,
    7           write_schema/2]).

compile an RDF schema to a prolog module

*/

   13:- use_module(library(semweb/rdf11)).   14:- use_module(library(semweb/rdfs)).   15
   16:- dynamic clause_comment/2.
 assert_schema(+Local, +Global) is det
as write_schema/2, but assert directly
   21assert_schema(Local,Global):-
   22        rdf_register_ns(Local,Global),
   23        assert_clauses(Local).
   24
   25assert_schema(Local):-
   26        rdf_current_prefix(Local,_),
   27        assert_clauses(Local).
   28
   29assert_clauses(M):-
   30        forall(inf_clause(M,X,[]),
   31               M:assert(X)).
 write_schema(+Prefix, +Global, +Opts)
writes out prolog wrapping predicates for ontology Global, using prefix Prefix

E.g. write_schema(bp2,'http://www.biopax.org/release/biopax-level2.owl#')

   38write_schema(Local,Opts):-
   39        write_schema(Local,_,Opts).
   40write_schema(Local,Global,Opts):-
   41        (   var(Global)
   42        ->  (   rdf_current_prefix(Local,Global)
   43            ->  true
   44            ;   true)
   45        ;   rdf_register_ns(Local,Global)),
   46        write_module_schema(Local,[module(Local)|Opts]).
   47
   48% prolog program consists of header and clauses
   49write_module_schema(M,Opts):-
   50        write_header(M,Opts),
   51        write_clauses(M,Opts).
   52
   53% header consists of module declaration and exports directives
   54write_header(M,Opts):-
   55        format('%% <module> ~w~n',[M]),
   56        format('% Autogenerated by rdfs2pl -- see https://github.com/cmungall/rdfs2pl/~n',[]),
   57        nl,
   58        findall(E,mod_exports(M,E,Opts),Exports),
   59        writep( (:- module(M,Exports)) ),
   60        writep( (:- use_module(library(semweb/rdf11))) ),
   61        writep( (:- use_module(library(semweb/rdfs))) ),
   62        nl,
   63        forall((mod_exports(M,Op,Opts),Op=op(_,_,_)),
   64               writep( (:- Op) )),
   65        nl.
   66
   67write_clauses(M,Opts):-
   68        setof(X,inf_clause(M,X,Opts),Xs),
   69        maplist(write_clause,Xs).
   70
   71write_clause(X):-
   72        %X=..[_,Head|Args],
   73        %Head =.. [_,_,Head2],
   74        %format('%% ~w.~n',[Head2]),
   75                                %format('%~n'),
   76        (   clause_comment(X,Comment)
   77        ->  write(Comment)
   78        ;   true),
   79        writep(X),
   80        nl.
   81
   82
   83%%%%
   84% UTIL
   85%%%%
 maketerm(+URI, +Args, ?Term)
see maketerm/6
   91maketerm(URI,Args,Term):-
   92        maketerm(URI,Args,Term,_,_,[]).
   93maketerm(URI,Args,Term,Opts):-
   94        maketerm(URI,Args,Term,_,_,Opts).
 maketerm(+URI, +Args, ?Term, ?NS, ?Functor, +Opts)
unifies Term with a term Pred(Args) such that Pred is a prolog-safe variant of URI (or optionally, the label for URI)

note: NS not used

  103maketerm(URI,Args,Term,_NS,_Functor,Opts):-
  104        member(use_labels(true),Opts),
  105        ont_label(URI,Label),
  106        member(module(M),Opts),
  107        !,
  108        psafe(Label,Pred,Opts),
  109        debug(schema,' pred= ~w ',[Pred]),
  110        T=..[Pred|Args],
  111        Term=..[':',M,T].
  112        
  113maketerm(URI,Args,Term,NS,Functor,Opts):-
  114        rdf_global_id(NS:Functor,URI),
  115        debug(schema,' P2P ~w ',[Functor]),
  116        property_to_predicate(Functor,FunctorSafe,Opts),
  117        T1=..[FunctorSafe|Args],
  118        Term=..[':',NS,T1].
  119
  120make_comment(Clause, _:Term, class, Obj) :-
  121        numbervars(Term,8,_),
  122        sformat(S,'%! ~w~n%~n%  Any instance of <~w>~n%~n',[Term,Obj]),
  123        assert(clause_comment(Clause,S)),
  124        make_comment_from_def(Clause,Obj).
  125make_comment(Clause, _:Term, property, Obj) :-
  126        numbervars(Term,8,_),
  127        sformat(S,'%! ~w~n%~n%  Any relationship of type <~w>~n%~n',[Term,Obj]),
  128        assert(clause_comment(Clause,S)),
  129        make_comment_from_def(Clause,Obj).
  130
  131make_aux_comment(Clause, _:Term, Aux) :-
  132        numbervars(Term,8,_),
  133        Term =.. [P|_],
  134        sformat(S,'%! ~w~n%~n%  As ~w/2 ~w~n%~n',[Term,P,Aux]),
  135        assert(clause_comment(Clause,S)).
  136
  137make_comment_from_def(Clause,Obj) :-
  138        ont_desc(Obj,Desc),
  139        sformat(S,'%  _|~w|_~n',[Desc]),
  140        assert(clause_comment(Clause,S)),
  141        !.
  142make_comment_from_def(_,_).
  143
  144
  145
  146cls(C,Opts) :-
  147        % call unique
  148        setof(C,cls1(C,Opts),Cs),
  149        member(C,Cs).
  150        
  151cls1(C,Opts) :-
  152        \+ member( exclude_classes(true), Opts),
  153        rdfs_individual_of(C,owl:'Class'),
  154        \+ rdf_is_bnode(C).
 inf_clause(?Namespace, ?Clause, +Opts)
generates a clause to be used as a directive in a prolog program
  161inf_clause(NS, Clause, Opts) :-
  162        inf_clause_meta(NS, Clause, _, Opts).
  163inf_clause(NS, Directive, Opts) :-
  164        inf_clause_meta(NS, _, Meta, Opts),
  165        make_meta_directive(Meta, Directive).
 inf_clause_meta(?Namespace, ?Clause, +Opts)
generates a clause to be used as a directive in a prolog program

side effect: asserts clause_comment/2

  177% ## CLASSES
  178% 
  179% represented by unary predicates
  180
  181% unary predicate: C(I)
  182inf_clause_meta( _NS, (Head:-Body), Meta, Opts):-
  183         cls(C,Opts),
  184         maketerm(C,[r],Meta,Opts),
  185         maketerm(C,[I],Head,Opts),
  186         (   member(expand_subclass(Opts,true),Opts)
  187         *-> (   Body=rdf(I,rdf:type,C),
  188                 make_comment( (Head:-Body), Head, class, C)
  189             ;   rdfs_subclass_of(D,C),
  190                 Body=rdf(I,rdf:type,D))
  191         ;   Body=rdfs_individual_of(I,C),
  192             make_comment( (Head:-Body), Head, class, C)).
  193
  194% ## Properties
  195% 
  196% represented by binary+ predicates
  197
  198% basic binary predicate: P(S,O)
  199inf_clause_meta( NS, (Head:-Body), Meta, Opts ):-
  200         property(R),
  201         maketerm(R,[r,r],Meta,NS,_,Opts),
  202         maketerm(R,[Subj,Obj],Head,NS,_F,Opts),
  203         make_comment( (Head:-Body), Head, property, R),
  204         Body=rdf_has(Subj,R,Obj).
  205
  206% ternary predicate with graph: P(S,O,G)
  207inf_clause_meta( NS, (Head:-Body), Meta, Opts ):-
  208         property(R),
  209         maketerm(R,[r,r,g],Meta,NS,_,Opts),
  210         maketerm(R,[Subj,Obj,G],Head,NS,_F,Opts),
  211         Body=rdf(Subj,R,Obj,G),
  212         make_aux_comment( (Head:-Body), Head, ' where asserted in graph').
  213
  214% quad predicate with graph and reified node: P(S,O,G,N)
  215inf_clause_meta( NS, (Head:-Body), Meta, Opts ):-
  216         property(R),
  217         member(reify(true), Opts),
  218         NOpts=[suffix(node)|Opts],
  219         maketerm(R,[r,r,g,r],Meta,NS,_,NOpts),
  220         maketerm(R,[Subj,Obj,G,Node],Head,NS,_F,NOpts),
  221         Body=(rdf(Subj,R,Obj,G),
  222               rdf(Node,rdf:subject,Subj),
  223               rdf(Node,rdf:predicate,R),
  224               rdf(Node,rdf:object,Obj)),
  225         make_aux_comment( (Head:-Body), Head, ', where asserted in graph and rdf-reified by node').
  226         
  227
  228% ternary predicate with reified node, no graph: P_node(S,O,N)
  229inf_clause_meta( NS, (Head:-Body), Meta, Opts ):-
  230         property(R),
  231         member(reify(true), Opts),
  232         NOpts=[suffix(node)|Opts],
  233         maketerm(R,[r,r,r],Meta,NS,_,NOpts),
  234         maketerm(R,[Subj,Obj,Node],Head,NS,_F,NOpts),
  235         Body=(rdf(Subj,R,Obj),
  236               rdf(Node,rdf:subject,Subj),
  237               rdf(Node,rdf:predicate,R),
  238               rdf(Node,rdf:object,Obj)).
  239
  240% generate subclass_of_P(S,O) from property P 
  241inf_clause_meta( NS, (Head:-Body), Meta, Opts ):-
  242         rdfs_individual_of(R,owl:'ObjectProperty'),
  243         NOpts=[prefix(subclass_of)|Opts],
  244         maketerm(R,[r,r],Meta,NS,_,NOpts),
  245         maketerm(R,[Subj,Obj],Head,NS,_F,NOpts),
  246         Body=(rdf(Subj,rdfs:subClassOf,Restr),
  247               rdf(Restr,owl:onProperty,R),
  248               rdf(Restr,owl:someValuesFrom,Obj)),
  249         make_aux_comment( (Head:-Body), Head, ', TODO').
  250
  251
  252% generate P_axiom(S,O,G,N) from property P
  253inf_clause_meta( NS, (Head:-Body), Meta, Opts ):-
  254         property(R),
  255         member(reify_owl(true), Opts),
  256         NOpts = [suffix(axiom)|Opts],
  257         maketerm(R,[r,r,g,r],Meta,NS,_,NOpts),
  258         maketerm(R,[Subj,Obj,G,Axiom],Head,NS,_F,NOpts),
  259         Body=(rdf(Subj,R,Obj,G),
  260               rdf(Axiom,owl:annotatedSource,Subj),
  261               rdf(Axiom,owl:annotatedProperty,R),
  262               rdf(Axiom,owl:annotatedTarget,Obj)),
  263         make_aux_comment( (Head:-Body), Head, ', where asserted in graph and owl-reified by node').
  264
  265
  266% generate P_axiom(S,O,N) from property P
  267inf_clause_meta( NS, (Head:-Body), Meta, Opts ):-
  268         property(R),
  269         member(reify_owl(true), Opts),
  270         NOpts = [suffix(axiom)|Opts],
  271         maketerm(R,[r,r,r],Meta,NS,_,NOpts),
  272         maketerm(R,[Subj,Obj,Axiom],Head,NS,_F,NOpts),
  273         Body=(rdf(Subj,R,Obj),
  274               rdf(Axiom,owl:annotatedSource,Subj),
  275               rdf(Axiom,owl:annotatedProperty,R),
  276               rdf(Axiom,owl:annotatedTarget,Obj)),
  277         make_aux_comment( (Head:-Body), Head, ', where owl-reified by node').
  278
  279               
  280
  281property_to_predicate(R,Pred,Opts):-
  282        property_to_predicate1(R,Pred0,Opts),
  283        safe_predicate(Pred0,Pred,Opts).
  284
  285property_to_predicate1(R,Pred,Opts):-
  286        member(use_labels(true),Opts),
  287        !,
  288        debug(schema,'FETCHING ~w ',[R]),
  289        ont_label(R,Label),
  290        debug(schema,'~w ==> ~w',[R,Label]),
  291        downcase_atom(Label,R1),
  292        concat_atom(L,'-',R1),
  293        concat_atom(L,'_',Pred).
  294property_to_predicate1(R,Pred,Opts):-
  295        member(prolog_properties(true),Opts),
  296        !,
  297        downcase_atom(R,R1),
  298        concat_atom(L,'-',R1),
  299        concat_atom(L,'_',Pred).
  300property_to_predicate1(R,R,_).
  301
  302safe_predicate(P1,P2,Opts):-
  303        T=..[P1,_,_],
  304        predicate_property(T,_),
  305        !,
  306        (   member(prefix(M),Opts)
  307        ->  concat_atom([M,P1],'_',P2)
  308        ;   atom_concat(P1,'_',P2)).
  309safe_predicate(P,P,_).
  310
  311ont_label(X,Label) :- rdfs_label(X,Label),!.
  312ont_label(X,Label) :- rdf(X,rdfs:label,S),S=literal(type(_,Label)).
  313
  314ont_desc(X,Label) :- rdf(X,'http://purl.obolibrary.org/obo/IAO_0000115',S),S=literal(type(_,Label)).
  315
  316
  317
  318mod_exports( NS, F/N, Opts):-
  319        cls(C,Opts),
  320        maketerm(C,[-], NS:Term,Opts),
  321        functor(Term,F,N).
  322
  323mod_exports( NS, F/N, Opts ):-
  324        property(R),
  325        maketerm(R,[-,-], NS:Term,Opts),
  326        functor(Term,F,N).
  327
  328mod_exports( NS, F/N, Opts ):-
  329        property(R),
  330        maketerm(R,[-,-,-], NS:Term,Opts),
  331        functor(Term,F,N).
  332
  333mod_exports( NS, F/N, Opts ):-
  334        property(R),
  335        member(reify(true), Opts),
  336        maketerm(R,[-,-,-], NS:Term,[suffix(node)|Opts]),
  337        functor(Term,F,N).
  338mod_exports( NS, F/N, Opts ):-
  339        property(R),
  340        member(reify(true), Opts),
  341        maketerm(R,[-,-,-,-], NS:Term,[suffix(node)|Opts]),
  342        functor(Term,F,N).
  343
  344mod_exports( NS, F/N, Opts ):-
  345        property(R),
  346        member(reify_owl(true), Opts),
  347        maketerm(R,[-,-,-], NS:Term,[suffix(axiom)|Opts]),
  348        functor(Term,F,N).
  349mod_exports( NS, F/N, Opts ):-
  350        property(R),
  351        member(reify_owl(true), Opts),
  352        maketerm(R,[-,-,-,-], NS:Term,[suffix(axiom)|Opts]),
  353        functor(Term,F,N).
  354
  355mod_exports( NS, op(300,xfy,F), Opts ):-
  356        option(ops(true),Opts,true),
  357        property(R),
  358        maketerm(R,[], NS:F,Opts).
  359
  360/*
  361inf_op( NS, F, Opts ):-
  362        rdfs_individual_of(C,owl:'ObjectProperty'),
  363        rdf_global_id(NS:F0,C),
  364        property_to_predicate(F0,F,Opts).
  365
  366inf_op( NS, F, Opts ):-
  367        rdfs_individual_of(C,owl:'DatatypeProperty'),
  368        rdf_global_id(NS:F0,C),
  369        property_to_predicate(F0,F,Opts).
  370*/
  371
  372property(R) :-
  373        setof(R,property1(R),Rs),member(R,Rs).  % call unique
  374
  375property1(R) :- rdfs_individual_of(R,owl:'ObjectProperty').
  376property1(R) :- rdfs_individual_of(R,owl:'DatatypeProperty').
  377property1(R) :- rdfs_individual_of(R,owl:'AnnotationProperty').
  378property1(R) :- rdf(R,rdf:type,rdf:'Property').
  379        
  380
  381writep(X):-
  382        numbervars(X,8,_,[]),
  383        writeq(X),
  384        write('.'),
  385        nl.
  386
  387
  388
  389% TODO
  390reserved(member).
  391
  392suffix_reserved(A,B) :-
  393        reserved(A),
  394        !,
  395        atom_concat(A,'_triple',B).
  396suffix_reserved(A,A).
  397
  398psafe(N,Safe,Opts) :-
  399        select(suffix(Suffix),Opts,Opts2),
  400        !,
  401        psafe(N,X,Opts2),
  402        concat_atom([X,Suffix],'_',Safe).
  403psafe(N,Safe,Opts) :-
  404        select(prefix(Prefix),Opts,Opts2),
  405        !,
  406        psafe(N,X,Opts2),
  407        concat_atom([Prefix,X],'_',Safe).
  408psafe(N,Safe,_) :-
  409        atom_chars(N,[C|L]),
  410        downcase_atom(C,C2),
  411        lsafe([C2|L],Cs2),
  412        atom_chars(Safe1,Cs2),
  413        suffix_reserved(Safe1,Safe).
  414
  415        
  416safe(N,Safe) :-
  417        atom_chars(N,Cs),
  418        lsafe(Cs,Cs2),
  419        atom_chars(Safe,Cs2).
  420
  421lsafe([],[]).
  422lsafe([H|L],[H2|L2]) :-
  423        csafe(H,H2),
  424        lsafe(L,L2).
  425
  426csafe(' ','_') :- !.
  427csafe('-','_') :- !.
  428csafe('_','_') :- !.
  429csafe(C,C) :-
  430        C @>= 'a',
  431        C @=< 'z',
  432        !.
  433csafe(C,C) :-
  434        C @>= 'A',
  435        C @=< 'Z',
  436        !.
  437csafe(C,C) :-
  438        C @>= '0',
  439        C @=< '9',
  440        !.
  441csafe(_,'_').
  442
  443
  444make_meta_directive(Meta, (:- rdf_meta