Skip to content

Commit

Permalink
Allow arbitrary annotation properties as qualifier tags in OBO #1099
Browse files Browse the repository at this point in the history
Allowing arbitrary defined annotation properties as qualifier tags.

Use oboInOWL as the default namespace when looking up tag IRIs.
This helps with backwards compatibility for undeclared annotation
properties.

Enforce oio namespace for created_by and creation_date.
  • Loading branch information
ignazio1977 committed Jan 15, 2024
1 parent 49831fc commit 3740cef
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ public enum Obo2OWLVocabulary implements HasIRI {
/**IRI_IAO_0100001. */ IRI_IAO_0100001(DEFAULT_IRI_PREFIX, "IAO_0100001", "term replaced by", OboFormatTag.TAG_REPLACED_BY.getTag()),
/**IRI_OIO_shorthand. */ IRI_OIO_shorthand(OIOVOCAB_IRI_PREFIX, SHORTHAND, SHORTHAND, SHORTHAND),
/**IRI_OIO_consider. */ IRI_OIO_consider(OIOVOCAB_IRI_PREFIX, "consider", "consider", OboFormatTag.TAG_CONSIDER.getTag()),
/**IRI_OIO_id*/ IRI_OIO_id(OIOVOCAB_IRI_PREFIX, "id", "id", OboFormatTag.TAG_ID.getTag()),
/**IRI_OIO_created_by*/ IRI_OIO_created_by(OIOVOCAB_IRI_PREFIX, "created_by", "created by", OboFormatTag.TAG_CREATED_BY.getTag()),
/**IRI_OIO_creation_date*/ IRI_OIO_creation_date(OIOVOCAB_IRI_PREFIX, "creation_date", "creation date", OboFormatTag.TAG_CREATION_DATE.getTag()),
/**IRI_OIO_hasOBOFormatVersion. */ IRI_OIO_hasOBOFormatVersion(OIOVOCAB_IRI_PREFIX, "hasOBOFormatVersion", "has_obo_format_version", OboFormatTag.TAG_FORMAT_VERSION.getTag()),
/**IRI_OIO_treatXrefsAsIsA. */ IRI_OIO_treatXrefsAsIsA(OIOVOCAB_IRI_PREFIX, "treat-xrefs-as-is_a", "treat-xrefs-as-is_a", OboFormatTag.TAG_TREAT_XREFS_AS_IS_A.getTag()),
/**IRI_OIO_treatXrefsAsHasSubClass. */ IRI_OIO_treatXrefsAsHasSubClass(OIOVOCAB_IRI_PREFIX, "treat-xrefs-as-has-subclass", "treat-xrefs-as-has-subclass", OboFormatTag.TAG_TREAT_XREFS_AS_HAS_SUBCLASS.getTag()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,4 @@ void testBOMError32big(int[] b, String input) throws IOException {
loadFrom(in);
}
}

@ParameterizedTest
@MethodSource("data")
void testBOMError32bigReader(int[] b, String input) throws Exception {
try (InputStream in = in(b, input);
InputStreamReader r = new InputStreamReader(in);
ReaderDocumentSource source = new ReaderDocumentSource(r)) {
m.loadOntologyFromOntologyDocument(source);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ void shouldLoad() {
literal("A unit of measurement is a standardized quantity of a physical quality.")),
AnnotationAssertion(Annotation(ANNPROPS.hasDbXref, LITERALS.literal),
ANNPROPS.iao0000115, CLASSES.uo1.getIRI(),
literal("A unit which is a standard measure of the distance between two points.")));
literal("A unit which is a standard measure of the distance between two points.")),
AnnotationAssertion(RDFSLabel(), ANNPROPS.createdBy.getIRI(), literal("created by")),
AnnotationAssertion(RDFSLabel(), ANNPROPS.id.getIRI(), literal("id")));
assertEquals(expected, asUnorderedSet(ontology.axioms()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import javax.annotation.Nullable;

import org.semanticweb.owlapi.documents.StringDocumentTarget;
import org.semanticweb.owlapi.formats.OBODocumentFormat;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.obolibrary.obo2owl.OWLAPIOwl2Obo;
Expand Down Expand Up @@ -43,14 +44,19 @@ public List<Diff> roundTripOBODoc(OBODoc obodoc, boolean isExpectRoundtrip)
OWLOntology oo = convert(obodoc);
StringDocumentTarget oo1 = saveOntology(oo);
OBODoc obodoc2 = convert(oo);
StringDocumentTarget oo2 = saveOntology(convert(obodoc2));
OWLOntology o2 = convert(obodoc2);
StringDocumentTarget oo2 = saveOntology(o2);
String s1 = oo1.toString();
String s2 = oo2.toString();
assertEquals(s1, s2);
obodoc2.check();
List<Diff> diffs = OBODocDiffer.getDiffs(obodoc, obodoc2);
if (isExpectRoundtrip) {
assertEquals(0, diffs.size(), "Expected no diffs but " + diffs);
if (diffs.size() > 0) {
StringDocumentTarget out1 = saveOntology(oo, new OBODocumentFormat());
StringDocumentTarget out2 = saveOntology(o2, new OBODocumentFormat());
assertEquals(out1.toString(), out2.toString());
}
}
return diffs;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ void testRoundTripOWLRO() {
Collection<QualifierValue> values = clause.getQualifierValues();
assertEquals(1, values.size());
QualifierValue value = values.iterator().next();
assertEquals("http://purl.obolibrary.org/obo/IAO_0000116", value.getQualifier());
assertEquals("IAO:0000116", value.getQualifier());
assertEquals("From Allen terminology", value.getValue());
found = true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.semanticweb.owlapi.obolibrarytest.oboformat;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.jupiter.api.Test;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAnnotationProperty;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.utilities.OWLAPIStreamUtils;
import org.semanticweb.owlapi.vocab.OWL2Datatype;

class TagIRIsTest extends OboFormatTestBasics {

@Test
void testTagIRIMapping() {
OWLAnnotationProperty definition =
df.getOWLAnnotationProperty(df.getIRI("http://purl.obolibrary.org/obo/IAO_0000115"));
OWLAnnotationProperty oioCreatedBy = df.getOWLAnnotationProperty(
df.getIRI("http://www.geneontology.org/formats/oboInOwl#created_by"));
OWLAnnotationProperty oioInventedBy = df.getOWLAnnotationProperty(
df.getIRI("http://www.geneontology.org/formats/oboInOwl#invented_by"));
OWLAnnotationProperty source =
df.getOWLAnnotationProperty(df.getIRI("http://purl.obolibrary.org/obo/MYONT_20"));
OWLOntology ont = load("obo/tag_iris.obo", m);
Set<OWLAxiom> axioms = OWLAPIStreamUtils.asSet(ont.axioms());
OWLClass term1 = df.getOWLClass(df.getIRI("http://purl.obolibrary.org/obo/MYONT_1"));
OWLClass term2 = df.getOWLClass(df.getIRI("http://purl.obolibrary.org/obo/MYONT_2"));
OWLClass term3 = df.getOWLClass(df.getIRI("http://purl.obolibrary.org/obo/MYONT_3"));
OWLClass term4 = df.getOWLClass(df.getIRI("http://purl.obolibrary.org/obo/MYONT_4"));
Set<OWLAnnotation> annotations = Stream
.of(df.getOWLAnnotation(df.getRDFSComment(), string("Here is a sub-annotation.")),
df.getOWLAnnotation(df.getRDFSSeeAlso(), string("A nested see also value.")))
.collect(Collectors.toSet());
assertTrue(axioms.contains(df.getOWLAnnotationAssertionAxiom(definition, term1.getIRI(),
string("Definition of term one."), annotations)));
assertTrue(axioms.contains(df.getOWLAnnotationAssertionAxiom(df.getRDFSSeeAlso(),
term1.getIRI(), string("See also value."))));
assertTrue(axioms.contains(df.getOWLAnnotationAssertionAxiom(definition, term2.getIRI(),
string("Definition of term two."), Collections
.singleton(df.getOWLAnnotation(source, string("A nested annotation value."))))));
assertTrue(axioms.contains(df.getOWLAnnotationAssertionAxiom(definition, term3.getIRI(),
string("Definition of term three."), Collections
.singleton(df.getOWLAnnotation(source, string("A definition source value."))))));
assertTrue(
axioms.contains(
df.getOWLAnnotationAssertionAxiom(oioCreatedBy, term3.getIRI(), string("goc:bro"))),
"created_by is built in and should not be overridden by a typedef");
assertTrue(
axioms.contains(df.getOWLAnnotationAssertionAxiom(definition, term4.getIRI(),
string("Definition of term four."),
Collections
.singleton(df.getOWLAnnotation(oioInventedBy, string("An inventor value."))))),
"An undeclared tag should have oio namespace");

}

protected OWLLiteral string(String l) {
return df.getOWLLiteral(l, OWL2Datatype.XSD_STRING);
}
}
56 changes: 56 additions & 0 deletions contract/src/test/resources/obo/tag_iris.obo
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
format-version: 1.2
ontology: myont

[Term]
id: MYONT:1
name: term one
def: "Definition of term one." [] {comment="Here is a sub-annotation.", seeAlso="A nested see also value."}
property_value: seeAlso "See also value." xsd:string

[Term]
id: MYONT:2
name: term two
def: "Definition of term two." [] {MYONT:20="A nested annotation value."}
property_value: MYONT:21 "A top level annotation value." xsd:string

[Term]
id: MYONT:3
name: term three
def: "Definition of term three." [] {source="A definition source value."}
intersection_of: MYONT:2 ! term two
intersection_of: results_in_transport_across GO:0005739 ! mitochondrion
created_by: goc:bro

[Term]
id: MYONT:4
name: term four
def: "Definition of term four." [] {invented_by="An inventor value."}

[Typedef]
id: source
name: source
xref: MYONT:20
is_metadata_tag: true

[Typedef]
id: MYONT:21
name: source2
is_metadata_tag: true

[Typedef]
id: seeAlso
name: see also
xref: http://www.w3.org/2000/01/rdf-schema#seeAlso
is_metadata_tag: true

[Typedef]
id: results_in_transport_across
name: results in transport across
namespace: external
xref: RO:0002342

[Typedef]
id: created_by
name: created by
namespace: external
xref: http://purl.org/dc/terms/creator
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.semanticweb.owlapi.utilities.OWLAPIPreconditions.checkNotNull;
import static org.semanticweb.owlapi.utilities.OWLAPIPreconditions.verifyNotNull;
import static org.semanticweb.owlapi.vocab.Obo2OWLConstants.DEFAULT_IRI_PREFIX;
import static org.semanticweb.owlapi.vocab.Obo2OWLConstants.OIOVOCAB_IRI_PREFIX;

import java.io.File;
import java.io.FileOutputStream;
Expand Down Expand Up @@ -1375,14 +1376,22 @@ protected OWLIndividual trIndividual(String instId) {
return df.getOWLNamedIndividual(iri);
}

private IRI trTagToIRIIncludingTypedefs(String tag) {
IRI iri = ANNOTATIONPROPERTYMAP.get(tag);
if (iri == null) {
iri = oboIdToIRI(tag, true);
}
return iri;
}

/**
* Translate tag to annotation prop.
*
* @param tag the tag
* @return the OWL annotation property
*/
protected OWLAnnotationProperty trTagToAnnotationProp(String tag) {
IRI iri = trTagToIRI(tag, df);
IRI iri = trTagToIRIIncludingTypedefs(tag);
OWLAnnotationProperty ap = df.getOWLAnnotationProperty(iri);
if (!apToDeclare.contains(ap)) {
apToDeclare.add(ap);
Expand Down Expand Up @@ -1463,9 +1472,19 @@ protected OWLAnnotationValue trLiteral(Object value) {
* @return the iri
*/
public IRI oboIdToIRI(String id) {
return oboIdToIRI(id, false);
}

/**
* Obo id to iri.
*
* @param id the id
* @return the iri
*/
public IRI oboIdToIRI(String id, boolean oboInOwlDefault) {
IRI iri = idToIRICache.get(id);
if (iri == null) {
iri = loadOboToIRI(id);
iri = loadOboToIRI(id, oboInOwlDefault);
idToIRICache.put(id, iri);
}
return iri;
Expand All @@ -1478,6 +1497,16 @@ public IRI oboIdToIRI(String id) {
* @return the iri
*/
public IRI loadOboToIRI(String id) {
return loadOboToIRI(id, false);
}

/**
* Obo id to iri.
*
* @param id the id
* @return the iri
*/
public IRI loadOboToIRI(String id, boolean oboInOwlDefault) {
if (id.contains(" ")) {
LOG.error("id contains space: \"{}\"", id);
throw new OWLParserException("spaces not allowed: '" + id + '\'');
Expand Down Expand Up @@ -1514,10 +1543,10 @@ public IRI loadOboToIRI(String id) {
return oboIdToIRI(xid);
}
}
return otherProtocols(id);
return otherProtocols(id, oboInOwlDefault);
}

protected IRI otherProtocols(String id) {
protected IRI otherProtocols(String id, boolean oboInOwlDefault) {
String[] idParts = id.split(":", 2);
String db;
String localId;
Expand All @@ -1537,7 +1566,15 @@ protected IRI otherProtocols(String id) {
db = getDefaultIDSpace() + '#';
localId = idParts[0];
}
String uriPrefix = uriPrefix(db);
String uriPrefix;
if (oboInOwlDefault) {
uriPrefix = OIOVOCAB_IRI_PREFIX;
} else {
uriPrefix = DEFAULT_IRI_PREFIX + db;
if (idSpaceMap.containsKey(db)) {
uriPrefix = idSpaceMap.get(db);
}
}
String safeId = safeID(localId);
try {
return df.getIRI(uriPrefix + safeId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,16 @@ public static String getIdentifierFromObject(OWLObject obj, OWLOntology ont)
* @return obo identifier
*/
public static String getIdentifier(IRI iriId) {
String iri = iriId.toString();
return getIdentifier(iriId.toString());
}

/**
* See table 5.9.2. Translation of identifiers
*
* @param iri the iri
* @return obo identifier
*/
public static String getIdentifier(String iri) {
// canonical IRIs
String id = getId(iri);
String[] s = BLANK_NODE_MARKER.split(id);
Expand Down Expand Up @@ -485,6 +494,8 @@ protected static String tagFromPrefix(String iri, @Nullable String tag) {
}
if (iri.startsWith(Obo2OWLConstants.OIOVOCAB_IRI_PREFIX)) {
return iri.substring(Obo2OWLConstants.OIOVOCAB_IRI_PREFIX.length());
} else {
return getIdentifier(iri);
}
}
return tag;
Expand Down

0 comments on commit 3740cef

Please sign in to comment.