diff --git a/core/src/main/java/org/incenp/obofoundry/kgcl/owl/OntologyBasedLabelResolver.java b/core/src/main/java/org/incenp/obofoundry/kgcl/owl/OntologyBasedLabelResolver.java index 40d2791..c9cfd7e 100644 --- a/core/src/main/java/org/incenp/obofoundry/kgcl/owl/OntologyBasedLabelResolver.java +++ b/core/src/main/java/org/incenp/obofoundry/kgcl/owl/OntologyBasedLabelResolver.java @@ -27,6 +27,7 @@ import org.semanticweb.owlapi.model.OWLEntity; import org.semanticweb.owlapi.model.OWLOntology; import org.semanticweb.owlapi.model.parameters.Imports; +import org.semanticweb.owlapi.vocab.OWLRDFVocabulary; /** * An object to resolve labels into identifiers using the {@code rdfs:label} @@ -63,6 +64,22 @@ public String resolve(String label) { } resolved = idMap.get(label); } + + // We accept "is_a" as a shortcut for "rdfs:subClassOf". We check for it only + // after everything else, to avoid masking another class or relation in the + // ontology that would have a "is_a" label (admittedly such a label would be a + // very bad idea, but just in case). + // FIXME: Ideally, "is_a" should be resolved into "rdfs:subClassOf" when it is + // used between classes, and into "rdfs:subPropertyOf" when it is used between + // properties. But providing the resolver with the necessary context to do that + // would complicate things too much for arguably little gain (it is assumed that + // most uses of "is_a" will be between classes). So, "is_a" can only be used as + // a shortcut when dealing with classes. For subsumption relations between + // properties, "rdfs:subPropertyOf" should be used explicitly. + if ( resolved == null && label.equals("is_a") ) { + resolved = OWLRDFVocabulary.RDFS_SUBCLASS_OF.getIRI().toString(); + } + return resolved; } diff --git a/core/src/test/java/org/incenp/obofoundry/kgcl/owl/OntologyBasedLabelResolverTest.java b/core/src/test/java/org/incenp/obofoundry/kgcl/owl/OntologyBasedLabelResolverTest.java index 43e3b60..2c4147d 100644 --- a/core/src/test/java/org/incenp/obofoundry/kgcl/owl/OntologyBasedLabelResolverTest.java +++ b/core/src/test/java/org/incenp/obofoundry/kgcl/owl/OntologyBasedLabelResolverTest.java @@ -31,6 +31,7 @@ import org.semanticweb.owlapi.model.OWLOntology; import org.semanticweb.owlapi.model.OWLOntologyCreationException; import org.semanticweb.owlapi.model.OWLOntologyManager; +import org.semanticweb.owlapi.vocab.OWLRDFVocabulary; public class OntologyBasedLabelResolverTest { @@ -74,4 +75,23 @@ void testResolveOBOShorthands() { Assertions.assertEquals("http://www.co-ode.org/ontologies/pizza/pizza.owl#hasBase", resolver.resolve("has_base")); } + + @Test + void testResolveSpecialShorthands() { + // Check that "is_a" resolves into rdfs:subClassOf + SimpleLabelResolver resolver = new OntologyBasedLabelResolver(ontology); + Assertions.assertEquals(OWLRDFVocabulary.RDFS_SUBCLASS_OF.getIRI().toString(), resolver.resolve("is_a")); + + // Unless a class with a "is_a" label exists in the ontology + OWLOntologyManager mgr = ontology.getOWLOntologyManager(); + OWLDataFactory factory = mgr.getOWLDataFactory(); + IRI dummy = IRI.create("http://www.co-ode.org/ontologies/pizza/pizza.owl#dummy"); + mgr.addAxiom(ontology, factory.getOWLDeclarationAxiom(factory.getOWLClass(dummy))); + mgr.addAxiom(ontology, + factory.getOWLAnnotationAssertionAxiom( + factory.getOWLAnnotationProperty(OWLRDFVocabulary.RDFS_LABEL.getIRI()), dummy, + factory.getOWLLiteral("is_a"))); + resolver = new OntologyBasedLabelResolver(ontology); + Assertions.assertEquals(dummy.toString(), resolver.resolve("is_a")); + } }