View source with raw comments or as raw
    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)  2003-2015, University of Amsterdam
    7                              VU University Amsterdam
    8    All rights reserved.
    9
   10    Redistribution and use in source and binary forms, with or without
   11    modification, are permitted provided that the following conditions
   12    are met:
   13
   14    1. Redistributions of source code must retain the above copyright
   15       notice, this list of conditions and the following disclaimer.
   16
   17    2. Redistributions in binary form must reproduce the above copyright
   18       notice, this list of conditions and the following disclaimer in
   19       the documentation and/or other materials provided with the
   20       distribution.
   21
   22    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   23    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   24    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   25    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   26    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   27    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   28    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   29    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   30    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33    POSSIBILITY OF SUCH DAMAGE.
   34*/
   35
   36:- module(rdfs,
   37          [ rdfs_subproperty_of/2,      % ?SubProperties, ?Property
   38            rdfs_subclass_of/2,         % ?SubClass, ?Class
   39            rdfs_class_property/2,      % +Class, ?Property
   40            rdfs_individual_of/2,       % ?Resource, ?Class
   41
   42            rdfs_label/2,               % ?Resource, ?Label
   43            rdfs_label/3,               % ?Resource, ?Language, ?Label
   44            rdfs_ns_label/2,            % +Resource, -Label
   45            rdfs_ns_label/3,            % +Resource, ?Label, -Label
   46
   47            rdfs_member/2,              % ?Object, +Set
   48            rdfs_list_to_prolog_list/2, % +Set, -List
   49            rdfs_assert_list/3,         % +List, -Resource, +DB
   50            rdfs_assert_list/2,         % +List, -Resource
   51
   52            rdfs_find/5                 % +String, +Dom, +Props, +Method, -Subj
   53          ]).   54:- use_module(library(lists)).   55:- use_module(rdf_db).

RDFS handling

This module provides various primitives for more high-level handling of RDF models from an RDFS viewpoint. Note that there exist two approaches for languages on top of RDF:

   71                 /*******************************
   72                 *          EXPANSION           *
   73                 *******************************/
   74
   75:- rdf_meta
   76    rdfs_subproperty_of(r,r),
   77    rdfs_subclass_of(r,r),
   78    rdfs_class_property(r,r),
   79    rdfs_individual_of(r,r),
   80    rdfs_label(r,-),
   81    rdfs_label(r,?,-).   82
   83
   84                 /*******************************
   85                 *      PROPERTY HIERARCHY      *
   86                 *******************************/
 rdfs_subproperty_of(+SubProperty, ?Property) is nondet
rdfs_subproperty_of(?SubProperty, +Property) is nondet
Query the property hierarchy.
   93rdfs_subproperty_of(SubProperty, Property) :-
   94    rdf_reachable(SubProperty, rdfs:subPropertyOf, Property).
   95
   96
   97                 /*******************************
   98                 *        CLASS HIERARCHY       *
   99                 *******************************/
 rdfs_subclass_of(+Class, ?Super) is nondet
rdfs_subclass_of(?Class, +Super) is nondet
Generate sub/super classes. rdf_reachable/3 considers the rdfs:subPropertyOf relation as well as cycles. Note that by definition all classes are subclass of rdfs:Resource, a case which is dealt with by the 1st and 3th clauses :-(

According to production 2.4 "rdfs:Datatype", Each instance of rdfs:Datatype is a subclass of rdfs:Literal.

  112rdfs_subclass_of(Class, Super) :-
  113    rdf_equal(rdfs:'Resource', Resource),
  114    Super == Resource,
  115    !,
  116    rdfs_individual_of(Class, rdfs:'Class').
  117rdfs_subclass_of(Class, Super) :-
  118    rdf_reachable(Class, rdfs:subClassOf, Super).
  119rdfs_subclass_of(Class, Super) :-
  120    nonvar(Class),
  121    var(Super),
  122    \+ rdf_reachable(Class, rdfs:subClassOf, rdfs:'Resource'),
  123    rdfs_individual_of(Class, rdfs:'Class'),
  124    rdf_equal(Super, rdfs:'Resource').
  125rdfs_subclass_of(Class, Super) :-       % production 2.4
  126    (   nonvar(Class)
  127    ->  rdf_has(Class, rdf:type, CType),
  128        rdf_reachable(CType, rdfs:subClassOf, rdfs:'Datatype'),
  129        \+ rdf_reachable(Class, rdfs:subClassOf, rdfs:'Literal'),
  130        rdf_equal(Super, rdfs:'Literal')
  131    ;   nonvar(Super)
  132    ->  rdf_reachable(Super, rdfs:subClassOf, rdfs:'Literal'),
  133        rdfs_individual_of(Class, rdfs:'Datatype')
  134    ).
  135
  136
  137                 /*******************************
  138                 *          INDIVIDUALS         *
  139                 *******************************/
 rdfs_individual_of(+Resource, +Class) is semidet
rdfs_individual_of(+Resource, -Class) is nondet
rdfs_individual_of(-Resource, +Class) is nondet
Generate resources belonging to a class or classes a resource belongs to. We assume everything at the `object' end of a triple is a class. A validator should confirm this property.

rdfs_individual_of(+, -) does not exploit domain and range properties, deriving that if rdf(R, P, _) is present R must satisfy the domain of P (and similar for range).

There are a few hacks:

  158rdfs_individual_of(Resource, Class) :-
  159    nonvar(Resource),
  160    !,
  161    (   nonvar(Class)
  162    ->  (   rdf_equal(Class, rdfs:'Resource')
  163        ->  true
  164        ;   rdfs_individual_of_r_c(Resource, Class)
  165        ->  true
  166        )
  167    ;   rdfs_individual_of_r_c(Resource, Class)
  168    ).
  169rdfs_individual_of(Resource, Class) :-
  170    nonvar(Class),
  171    !,
  172    (   rdf_equal(Class, rdfs:'Resource')
  173    ->  rdf_subject(Resource)
  174    ;   rdfs_subclass_of(SubClass, Class),
  175        rdf_has(Resource, rdf:type, SubClass)
  176    ).
  177rdfs_individual_of(_Resource, _Class) :-
  178    throw(error(instantiation_error, _)).
 rdfs_individual_of_r_c(+Resource, ?Class) is nondet
  182rdfs_individual_of_r_c(literal(_), Class) :-
  183    !,
  184    rdfs_subclass_of(Class, rdfs:'Literal').
  185rdfs_individual_of_r_c(^^(_,_), Class) :-
  186    !,
  187    rdfs_subclass_of(Class, rdfs:'Literal').
  188rdfs_individual_of_r_c(@(_,_), Class) :-
  189    !,
  190    rdfs_subclass_of(Class, rdfs:'Literal').
  191rdfs_individual_of_r_c(Resource, Class) :-
  192    (   rdf_has(Resource, rdf:type, MyClass)
  193    *-> rdfs_subclass_of(MyClass, Class)
  194    ;   rdf_equal(Class, rdfs:'Resource')
  195    ).
 rdfs_label(+Resource, -Label)
rdfs_label(-Resource, +Label)
Convert between class and label. If the label is generated from the resource the it uses both rdfs:label and its sub-properties, but labels registered with rdfs:label are returned first.
  205rdfs_label(Resource, Label) :-
  206    rdfs_label(Resource, _, Label).
 rdfs_label(+Resource, ?Lang, -Label) is multi
rdfs_label(+Resource, ?Lang, +Label) is semidet
rdfs_label(-Resource, ?Lang, ?Label) is nondet
Resource has Label in Lang. If Resource is nonvar calls take_label/3 which is guaranteed to succeed label.
  215rdfs_label(Resource, Lang, Label) :-
  216    nonvar(Resource),
  217    !,
  218    take_label(Resource, Lang, Label).
  219rdfs_label(Resource, Lang, Label) :-
  220    rdf_has(Resource, rdfs:label, literal(lang(Lang, Label))).
 rdfs_ns_label(+Resource, -Label) is multi
 rdfs_ns_label(+Resource, ?Lang, -Label) is multi
Present label with namespace indication. This predicate is intended to provide meaningful short names applicable to ontology maintainers. Note that this predicate is non-deterministic if the resource has multiple rdfs:label properties
  230rdfs_ns_label(Resource, Label) :-
  231    rdfs_ns_label(Resource, _, Label).
  232
  233rdfs_ns_label(Resource, Lang, Label) :-
  234    rdfs_label(Resource, Lang, Label0),
  235    (   rdf_global_id(NS:_, Resource),
  236        Label0 \== ''
  237    ->  atomic_list_concat([NS, Label0], :, Label)
  238    ;   \+ rdf_has(Resource, rdfs:label, _)
  239    ->  Label = Resource
  240    ;   member(Sep, [#,/]),
  241        sub_atom(Resource, B, L, A, Sep),
  242        sub_atom(Resource, _, A, 0, Frag),
  243        \+ sub_atom(Frag, _, _, _, Sep)
  244    ->  Len is B+L,
  245        sub_atom(Resource, 0, Len, _, NS),
  246        atomic_list_concat([NS, Label0], :, Label)
  247    ;   Label = Label0
  248    ).
 take_label(+Resource, ?Lang, -Label) is multi
Get the label to use for a resource in the give Language. First tries label_of/3. If this fails, break the Resource over # or / and if all fails, unify Label with Resource.
  257take_label(Resource, Lang, Label) :-
  258    (   label_of(Resource, Lang, Label)
  259    *-> true
  260    ;   after_char(Resource, '#', Local)
  261    ->  Label = Local
  262    ;   after_char(Resource, '/', Local)
  263    ->  Label = Local
  264    ;   Label = Resource
  265    ).
  266
  267after_char(Atom, Char, Rest) :-
  268    State = last(-),
  269    (   sub_atom(Atom, _, _, L, Char),
  270        nb_setarg(1, State, L),
  271        fail
  272    ;   arg(1, State, L),
  273        L \== (-)
  274    ),
  275    sub_atom(Atom, _, L, 0, Rest).
 label_of(+Resource, ?Lang, ?Label) is nondet
True if rdf_has(Resource, rdfs:label, literal(Lang, Label)) is true, but guaranteed to generate rdfs:label before any subproperty thereof.
  284label_of(Resource, Lang, Label) :-
  285    rdf(Resource, rdfs:label, literal(lang(Lang, Label))),
  286    nonvar(Lang).
  287label_of(Resource, Lang, Label) :-
  288    rdf_equal(rdfs:label, LabelP),
  289    rdf_has(Resource, LabelP, literal(lang(Lang, Label)), P),
  290    nonvar(Lang),
  291    P \== LabelP.
  292label_of(Resource, Lang, Label) :-
  293    var(Lang),
  294    rdf_has(Resource, rdfs:label, literal(type(xsd:string, Label))).
 rdfs_class_property(+Class, ?Property)
Enumerate the properties in the domain of Class.
  300rdfs_class_property(Class, Property) :-
  301    rdfs_individual_of(Property, rdf:'Property'),
  302    rdf_has(Property, rdfs:domain, Domain),
  303    rdfs_subclass_of(Class, Domain).
  304
  305
  306                 /*******************************
  307                 *           COLLECTIONS        *
  308                 *******************************/
 rdfs_member(?Element, +Set)
As Prolog member on sets. Operates both on attributes parsed as parseType="Collection" as well as on Bag, Set and Alt.
  315rdfs_member(Element, Set) :-
  316    rdf_has(Set, rdf:first, _),
  317    !,
  318    rdfs_collection_member(Element, Set).
  319rdfs_member(Element, Set) :-
  320    container_class(Class),
  321    rdfs_individual_of(Set, Class),
  322    !,
  323    (   nonvar(Element)
  324    ->  rdf(Set, Predicate, Element),
  325        rdf_member_property(Predicate, _N)
  326    ;   findall(N-V, rdf_nth(Set, N, V), Pairs),
  327        keysort(Pairs, Sorted),
  328        member(_-Element, Sorted)
  329    ).
  330
  331rdf_nth(Set, N, V) :-
  332    rdf(Set, P, V),
  333    rdf_member_property(P, N).
  334
  335:- rdf_meta container_class(r).  336
  337container_class(rdf:'Bag').
  338container_class(rdf:'Seq').
  339container_class(rdf:'Alt').
  340
  341
  342rdfs_collection_member(Element, Set) :-
  343    rdf_has(Set, rdf:first, Element).
  344rdfs_collection_member(Element, Set) :-
  345    rdf_has(Set, rdf:rest, Tail),
  346    !,
  347    rdfs_collection_member(Element, Tail).
 rdfs_list_to_prolog_list(+RDFSList, -PrologList)
Convert ann RDFS list (result from parseType=Collection) into a Prolog list of elements.
  355rdfs_list_to_prolog_list(Set, []) :-
  356    rdf_equal(Set, rdf:nil),
  357    !.
  358rdfs_list_to_prolog_list(Set, [H|T]) :-
  359    rdf_has(Set, rdf:first, H),
  360    rdf_has(Set, rdf:rest, Tail),
  361    !,
  362    rdfs_list_to_prolog_list(Tail, T).
 rdfs_assert_list(+Resources, -List) is det
 rdfs_assert_list(+Resources, -List, +DB) is det
Create an RDF list from the given Resources.
  370rdfs_assert_list(Resources, List) :-
  371    rdfs_assert_list(Resources, List, user).
  372
  373rdfs_assert_list([], Nil, _) :-
  374    rdf_equal(rdf:nil, Nil).
  375rdfs_assert_list([H|T], List, DB) :-
  376    rdfs_assert_list(T, Tail, DB),
  377    rdf_bnode(List),
  378    rdf_assert(List, rdf:rest, Tail, DB),
  379    rdf_assert(List, rdf:first, H, DB),
  380    rdf_assert(List, rdf:type, rdf:'List', DB).
  381
  382
  383                 /*******************************
  384                 *     SEARCH IN HIERARCHY      *
  385                 *******************************/
 rdfs_find(+String, +Domain, ?Properties, +Method, -Subject)
Search all classes below Domain for a literal property with that matches String. Method is one of

domain is defined by owl_satisfy from owl.pl

Note that the rdfs:label field is handled by rdfs_label/2, making the URI-ref fragment name the last resort to determine the label.

  403rdfs_find(String, Domain, Fields, Method, Subject) :-
  404    var(Fields),
  405    !,
  406    For =.. [Method,String],
  407    rdf_has(Subject, Field, literal(For, _)),
  408    owl_satisfies(Domain, Subject),
  409    Fields = [Field].               % report where we found it.
  410rdfs_find(String, Domain, Fields, Method, Subject) :-
  411    globalise_list(Fields, GlobalFields),
  412    For =.. [Method,String],
  413    member(Field, GlobalFields),
  414    (   Field == resource
  415    ->  rdf_subject(Subject),
  416        rdf_match_label(Method, String, Subject)
  417    ;   rdf_has(Subject, Field, literal(For, _))
  418    ),
  419    owl_satisfies(Domain, Subject).
  420
  421owl_satisfies(Domain, _) :-
  422    rdf_equal(rdfs:'Resource', Domain),
  423    !.
  424                                        % Descriptions
  425owl_satisfies(class(Domain), Resource) :-
  426    !,
  427    (   rdf_equal(Domain, rdfs:'Resource')
  428    ->  true
  429    ;   rdfs_subclass_of(Resource, Domain)
  430    ).
  431owl_satisfies(union_of(Domains), Resource) :-
  432    !,
  433    member(Domain, Domains),
  434    owl_satisfies(Domain, Resource),
  435    !.
  436owl_satisfies(intersection_of(Domains), Resource) :-
  437    !,
  438    in_all_domains(Domains, Resource).
  439owl_satisfies(complement_of(Domain), Resource) :-
  440    !,
  441    \+ owl_satisfies(Domain, Resource).
  442owl_satisfies(one_of(List), Resource) :-
  443    !,
  444    memberchk(Resource, List).
  445                                        % Restrictions
  446owl_satisfies(all_values_from(Domain), Resource) :-
  447    (   rdf_equal(Domain, rdfs:'Resource')
  448    ->  true
  449    ;   rdfs_individual_of(Resource, Domain)
  450    ),
  451    !.
  452owl_satisfies(some_values_from(_Domain), _Resource) :- !.
  453owl_satisfies(has_value(Value), Resource) :-
  454    rdf_equal(Value, Resource).
  455
  456
  457in_all_domains([], _).
  458in_all_domains([H|T], Resource) :-
  459    owl_satisfies(H, Resource),
  460    in_all_domains(T, Resource).
  461
  462globalise_list([], []) :- !.
  463globalise_list([H0|T0], [H|T]) :-
  464    !,
  465    globalise_list(H0, H),
  466    globalise_list(T0, T).
  467globalise_list(X, G) :-
  468    rdf_global_id(X, G)