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(semweb/rdf_prefixes),
   55              [ (rdf_meta)/1, op(_,_,rdf_meta)
   56              ]).   57:- use_module(rdf_db,
   58              [ rdf_reachable/3, rdf_equal/2, rdf_has/3, rdf_subject/1,
   59                rdf_global_id/2, rdf/3, rdf_has/4, rdf_member_property/2,
   60                rdf_bnode/1, rdf_assert/4, rdf_match_label/3
   61              ]).   62
   63:- autoload(library(lists),[member/2]).

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:

   78                 /*******************************
   79                 *          EXPANSION           *
   80                 *******************************/
   81
   82:- rdf_meta
   83    rdfs_subproperty_of(r,r),
   84    rdfs_subclass_of(r,r),
   85    rdfs_class_property(r,r),
   86    rdfs_individual_of(r,r),
   87    rdfs_label(r,-),
   88    rdfs_label(r,?,-).   89
   90
   91                 /*******************************
   92                 *      PROPERTY HIERARCHY      *
   93                 *******************************/
 rdfs_subproperty_of(+SubProperty, ?Property) is nondet
rdfs_subproperty_of(?SubProperty, +Property) is nondet
Query the property hierarchy.
  100rdfs_subproperty_of(SubProperty, Property) :-
  101    rdf_reachable(SubProperty, rdfs:subPropertyOf, Property).
  102
  103
  104                 /*******************************
  105                 *        CLASS HIERARCHY       *
  106                 *******************************/
 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.

  119rdfs_subclass_of(Class, Super) :-
  120    rdf_equal(rdfs:'Resource', Resource),
  121    Super == Resource,
  122    !,
  123    rdfs_individual_of(Class, rdfs:'Class').
  124rdfs_subclass_of(Class, Super) :-
  125    rdf_reachable(Class, rdfs:subClassOf, Super).
  126rdfs_subclass_of(Class, Super) :-
  127    nonvar(Class),
  128    var(Super),
  129    \+ rdf_reachable(Class, rdfs:subClassOf, rdfs:'Resource'),
  130    rdfs_individual_of(Class, rdfs:'Class'),
  131    rdf_equal(Super, rdfs:'Resource').
  132rdfs_subclass_of(Class, Super) :-       % production 2.4
  133    (   nonvar(Class)
  134    ->  rdf_has(Class, rdf:type, CType),
  135        rdf_reachable(CType, rdfs:subClassOf, rdfs:'Datatype'),
  136        \+ rdf_reachable(Class, rdfs:subClassOf, rdfs:'Literal'),
  137        rdf_equal(Super, rdfs:'Literal')
  138    ;   nonvar(Super)
  139    ->  rdf_reachable(Super, rdfs:subClassOf, rdfs:'Literal'),
  140        rdfs_individual_of(Class, rdfs:'Datatype')
  141    ).
  142
  143
  144                 /*******************************
  145                 *          INDIVIDUALS         *
  146                 *******************************/
 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:

  165rdfs_individual_of(Resource, Class) :-
  166    nonvar(Resource),
  167    !,
  168    (   nonvar(Class)
  169    ->  (   rdf_equal(Class, rdfs:'Resource')
  170        ->  true
  171        ;   rdfs_individual_of_r_c(Resource, Class)
  172        ->  true
  173        )
  174    ;   rdfs_individual_of_r_c(Resource, Class)
  175    ).
  176rdfs_individual_of(Resource, Class) :-
  177    nonvar(Class),
  178    !,
  179    (   rdf_equal(Class, rdfs:'Resource')
  180    ->  rdf_subject(Resource)
  181    ;   rdfs_subclass_of(SubClass, Class),
  182        rdf_has(Resource, rdf:type, SubClass)
  183    ).
  184rdfs_individual_of(_Resource, _Class) :-
  185    throw(error(instantiation_error, _)).
 rdfs_individual_of_r_c(+Resource, ?Class) is nondet
  189rdfs_individual_of_r_c(literal(_), Class) :-
  190    !,
  191    rdfs_subclass_of(Class, rdfs:'Literal').
  192rdfs_individual_of_r_c(^^(_,_), Class) :-
  193    !,
  194    rdfs_subclass_of(Class, rdfs:'Literal').
  195rdfs_individual_of_r_c(@(_,_), Class) :-
  196    !,
  197    rdfs_subclass_of(Class, rdfs:'Literal').
  198rdfs_individual_of_r_c(Resource, Class) :-
  199    (   rdf_has(Resource, rdf:type, MyClass)
  200    *-> rdfs_subclass_of(MyClass, Class)
  201    ;   rdf_equal(Class, rdfs:'Resource')
  202    ).
 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.
  212rdfs_label(Resource, Label) :-
  213    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.
  222rdfs_label(Resource, Lang, Label) :-
  223    nonvar(Resource),
  224    !,
  225    take_label(Resource, Lang, Label).
  226rdfs_label(Resource, Lang, Label) :-
  227    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
  237rdfs_ns_label(Resource, Label) :-
  238    rdfs_ns_label(Resource, _, Label).
  239
  240rdfs_ns_label(Resource, Lang, Label) :-
  241    rdfs_label(Resource, Lang, Label0),
  242    (   rdf_global_id(NS:_, Resource),
  243        Label0 \== ''
  244    ->  atomic_list_concat([NS, Label0], :, Label)
  245    ;   \+ rdf_has(Resource, rdfs:label, _)
  246    ->  Label = Resource
  247    ;   member(Sep, [#,/]),
  248        sub_atom(Resource, B, L, A, Sep),
  249        sub_atom(Resource, _, A, 0, Frag),
  250        \+ sub_atom(Frag, _, _, _, Sep)
  251    ->  Len is B+L,
  252        sub_atom(Resource, 0, Len, _, NS),
  253        atomic_list_concat([NS, Label0], :, Label)
  254    ;   Label = Label0
  255    ).
 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.
  264take_label(Resource, Lang, Label) :-
  265    (   label_of(Resource, Lang, Label)
  266    *-> true
  267    ;   after_char(Resource, '#', Local)
  268    ->  Label = Local
  269    ;   after_char(Resource, '/', Local)
  270    ->  Label = Local
  271    ;   Label = Resource
  272    ).
  273
  274after_char(Atom, Char, Rest) :-
  275    State = last(-),
  276    (   sub_atom(Atom, _, _, L, Char),
  277        nb_setarg(1, State, L),
  278        fail
  279    ;   arg(1, State, L),
  280        L \== (-)
  281    ),
  282    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.
  291label_of(Resource, Lang, Label) :-
  292    rdf(Resource, rdfs:label, literal(lang(Lang, Label))),
  293    nonvar(Lang).
  294label_of(Resource, Lang, Label) :-
  295    rdf_equal(rdfs:label, LabelP),
  296    rdf_has(Resource, LabelP, literal(lang(Lang, Label)), P),
  297    nonvar(Lang),
  298    P \== LabelP.
  299label_of(Resource, Lang, Label) :-
  300    var(Lang),
  301    rdf_has(Resource, rdfs:label, literal(type(xsd:string, Label))).
 rdfs_class_property(+Class, ?Property)
Enumerate the properties in the domain of Class.
  307rdfs_class_property(Class, Property) :-
  308    rdfs_individual_of(Property, rdf:'Property'),
  309    rdf_has(Property, rdfs:domain, Domain),
  310    rdfs_subclass_of(Class, Domain).
  311
  312
  313                 /*******************************
  314                 *           COLLECTIONS        *
  315                 *******************************/
 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.
  322rdfs_member(Element, Set) :-
  323    rdf_has(Set, rdf:first, _),
  324    !,
  325    rdfs_collection_member(Element, Set).
  326rdfs_member(Element, Set) :-
  327    container_class(Class),
  328    rdfs_individual_of(Set, Class),
  329    !,
  330    (   nonvar(Element)
  331    ->  rdf(Set, Predicate, Element),
  332        rdf_member_property(Predicate, _N)
  333    ;   findall(N-V, rdf_nth(Set, N, V), Pairs),
  334        keysort(Pairs, Sorted),
  335        member(_-Element, Sorted)
  336    ).
  337
  338rdf_nth(Set, N, V) :-
  339    rdf(Set, P, V),
  340    rdf_member_property(P, N).
  341
  342:- rdf_meta container_class(r).  343
  344container_class(rdf:'Bag').
  345container_class(rdf:'Seq').
  346container_class(rdf:'Alt').
  347
  348
  349rdfs_collection_member(Element, Set) :-
  350    rdf_has(Set, rdf:first, Element).
  351rdfs_collection_member(Element, Set) :-
  352    rdf_has(Set, rdf:rest, Tail),
  353    !,
  354    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.
  362rdfs_list_to_prolog_list(Set, []) :-
  363    rdf_equal(Set, rdf:nil),
  364    !.
  365rdfs_list_to_prolog_list(Set, [H|T]) :-
  366    rdf_has(Set, rdf:first, H),
  367    rdf_has(Set, rdf:rest, Tail),
  368    !,
  369    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.
  377rdfs_assert_list(Resources, List) :-
  378    rdfs_assert_list(Resources, List, user).
  379
  380rdfs_assert_list([], Nil, _) :-
  381    rdf_equal(rdf:nil, Nil).
  382rdfs_assert_list([H|T], List, DB) :-
  383    rdfs_assert_list(T, Tail, DB),
  384    rdf_bnode(List),
  385    rdf_assert(List, rdf:rest, Tail, DB),
  386    rdf_assert(List, rdf:first, H, DB),
  387    rdf_assert(List, rdf:type, rdf:'List', DB).
  388
  389
  390                 /*******************************
  391                 *     SEARCH IN HIERARCHY      *
  392                 *******************************/
 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.

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