Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix how Template adds entities to the QuotedEntityChecker #1104

Merged
merged 9 commits into from
Nov 29, 2023
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Fix how Template adds entities to the QuotedEntityChecker [#1104]


## [1.9.5] - 2023-09-20

### Added
Expand Down Expand Up @@ -379,6 +384,7 @@ First official release of ROBOT!
[#1148]: https://github.com/ontodev/robot/pull/1148
[#1135]: https://github.com/ontodev/robot/pull/1135
[#1119]: https://github.com/ontodev/robot/pull/1119
[#1104]: https://github.com/ontodev/robot/pull/1104
[#1100]: https://github.com/ontodev/robot/pull/1100
[#1091]: https://github.com/ontodev/robot/issues/1091
[#1089]: https://github.com/ontodev/robot/issues/1089
Expand Down
14 changes: 8 additions & 6 deletions docs/extract.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,14 @@ For more details see the [MIREOT paper](http://dx.doi.org/10.3233/AO-2011-0087).

The subset method extracts a sub-ontology that contains only the seed terms (that you specify with `--term` and `--term-file` options) and the relations between them. This method uses the [relation-graph](https://github.com/balhoff/relation-graph) to materialize the existential relations among the seed terms. Procedurally, the subset method materializes the input ontology and adds the inferred axioms to the input ontology. Then filters the ontology with the given seed terms. Finally, it reduces the filtered ontology to remove redundant subClassOf axioms.

robot extract --method subset \
--input subset.obo \
--term "obo:ONT_1" \
--term "obo:ONT_5" \
--term "BFO:0000050" \
--output results/subset_result.owl
```
robot extract --method subset \
--input subset.obo \
--term "obo:ONT_1" \
--term "obo:ONT_5" \
--term "BFO:0000050" \
--output results/subset_result.owl
```
jamesaoverton marked this conversation as resolved.
Show resolved Hide resolved
ROBOT expects any `--term` or IRI in the `--term-file` to exist in the input ontology. If none of the input terms exist, the command will fail with an [empty terms error](errors#empty-terms-error). This can be overridden by including `--force true`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,9 @@ public void add(OWLEntity entity, String name) {
if (entity == null) {
return;
}
if (name == null) {
return;
}

Map<String, IRI> map = pickMap(entity);
if (map == null) {
Expand Down
171 changes: 87 additions & 84 deletions robot-core/src/main/java/org/obolibrary/robot/Template.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public Template(@Nonnull String name, @Nonnull List<List<String>> rows) throws E

// Add the contents of the tableRows
addTable(rows);
addLabels();
addEntities();
createParser();
}

Expand Down Expand Up @@ -203,7 +203,7 @@ public Template(@Nonnull String name, @Nonnull List<List<String>> rows, IOHelper

// Add the contents of the tableRows
addTable(rows);
addLabels();
addEntities();
createParser();
}

Expand Down Expand Up @@ -237,7 +237,7 @@ public Template(@Nonnull String name, @Nonnull List<List<String>> rows, OWLOntol

// Add the contents of the tableRows
addTable(rows);
addLabels();
addEntities();
createParser();
}

Expand Down Expand Up @@ -276,7 +276,7 @@ public Template(

// Add the contents of the tableRows
addTable(rows);
addLabels();
addEntities();
createParser();
}

Expand Down Expand Up @@ -320,7 +320,7 @@ public Template(

// Add the contents of the tableRows
addTable(rows);
addLabels();
addEntities();
createParser();
parser.setOWLEntityChecker(this.checker);
}
Expand Down Expand Up @@ -557,102 +557,103 @@ private void addTable(List<List<String>> rows) throws Exception {
}
}

/** Add the labels from the rows of the template to the QuotedEntityChecker. */
private void addLabels() {
// If there's no label column, we can't add labels
if (labelColumn == -1) {
/** Add the entities from the rows of the template to the QuotedEntityChecker. */
private void addEntities() {
for (List<String> row : tableRows) {
addEntity(row);
}
}

/** Add the entity from this row of the template to the QuotedEntityChecker. */
private void addEntity(List<String> row) {
String id = null;
try {
id = row.get(idColumn);
} catch (IndexOutOfBoundsException e) {
// ignore
}

if (id == null) {
return;
}
matentzn marked this conversation as resolved.
Show resolved Hide resolved
for (List<String> row : tableRows) {
String id = null;
if (idColumn != -1) {
try {
id = row.get(idColumn);
} catch (IndexOutOfBoundsException e) {
// ignore
}
}

String label = null;
String label = null;
try {
label = row.get(labelColumn);
} catch (IndexOutOfBoundsException e) {
// ignore
}

String type = null;
if (typeColumn != -1) {
try {
label = row.get(labelColumn);
type = row.get(typeColumn);
} catch (IndexOutOfBoundsException e) {
// ignore
}
}
if (type == null || type.trim().isEmpty()) {
type = "class";
}

if (idColumn != -1 && id == null) {
continue;
}

if (id == null || label == null) {
continue;
jamesaoverton marked this conversation as resolved.
Show resolved Hide resolved
}

String type = null;
if (typeColumn != -1) {
try {
type = row.get(typeColumn);
} catch (IndexOutOfBoundsException e) {
// ignore
}
}
if (type == null || type.trim().isEmpty()) {
type = "class";
}
IRI iri = ioHelper.createIRI(id);
if (iri == null) {
iri = IRI.create(id);
}

IRI iri = ioHelper.createIRI(id);
if (iri == null) {
iri = IRI.create(id);
}
// Try to resolve a CURIE
IRI typeIRI = ioHelper.createIRI(type);

// Try to resolve a CURIE
IRI typeIRI = ioHelper.createIRI(type);
// Set to IRI string or to type string
String typeOrIRI = type;
if (typeIRI != null) {
typeOrIRI = typeIRI.toString();
}

// Set to IRI string or to type string
String typeOrIRI = type;
if (typeIRI != null) {
typeOrIRI = typeIRI.toString();
}
// Check against builtin types (ignore case), otherwise treat as individual
OWLEntity entity;
String lowerCaseType = typeOrIRI.toLowerCase();
switch (lowerCaseType) {
case "":
case "http://www.w3.org/2002/07/owl#class":
case "class":
entity = dataFactory.getOWLEntity(EntityType.CLASS, iri);
break;

// Check against builtin types (ignore case), otherwise treat as individual
OWLEntity entity;
String lowerCaseType = typeOrIRI.toLowerCase();
switch (lowerCaseType) {
case "":
case "http://www.w3.org/2002/07/owl#class":
case "class":
entity = dataFactory.getOWLEntity(EntityType.CLASS, iri);
break;
case "http://www.w3.org/2002/07/owl#objectproperty":
case "object property":
entity = dataFactory.getOWLEntity(EntityType.OBJECT_PROPERTY, iri);
break;

case "http://www.w3.org/2002/07/owl#objectproperty":
case "object property":
entity = dataFactory.getOWLEntity(EntityType.OBJECT_PROPERTY, iri);
break;
case "http://www.w3.org/2002/07/owl#dataproperty":
case "data property":
entity = dataFactory.getOWLEntity(EntityType.DATA_PROPERTY, iri);
break;

case "http://www.w3.org/2002/07/owl#dataproperty":
case "data property":
entity = dataFactory.getOWLEntity(EntityType.DATA_PROPERTY, iri);
break;
case "http://www.w3.org/2002/07/owl#annotationproperty":
case "annotation property":
entity = dataFactory.getOWLEntity(EntityType.ANNOTATION_PROPERTY, iri);
break;

case "http://www.w3.org/2002/07/owl#annotationproperty":
case "annotation property":
entity = dataFactory.getOWLEntity(EntityType.ANNOTATION_PROPERTY, iri);
break;
case "http://www.w3.org/2002/07/owl#datatype":
case "datatype":
entity = dataFactory.getOWLEntity(EntityType.DATATYPE, iri);
break;

case "http://www.w3.org/2002/07/owl#datatype":
case "datatype":
entity = dataFactory.getOWLEntity(EntityType.DATATYPE, iri);
break;
case "http://www.w3.org/2002/07/owl#individual":
case "individual":
case "http://www.w3.org/2002/07/owl#namedindividual":
case "named individual":
default:
// Assume type is an individual (checked later)
entity = dataFactory.getOWLEntity(EntityType.NAMED_INDIVIDUAL, iri);
break;
}

case "http://www.w3.org/2002/07/owl#individual":
case "individual":
case "http://www.w3.org/2002/07/owl#namedindividual":
case "named individual":
default:
// Assume type is an individual (checked later)
entity = dataFactory.getOWLEntity(EntityType.NAMED_INDIVIDUAL, iri);
break;
}
if (id != null) {
checker.add(entity, id);
}
if (label != null) {
checker.add(entity, label);
}
}
Expand Down Expand Up @@ -795,6 +796,8 @@ private void processRow(List<String> row) throws Exception {
case "http://www.w3.org/2002/07/owl#namedindividual":
case "named individual":
default:
// This is a bit unsafe imo, for example in the case of where the datatype turns out to be
// http://www.w3.org/2002/07/owl#DatatypeProperty""
addIndividualAxioms(iri, row);
break;
}
Expand Down
29 changes: 29 additions & 0 deletions robot-core/src/test/java/org/obolibrary/robot/TemplateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,35 @@ public void testLegacyTemplateCSV() throws Exception {
assertIdentical("/template.owl", template);
}

/**
* Test a strange case where a sequence .
*
* @throws Exception if entities cannot be found
*/
@Test
public void testNoLabelsNoTypes() throws Exception {
String path = "/sequence-template.csv";
List<List<String>> rows = TemplateHelper.readCSV(this.getClass().getResourceAsStream(path));
Template t = new Template(path, rows);
t.generateOutputOntology("http://test.com/template.owl", false, null);
}

/**
* Test a strange case where a sequence .
*
* @throws Exception if entities cannot be found
*/
@Test
public void testNoLabels() throws Exception {
String path = "/workflow-template.csv";
List<List<String>> rows = TemplateHelper.readCSV(this.getClass().getResourceAsStream(path));
IOHelper ioHelper = new IOHelper();
ioHelper.addPrefix("ex", "http://example.com/");
Template t = new Template(path, rows, ioHelper);
OWLOntology template = t.generateOutputOntology("http://test.com/template.owl", false, null);
assertIdentical("/workflow-template.ttl", template);
}

/**
* Test multiple templates.
*
Expand Down
4 changes: 4 additions & 0 deletions robot-core/src/test/resources/sequence-template.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ID,isa
ID,SC %
CL:4030028,CL:0000561
CL:0000561,CL:0000099
5 changes: 5 additions & 0 deletions robot-core/src/test/resources/workflow-template.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Identifier,Type,Class Restriction Lower,Class Restriction Upper,Domain,Range
ID,TYPE,SC %,SC %,DOMAIN,RANGE
ex:consists_of,owl:ObjectProperty,,,ex:Workflow,ex:Task
ex:Workflow,class,(ex:consists_of min 1 ex:Task),(ex:consists_of max 7 ex:Task),,
ex:Task,class,,,,
42 changes: 42 additions & 0 deletions robot-core/src/test/resources/workflow-template.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@base <http://www.w3.org/2002/07/owl#> .

<http://test.com/template.owl> rdf:type owl:Ontology .

#################################################################
# Object Properties
#################################################################

### http://example.com/consists_of
<http://example.com/consists_of> rdf:type owl:ObjectProperty ;
rdfs:domain <http://example.com/Workflow> ;
rdfs:range <http://example.com/Task> .


#################################################################
# Classes
#################################################################

### http://example.com/Task
<http://example.com/Task> rdf:type owl:Class .


### http://example.com/Workflow
<http://example.com/Workflow> rdf:type owl:Class ;
rdfs:subClassOf [ rdf:type owl:Restriction ;
owl:onProperty <http://example.com/consists_of> ;
owl:minQualifiedCardinality "1"^^xsd:nonNegativeInteger ;
owl:onClass <http://example.com/Task>
] ,
[ rdf:type owl:Restriction ;
owl:onProperty <http://example.com/consists_of> ;
owl:maxQualifiedCardinality "7"^^xsd:nonNegativeInteger ;
owl:onClass <http://example.com/Task>
] .


### Generated by the OWL API (version 4.5.26) https://github.com/owlcs/owlapi
Loading