Source code for djangordf.reasoning.skos

"""SKOS-specific reasoner.

Propagates ``skos:broader`` / ``skos:narrower`` to their transitive
variants and closes the transitive predicates under composition.
Also enforces ``skos:exactMatch`` symmetry.
"""
from typing import Sequence

from rdflib import URIRef

from .base import Reasoner


_SKOS = "http://www.w3.org/2004/02/skos/core#"
_BROADER = _SKOS + "broader"
_NARROWER = _SKOS + "narrower"
_BROADER_TRANS = _SKOS + "broaderTransitive"
_NARROWER_TRANS = _SKOS + "narrowerTransitive"
_EXACT_MATCH = _SKOS + "exactMatch"


def _rule(template: str, src: URIRef, tgt: URIRef) -> str:
    return template.format(src=src, tgt=tgt)


[docs] class SKOSReasoner(Reasoner): """Run SKOS entailment rules to a fixpoint.""" _BROADER_TO_TRANSITIVE = ( "INSERT {{ GRAPH <{tgt}> {{ ?a <" + _BROADER_TRANS + "> ?b }} }} " "WHERE {{ GRAPH <{src}> {{ " "?a <" + _BROADER + "> ?b . " "}} " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ " "?a <" + _BROADER_TRANS + "> ?b " "}} }} }}" ) _BROADER_TRANSITIVE_CLOSURE = ( "INSERT {{ GRAPH <{tgt}> {{ ?a <" + _BROADER_TRANS + "> ?c }} }} " "WHERE {{ GRAPH <{src}> {{ " "?a <" + _BROADER_TRANS + "> ?b . " "?b <" + _BROADER_TRANS + "> ?c . " "}} " "FILTER (?a != ?c) " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ " "?a <" + _BROADER_TRANS + "> ?c " "}} }} }}" ) _NARROWER_TO_TRANSITIVE = ( "INSERT {{ GRAPH <{tgt}> {{ ?a <" + _NARROWER_TRANS + "> ?b }} }} " "WHERE {{ GRAPH <{src}> {{ " "?a <" + _NARROWER + "> ?b . " "}} " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ " "?a <" + _NARROWER_TRANS + "> ?b " "}} }} }}" ) _NARROWER_TRANSITIVE_CLOSURE = ( "INSERT {{ GRAPH <{tgt}> {{ ?a <" + _NARROWER_TRANS + "> ?c }} }} " "WHERE {{ GRAPH <{src}> {{ " "?a <" + _NARROWER_TRANS + "> ?b . " "?b <" + _NARROWER_TRANS + "> ?c . " "}} " "FILTER (?a != ?c) " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ " "?a <" + _NARROWER_TRANS + "> ?c " "}} }} }}" ) _EXACT_MATCH_SYMMETRY = ( "INSERT {{ GRAPH <{tgt}> {{ ?b <" + _EXACT_MATCH + "> ?a }} }} " "WHERE {{ GRAPH <{src}> {{ " "?a <" + _EXACT_MATCH + "> ?b . " "}} " "FILTER (?a != ?b) " "FILTER NOT EXISTS {{ GRAPH <{tgt}> {{ " "?b <" + _EXACT_MATCH + "> ?a " "}} }} }}" )
[docs] def rules(self, source_graph: URIRef, target_graph: URIRef) -> Sequence[str]: return [ _rule(self._BROADER_TO_TRANSITIVE, source_graph, target_graph), _rule(self._BROADER_TRANSITIVE_CLOSURE, source_graph, target_graph), _rule(self._NARROWER_TO_TRANSITIVE, source_graph, target_graph), _rule(self._NARROWER_TRANSITIVE_CLOSURE, source_graph, target_graph), _rule(self._EXACT_MATCH_SYMMETRY, source_graph, target_graph), ]