Search code examples
pythonontologyswrlowlready

Use the reasoner of the library owlready2 on an ontology already in a file


I have used owlready2 (https://owlready2.readthedocs.io/en/latest/)

I'm trying to

  1. read an ontology on disk (onto.xml)
  2. add a swrl rule
  3. run the reasoner on it
  4. and then save the resulting ontology with the new facts inferred.

I'm a bit stuck right now.

I tried the examples, but I cannot understand why I have to define classes in the python program (https://owlready2.readthedocs.io/en/latest/rule.html) I tried this but I already have Classes, ObjectProperties and the Individuals in my onto.xml.

Defining classes, objectproperties and individuals all in the python works, the reasoner answers.

My prefered examples are this kind https://stackoverflow.com/questions/69224096/swrl-rules-in-owl-2/78320189 with the brothers and uncles, quite easy to follow.

Bye

Here's a basic_reader.py

#!/usr/bin/env python3
# Owlready2 currently reads the following file format: RDF/XML, OWL/XML, NTriples. The file format is automatically detected.
import argparse
import os

import owlready2 as owl

parser = argparse.ArgumentParser()
parser.add_argument("--ontology", help="ontology file", required=True)
args = parser.parse_args()

path2in = args.ontology
onto = owl.get_ontology(path2in).load()

print(list(onto.classes()))

print(list(onto.individuals()))

That works with an ontology on a file

if you ontology is in ttl format you can convert it on the fly like this :

#!/usr/bin/env python3
# Owlready2 currently reads the following file format: RDF/XML, OWL/XML, NTriples. The file format is automatically detected.
import argparse
import os

import owlready2 as owl

parser = argparse.ArgumentParser()
parser.add_argument("--ontology", help="ontology file as a ttl file", required=True)
args = parser.parse_args()

path2in = args.ontology
path2out = path2in.replace(".ttl", ".xml")

cmd2 = f"ontospy ser -f xml {path2in} 2>/dev/null > {path2out}"
os.system(cmd2)


onto = owl.get_ontology(path2out).load()

print(list(onto.classes()))

print(list(onto.individuals()))

Solution

  • I reply to myself with this working example :

    def main():
        """add a swrl rule."""
        parser = argparse.ArgumentParser()
        parser.add_argument("--ontology", help="ontology file", required=True)
        parser.add_argument(
            "--destination", help="destination ontology file", required=True
        )
    
        args = parser.parse_args()
    
        input_file = args.ontology
        output_file = args.destination
    
        onto = owl.get_ontology(input_file).load()
    
        with onto:
            swrl_rule = """ http://maccve/onto#Machine(?m) ^ http://maccve/onto#Package(?p) ^ http://maccve/onto#CVE(?c) ^ http://maccve/onto#mcontains(?m, ?p) ^ http://maccve/onto#has_CVE(?p, ?c) -> http://maccve/onto#contains_CVE(?m, ?c) """
    
            rule = owl.Imp()
            rule.set_as_rule(swrl_rule)
            onto.save(file=output_file, format="rdfxml")
    
    if __name__ == "__main__":
        main()
    

    So let's try with this ontology

    @prefix : <http://maccve/onto#> .
    @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
    @prefix owl: <http://www.w3.org/2002/07/owl#> .
    
    :Machine a owl:Class .
    :CVE a owl:Class .
    :Package a owl:Class .
    
    # Machine contains Package
    :mcontains a owl:ObjectProperty ;
             rdfs:domain :Machine ;
             rdfs:range :Package .
    
    # Package has_CVE CVE
    :has_CVE a owl:ObjectProperty ;
             rdfs:domain :Package ;
             rdfs:range :CVE .
    
    # Cette property est determinée par swrl
    :contains_CVE a owl:ObjectProperty ;
             rdfs:domain :Machine ;
             rdfs:range :CVE .
    
    
    :www1 a owl:NamedIndividual, :Machine .
    :www2 a owl:NamedIndividual, :Machine .
    
    :apache12 a owl:NamedIndividual, :Package .
    :apache22 a owl:NamedIndividual, :Package .
    
    :CVE1212 a owl:NamedIndividual, :CVE .
    
    :www1 :mcontains :apache12 .
    :www2 :mcontains :apache22 .
    :apache22 :has_CVE :CVE1212 .
    

    if the rule work it will infer that machine :www2 :mcontains a :CVE1212

    The tool must take an xml in input, so before adding the rule you must convert it to xml