How to add qualified cardinality in JENA

余生颓废 提交于 2019-11-30 15:30:23
Joshua Taylor

I actually just ran into this while handling another question, Adding more complicated subclass axiom. Creating this in Jena is a little bit tricky because support for the qualified cardinality restrictions is an OWL2 feature, and Jena has limited support for OWL2:

Jena Ontology API

Note that, at present, the Jena ontology API has only limited support for OWL2's qualified cardinality restrictions (i.e. cardinalityQ, minCardinalityQ and maxCardinalityQ). Qualified cardinality restrictions are encapsulated in the interfaces CardinalityQRestriction, MinCardinalityQRestriction and CardinalityQRestriction. OntModel also provides methods for creating and accessing qualified cardinality restrictions. Since they are not part of the OWL 1.0 language definition, qualified cardinality restrictions are not supported in OWL ontologies. Qualified cardinality restrictions were added to the OWL 2 update. OWL2 support in Jena will be added in due course.

Additionally, the Javadoc for the OWL2 vocabulary class says:

OWL2 vocabulary. NOTE: Jena does not provide OWL2 inference or OntModel support. These constants are provided for the convenience of users who are doing OWL2 work with the current OWL1 support and desire a suitable set of names.

You might also see a response that I posted to the Jena mailing list about a similar question, Re: Owl maxCardinality restriction.

But you want to create one anyway? Then you're one of those “users who are doing OWL2 work with the current OWL1 support and desire a suitable set of names.” To find out how the OWL2 construction should be serialized in RDF, we need to take a look at OWL 2 Web Ontology Language Mapping to RDF Graphs (Second Edition), particularly section 2 Mapping from the Structural Specification to RDF Graphs, which tells us that the class expression

ObjectExactCardinality( n OPE CE )

is serialized as the following set of triples

_:x rdf:type owl:Restriction .
_:x owl:onProperty T(OPE) .
_:x owl:qualifiedCardinality "n"^^xsd:nonNegativeInteger .
_:x owl:onClass T(CE) .

where _:x is the resource that is the class. The non-qualified case, which Jena already handles, turns

ObjectExactCardinality( n OPE )

into

_:x rdf:type owl:Restriction .
_:x owl:onProperty T(OPE) .
_:x owl:cardinality "n"^^xsd:nonNegativeInteger .

If we had one of the latter, we could replace its owl:cardinality property with an owl:qualifiedCardinality property, and add the appropriate owl:onClass property. Here's some Java code that does just that:

import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.ontology.OntProperty;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.OWL2;

public class QualifiedRestrictionExample {
    public static OntClass createCardinalityQRestriction(
            OntModel model,
            String uri,
            Property prop,
            int cardinality, 
            OntClass clas ) {
        OntClass klass = model.createCardinalityRestriction( uri, prop, cardinality );
        klass.removeAll( OWL.cardinality );
        klass.addLiteral( OWL2.qualifiedCardinality, cardinality );
        klass.addProperty( OWL2.onClass, clas );
        return klass;
    }

    public static void main(String[] args) {
        String NS = "https://stackoverflow.com/q/20562107/1281433/";
        OntModel model = ModelFactory.createOntologyModel( OntModelSpec.OWL_DL_MEM );
        OntClass test = model.createClass( NS+"Test" );
        OntProperty j = model.createObjectProperty( NS+"JeVysledkom" );
        OntClass k = model.createClass( NS+"Kolik_Fazovy" );
        OntClass x = createCardinalityQRestriction(model, null, j, 1, k);
        test.addSuperClass( x );
        model.write( System.out, "RDF/XML-ABBREV" );
    }
}

Output:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <owl:Class rdf:about="https://stackoverflow.com/q/20562107/1281433/Kolik_Fazovy"/>
  <owl:Class rdf:about="https://stackoverflow.com/q/20562107/1281433/Test">
    <rdfs:subClassOf>
      <owl:Restriction>
        <owl:onClass rdf:resource="https://stackoverflow.com/q/20562107/1281433/Kolik_Fazovy"/>
        <owl:qualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#long"
        >1</owl:qualifiedCardinality>
        <owl:onProperty>
          <owl:ObjectProperty rdf:about="https://stackoverflow.com/q/20562107/1281433/JeVysledkom"/>
        </owl:onProperty>
      </owl:Restriction>
    </rdfs:subClassOf>
  </owl:Class>
</rdf:RDF>

In Protégé:

    private void createOneToMany(OntModel ontoModel, OntClass ontoClass, OntProperty prop, Resource resource) {
        OntClass allValuesFromRestriction = ontoModel.createAllValuesFromRestriction(null, prop, resource);
        ontoClass.addSuperClass(allValuesFromRestriction);

        OntClass minCardinalityRestriction = ontoModel.createMinCardinalityRestriction(null, prop, 1);
        ontoClass.addSuperClass(minCardinalityRestriction);
    }

    private void createZeroToMany(OntModel ontoModel, OntClass ontoClass, OntProperty prop, Resource resource) {
        OntClass allValuesFromRestriction = ontoModel.createAllValuesFromRestriction(null, prop, resource);
        ontoClass.addSuperClass(allValuesFromRestriction);

        OntClass minCardinalityRestriction = ontoModel.createMinCardinalityRestriction(null, prop, 0);
        ontoClass.addSuperClass(minCardinalityRestriction);
    }

    private void createZeroToOne(OntModel ontoModel, OntClass ontoClass1, OntProperty prop, OntClass ontoClass2) {

        OntClass minCardinalityRestriction = ontoModel.createMinCardinalityRestriction(null, prop, 0);
        ontoClass1.addSuperClass(minCardinalityRestriction);

        OntClass maxCardinalityRestriction = ontoModel.createMaxCardinalityRestriction(null, prop, 1);
        ontoClass1.addSuperClass(maxCardinalityRestriction);
    }

    private void createOneToOne(OntModel ontoModel, OntClass ontoClass1, OntProperty prop, OntClass ontoClass2) {
        OntClass minCardinalityRestriction = ontoModel.createMinCardinalityRestriction(null, prop, 1);
        ontoClass1.addSuperClass(minCardinalityRestriction);

        OntClass maxCardinalityRestriction = ontoModel.createMaxCardinalityRestriction(null, prop, 1);
        ontoClass1.addSuperClass(maxCardinalityRestriction);
    }

Then you can just do:

OntModel ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
OntClass task = ontModel.createClass(OWL.NS + "Task");
OntClass actor = ontModel.createClass(OWL.NS + "Actor");
OntProperty propTask = ontModel.createObjectProperty( OWL.NS + "Task-performedBy-Actor");
OntProperty propActor = ontModel.createObjectProperty( OWL.NS + "Actor-performs-Task");

To call:

   createOneToMany(ontModel, task, prop, actor);
   createZeroToMany(ontModel, task, prop, actor);
   createOneToOne(ontModel, task, propTask, actor);
   createZeroToOne(ontModel, actor, propActor, task);

Sample of result:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
  <owl:Class rdf:about="http://www.w3.org/2002/07/owl#Task">
    <rdfs:subClassOf>
      <owl:Restriction rdf:nodeID="A0">
        <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#int"
        >1</owl:minCardinality>
        <owl:onProperty>
          <owl:ObjectProperty rdf:about="http://www.w3.org/2002/07/owl#Actor-performs-Task"/>
        </owl:onProperty>
      </owl:Restriction>
    </rdfs:subClassOf>
  </owl:Class>
  <owl:Class rdf:about="http://www.w3.org/2002/07/owl#Actor">
    <rdfs:subClassOf>
      <owl:Restriction>
        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#int"
        >1</owl:maxCardinality>
        <owl:onProperty rdf:resource="http://www.w3.org/2002/07/owl#Actor-performs-Task"/>
      </owl:Restriction>
    </rdfs:subClassOf>
    <rdfs:subClassOf rdf:nodeID="A0"/>
  </owl:Class>
  <owl:ObjectProperty rdf:about="http://www.w3.org/2002/07/owl#Task-performedBy-Actor"/>
</rdf:RDF>

Now there is also ONT-API, which is Jena extension for OWL2:

    String ns = "https://stackoverflow.com/q/20562107/1281433/";
    OntGraphModel model = OntModelFactory.createModel()
            .setNsPrefixes(OntModelFactory.STANDARD)
            .setNsPrefix("test", ns);

    OntClass c = model.createOntClass(ns + "Kolik_Fazovy");
    OntNOP p = model.createObjectProperty(ns + "JeVysledkom");
    model.createOntClass(ns + "Test").addSuperClass(model.createObjectCardinality(p, 1, c));

    // list all class expressions (2 owl classes, 1 restriction):
    Assert.assertEquals(3, model.ontObjects(OntCE.class).count());
    // print model
    model.write(System.out, "ttl");

Outout:

@prefix test:  <https://stackoverflow.com/q/20562107/1281433/> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix owl:   <http://www.w3.org/2002/07/owl#> .
@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .

test:Kolik_Fazovy  a  owl:Class .

test:JeVysledkom  a  owl:ObjectProperty .

test:Test  a             owl:Class ;
        rdfs:subClassOf  [ a                         owl:Restriction ;
                           owl:onClass               test:Kolik_Fazovy ;
                           owl:onProperty            test:JeVysledkom ;
                           owl:qualifiedCardinality  "1"^^xsd:nonNegativeInteger
                         ] .
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!