Repository: ontodev/robot
Pull request #564 (2019-09-03 14:46:23)

Fix nested axiom annotations
Regular axiom annotations (`>A*`) work fine, but nest axiom annotations (`>>A*`) are not being processed by the new template rework. Logger was also incorrectly warning that `>C*` templates shouldn't be used, but this method is also used for axiom annotations on logical axioms.


Patch:
diff --git a/robot-core/src/main/java/org/obolibrary/robot/Template.java b/robot-core/src/main/java/org/obolibrary/robot/Template.java
index 5c352140..e2597bc8 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/Template.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/Template.java
@@ -1970,35 +1970,18 @@ public class Template {
         TemplateHelper.getAnnotations(name, checker, template, value, rowNum, column);
 
     // Maybe get an annotation on the annotation
-    String nextTemplate;
-    try {
-      nextTemplate = templates.get(column + 1);
-    } catch (IndexOutOfBoundsException e) {
-      nextTemplate = null;
+    Set<OWLAnnotation> axiomAnnotations = maybeGetAxiomAnnotations(row, column);
+    if (axiomAnnotations.isEmpty()) {
+      // No annotations to add
+      return annotations;
     }
 
-    // Handle axiom annotations
-    if (nextTemplate != null && !nextTemplate.trim().isEmpty() && nextTemplate.startsWith(">A")) {
-      nextTemplate = nextTemplate.substring(1);
-      String nextValue;
-      try {
-        nextValue = row.get(column + 1);
-      } catch (IndexOutOfBoundsException e) {
-        nextValue = null;
-      }
-      if (nextValue != null && !nextValue.trim().equals("")) {
-        Set<OWLAnnotation> nextAnnotations =
-            TemplateHelper.getAnnotations(name, checker, nextTemplate, nextValue, rowNum, column);
-        Set<OWLAnnotation> fixedAnnotations = new HashSet<>();
-        for (OWLAnnotation annotation : annotations) {
-          fixedAnnotations.add(annotation.getAnnotatedAnnotation(nextAnnotations));
-        }
-        // Replace the annotation set with the annotated annotations
-        annotations = fixedAnnotations;
-      }
+    // Add annotations and return fixed set
+    Set<OWLAnnotation> fixedAnnotations = new HashSet<>();
+    for (OWLAnnotation annotation : annotations) {
+      fixedAnnotations.add(annotation.getAnnotatedAnnotation(axiomAnnotations));
     }
-
-    return annotations;
+    return fixedAnnotations;
   }
 
   /**
@@ -2006,33 +1989,54 @@ public class Template {
    * get axiom annotations on existing axiom annotations.
    *
    * @param row list of strings
-   * @param template template string for the column
+   * @param nextTemplate template string for the column
    * @param nextColumn next column number
    * @return set of OWLAnnotations, or an empty set
    * @throws Exception on issue getting the OWLAnnotations
    */
-  private Set<OWLAnnotation> getAxiomAnnotations(List<String> row, String template, int nextColumn)
-      throws Exception {
-    Set<OWLAnnotation> annotations = new HashSet<>();
-    if (template.startsWith(">C")) {
-      logger.warn(
-          String.format(
-              ">A* should be used for all axiom annotations\n(Template '%s' in column %d)",
-              template, nextColumn));
-    }
-    template = template.substring(1);
-    String nextValue;
-    try {
-      nextValue = row.get(nextColumn);
-    } catch (IndexOutOfBoundsException e) {
-      nextValue = null;
-    }
-    if (nextValue == null || nextValue.trim().equals("")) {
-      return annotations;
+  private Set<OWLAnnotation> getAxiomAnnotations(
+      List<String> row, String nextTemplate, int nextColumn) throws Exception {
+    // template must not be blank
+    // and it must start with >
+    if (!nextTemplate.trim().isEmpty() && (nextTemplate.startsWith(">"))) {
+      // Remove unknown number of >
+      while (nextTemplate.startsWith(">")) {
+        nextTemplate = nextTemplate.substring(1);
+      }
+
+      String nextValue;
+      try {
+        nextValue = row.get(nextColumn);
+      } catch (IndexOutOfBoundsException e) {
+        // No value, nothing else to add
+        return new HashSet<>();
+      }
+
+      if (!nextValue.trim().isEmpty()) {
+        // First get the set of axiom annotations
+        Set<OWLAnnotation> nextAnnotations =
+            TemplateHelper.getAnnotations(
+                name, checker, nextTemplate, nextValue, rowNum, nextColumn);
+
+        // Maybe get another level of axiom annotations
+        Set<OWLAnnotation> nextNextAnnotations = maybeGetAxiomAnnotations(row, nextColumn);
+        if (nextNextAnnotations.isEmpty()) {
+          // Empty means nothing to add
+          return nextAnnotations;
+        }
+
+        // Add those additional axiom annotations
+        Set<OWLAnnotation> fixedAnnotations = new HashSet<>();
+        for (OWLAnnotation annotation : nextAnnotations) {
+          fixedAnnotations.add(annotation.getAnnotatedAnnotation(nextNextAnnotations));
+        }
+        return fixedAnnotations;
+      }
     }
-    annotations.addAll(
-        TemplateHelper.getAnnotations(name, checker, template, nextValue, rowNum, nextColumn));
-    return annotations;
+    // if the template doesn't start with >, it is not an axiom annotation
+    // or maybe the value cell was empty
+    // return an empty set
+    return new HashSet<>();
   }
 
   /**
@@ -2052,16 +2056,16 @@ public class Template {
     try {
       nextTemplate = templates.get(column + 1);
     } catch (IndexOutOfBoundsException e) {
-      nextTemplate = null;
+      return new HashSet<>();
     }
 
-    Set<OWLAnnotation> axiomAnnotations = new HashSet<>();
     // If the next template string is not null, not empty, and it starts with >
     // Get the axiom annotations from the row
-    if (nextTemplate != null && !nextTemplate.trim().isEmpty() && (nextTemplate.startsWith(">"))) {
-      axiomAnnotations = getAxiomAnnotations(row, nextTemplate, column + 1);
+    if (!nextTemplate.trim().isEmpty() && (nextTemplate.startsWith(">"))) {
+      return getAxiomAnnotations(row, nextTemplate, column + 1);
+    } else {
+      return new HashSet<>();
     }
-    return axiomAnnotations;
   }
 
   /**


Test patch:
diff --git a/robot-core/src/test/resources/legacy-template.csv b/robot-core/src/test/resources/legacy-template.csv
index 2ea0c73b..8928cec0 100644
--- a/robot-core/src/test/resources/legacy-template.csv
+++ b/robot-core/src/test/resources/legacy-template.csv
@@ -1,5 +1,5 @@
-Label,Label Comment,ID,Synonyms,Type,Parent,Parts,Parts Annotation
-A rdfs:label,>AL rdfs:comment@en,ID,A IAO:0000118 SPLIT=|,CLASS_TYPE,C %,C part_of some %,>C rdfs:comment
+Label,Label Comment,Nested Comment,ID,Synonyms,Type,Parent,Parts,Parts Annotation
+A rdfs:label,>AL rdfs:comment@en,>>A rdfs:comment,ID,A IAO:0000118 SPLIT=|,CLASS_TYPE,C %,C part_of some %,>C rdfs:comment
 skip this row
-test 3,test 3 comment,GO:1234,synonym 1|synonym 2,subclass,test2,test one,test one comment
-test 4,test 4 comment,GO:1235,,equivalent,test one,(test2 and 'test 3'),test2 and test 3 comment
+test 3,test 3 comment,test 3 comment comment,GO:1234,synonym 1|synonym 2,subclass,test2,test one,test one comment
+test 4,test 4 comment,,GO:1235,,equivalent,test one,(test2 and 'test 3'),test2 and test 3 comment
diff --git a/robot-core/src/test/resources/template.csv b/robot-core/src/test/resources/template.csv
index 1f5fbfe6..c5d30670 100644
--- a/robot-core/src/test/resources/template.csv
+++ b/robot-core/src/test/resources/template.csv
@@ -1,5 +1,5 @@
-Label,Label Comment,ID,Synonyms,Parent,Parts,Parts Annotation,Equivalent,Eq Annotation
-A rdfs:label,>AL rdfs:comment@en,ID,A IAO:0000118 SPLIT=|,SC %,SC part_of some %,>A rdfs:comment,EC %,>A rdfs:comment
+Label,Label Comment,Nested Comment,ID,Synonyms,Parent,Parts,Parts Annotation,Equivalent,Eq Annotation
+A rdfs:label,>AL rdfs:comment@en,>>A rdfs:comment,ID,A IAO:0000118 SPLIT=|,SC %,SC part_of some %,>A rdfs:comment,EC %,>A rdfs:comment
 skip this row
-test 3,test 3 comment,GO:1234,synonym 1|synonym 2,test2,test one,test one comment,,
-test 4,test 4 comment,GO:1235,,,,,'test one' and (part_of some (test2 and 'test 3')),test2 and test 3 comment
+test 3,test 3 comment,test 3 comment comment,GO:1234,synonym 1|synonym 2,test2,test one,test one comment,,
+test 4,test 4 comment,,GO:1235,,,,,'test one' and (part_of some (test2 and 'test 3')),test2 and test 3 comment
diff --git a/robot-core/src/test/resources/template.owl b/robot-core/src/test/resources/template.owl
index 5b79fa17..9e720b42 100644
--- a/robot-core/src/test/resources/template.owl
+++ b/robot-core/src/test/resources/template.owl
@@ -1,17 +1,17 @@
 <?xml version="1.0"?>
-<rdf:RDF xmlns="http://test.com/template.owl#"
-     xml:base="http://test.com/template.owl"
-     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+<rdf:RDF xmlns="http://www.w3.org/2002/07/owl#"
+     xml:base="http://www.w3.org/2002/07/owl"
+     xmlns:obo="http://purl.obolibrary.org/obo/"
      xmlns:owl="http://www.w3.org/2002/07/owl#"
+     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:xml="http://www.w3.org/XML/1998/namespace"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
-     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
-     xmlns:obo="http://purl.obolibrary.org/obo/">
-    <owl:Ontology rdf:about="http://test.com/template.owl"/>
-
+     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
+    <Ontology rdf:about="http://test.com/template.owl"/>
+    
 
 
-    <!--
+    <!-- 
     ///////////////////////////////////////////////////////////////////////////////////////
     //
     // Classes
@@ -19,97 +19,105 @@
     ///////////////////////////////////////////////////////////////////////////////////////
      -->
 
-
+    
 
 
     <!-- http://purl.obolibrary.org/obo/GO_1234 -->
 
-    <owl:Class rdf:about="http://purl.obolibrary.org/obo/GO_1234">
+    <Class rdf:about="http://purl.obolibrary.org/obo/GO_1234">
         <rdfs:subClassOf rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test2"/>
         <rdfs:subClassOf>
-            <owl:Restriction>
-                <owl:onProperty rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#part_of"/>
-                <owl:someValuesFrom rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test1"/>
-            </owl:Restriction>
+            <Restriction>
+                <onProperty rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#part_of"/>
+                <someValuesFrom rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test1"/>
+            </Restriction>
         </rdfs:subClassOf>
         <obo:IAO_0000118 rdf:datatype="http://www.w3.org/2001/XMLSchema#string">synonym 1</obo:IAO_0000118>
         <obo:IAO_0000118 rdf:datatype="http://www.w3.org/2001/XMLSchema#string">synonym 2</obo:IAO_0000118>
         <rdfs:label rdf:datatype="http://www.w3.org/2001/XMLSchema#string">test 3</rdfs:label>
-    </owl:Class>
-    <owl:Axiom>
-        <owl:annotatedSource rdf:resource="http://purl.obolibrary.org/obo/GO_1234"/>
-        <owl:annotatedProperty rdf:resource="http://www.w3.org/2000/01/rdf-schema#subClassOf"/>
-        <owl:annotatedTarget>
-            <owl:Restriction>
-                <owl:onProperty rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#part_of"/>
-                <owl:someValuesFrom rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test1"/>
-            </owl:Restriction>
-        </owl:annotatedTarget>
+    </Class>
+    <Axiom>
+        <annotatedSource rdf:resource="http://purl.obolibrary.org/obo/GO_1234"/>
+        <annotatedProperty rdf:resource="http://www.w3.org/2000/01/rdf-schema#subClassOf"/>
+        <annotatedTarget>
+            <Restriction>
+                <onProperty rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#part_of"/>
+                <someValuesFrom rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test1"/>
+            </Restriction>
+        </annotatedTarget>
         <rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">test one comment</rdfs:comment>
-    </owl:Axiom>
-    <owl:Axiom>
-        <owl:annotatedSource rdf:resource="http://purl.obolibrary.org/obo/GO_1234"/>
-        <owl:annotatedProperty rdf:resource="http://www.w3.org/2000/01/rdf-schema#label"/>
-        <owl:annotatedTarget rdf:datatype="http://www.w3.org/2001/XMLSchema#string">test 3</owl:annotatedTarget>
-        <rdfs:comment xml:lang="en">test 3 comment</rdfs:comment>
-    </owl:Axiom>
-
+    </Axiom>
+    <Annotation>
+        <annotatedSource>
+            <Axiom rdf:nodeID="genid4">
+                <annotatedSource rdf:resource="http://purl.obolibrary.org/obo/GO_1234"/>
+                <annotatedProperty rdf:resource="http://www.w3.org/2000/01/rdf-schema#label"/>
+                <annotatedTarget rdf:datatype="http://www.w3.org/2001/XMLSchema#string">test 3</annotatedTarget>
+                <rdfs:comment xml:lang="en">test 3 comment</rdfs:comment>
+            </Axiom>
+        </annotatedSource>
+        <annotatedProperty rdf:resource="http://www.w3.org/2000/01/rdf-schema#comment"/>
+        <annotatedTarget xml:lang="en">test 3 comment</annotatedTarget>
+        <rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">test 3 comment comment</rdfs:comment>
+    </Annotation>
+    
 
 
     <!-- http://purl.obolibrary.org/obo/GO_1235 -->
 
-    <owl:Class rdf:about="http://purl.obolibrary.org/obo/GO_1235">
-        <owl:equivalentClass>
-            <owl:Class>
-                <owl:intersectionOf rdf:parseType="Collection">
+    <Class rdf:about="http://purl.obolibrary.org/obo/GO_1235">
+        <equivalentClass>
+            <Class>
+                <intersectionOf rdf:parseType="Collection">
                     <rdf:Description rdf:about="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test1"/>
-                    <owl:Restriction>
-                        <owl:onProperty rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#part_of"/>
-                        <owl:someValuesFrom>
-                            <owl:Class>
-                                <owl:intersectionOf rdf:parseType="Collection">
+                    <Restriction>
+                        <onProperty rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#part_of"/>
+                        <someValuesFrom>
+                            <Class>
+                                <intersectionOf rdf:parseType="Collection">
                                     <rdf:Description rdf:about="http://purl.obolibrary.org/obo/GO_1234"/>
                                     <rdf:Description rdf:about="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test2"/>
-                                </owl:intersectionOf>
-                            </owl:Class>
-                        </owl:someValuesFrom>
-                    </owl:Restriction>
-                </owl:intersectionOf>
-            </owl:Class>
-        </owl:equivalentClass>
+                                </intersectionOf>
+                            </Class>
+                        </someValuesFrom>
+                    </Restriction>
+                </intersectionOf>
+            </Class>
+        </equivalentClass>
         <rdfs:label rdf:datatype="http://www.w3.org/2001/XMLSchema#string">test 4</rdfs:label>
-    </owl:Class>
-    <owl:Axiom>
-        <owl:annotatedSource rdf:resource="http://purl.obolibrary.org/obo/GO_1235"/>
-        <owl:annotatedProperty rdf:resource="http://www.w3.org/2002/07/owl#equivalentClass"/>
-        <owl:annotatedTarget>
-            <owl:Class>
-                <owl:intersectionOf rdf:parseType="Collection">
+    </Class>
+    <Axiom>
+        <annotatedSource rdf:resource="http://purl.obolibrary.org/obo/GO_1235"/>
+        <annotatedProperty rdf:resource="http://www.w3.org/2002/07/owl#equivalentClass"/>
+        <annotatedTarget>
+            <Class>
+                <intersectionOf rdf:parseType="Collection">
                     <rdf:Description rdf:about="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test1"/>
-                    <owl:Restriction>
-                        <owl:onProperty rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#part_of"/>
-                        <owl:someValuesFrom>
-                            <owl:Class>
-                                <owl:intersectionOf rdf:parseType="Collection">
+                    <Restriction>
+                        <onProperty rdf:resource="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#part_of"/>
+                        <someValuesFrom>
+                            <Class>
+                                <intersectionOf rdf:parseType="Collection">
                                     <rdf:Description rdf:about="http://purl.obolibrary.org/obo/GO_1234"/>
                                     <rdf:Description rdf:about="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test2"/>
-                                </owl:intersectionOf>
-                            </owl:Class>
-                        </owl:someValuesFrom>
-                    </owl:Restriction>
-                </owl:intersectionOf>
-            </owl:Class>
-        </owl:annotatedTarget>
+                                </intersectionOf>
+                            </Class>
+                        </someValuesFrom>
+                    </Restriction>
+                </intersectionOf>
+            </Class>
+        </annotatedTarget>
         <rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">test2 and test 3 comment</rdfs:comment>
-    </owl:Axiom>
-    <owl:Axiom>
-        <owl:annotatedSource rdf:resource="http://purl.obolibrary.org/obo/GO_1235"/>
-        <owl:annotatedProperty rdf:resource="http://www.w3.org/2000/01/rdf-schema#label"/>
-        <owl:annotatedTarget rdf:datatype="http://www.w3.org/2001/XMLSchema#string">test 4</owl:annotatedTarget>
+    </Axiom>
+    <Axiom>
+        <annotatedSource rdf:resource="http://purl.obolibrary.org/obo/GO_1235"/>
+        <annotatedProperty rdf:resource="http://www.w3.org/2000/01/rdf-schema#label"/>
+        <annotatedTarget rdf:datatype="http://www.w3.org/2001/XMLSchema#string">test 4</annotatedTarget>
         <rdfs:comment xml:lang="en">test 4 comment</rdfs:comment>
-    </owl:Axiom>
+    </Axiom>
 </rdf:RDF>
 
 
 
-<!-- Generated by the OWL API (version 4.2.6.20160910-2108) https://github.com/owlcs/owlapi -->
+<!-- Generated by the OWL API (version 4.5.6) https://github.com/owlcs/owlapi -->
+