Skip to content

Commit 08b89af

Browse files
Merge pull request #1104 from ontodev/template-cycle-bug
Fix how Template adds entities to the QuotedEntityChecker
2 parents 2f9eca4 + 3de1c0c commit 08b89af

File tree

8 files changed

+184
-90
lines changed

8 files changed

+184
-90
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
12+
- Fix how Template adds entities to the QuotedEntityChecker [#1104]
13+
14+
1015
## [1.9.5] - 2023-09-20
1116

1217
### Added
@@ -379,6 +384,7 @@ First official release of ROBOT!
379384
[#1148]: https://github.com/ontodev/robot/pull/1148
380385
[#1135]: https://github.com/ontodev/robot/pull/1135
381386
[#1119]: https://github.com/ontodev/robot/pull/1119
387+
[#1104]: https://github.com/ontodev/robot/pull/1104
382388
[#1100]: https://github.com/ontodev/robot/pull/1100
383389
[#1091]: https://github.com/ontodev/robot/issues/1091
384390
[#1089]: https://github.com/ontodev/robot/issues/1089

docs/extract.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,14 @@ For more details see the [MIREOT paper](http://dx.doi.org/10.3233/AO-2011-0087).
7979

8080
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.
8181

82-
robot extract --method subset \
83-
--input subset.obo \
84-
--term "obo:ONT_1" \
85-
--term "obo:ONT_5" \
86-
--term "BFO:0000050" \
87-
--output results/subset_result.owl
82+
```
83+
robot extract --method subset \
84+
--input subset.obo \
85+
--term "obo:ONT_1" \
86+
--term "obo:ONT_5" \
87+
--term "BFO:0000050" \
88+
--output results/subset_result.owl
89+
```
8890
8991
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`.
9092

robot-core/src/main/java/org/obolibrary/robot/QuotedEntityChecker.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,9 @@ public void add(OWLEntity entity, String name) {
249249
if (entity == null) {
250250
return;
251251
}
252+
if (name == null) {
253+
return;
254+
}
252255

253256
Map<String, IRI> map = pickMap(entity);
254257
if (map == null) {

robot-core/src/main/java/org/obolibrary/robot/Template.java

Lines changed: 87 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ public Template(@Nonnull String name, @Nonnull List<List<String>> rows) throws E
173173

174174
// Add the contents of the tableRows
175175
addTable(rows);
176-
addLabels();
176+
addEntities();
177177
createParser();
178178
}
179179

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

204204
// Add the contents of the tableRows
205205
addTable(rows);
206-
addLabels();
206+
addEntities();
207207
createParser();
208208
}
209209

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

238238
// Add the contents of the tableRows
239239
addTable(rows);
240-
addLabels();
240+
addEntities();
241241
createParser();
242242
}
243243

@@ -276,7 +276,7 @@ public Template(
276276

277277
// Add the contents of the tableRows
278278
addTable(rows);
279-
addLabels();
279+
addEntities();
280280
createParser();
281281
}
282282

@@ -320,7 +320,7 @@ public Template(
320320

321321
// Add the contents of the tableRows
322322
addTable(rows);
323-
addLabels();
323+
addEntities();
324324
createParser();
325325
parser.setOWLEntityChecker(this.checker);
326326
}
@@ -557,102 +557,103 @@ private void addTable(List<List<String>> rows) throws Exception {
557557
}
558558
}
559559

560-
/** Add the labels from the rows of the template to the QuotedEntityChecker. */
561-
private void addLabels() {
562-
// If there's no label column, we can't add labels
563-
if (labelColumn == -1) {
560+
/** Add the entities from the rows of the template to the QuotedEntityChecker. */
561+
private void addEntities() {
562+
for (List<String> row : tableRows) {
563+
addEntity(row);
564+
}
565+
}
566+
567+
/** Add the entity from this row of the template to the QuotedEntityChecker. */
568+
private void addEntity(List<String> row) {
569+
String id = null;
570+
try {
571+
id = row.get(idColumn);
572+
} catch (IndexOutOfBoundsException e) {
573+
// ignore
574+
}
575+
576+
if (id == null) {
564577
return;
565578
}
566-
for (List<String> row : tableRows) {
567-
String id = null;
568-
if (idColumn != -1) {
569-
try {
570-
id = row.get(idColumn);
571-
} catch (IndexOutOfBoundsException e) {
572-
// ignore
573-
}
574-
}
575579

576-
String label = null;
580+
String label = null;
581+
try {
582+
label = row.get(labelColumn);
583+
} catch (IndexOutOfBoundsException e) {
584+
// ignore
585+
}
586+
587+
String type = null;
588+
if (typeColumn != -1) {
577589
try {
578-
label = row.get(labelColumn);
590+
type = row.get(typeColumn);
579591
} catch (IndexOutOfBoundsException e) {
580592
// ignore
581593
}
594+
}
595+
if (type == null || type.trim().isEmpty()) {
596+
type = "class";
597+
}
582598

583-
if (idColumn != -1 && id == null) {
584-
continue;
585-
}
586-
587-
if (id == null || label == null) {
588-
continue;
589-
}
590-
591-
String type = null;
592-
if (typeColumn != -1) {
593-
try {
594-
type = row.get(typeColumn);
595-
} catch (IndexOutOfBoundsException e) {
596-
// ignore
597-
}
598-
}
599-
if (type == null || type.trim().isEmpty()) {
600-
type = "class";
601-
}
599+
IRI iri = ioHelper.createIRI(id);
600+
if (iri == null) {
601+
iri = IRI.create(id);
602+
}
602603

603-
IRI iri = ioHelper.createIRI(id);
604-
if (iri == null) {
605-
iri = IRI.create(id);
606-
}
604+
// Try to resolve a CURIE
605+
IRI typeIRI = ioHelper.createIRI(type);
607606

608-
// Try to resolve a CURIE
609-
IRI typeIRI = ioHelper.createIRI(type);
607+
// Set to IRI string or to type string
608+
String typeOrIRI = type;
609+
if (typeIRI != null) {
610+
typeOrIRI = typeIRI.toString();
611+
}
610612

611-
// Set to IRI string or to type string
612-
String typeOrIRI = type;
613-
if (typeIRI != null) {
614-
typeOrIRI = typeIRI.toString();
615-
}
613+
// Check against builtin types (ignore case), otherwise treat as individual
614+
OWLEntity entity;
615+
String lowerCaseType = typeOrIRI.toLowerCase();
616+
switch (lowerCaseType) {
617+
case "":
618+
case "http://www.w3.org/2002/07/owl#class":
619+
case "class":
620+
entity = dataFactory.getOWLEntity(EntityType.CLASS, iri);
621+
break;
616622

617-
// Check against builtin types (ignore case), otherwise treat as individual
618-
OWLEntity entity;
619-
String lowerCaseType = typeOrIRI.toLowerCase();
620-
switch (lowerCaseType) {
621-
case "":
622-
case "http://www.w3.org/2002/07/owl#class":
623-
case "class":
624-
entity = dataFactory.getOWLEntity(EntityType.CLASS, iri);
625-
break;
623+
case "http://www.w3.org/2002/07/owl#objectproperty":
624+
case "object property":
625+
entity = dataFactory.getOWLEntity(EntityType.OBJECT_PROPERTY, iri);
626+
break;
626627

627-
case "http://www.w3.org/2002/07/owl#objectproperty":
628-
case "object property":
629-
entity = dataFactory.getOWLEntity(EntityType.OBJECT_PROPERTY, iri);
630-
break;
628+
case "http://www.w3.org/2002/07/owl#dataproperty":
629+
case "data property":
630+
entity = dataFactory.getOWLEntity(EntityType.DATA_PROPERTY, iri);
631+
break;
631632

632-
case "http://www.w3.org/2002/07/owl#dataproperty":
633-
case "data property":
634-
entity = dataFactory.getOWLEntity(EntityType.DATA_PROPERTY, iri);
635-
break;
633+
case "http://www.w3.org/2002/07/owl#annotationproperty":
634+
case "annotation property":
635+
entity = dataFactory.getOWLEntity(EntityType.ANNOTATION_PROPERTY, iri);
636+
break;
636637

637-
case "http://www.w3.org/2002/07/owl#annotationproperty":
638-
case "annotation property":
639-
entity = dataFactory.getOWLEntity(EntityType.ANNOTATION_PROPERTY, iri);
640-
break;
638+
case "http://www.w3.org/2002/07/owl#datatype":
639+
case "datatype":
640+
entity = dataFactory.getOWLEntity(EntityType.DATATYPE, iri);
641+
break;
641642

642-
case "http://www.w3.org/2002/07/owl#datatype":
643-
case "datatype":
644-
entity = dataFactory.getOWLEntity(EntityType.DATATYPE, iri);
645-
break;
643+
case "http://www.w3.org/2002/07/owl#individual":
644+
case "individual":
645+
case "http://www.w3.org/2002/07/owl#namedindividual":
646+
case "named individual":
647+
default:
648+
// Assume type is an individual (checked later)
649+
entity = dataFactory.getOWLEntity(EntityType.NAMED_INDIVIDUAL, iri);
650+
break;
651+
}
646652

647-
case "http://www.w3.org/2002/07/owl#individual":
648-
case "individual":
649-
case "http://www.w3.org/2002/07/owl#namedindividual":
650-
case "named individual":
651-
default:
652-
// Assume type is an individual (checked later)
653-
entity = dataFactory.getOWLEntity(EntityType.NAMED_INDIVIDUAL, iri);
654-
break;
655-
}
653+
if (id != null) {
654+
checker.add(entity, id);
655+
}
656+
if (label != null) {
656657
checker.add(entity, label);
657658
}
658659
}
@@ -795,6 +796,8 @@ private void processRow(List<String> row) throws Exception {
795796
case "http://www.w3.org/2002/07/owl#namedindividual":
796797
case "named individual":
797798
default:
799+
// This is a bit unsafe imo, for example in the case of where the datatype turns out to be
800+
// http://www.w3.org/2002/07/owl#DatatypeProperty""
798801
addIndividualAxioms(iri, row);
799802
break;
800803
}

robot-core/src/test/java/org/obolibrary/robot/TemplateTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,35 @@ public void testLegacyTemplateCSV() throws Exception {
4949
assertIdentical("/template.owl", template);
5050
}
5151

52+
/**
53+
* Test a strange case where a sequence .
54+
*
55+
* @throws Exception if entities cannot be found
56+
*/
57+
@Test
58+
public void testNoLabelsNoTypes() throws Exception {
59+
String path = "/sequence-template.csv";
60+
List<List<String>> rows = TemplateHelper.readCSV(this.getClass().getResourceAsStream(path));
61+
Template t = new Template(path, rows);
62+
t.generateOutputOntology("http://test.com/template.owl", false, null);
63+
}
64+
65+
/**
66+
* Test a strange case where a sequence .
67+
*
68+
* @throws Exception if entities cannot be found
69+
*/
70+
@Test
71+
public void testNoLabels() throws Exception {
72+
String path = "/workflow-template.csv";
73+
List<List<String>> rows = TemplateHelper.readCSV(this.getClass().getResourceAsStream(path));
74+
IOHelper ioHelper = new IOHelper();
75+
ioHelper.addPrefix("ex", "http://example.com/");
76+
Template t = new Template(path, rows, ioHelper);
77+
OWLOntology template = t.generateOutputOntology("http://test.com/template.owl", false, null);
78+
assertIdentical("/workflow-template.ttl", template);
79+
}
80+
5281
/**
5382
* Test multiple templates.
5483
*
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
ID,isa
2+
ID,SC %
3+
CL:4030028,CL:0000561
4+
CL:0000561,CL:0000099
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Identifier,Type,Class Restriction Lower,Class Restriction Upper,Domain,Range
2+
ID,TYPE,SC %,SC %,DOMAIN,RANGE
3+
ex:consists_of,owl:ObjectProperty,,,ex:Workflow,ex:Task
4+
ex:Workflow,class,(ex:consists_of min 1 ex:Task),(ex:consists_of max 7 ex:Task),,
5+
ex:Task,class,,,,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
2+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
3+
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
4+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
5+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
6+
@base <http://www.w3.org/2002/07/owl#> .
7+
8+
<http://test.com/template.owl> rdf:type owl:Ontology .
9+
10+
#################################################################
11+
# Object Properties
12+
#################################################################
13+
14+
### http://example.com/consists_of
15+
<http://example.com/consists_of> rdf:type owl:ObjectProperty ;
16+
rdfs:domain <http://example.com/Workflow> ;
17+
rdfs:range <http://example.com/Task> .
18+
19+
20+
#################################################################
21+
# Classes
22+
#################################################################
23+
24+
### http://example.com/Task
25+
<http://example.com/Task> rdf:type owl:Class .
26+
27+
28+
### http://example.com/Workflow
29+
<http://example.com/Workflow> rdf:type owl:Class ;
30+
rdfs:subClassOf [ rdf:type owl:Restriction ;
31+
owl:onProperty <http://example.com/consists_of> ;
32+
owl:minQualifiedCardinality "1"^^xsd:nonNegativeInteger ;
33+
owl:onClass <http://example.com/Task>
34+
] ,
35+
[ rdf:type owl:Restriction ;
36+
owl:onProperty <http://example.com/consists_of> ;
37+
owl:maxQualifiedCardinality "7"^^xsd:nonNegativeInteger ;
38+
owl:onClass <http://example.com/Task>
39+
] .
40+
41+
42+
### Generated by the OWL API (version 4.5.26) https://github.com/owlcs/owlapi

0 commit comments

Comments
 (0)