Repository: ontodev/robot (java)

Issue:
Is it possible for robot to enact entity substitution when outputting ontology?
I have the robot working on my GenEpiO ontology, which has a number of XML entities defined up front, like: xmlns:obo="http://purl.obolibrary.org/obo/" .  I was wondering if, as an output file space saving measure, there was a way for robot to implement these entities wherever they exist? e.g.     
   
```
<owl:Class rdf:about="http://purl.obolibrary.org/obo/ERO_0001965">
   =>     
   <owl:Class rdf:about="&obo;ERO_0001965">
```
I think the entities get replaced with expanded URL in the original genepio-edit.owl file whenever Protege saves it.  (If this is beyond robot's purview, then I will use an old-fashioned search & replace approach for the job.)

Pull request description:
Add option to use XML entities in XML output
Fixes #114, closes #115

Thanks Damion Dooley!

- update IOHelper to use `setUseNamespaceEntities`
- add option to CommandLineHelper
- add test to IOHelperTest
- add test file

Patch:
diff --git a/robot-command/src/main/java/org/obolibrary/robot/CommandLineHelper.java b/robot-command/src/main/java/org/obolibrary/robot/CommandLineHelper.java
index 218cc9b2..c389fee1 100644
--- a/robot-command/src/main/java/org/obolibrary/robot/CommandLineHelper.java
+++ b/robot-command/src/main/java/org/obolibrary/robot/CommandLineHelper.java
@@ -251,7 +251,8 @@ public class CommandLineHelper {
 
     /**
      * Given a command line, return an initialized IOHelper.
-     * The --prefix, --prefixes, and --noprefixes options are handled.
+     * The --prefix, --prefixes, --noprefixes and --xml-entities options
+     * are handled.
      *
      * @param line the command line to use
      * @return an initialized IOHelper
@@ -269,6 +270,8 @@ public class CommandLineHelper {
             ioHelper.addPrefix(prefix);
         }
 
+        ioHelper.setXMLEntityFlag(line.hasOption("xml-entities"));
+
         return ioHelper;
     }
 
@@ -538,6 +541,8 @@ public class CommandLineHelper {
         o.addOption("p", "prefix",  true,  "add a prefix 'foo: http://bar'");
         o.addOption("P", "prefixes", true, "use prefixes from JSON-LD file");
         o.addOption("noprefixes", false, "do not use default prefixes");
+        o.addOption("x", "xml-entities", false,
+                    "use entity substitution with ontology XML output");
         return o;
     }
 
diff --git a/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java b/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java
index f8949f17..f22c53f9 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java
@@ -49,6 +49,7 @@ import org.semanticweb.owlapi.formats.ManchesterSyntaxDocumentFormat;
 import org.semanticweb.owlapi.formats.FunctionalSyntaxDocumentFormat;
 import org.semanticweb.owlapi.formats.OWLXMLDocumentFormat;
 import org.semanticweb.owlapi.formats.TurtleDocumentFormat;
+import org.semanticweb.owlapi.rdf.rdfxml.renderer.XMLWriterPreferences;
 import org.semanticweb.owlapi.util.DefaultPrefixManager;
 import org.yaml.snakeyaml.Yaml;
 
@@ -79,6 +80,11 @@ public class IOHelper {
      */
     private Context context = new Context();
 
+    /**
+     * Store xml entities flag.
+     */
+    private Boolean useXMLEntities = false;
+
     /**
      * Create a new IOHelper with the default prefixes.
      */
@@ -438,8 +444,9 @@ public class IOHelper {
         //    ((PrefixOWLDocumentFormat) format)
         //        .copyPrefixesFrom(getPrefixManager());
         //}
-
         try {
+            XMLWriterPreferences.getInstance()
+                .setUseNamespaceEntities(getXMLEntityFlag());
             ontology.getOWLOntologyManager().saveOntology(
                     ontology, format, ontologyIRI);
         } catch (OWLOntologyStorageException e) {
@@ -682,6 +689,30 @@ public class IOHelper {
         }
     }
 
+    /**
+     * Set whether or not XML entities will be swapped into URIs
+     * in saveOntology XML output formats.
+     *
+     * @param map a map of strings for the new JSON-LD context
+     */
+    public void setXMLEntityFlag(Boolean entityFlag) {
+        try {
+            this.useXMLEntities = entityFlag;
+        } catch (Exception e) {
+            logger.warn("Could not set useXMLEntities {}", entityFlag);
+            logger.warn(e.getMessage());
+        }
+    }
+
+    /**
+     * Get the useXMLEntities flag.
+     *
+     * @return boolean useXMLEntities flag
+     */
+    public Boolean getXMLEntityFlag() {
+        return this.useXMLEntities;
+    }
+
     /**
      * Make an OWLAPI DefaultPrefixManager from a map of prefixes.
      *


Test patch:
diff --git a/robot-core/src/test/java/org/obolibrary/robot/IOHelperTest.java b/robot-core/src/test/java/org/obolibrary/robot/IOHelperTest.java
index b6959fe7..f6007e0b 100644
--- a/robot-core/src/test/java/org/obolibrary/robot/IOHelperTest.java
+++ b/robot-core/src/test/java/org/obolibrary/robot/IOHelperTest.java
@@ -15,6 +15,10 @@ import org.semanticweb.owlapi.model.IRI;
 import org.semanticweb.owlapi.model.OWLLiteral;
 import org.semanticweb.owlapi.util.DefaultPrefixManager;
 
+import org.apache.commons.io.FileUtils;
+import org.semanticweb.owlapi.model.OWLOntology;
+import org.semanticweb.owlapi.formats.RDFXMLDocumentFormat;
+
 /**
  * Tests for IOHelper.
  */
@@ -194,4 +198,32 @@ public class IOHelperTest extends CoreTest {
         assertEquals("en", literal.getLang());
     }
 
+    /**
+     * Test setting useXMLEntities flag and saving resulting ontology.
+     * Requires an "expected" ontology containing entity replacements.
+     *
+     * @throws IOException on file problem
+     */
+    @Test
+    public void testOntologyUseXMLEntities() throws IOException {
+        String ontologyInputPath = "/mireot.owl";
+        String ontologyExpectedPath = "/mireot_xmlentities.owl";
+
+        File tempFile = File.createTempFile("mireot_xmlentities_test", ".owl");
+        tempFile.deleteOnExit();
+        String ontologyOutputPath =
+            tempFile.getCanonicalFile().getAbsolutePath();
+
+        IOHelper ioHelper = new IOHelper();
+        ioHelper.setXMLEntityFlag(true);
+        OWLOntology simple = loadOntology(ontologyInputPath);
+        ioHelper.saveOntology(simple, new RDFXMLDocumentFormat(), tempFile);
+
+        OWLOntology expected = loadOntology(ontologyExpectedPath);
+        OWLOntology actual = ioHelper.loadOntology(ontologyOutputPath);
+        assertIdentical(expected, actual);
+
+    }
+
+
 }
diff --git a/robot-core/src/test/resources/mireot_xmlentities.owl b/robot-core/src/test/resources/mireot_xmlentities.owl
new file mode 100644
index 00000000..2aa4946f
--- /dev/null
+++ b/robot-core/src/test/resources/mireot_xmlentities.owl
@@ -0,0 +1,227 @@
+<?xml version="1.0"?>
+
+
+<!DOCTYPE rdf:RDF [
+    <!ENTITY foaf "http://xmlns.com/foaf/0.1/" >
+    <!ENTITY owl "http://www.w3.org/2002/07/owl#" >
+    <!ENTITY obo "http://purl.obolibrary.org/obo/" >
+    <!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
+    <!ENTITY xml "http://www.w3.org/XML/1998/namespace" >
+    <!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" >
+    <!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
+    <!ENTITY oboInOwl "http://www.geneontology.org/formats/oboInOwl#" >
+]>
+
+
+<rdf:RDF xmlns="&obo;uberon.owl#"
+     xml:base="&obo;uberon.owl"
+     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:owl="http://www.w3.org/2002/07/owl#"
+     xmlns:oboInOwl="http://www.geneontology.org/formats/oboInOwl#"
+     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/"
+     xmlns:foaf="http://xmlns.com/foaf/0.1/">
+    <owl:Ontology rdf:about="&obo;uberon.owl"/>
+
+
+
+    <!--
+    ///////////////////////////////////////////////////////////////////////////////////////
+    //
+    // Annotation properties
+    //
+    ///////////////////////////////////////////////////////////////////////////////////////
+     -->
+
+
+
+
+    <!-- http://purl.obolibrary.org/obo/IAO_0000115 -->
+
+    <owl:AnnotationProperty rdf:about="&obo;IAO_0000115"/>
+
+
+
+    <!-- http://purl.obolibrary.org/obo/UBPROP_0000003 -->
+
+    <owl:AnnotationProperty rdf:about="&obo;UBPROP_0000003"/>
+
+
+
+    <!-- http://purl.obolibrary.org/obo/UBPROP_0000008 -->
+
+    <owl:AnnotationProperty rdf:about="&obo;UBPROP_0000008"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#date_retrieved -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;date_retrieved"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#external_class -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;external_class"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#hasDbXref -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;hasDbXref"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#hasExactSynonym -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;hasExactSynonym"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#hasOBONamespace -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;hasOBONamespace"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#hasRelatedSynonym -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;hasRelatedSynonym"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#hasSynonymType -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;hasSynonymType"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#id -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;id"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#inSubset -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;inSubset"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#ontology -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;ontology"/>
+
+
+
+    <!-- http://www.geneontology.org/formats/oboInOwl#source -->
+
+    <owl:AnnotationProperty rdf:about="&oboInOwl;source"/>
+
+
+
+    <!-- http://www.w3.org/2000/01/rdf-schema#label -->
+
+    <owl:AnnotationProperty rdf:about="&rdfs;label"/>
+
+
+
+    <!-- http://xmlns.com/foaf/0.1/depicted_by -->
+
+    <owl:AnnotationProperty rdf:about="&foaf;depicted_by"/>
+
+
+
+    <!--
+    ///////////////////////////////////////////////////////////////////////////////////////
+    //
+    // Classes
+    //
+    ///////////////////////////////////////////////////////////////////////////////////////
+     -->
+
+
+
+
+    <!-- http://purl.obolibrary.org/obo/UBERON_0001235 -->
+
+    <owl:Class rdf:about="&obo;UBERON_0001235">
+        <obo:IAO_0000115 rdf:datatype="&xsd;string">the thick outer layer of the adrenal gland that produces and secretes steroid hormones such as corticosterone, estrone and aldosterone</obo:IAO_0000115>
+        <obo:UBPROP_0000003 rdf:datatype="&xsd;string">All craniates have groups of cells homologous to the mammalian adrenocortical and chromaffin tissues (medulla), but they are scattered in and near the kidneys in fishes. (...) The cortical and chromaffin tissues come together to form adrenal glands in tetrapods.[well established][VHOG]</obo:UBPROP_0000003>
+        <obo:UBPROP_0000008 rdf:datatype="&xsd;string">Kardong states that mammals are the first to have distinct cortext and medulla, but this contradicts XAO</obo:UBPROP_0000008>
+        <oboInOwl:hasDbXref rdf:resource="http://en.wikipedia.org/wiki/Adrenal_cortex"/>
+        <oboInOwl:hasDbXref rdf:resource="http://linkedlifedata.com/resource/umls/id/C0001613"/>
+        <oboInOwl:hasDbXref rdf:resource="http://ncicb.nci.nih.gov/xml/owl/EVS/Adrenal_Cortex"/>
+        <oboInOwl:hasDbXref rdf:resource="http://www.snomedbrowser.com/Codes/Details/362584002"/>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">AAO:0011009</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">BTO:0000045</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">CALOHA:TS-0015</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">EFO:0000237</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">EMAPA:18427</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">EV:0100136</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">FMA:15632</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">GAID:447</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">MA:0000118</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">MAT:0000494</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">MESH:A06.407.071.140</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">UMLS:C0001613</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">VHOG:0001481</oboInOwl:hasDbXref>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">XAO:0000165</oboInOwl:hasDbXref>
+        <oboInOwl:hasExactSynonym rdf:datatype="&xsd;string">adrenal gland cortex</oboInOwl:hasExactSynonym>
+        <oboInOwl:hasExactSynonym rdf:datatype="&xsd;string">cortex (glandula suprarenalis)</oboInOwl:hasExactSynonym>
+        <oboInOwl:hasExactSynonym rdf:datatype="&xsd;string">cortex of adrenal gland</oboInOwl:hasExactSynonym>
+        <oboInOwl:hasExactSynonym rdf:datatype="&xsd;string">cortex of suprarenal gland</oboInOwl:hasExactSynonym>
+        <oboInOwl:hasExactSynonym rdf:datatype="&xsd;string">suprarenal cortex</oboInOwl:hasExactSynonym>
+        <oboInOwl:hasOBONamespace rdf:datatype="&xsd;string">uberon</oboInOwl:hasOBONamespace>
+        <oboInOwl:hasRelatedSynonym rdf:datatype="&xsd;string">cortex glandulae suprarenalis</oboInOwl:hasRelatedSynonym>
+        <oboInOwl:hasRelatedSynonym rdf:datatype="&xsd;string">suprarenal</oboInOwl:hasRelatedSynonym>
+        <oboInOwl:id rdf:datatype="&xsd;string">UBERON:0001235</oboInOwl:id>
+        <oboInOwl:inSubset rdf:resource="&obo;uberon/core#efo_slim"/>
+        <oboInOwl:inSubset rdf:resource="&obo;uberon/core#uberon_slim"/>
+        <rdfs:label rdf:datatype="&xsd;string">adrenal cortex</rdfs:label>
+        <foaf:depicted_by rdf:resource="http://upload.wikimedia.org/wikipedia/commons/5/5c/Gray1185.png"/>
+        <foaf:depicted_by rdf:resource="http://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Gray1185.png/200px-Gray1185.png"/>
+    </owl:Class>
+    <owl:Axiom>
+        <owl:annotatedSource rdf:resource="&obo;UBERON_0001235"/>
+        <owl:annotatedProperty rdf:resource="&obo;IAO_0000115"/>
+        <owl:annotatedTarget rdf:datatype="&xsd;string">the thick outer layer of the adrenal gland that produces and secretes steroid hormones such as corticosterone, estrone and aldosterone</owl:annotatedTarget>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">MP:0008288,ISBN:0-683-40008-8,MGI:llw2</oboInOwl:hasDbXref>
+    </owl:Axiom>
+    <owl:Axiom>
+        <owl:annotatedSource rdf:resource="&obo;UBERON_0001235"/>
+        <owl:annotatedProperty rdf:resource="&obo;UBPROP_0000003"/>
+        <owl:annotatedTarget rdf:datatype="&xsd;string">All craniates have groups of cells homologous to the mammalian adrenocortical and chromaffin tissues (medulla), but they are scattered in and near the kidneys in fishes. (...) The cortical and chromaffin tissues come together to form adrenal glands in tetrapods.[well established][VHOG]</owl:annotatedTarget>
+        <oboInOwl:date_retrieved rdf:datatype="&xsd;string">2012-09-17</oboInOwl:date_retrieved>
+        <oboInOwl:external_class rdf:datatype="&xsd;string">VHOG:0001481</oboInOwl:external_class>
+        <oboInOwl:ontology rdf:datatype="&xsd;string">VHOG</oboInOwl:ontology>
+        <oboInOwl:source rdf:resource="http://bgee.unil.ch/"/>
+        <oboInOwl:source rdf:datatype="&xsd;string">ISBN:978-0030223693 Liem KF, Bemis WE, Walker WF, Grande L, Functional Anatomy of the Vertebrates: An Evolutionary Perspective (2001) p.518 and Figure 15-9</oboInOwl:source>
+    </owl:Axiom>
+    <owl:Axiom>
+        <owl:annotatedSource rdf:resource="&obo;UBERON_0001235"/>
+        <owl:annotatedProperty rdf:resource="&oboInOwl;hasDbXref"/>
+        <owl:annotatedTarget rdf:datatype="&xsd;string">UMLS:C0001613</owl:annotatedTarget>
+        <oboInOwl:source rdf:datatype="&xsd;string">ncithesaurus:Adrenal_Cortex</oboInOwl:source>
+    </owl:Axiom>
+    <owl:Axiom>
+        <owl:annotatedSource rdf:resource="&obo;UBERON_0001235"/>
+        <owl:annotatedProperty rdf:resource="&oboInOwl;hasRelatedSynonym"/>
+        <owl:annotatedTarget rdf:datatype="&xsd;string">cortex glandulae suprarenalis</owl:annotatedTarget>
+        <oboInOwl:hasDbXref rdf:resource="http://en.wikipedia.org/wiki/Adrenal_cortex"/>
+        <oboInOwl:hasSynonymType rdf:resource="&obo;uberon/core#LATIN"/>
+    </owl:Axiom>
+    <owl:Axiom>
+        <owl:annotatedSource rdf:resource="&obo;UBERON_0001235"/>
+        <owl:annotatedProperty rdf:resource="&oboInOwl;hasRelatedSynonym"/>
+        <owl:annotatedTarget rdf:datatype="&xsd;string">cortex glandulae suprarenalis</owl:annotatedTarget>
+        <oboInOwl:hasDbXref rdf:datatype="&xsd;string">BTO:0000045</oboInOwl:hasDbXref>
+    </owl:Axiom>
+</rdf:RDF>
+
+
+
+<!-- Generated by the OWL API (version 4.2.6) https://github.com/owlcs/owlapi -->
+