Repository: ontodev/robot
Pull request #386 (2018-10-26 10:52:11)

Add support for IRI annotations by entity name
See #379 

I added a `@Deprecated` tag to an [old method](https://github.com/ontodev/robot/pull/386/files#diff-10ebd02e759abefcf8fb1aedeebf6714R156) in this change, but I'm happy to remove this if we don't want to deprecate methods yet.


Patch:
diff --git a/docs/examples/template.csv b/docs/examples/template.csv
index fcc2cca4..4932d6c8 100644
--- a/docs/examples/template.csv
+++ b/docs/examples/template.csv
@@ -2,4 +2,4 @@ ID,Label,Definition,Definition Source,See Also,Editor,RDF Type,Class Type,Parent
 ID,A rdfs:label,A IAO:0000115,A IAO:0000119,AI rdfs:seeAlso,A IAO:0000117,TYPE,CLASS_TYPE,CI
 ex:F344N,F 344/N,An inbred strain of rat used in many scientific investigations.,James A. Overton,http://www.informatics.jax.org/external/festing/rat/docs/F344.shtml,James A. Overton,owl:Class,subclass,NCBITaxon:10116
 ex:B6C3F1,B6C3F1,An inbred strain of mouse used in many scientific investigations.,James A. Overton,http://jaxmice.jax.org/strain/100010.html,James A. Overton,owl:Class,subclass,NCBITaxon:10090
-ex:rat-1234,rat 1234,,,,,ex:F344N,,
+ex:rat-1234,rat 1234,,,F 344/N,,ex:F344N,,
diff --git a/docs/examples/template.owl b/docs/examples/template.owl
index 0743113a..8469fad7 100644
--- a/docs/examples/template.owl
+++ b/docs/examples/template.owl
@@ -111,10 +111,11 @@
     <owl:NamedIndividual rdf:about="http://example.com/rat-1234">
         <rdf:type rdf:resource="http://example.com/F344N"/>
         <rdfs:label rdf:datatype="http://www.w3.org/2001/XMLSchema#string">rat 1234</rdfs:label>
+        <rdfs:seeAlso rdf:resource="http://example.com/F344N"/>
     </owl:NamedIndividual>
 </rdf:RDF>
 
 
 
-<!-- Generated by the OWL API (version 0.0.1-SNAPSHOT) https://github.com/owlcs/owlapi -->
+<!-- Generated by the OWL API (version 4.2.8.20170104-2310) https://github.com/owlcs/owlapi -->
 
diff --git a/robot-core/src/main/java/org/obolibrary/robot/QuotedEntityChecker.java b/robot-core/src/main/java/org/obolibrary/robot/QuotedEntityChecker.java
index fe336516..fead3823 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/QuotedEntityChecker.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/QuotedEntityChecker.java
@@ -276,6 +276,48 @@ public class QuotedEntityChecker implements OWLEntityChecker {
     return null;
   }
 
+  /**
+   * Get the IRI for the given name by checking all maps. If not found, create as a new IRI if
+   * create is true.
+   *
+   * @param name the name of the entity to find the IRI for
+   * @param create when true and an IOHelper is defined, create the IRI
+   * @return the IRI of the entity or null if not found or created
+   */
+  public IRI getIRI(String name, boolean create) {
+    IRI iri = getIRI(classes, name);
+    if (iri != null) {
+      return iri;
+    }
+    iri = getIRI(annotationProperties, name);
+    if (iri != null) {
+      return iri;
+    }
+    iri = getIRI(dataProperties, name);
+    if (iri != null) {
+      return iri;
+    }
+    iri = getIRI(objectProperties, name);
+    if (iri != null) {
+      return iri;
+    }
+    iri = getIRI(namedIndividuals, name);
+    if (iri != null) {
+      return iri;
+    }
+    iri = getIRI(datatypes, name);
+    if (iri != null) {
+      return iri;
+    }
+    if (create && ioHelper != null) {
+      iri = ioHelper.createIRI(name);
+      if (iri != null) {
+        return iri;
+      }
+    }
+    return null;
+  }
+
   /**
    * Get the label for the given IRI. Quotation marks will be removed if necessary.
    *
diff --git a/robot-core/src/main/java/org/obolibrary/robot/TemplateHelper.java b/robot-core/src/main/java/org/obolibrary/robot/TemplateHelper.java
index 8d2f26ab..09e56524 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/TemplateHelper.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/TemplateHelper.java
@@ -114,12 +114,46 @@ public class TemplateHelper {
    * Create an OWLAnnotation based on the template string and cell value.
    *
    * @param checker used to resolve the annotation property
+   * @param template the template string
+   * @param value the value for the annotation
+   * @return OWLAnnotation, or null if template string is not supported
+   * @throws Exception if annotation cannot be created
+   */
+  public static OWLAnnotation getAnnotation(
+      QuotedEntityChecker checker, String template, String value) throws Exception {
+    if (template.startsWith("A ")) {
+      return getStringAnnotation(checker, template, value);
+    } else if (template.startsWith("AT ")) {
+      if (template.contains("^^")) {
+        return getTypedAnnotation(checker, template, value);
+      } else {
+        throw new Exception(String.format(typedFormatError, template));
+      }
+    } else if (template.startsWith("AL ")) {
+      if (template.contains("@")) {
+        return getLanguageAnnotation(checker, template, value);
+      } else {
+        throw new Exception(String.format(languageFormatError, template));
+      }
+    } else if (template.startsWith("AI ")) {
+      return getIRIAnnotation(checker, template, value);
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Create an OWLAnnotation based on the template string and cell value. Replaced by
+   * getAnnotation(QuotedEntityChecker checker, String template, String value).
+   *
+   * @param checker used to resolve the annotation property
    * @param ioHelper IOHelper used to create IRIs from values
    * @param template the template string
    * @param value the value for the annotation
    * @return OWLAnnotation, or null if template string is not supported
    * @throws Exception if annotation property cannot be found
    */
+  @Deprecated
   public static OWLAnnotation getAnnotation(
       QuotedEntityChecker checker, IOHelper ioHelper, String template, String value)
       throws Exception {
@@ -212,35 +246,36 @@ public class TemplateHelper {
       Map<OWLClassExpression, Set<OWLAnnotation>> annotatedExpressions)
       throws Exception {
     Set<OWLAxiom> axioms = new HashSet<>();
-    if (classType.equals("subclass")) {
-      for (OWLClassExpression expression : classExpressions) {
-        axioms.add(dataFactory.getOWLSubClassOfAxiom(cls, expression));
-      }
-      for (Entry<OWLClassExpression, Set<OWLAnnotation>> annotatedEx :
-          annotatedExpressions.entrySet()) {
-        axioms.add(
-            dataFactory.getOWLSubClassOfAxiom(cls, annotatedEx.getKey(), annotatedEx.getValue()));
-      }
-      return axioms;
-    } else if (classType.equals("equivalent")) {
-      // Since it's an intersection, all annotations will be added to the same axiom
-      Set<OWLAnnotation> annotations = new HashSet<>();
-      for (Entry<OWLClassExpression, Set<OWLAnnotation>> annotatedEx :
-          annotatedExpressions.entrySet()) {
-        classExpressions.add(annotatedEx.getKey());
-        annotations.addAll(annotatedEx.getValue());
-      }
-      OWLObjectIntersectionOf intersection =
-          dataFactory.getOWLObjectIntersectionOf(classExpressions);
-      OWLAxiom axiom;
-      if (!annotations.isEmpty()) {
-        axiom = dataFactory.getOWLEquivalentClassesAxiom(cls, intersection, annotations);
-      } else {
-        axiom = dataFactory.getOWLEquivalentClassesAxiom(cls, intersection);
-      }
-      return Sets.newHashSet(axiom);
-    } else {
-      throw new Exception(String.format(classTypeError, classType));
+    switch (classType) {
+      case "subclass":
+        for (OWLClassExpression expression : classExpressions) {
+          axioms.add(dataFactory.getOWLSubClassOfAxiom(cls, expression));
+        }
+        for (Entry<OWLClassExpression, Set<OWLAnnotation>> annotatedEx :
+            annotatedExpressions.entrySet()) {
+          axioms.add(
+              dataFactory.getOWLSubClassOfAxiom(cls, annotatedEx.getKey(), annotatedEx.getValue()));
+        }
+        return axioms;
+      case "equivalent":
+        // Since it's an intersection, all annotations will be added to the same axiom
+        Set<OWLAnnotation> annotations = new HashSet<>();
+        for (Entry<OWLClassExpression, Set<OWLAnnotation>> annotatedEx :
+            annotatedExpressions.entrySet()) {
+          classExpressions.add(annotatedEx.getKey());
+          annotations.addAll(annotatedEx.getValue());
+        }
+        OWLObjectIntersectionOf intersection =
+            dataFactory.getOWLObjectIntersectionOf(classExpressions);
+        OWLAxiom axiom;
+        if (!annotations.isEmpty()) {
+          axiom = dataFactory.getOWLEquivalentClassesAxiom(cls, intersection, annotations);
+        } else {
+          axiom = dataFactory.getOWLEquivalentClassesAxiom(cls, intersection);
+        }
+        return Sets.newHashSet(axiom);
+      default:
+        throw new Exception(String.format(classTypeError, classType));
     }
   }
 
@@ -333,8 +368,27 @@ public class TemplateHelper {
   }
 
   /**
-   * Return an IRI annotation for the given template string and value. The template string format is
-   * "AI [name]" and the value is a string that can be interpreted as an IRI.
+   * Return an IRI annotation for the given template string and string value. The template string
+   * format is "AI [name]" and the value is the name of an entity or an IRI.
+   *
+   * @param checker used to resolve the annotation property
+   * @param template the template string
+   * @param value the value for the annotation
+   * @return a new annotation axiom with property and an IRI value
+   * @throws Exception if the annotation property cannot be found or the IRI cannot be created
+   */
+  public static OWLAnnotation getIRIAnnotation(
+      QuotedEntityChecker checker, String template, String value) throws Exception {
+    IRI iri = checker.getIRI(value, true);
+    if (iri == null) {
+      throw new Exception(String.format(iriError, value));
+    }
+    return getIRIAnnotation(checker, template, iri);
+  }
+
+  /**
+   * Return an IRI annotation for the given template string and IRI value. The template string
+   * format is "AI [name]" and the value is an IRI.
    *
    * @param checker used to resolve the annotation property
    * @param template the template string
@@ -524,12 +578,14 @@ public class TemplateHelper {
     }
     String extension = FilenameUtils.getExtension(file.getName());
     extension = extension.trim().toLowerCase();
-    if (extension.equals("csv")) {
-      return readCSV(new FileReader(path));
-    } else if (extension.equals("tsv") || extension.equals("tab")) {
-      return readTSV(new FileReader(path));
-    } else {
-      throw new IOException(String.format(fileTypeError, path));
+    switch (extension) {
+      case "csv":
+        return readCSV(new FileReader(path));
+      case "tsv":
+      case "tab":
+        return readTSV(new FileReader(path));
+      default:
+        throw new IOException(String.format(fileTypeError, path));
     }
   }
 
diff --git a/robot-core/src/main/java/org/obolibrary/robot/TemplateOperation.java b/robot-core/src/main/java/org/obolibrary/robot/TemplateOperation.java
index 8e9f3afe..50782bf1 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/TemplateOperation.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/TemplateOperation.java
@@ -528,7 +528,7 @@ public class TemplateOperation {
           annotations.add(dataFactory.getOWLAnnotation(rdfType, type));
         } else if (template.startsWith("A")) {
           lastAxiomAnnotation = null;
-          lastAnnotation = TemplateHelper.getAnnotation(checker, ioHelper, template, value);
+          lastAnnotation = TemplateHelper.getAnnotation(checker, template, value);
           annotations.add(lastAnnotation);
         } else if (template.startsWith(">A")) {
           if (lastAnnotation == null) {
@@ -545,8 +545,7 @@ public class TemplateOperation {
                     "an annotation"));
           }
           // Get annotation based on annotation type
-          lastAxiomAnnotation =
-              TemplateHelper.getAnnotation(checker, ioHelper, template.substring(1), value);
+          lastAxiomAnnotation = TemplateHelper.getAnnotation(checker, template.substring(1), value);
           // If the last annotation is already in the map, get it's existing annotations
           if (nested.containsKey(lastAnnotation)) {
             axiomAnnotations = nested.get(lastAnnotation);
@@ -580,7 +579,7 @@ public class TemplateOperation {
           axiomAnnotationAnnotations = axiomAnnotations.get(lastAxiomAnnotation);
           // Add this iteration of annotation and put into the nested map
           axiomAnnotationAnnotations.add(
-              TemplateHelper.getAnnotation(checker, ioHelper, template.substring(2), value));
+              TemplateHelper.getAnnotation(checker, template.substring(2), value));
           axiomAnnotations.put(lastAxiomAnnotation, axiomAnnotationAnnotations);
           nested.put(lastAnnotation, axiomAnnotations);
         }


Test patch:
diff --git a/robot-core/src/test/java/org/obolibrary/robot/TemplateOperationTest.java b/robot-core/src/test/java/org/obolibrary/robot/TemplateOperationTest.java
index b8dbbb13..1bed72ba 100644
--- a/robot-core/src/test/java/org/obolibrary/robot/TemplateOperationTest.java
+++ b/robot-core/src/test/java/org/obolibrary/robot/TemplateOperationTest.java
@@ -58,12 +58,17 @@ public class TemplateOperationTest extends CoreTest {
     checker.addProperty(dataFactory.getRDFSLabel());
     checker.addAll(simpleParts);
 
+    // Test getting classes by label without IOHelper
     IRI iri = IRI.create(base + "simple.owl#test1");
     OWLClass cls = dataFactory.getOWLClass(iri);
     assertEquals(cls, checker.getOWLClass("test one"));
     assertEquals(cls, checker.getOWLClass("'test one'"));
     assertEquals(cls, checker.getOWLClass("Test 1"));
 
+    // Test getting IRI by label
+    assertEquals(checker.getIRI("test one", false), cls.getIRI());
+
+    // Test getting class by label with IOHelper
     IOHelper ioHelper = new IOHelper();
     iri = ioHelper.createIRI("GO:XXXX");
     cls = dataFactory.getOWLClass(iri);
@@ -92,10 +97,15 @@ public class TemplateOperationTest extends CoreTest {
    */
   @Test
   public void testTemplateCSV() throws Exception {
-    Map<String, List<List<String>>> tables = new LinkedHashMap<String, List<List<String>>>();
+    Map<String, List<List<String>>> tables = new LinkedHashMap<>();
     String path = "/template.csv";
     tables.put(path, TemplateHelper.readCSV(this.getClass().getResourceAsStream(path)));
     OWLOntology simpleParts = loadOntology("/simple_parts.owl");
+
+    QuotedEntityChecker checker = new QuotedEntityChecker();
+    checker.addProperty(dataFactory.getRDFSLabel());
+    checker.addAll(simpleParts);
+
     OWLOntology template = TemplateOperation.template(tables, simpleParts);
     OntologyHelper.setOntologyIRI(template, IRI.create("http://test.com/template.owl"), null);
     assertIdentical("/template.owl", template);