Repository: ontodev/robot
Pull request #419 (2018-12-28 14:14:53)

Add rename command
See #293

```
usage: robot rename --input <file> --mapping <file> --output <file>
 -A,--add-prefix <arg>      add a new prefix to ontology file header
    --catalog <arg>         use catalog from provided file
 -f,--full <arg>            table of mappings for renaming
 -h,--help                  print usage information
 -i,--input <arg>           load ontology from a file
 -I,--input-iri <arg>       load ontology from an IRI
 -noprefixes                do not use default prefixes
 -o,--output <arg>          save ontology to a file
 -p,--prefix <arg>          add a prefix 'foo: http://bar'
 -P,--prefixes <arg>        use prefixes from JSON-LD file
 -r,--partial <arg>         table of partial mappings for renaming
 -V,--version               print version information
 -v,--verbose               increased logging
 -vv,--very-verbose         high logging
 -vvv,--very-very-verbose   maximum logging, including stack traces
 -x,--xml-entities          use entity substitution with ontology XML
                            output
```

The `--add-prefix` option makes sure that the prefix appears in the final output file, which does not happen if you just use `--prefix`.

Right now, the `--full` and `--partial` files expect a header - should this be assumed? Or should we do no headers?


Patch:
diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html
index 749d776a..a2609506 100644
--- a/docs/_layouts/default.html
+++ b/docs/_layouts/default.html
@@ -41,6 +41,7 @@
           <a href="/reduce">reduce</a><br>
           <a href="/relax">relax</a><br>
           <a href="/remove">remove</a><br>
+          <a href="/rename">rename</a><br>
           <a href="/repair">repair</a><br>
           <a href="/report">report</a><br>
           <a href="/template">template</a><br>
diff --git a/docs/examples/full-rename.owl b/docs/examples/full-rename.owl
new file mode 100644
index 00000000..1e52605e
--- /dev/null
+++ b/docs/examples/full-rename.owl
@@ -0,0 +1,365 @@
+<?xml version="1.0"?>
+<rdf:RDF xmlns="http://purl.obolibrary.org/obo/bfo.owl#"
+     xml:base="http://purl.obolibrary.org/obo/bfo.owl"
+     xmlns:dc="http://purl.org/dc/elements/1.1/"
+     xmlns:fb="http://foo.bar/"
+     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:foaf="http://xmlns.com/foaf/0.1/"
+     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+     xmlns:oboInOwl="http://www.geneontology.org/formats/oboInOwl#">
+    <owl:Ontology rdf:about="http://purl.obolibrary.org/obo/ro/core.owl">
+        <owl:imports rdf:resource="http://purl.obolibrary.org/obo/ro/annotations.owl"/>
+        <owl:imports rdf:resource="http://purl.obolibrary.org/obo/ro/bfo-classes-minimal.owl"/>
+        <foaf:homepage rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">https://code.google.com/p/obo-relations/w/ROCore</foaf:homepage>
+    </owl:Ontology>
+    
+
+
+    <!-- 
+    ///////////////////////////////////////////////////////////////////////////////////////
+    //
+    // Object Properties
+    //
+    ///////////////////////////////////////////////////////////////////////////////////////
+     -->
+
+    
+
+
+    <!-- http://foo.bar/BFO_1234567 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/BFO_1234567">
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/BFO_0000050"/>
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#TransitiveProperty"/>
+        <obo:IAO_0000111 xml:lang="en">has part</obo:IAO_0000111>
+        <obo:IAO_0000116 xml:lang="en">Ambiguous between continuant-parthood and occurrent-parthood</obo:IAO_0000116>
+        <obo:IAO_0000118 xml:lang="en">has_part</obo:IAO_0000118>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">has part</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/BFO_0000050 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/BFO_0000050">
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#TransitiveProperty"/>
+        <obo:IAO_0000111 xml:lang="en">is part of</obo:IAO_0000111>
+        <obo:IAO_0000116 xml:lang="en">Ambiguous between continuant-parthood and occurrent-parthood</obo:IAO_0000116>
+        <obo:IAO_0000118 xml:lang="en">part_of</obo:IAO_0000118>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">part of</rdfs:label>
+        <rdfs:seeAlso>http://www.obofoundry.org/ro/#OBO_REL:part_of</rdfs:seeAlso>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/BFO_0000054 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/BFO_0000054">
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/BFO_0000055"/>
+        <rdfs:range rdf:resource="http://purl.obolibrary.org/obo/BFO_0000015"/>
+        <obo:IAO_0000111 xml:lang="en">realized in</obo:IAO_0000111>
+        <obo:IAO_0000118 xml:lang="en">is realized by</obo:IAO_0000118>
+        <obo:IAO_0000118 xml:lang="en">realized_in</obo:IAO_0000118>
+        <rdfs:label xml:lang="en">realized in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/BFO_0000055 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/BFO_0000055">
+        <rdfs:domain rdf:resource="http://purl.obolibrary.org/obo/BFO_0000015"/>
+        <obo:IAO_0000111 xml:lang="en">realizes</obo:IAO_0000111>
+        <rdfs:label xml:lang="en">realizes</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/BFO_0000066 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/BFO_0000066">
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/BFO_0000067"/>
+        <rdfs:domain rdf:resource="http://purl.obolibrary.org/obo/BFO_0000003"/>
+        <rdfs:range rdf:resource="http://purl.obolibrary.org/obo/BFO_0000004"/>
+        <owl:propertyChainAxiom rdf:parseType="Collection">
+            <rdf:Description rdf:about="http://purl.obolibrary.org/obo/BFO_0000050"/>
+            <rdf:Description rdf:about="http://purl.obolibrary.org/obo/BFO_0000066"/>
+        </owl:propertyChainAxiom>
+        <owl:propertyChainAxiom rdf:parseType="Collection">
+            <rdf:Description rdf:about="http://purl.obolibrary.org/obo/BFO_0000066"/>
+            <rdf:Description rdf:about="http://purl.obolibrary.org/obo/BFO_0000050"/>
+        </owl:propertyChainAxiom>
+        <obo:IAO_0000111 xml:lang="en">occurs in</obo:IAO_0000111>
+        <obo:IAO_0000118 xml:lang="en">Intended meaning:
+domain: occurrent
+range: independent continuant
+time: atemporal</obo:IAO_0000118>
+        <obo:IAO_0000118 xml:lang="en">occurs_in</obo:IAO_0000118>
+        <obo:IAO_0000118 xml:lang="en">unfolds in</obo:IAO_0000118>
+        <obo:IAO_0000118 xml:lang="en">unfolds_in</obo:IAO_0000118>
+        <rdfs:label xml:lang="en">occurs in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/BFO_0000067 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/BFO_0000067">
+        <obo:IAO_0000111 xml:lang="en">site of</obo:IAO_0000111>
+        <rdfs:label xml:lang="en">contains process</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0000052 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0000052">
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/RO_0000053"/>
+        <obo:IAO_0000111 xml:lang="en">inheres in</obo:IAO_0000111>
+        <obo:IAO_0000116 xml:lang="en">Intended meaning:
+domain: specifically dependent continuant
+range: independent continuant
+time: at all times
+
+A specifically dependent continuant A inheres in its independent continuant B at all times during which A exists.</obo:IAO_0000116>
+        <obo:IAO_0000118 xml:lang="en">inheres_in</obo:IAO_0000118>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">inheres in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0000053 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0000053">
+        <rdfs:range rdf:resource="http://purl.obolibrary.org/obo/BFO_0000020"/>
+        <obo:IAO_0000111 xml:lang="en">bearer of</obo:IAO_0000111>
+        <obo:IAO_0000118 xml:lang="en">bearer_of</obo:IAO_0000118>
+        <obo:IAO_0000118 xml:lang="en">is bearer of</obo:IAO_0000118>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">bearer of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0000056 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0000056">
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/RO_0000057"/>
+        <rdfs:domain rdf:resource="http://purl.obolibrary.org/obo/BFO_0000002"/>
+        <rdfs:range rdf:resource="http://purl.obolibrary.org/obo/BFO_0000003"/>
+        <obo:IAO_0000111 xml:lang="en">participates in</obo:IAO_0000111>
+        <obo:IAO_0000118 xml:lang="en">participates_in</obo:IAO_0000118>
+        <rdfs:label xml:lang="en">participates in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0000057 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0000057">
+        <rdfs:domain rdf:resource="http://purl.obolibrary.org/obo/BFO_0000003"/>
+        <rdfs:range rdf:resource="http://purl.obolibrary.org/obo/BFO_0000002"/>
+        <obo:IAO_0000111 xml:lang="en">has participant</obo:IAO_0000111>
+        <obo:IAO_0000116 xml:lang="en">Has_participant is a primitive instance-level relation between a process, a continuant, and a time at which the continuant participates in some way in the process. The relation obtains, for example, when this particular process of oxygen exchange across this particular alveolar membrane has_participant this particular sample of hemoglobin at this particular time.</obo:IAO_0000116>
+        <obo:IAO_0000118 xml:lang="en">has_participant</obo:IAO_0000118>
+        <dc:source>http://www.obofoundry.org/ro/#OBO_REL:has_participant</dc:source>
+        <rdfs:label xml:lang="en">has participant</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0000058 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0000058">
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/RO_0000059"/>
+        <rdfs:domain rdf:resource="http://purl.obolibrary.org/obo/BFO_0000031"/>
+        <rdfs:range rdf:resource="http://purl.obolibrary.org/obo/BFO_0000020"/>
+        <obo:IAO_0000112 xml:lang="en">A journal article is an information artifact that inheres in some number of printed journals. For each copy of the printed journal there is some quality that carries the journal article, such as a pattern of ink. The journal article (a generically dependent continuant) is concretized as the quality (a specifically dependent continuant), and both depend on that copy of the printed journal (an independent continuant).</obo:IAO_0000112>
+        <obo:IAO_0000112 xml:lang="en">An investigator reads a protocol and forms a plan to carry out an assay. The plan is a realizable entity (a specifically dependent continuant) that concretizes the protocol (a generically dependent continuant), and both depend on the investigator (an independent continuant). The plan is then realized by the assay (a process).</obo:IAO_0000112>
+        <obo:IAO_0000115 xml:lang="en">A relationship between a generically dependent continuant and a specifically dependent continuant, in which the generically dependent continuant depends on some independent continuant in virtue of the fact that the specifically dependent continuant also depends on that same independent continuant. A generically dependent continuant may be concretized as multiple specifically dependent continuants.</obo:IAO_0000115>
+        <rdfs:label xml:lang="en">is concretized as</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0000059 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0000059">
+        <rdfs:domain rdf:resource="http://purl.obolibrary.org/obo/BFO_0000020"/>
+        <rdfs:range rdf:resource="http://purl.obolibrary.org/obo/BFO_0000031"/>
+        <obo:IAO_0000112 xml:lang="en">A journal article is an information artifact that inheres in some number of printed journals. For each copy of the printed journal there is some quality that carries the journal article, such as a pattern of ink. The quality (a specifically dependent continuant) concretizes the journal article (a generically dependent continuant), and both depend on that copy of the printed journal (an independent continuant).</obo:IAO_0000112>
+        <obo:IAO_0000112 xml:lang="en">An investigator reads a protocol and forms a plan to carry out an assay. The plan is a realizable entity (a specifically dependent continuant) that concretizes the protocol (a generically dependent continuant), and both depend on the investigator (an independent continuant). The plan is then realized by the assay (a process).</obo:IAO_0000112>
+        <obo:IAO_0000115 xml:lang="en">A relationship between a specifically dependent continuant and a generically dependent continuant, in which the generically dependent continuant depends on some independent continuant in virtue of the fact that the specifically dependent continuant also depends on that same independent continuant. Multiple specifically dependent continuants can concretize the same generically dependent continuant.</obo:IAO_0000115>
+        <rdfs:label xml:lang="en">concretizes</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0000081 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0000081">
+        <rdfs:subPropertyOf rdf:resource="http://purl.obolibrary.org/obo/RO_0000052"/>
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/RO_0000087"/>
+        <obo:IAO_0000118 xml:lang="en">is role of</obo:IAO_0000118>
+        <obo:IAO_0000118 xml:lang="en">role_of</obo:IAO_0000118>
+        <rdfs:label xml:lang="en">role of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0000086 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0000086">
+        <rdfs:subPropertyOf rdf:resource="http://purl.obolibrary.org/obo/RO_0000053"/>
+        <rdfs:range rdf:resource="http://purl.obolibrary.org/obo/BFO_0000019"/>
+        <rdfs:label xml:lang="en">has quality</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0000087 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0000087">
+        <rdfs:subPropertyOf rdf:resource="http://purl.obolibrary.org/obo/RO_0000053"/>
+        <rdfs:range rdf:resource="http://purl.obolibrary.org/obo/BFO_0000023"/>
+        <obo:IAO_0000118 xml:lang="en">has_role</obo:IAO_0000118>
+        <rdfs:label xml:lang="en">has role</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0001000 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0001000">
+        <rdfs:subPropertyOf rdf:resource="http://www.w3.org/2002/07/owl#topObjectProperty"/>
+        <obo:IAO_0000114 rdf:resource="http://purl.obolibrary.org/obo/IAO_0000125"/>
+        <rdfs:label xml:lang="en">derives from</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0001001 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0001001">
+        <rdfs:subPropertyOf rdf:resource="http://www.w3.org/2002/07/owl#topObjectProperty"/>
+        <obo:IAO_0000114 rdf:resource="http://purl.obolibrary.org/obo/IAO_0000125"/>
+        <rdfs:label xml:lang="en">derives into</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0001015 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0001015">
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/RO_0001025"/>
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#TransitiveProperty"/>
+        <obo:IAO_0000111 xml:lang="en">is location of</obo:IAO_0000111>
+        <obo:IAO_0000118 xml:lang="en">location_of</obo:IAO_0000118>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">location of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0001018 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0001018">
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/RO_0001019"/>
+        <obo:IAO_0000111 xml:lang="en">contained in</obo:IAO_0000111>
+        <obo:IAO_0000116>Containment is location not involving parthood, and arises only where some immaterial continuant is involved.</obo:IAO_0000116>
+        <obo:IAO_0000116 xml:lang="en">Containment obtains in each case between material and immaterial continuants, for instance: lung contained_in thoracic cavity; bladder contained_in pelvic cavity. Hence containment is not a transitive relation.    If c part_of c1 at t then we have also, by our definition and by the axioms of mereology applied to spatial regions, c located_in c1 at t. Thus, many examples of instance-level location relations for continuants are in fact cases of instance-level parthood. For material continuants location and parthood coincide. Containment is location not involving parthood, and arises only where some immaterial continuant is involved. To understand this relation, we first define overlap for continuants as follows:    c1 overlap c2 at t =def for some c, c part_of c1 at t and c part_of c2 at t. The containment relation on the instance level can then be defined (see definition):</obo:IAO_0000116>
+        <obo:IAO_0000116 xml:lang="en">Intended meaning:
+domain: material entity
+range: spatial region or site (immaterial continuant)
+        </obo:IAO_0000116>
+        <obo:IAO_0000118 xml:lang="en">contained_in</obo:IAO_0000118>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">contained in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0001019 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0001019">
+        <obo:IAO_0000111 xml:lang="en">contains</obo:IAO_0000111>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">contains</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0001025 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0001025">
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#TransitiveProperty"/>
+        <obo:IAO_0000111 xml:lang="en">located in</obo:IAO_0000111>
+        <obo:IAO_0000116 xml:lang="en">Location as a relation between instances: The primitive instance-level relation c located_in r at t reflects the fact that each continuant is at any given time associated with exactly one spatial region, namely its exact location. Following we can use this relation to define a further instance-level location relation - not between a continuant and the region which it exactly occupies, but rather between one continuant and another. c is located in c1, in this sense, whenever the spatial region occupied by c is part_of the spatial region occupied by c1.    Note that this relation comprehends both the relation of exact location between one continuant and another which obtains when r and r1 are identical (for example, when a portion of fluid exactly fills a cavity), as well as those sorts of inexact location relations which obtain, for example, between brain and head or between ovum and uterus</obo:IAO_0000116>
+        <obo:IAO_0000118 xml:lang="en">located_in</obo:IAO_0000118>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <dc:source>http://www.obofoundry.org/ro/#OBO_REL:located_in</dc:source>
+        <rdfs:label xml:lang="en">located in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0002000 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0002000">
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/RO_0002002"/>
+        <obo:IAO_0000115 rdf:datatype="http://www.w3.org/2001/XMLSchema#string">The relationships between a boundary (a 2D immaterial entity) and the material entity that it delimits.</obo:IAO_0000115>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">boundary of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0002002 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0002002">
+        <obo:IAO_0000115 rdf:datatype="http://www.w3.org/2001/XMLSchema#string">The relationship between a material entity and the boundary (2D immaterial entity) that delimits it.</obo:IAO_0000115>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">has boundary</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0002350 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0002350">
+        <rdfs:subPropertyOf rdf:resource="http://purl.obolibrary.org/obo/BFO_0000050"/>
+        <owl:inverseOf rdf:resource="http://purl.obolibrary.org/obo/RO_0002351"/>
+        <obo:IAO_0000112>An organism that is a member of a population of organisms</obo:IAO_0000112>
+        <obo:IAO_0000115>is member of is a mereological relation between a item and a collection.</obo:IAO_0000115>
+        <obo:IAO_0000118>is member of</obo:IAO_0000118>
+        <obo:IAO_0000118>member part of</obo:IAO_0000118>
+        <obo:IAO_0000119>SIO</obo:IAO_0000119>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">member of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://purl.obolibrary.org/obo/RO_0002351 -->
+
+    <owl:ObjectProperty rdf:about="http://purl.obolibrary.org/obo/RO_0002351">
+        <rdfs:subPropertyOf rdf:resource="http://foo.bar/BFO_1234567"/>
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#IrreflexiveProperty"/>
+        <obo:IAO_0000115>has member is a mereological relation between a collection and an item.</obo:IAO_0000115>
+        <obo:IAO_0000119>SIO</obo:IAO_0000119>
+        <obo:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">has member</rdfs:label>
+    </owl:ObjectProperty>
+</rdf:RDF>
+
+
+
+<!-- Generated by the OWL API (version 4.5.6) https://github.com/owlcs/owlapi -->
+
diff --git a/docs/examples/full-rename.tsv b/docs/examples/full-rename.tsv
new file mode 100644
index 00000000..6b2938cd
--- /dev/null
+++ b/docs/examples/full-rename.tsv
@@ -0,0 +1,2 @@
+Old IRI	new IRI
+obo:BFO_0000051	fb:BFO_1234567
diff --git a/docs/examples/partial-rename.owl b/docs/examples/partial-rename.owl
new file mode 100644
index 00000000..66817028
--- /dev/null
+++ b/docs/examples/partial-rename.owl
@@ -0,0 +1,483 @@
+<?xml version="1.0"?>
+<rdf:RDF xmlns="http://purl.obolibrary.org/obo/bfo.owl#"
+     xml:base="http://purl.obolibrary.org/obo/bfo.owl"
+     xmlns:dc="http://purl.org/dc/elements/1.1/"
+     xmlns:fb="http://foo.bar/"
+     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:foaf="http://xmlns.com/foaf/0.1/"
+     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+     xmlns:oboInOwl="http://www.geneontology.org/formats/oboInOwl#">
+    <owl:Ontology rdf:about="http://purl.obolibrary.org/obo/ro/core.owl">
+        <owl:imports rdf:resource="http://purl.obolibrary.org/obo/ro/annotations.owl"/>
+        <owl:imports rdf:resource="http://purl.obolibrary.org/obo/ro/bfo-classes-minimal.owl"/>
+        <foaf:homepage rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">https://code.google.com/p/obo-relations/w/ROCore</foaf:homepage>
+    </owl:Ontology>
+    
+
+
+    <!-- 
+    ///////////////////////////////////////////////////////////////////////////////////////
+    //
+    // Annotation properties
+    //
+    ///////////////////////////////////////////////////////////////////////////////////////
+     -->
+
+    
+
+
+    <!-- http://foo.bar/IAO_0000111 -->
+
+    <owl:AnnotationProperty rdf:about="http://foo.bar/IAO_0000111"/>
+    
+
+
+    <!-- http://foo.bar/IAO_0000112 -->
+
+    <owl:AnnotationProperty rdf:about="http://foo.bar/IAO_0000112"/>
+    
+
+
+    <!-- http://foo.bar/IAO_0000114 -->
+
+    <owl:AnnotationProperty rdf:about="http://foo.bar/IAO_0000114"/>
+    
+
+
+    <!-- http://foo.bar/IAO_0000115 -->
+
+    <owl:AnnotationProperty rdf:about="http://foo.bar/IAO_0000115"/>
+    
+
+
+    <!-- http://foo.bar/IAO_0000116 -->
+
+    <owl:AnnotationProperty rdf:about="http://foo.bar/IAO_0000116"/>
+    
+
+
+    <!-- http://foo.bar/IAO_0000118 -->
+
+    <owl:AnnotationProperty rdf:about="http://foo.bar/IAO_0000118"/>
+    
+
+
+    <!-- http://foo.bar/IAO_0000119 -->
+
+    <owl:AnnotationProperty rdf:about="http://foo.bar/IAO_0000119"/>
+    
+
+
+    <!-- http://foo.bar/RO_0001900 -->
+
+    <owl:AnnotationProperty rdf:about="http://foo.bar/RO_0001900"/>
+    
+
+
+    <!-- 
+    ///////////////////////////////////////////////////////////////////////////////////////
+    //
+    // Object Properties
+    //
+    ///////////////////////////////////////////////////////////////////////////////////////
+     -->
+
+    
+
+
+    <!-- http://foo.bar/BFO_0000050 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/BFO_0000050">
+        <owl:inverseOf rdf:resource="http://foo.bar/BFO_0000051"/>
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#TransitiveProperty"/>
+        <fb:IAO_0000111 xml:lang="en">is part of</fb:IAO_0000111>
+        <fb:IAO_0000116 xml:lang="en">Ambiguous between continuant-parthood and occurrent-parthood</fb:IAO_0000116>
+        <fb:IAO_0000118 xml:lang="en">part_of</fb:IAO_0000118>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">part of</rdfs:label>
+        <rdfs:seeAlso>http://www.obofoundry.org/ro/#OBO_REL:part_of</rdfs:seeAlso>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/BFO_0000051 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/BFO_0000051">
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#TransitiveProperty"/>
+        <fb:IAO_0000111 xml:lang="en">has part</fb:IAO_0000111>
+        <fb:IAO_0000116 xml:lang="en">Ambiguous between continuant-parthood and occurrent-parthood</fb:IAO_0000116>
+        <fb:IAO_0000118 xml:lang="en">has_part</fb:IAO_0000118>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">has part</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/BFO_0000054 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/BFO_0000054">
+        <owl:inverseOf rdf:resource="http://foo.bar/BFO_0000055"/>
+        <rdfs:range rdf:resource="http://foo.bar/BFO_0000015"/>
+        <fb:IAO_0000111 xml:lang="en">realized in</fb:IAO_0000111>
+        <fb:IAO_0000118 xml:lang="en">is realized by</fb:IAO_0000118>
+        <fb:IAO_0000118 xml:lang="en">realized_in</fb:IAO_0000118>
+        <rdfs:label xml:lang="en">realized in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/BFO_0000055 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/BFO_0000055">
+        <rdfs:domain rdf:resource="http://foo.bar/BFO_0000015"/>
+        <fb:IAO_0000111 xml:lang="en">realizes</fb:IAO_0000111>
+        <rdfs:label xml:lang="en">realizes</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/BFO_0000066 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/BFO_0000066">
+        <owl:inverseOf rdf:resource="http://foo.bar/BFO_0000067"/>
+        <rdfs:domain rdf:resource="http://foo.bar/BFO_0000003"/>
+        <rdfs:range rdf:resource="http://foo.bar/BFO_0000004"/>
+        <owl:propertyChainAxiom rdf:parseType="Collection">
+            <rdf:Description rdf:about="http://foo.bar/BFO_0000050"/>
+            <rdf:Description rdf:about="http://foo.bar/BFO_0000066"/>
+        </owl:propertyChainAxiom>
+        <owl:propertyChainAxiom rdf:parseType="Collection">
+            <rdf:Description rdf:about="http://foo.bar/BFO_0000066"/>
+            <rdf:Description rdf:about="http://foo.bar/BFO_0000050"/>
+        </owl:propertyChainAxiom>
+        <fb:IAO_0000111 xml:lang="en">occurs in</fb:IAO_0000111>
+        <fb:IAO_0000118 xml:lang="en">Intended meaning:
+domain: occurrent
+range: independent continuant
+time: atemporal</fb:IAO_0000118>
+        <fb:IAO_0000118 xml:lang="en">occurs_in</fb:IAO_0000118>
+        <fb:IAO_0000118 xml:lang="en">unfolds in</fb:IAO_0000118>
+        <fb:IAO_0000118 xml:lang="en">unfolds_in</fb:IAO_0000118>
+        <rdfs:label xml:lang="en">occurs in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/BFO_0000067 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/BFO_0000067">
+        <fb:IAO_0000111 xml:lang="en">site of</fb:IAO_0000111>
+        <rdfs:label xml:lang="en">contains process</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0000052 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0000052">
+        <owl:inverseOf rdf:resource="http://foo.bar/RO_0000053"/>
+        <fb:IAO_0000111 xml:lang="en">inheres in</fb:IAO_0000111>
+        <fb:IAO_0000116 xml:lang="en">Intended meaning:
+domain: specifically dependent continuant
+range: independent continuant
+time: at all times
+
+A specifically dependent continuant A inheres in its independent continuant B at all times during which A exists.</fb:IAO_0000116>
+        <fb:IAO_0000118 xml:lang="en">inheres_in</fb:IAO_0000118>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">inheres in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0000053 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0000053">
+        <rdfs:range rdf:resource="http://foo.bar/BFO_0000020"/>
+        <fb:IAO_0000111 xml:lang="en">bearer of</fb:IAO_0000111>
+        <fb:IAO_0000118 xml:lang="en">bearer_of</fb:IAO_0000118>
+        <fb:IAO_0000118 xml:lang="en">is bearer of</fb:IAO_0000118>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">bearer of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0000056 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0000056">
+        <owl:inverseOf rdf:resource="http://foo.bar/RO_0000057"/>
+        <rdfs:domain rdf:resource="http://foo.bar/BFO_0000002"/>
+        <rdfs:range rdf:resource="http://foo.bar/BFO_0000003"/>
+        <fb:IAO_0000111 xml:lang="en">participates in</fb:IAO_0000111>
+        <fb:IAO_0000118 xml:lang="en">participates_in</fb:IAO_0000118>
+        <rdfs:label xml:lang="en">participates in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0000057 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0000057">
+        <rdfs:domain rdf:resource="http://foo.bar/BFO_0000003"/>
+        <rdfs:range rdf:resource="http://foo.bar/BFO_0000002"/>
+        <fb:IAO_0000111 xml:lang="en">has participant</fb:IAO_0000111>
+        <fb:IAO_0000116 xml:lang="en">Has_participant is a primitive instance-level relation between a process, a continuant, and a time at which the continuant participates in some way in the process. The relation obtains, for example, when this particular process of oxygen exchange across this particular alveolar membrane has_participant this particular sample of hemoglobin at this particular time.</fb:IAO_0000116>
+        <fb:IAO_0000118 xml:lang="en">has_participant</fb:IAO_0000118>
+        <dc:source>http://www.obofoundry.org/ro/#OBO_REL:has_participant</dc:source>
+        <rdfs:label xml:lang="en">has participant</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0000058 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0000058">
+        <owl:inverseOf rdf:resource="http://foo.bar/RO_0000059"/>
+        <rdfs:domain rdf:resource="http://foo.bar/BFO_0000031"/>
+        <rdfs:range rdf:resource="http://foo.bar/BFO_0000020"/>
+        <fb:IAO_0000112 xml:lang="en">A journal article is an information artifact that inheres in some number of printed journals. For each copy of the printed journal there is some quality that carries the journal article, such as a pattern of ink. The journal article (a generically dependent continuant) is concretized as the quality (a specifically dependent continuant), and both depend on that copy of the printed journal (an independent continuant).</fb:IAO_0000112>
+        <fb:IAO_0000112 xml:lang="en">An investigator reads a protocol and forms a plan to carry out an assay. The plan is a realizable entity (a specifically dependent continuant) that concretizes the protocol (a generically dependent continuant), and both depend on the investigator (an independent continuant). The plan is then realized by the assay (a process).</fb:IAO_0000112>
+        <fb:IAO_0000115 xml:lang="en">A relationship between a generically dependent continuant and a specifically dependent continuant, in which the generically dependent continuant depends on some independent continuant in virtue of the fact that the specifically dependent continuant also depends on that same independent continuant. A generically dependent continuant may be concretized as multiple specifically dependent continuants.</fb:IAO_0000115>
+        <rdfs:label xml:lang="en">is concretized as</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0000059 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0000059">
+        <rdfs:domain rdf:resource="http://foo.bar/BFO_0000020"/>
+        <rdfs:range rdf:resource="http://foo.bar/BFO_0000031"/>
+        <fb:IAO_0000112 xml:lang="en">A journal article is an information artifact that inheres in some number of printed journals. For each copy of the printed journal there is some quality that carries the journal article, such as a pattern of ink. The quality (a specifically dependent continuant) concretizes the journal article (a generically dependent continuant), and both depend on that copy of the printed journal (an independent continuant).</fb:IAO_0000112>
+        <fb:IAO_0000112 xml:lang="en">An investigator reads a protocol and forms a plan to carry out an assay. The plan is a realizable entity (a specifically dependent continuant) that concretizes the protocol (a generically dependent continuant), and both depend on the investigator (an independent continuant). The plan is then realized by the assay (a process).</fb:IAO_0000112>
+        <fb:IAO_0000115 xml:lang="en">A relationship between a specifically dependent continuant and a generically dependent continuant, in which the generically dependent continuant depends on some independent continuant in virtue of the fact that the specifically dependent continuant also depends on that same independent continuant. Multiple specifically dependent continuants can concretize the same generically dependent continuant.</fb:IAO_0000115>
+        <rdfs:label xml:lang="en">concretizes</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0000081 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0000081">
+        <rdfs:subPropertyOf rdf:resource="http://foo.bar/RO_0000052"/>
+        <owl:inverseOf rdf:resource="http://foo.bar/RO_0000087"/>
+        <fb:IAO_0000118 xml:lang="en">is role of</fb:IAO_0000118>
+        <fb:IAO_0000118 xml:lang="en">role_of</fb:IAO_0000118>
+        <rdfs:label xml:lang="en">role of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0000086 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0000086">
+        <rdfs:subPropertyOf rdf:resource="http://foo.bar/RO_0000053"/>
+        <rdfs:range rdf:resource="http://foo.bar/BFO_0000019"/>
+        <rdfs:label xml:lang="en">has quality</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0000087 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0000087">
+        <rdfs:subPropertyOf rdf:resource="http://foo.bar/RO_0000053"/>
+        <rdfs:range rdf:resource="http://foo.bar/BFO_0000023"/>
+        <fb:IAO_0000118 xml:lang="en">has_role</fb:IAO_0000118>
+        <rdfs:label xml:lang="en">has role</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0001000 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0001000">
+        <rdfs:subPropertyOf rdf:resource="http://www.w3.org/2002/07/owl#topObjectProperty"/>
+        <fb:IAO_0000114 rdf:resource="http://purl.obolibrary.org/obo/IAO_0000125"/>
+        <rdfs:label xml:lang="en">derives from</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0001001 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0001001">
+        <rdfs:subPropertyOf rdf:resource="http://www.w3.org/2002/07/owl#topObjectProperty"/>
+        <fb:IAO_0000114 rdf:resource="http://purl.obolibrary.org/obo/IAO_0000125"/>
+        <rdfs:label xml:lang="en">derives into</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0001015 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0001015">
+        <owl:inverseOf rdf:resource="http://foo.bar/RO_0001025"/>
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#TransitiveProperty"/>
+        <fb:IAO_0000111 xml:lang="en">is location of</fb:IAO_0000111>
+        <fb:IAO_0000118 xml:lang="en">location_of</fb:IAO_0000118>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">location of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0001018 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0001018">
+        <owl:inverseOf rdf:resource="http://foo.bar/RO_0001019"/>
+        <fb:IAO_0000111 xml:lang="en">contained in</fb:IAO_0000111>
+        <fb:IAO_0000116>Containment is location not involving parthood, and arises only where some immaterial continuant is involved.</fb:IAO_0000116>
+        <fb:IAO_0000116 xml:lang="en">Containment obtains in each case between material and immaterial continuants, for instance: lung contained_in thoracic cavity; bladder contained_in pelvic cavity. Hence containment is not a transitive relation.    If c part_of c1 at t then we have also, by our definition and by the axioms of mereology applied to spatial regions, c located_in c1 at t. Thus, many examples of instance-level location relations for continuants are in fact cases of instance-level parthood. For material continuants location and parthood coincide. Containment is location not involving parthood, and arises only where some immaterial continuant is involved. To understand this relation, we first define overlap for continuants as follows:    c1 overlap c2 at t =def for some c, c part_of c1 at t and c part_of c2 at t. The containment relation on the instance level can then be defined (see definition):</fb:IAO_0000116>
+        <fb:IAO_0000116 xml:lang="en">Intended meaning:
+domain: material entity
+range: spatial region or site (immaterial continuant)
+        </fb:IAO_0000116>
+        <fb:IAO_0000118 xml:lang="en">contained_in</fb:IAO_0000118>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">contained in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0001019 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0001019">
+        <fb:IAO_0000111 xml:lang="en">contains</fb:IAO_0000111>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">contains</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0001025 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0001025">
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#TransitiveProperty"/>
+        <fb:IAO_0000111 xml:lang="en">located in</fb:IAO_0000111>
+        <fb:IAO_0000116 xml:lang="en">Location as a relation between instances: The primitive instance-level relation c located_in r at t reflects the fact that each continuant is at any given time associated with exactly one spatial region, namely its exact location. Following we can use this relation to define a further instance-level location relation - not between a continuant and the region which it exactly occupies, but rather between one continuant and another. c is located in c1, in this sense, whenever the spatial region occupied by c is part_of the spatial region occupied by c1.    Note that this relation comprehends both the relation of exact location between one continuant and another which obtains when r and r1 are identical (for example, when a portion of fluid exactly fills a cavity), as well as those sorts of inexact location relations which obtain, for example, between brain and head or between ovum and uterus</fb:IAO_0000116>
+        <fb:IAO_0000118 xml:lang="en">located_in</fb:IAO_0000118>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <dc:source>http://www.obofoundry.org/ro/#OBO_REL:located_in</dc:source>
+        <rdfs:label xml:lang="en">located in</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0002000 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0002000">
+        <owl:inverseOf rdf:resource="http://foo.bar/RO_0002002"/>
+        <fb:IAO_0000115 rdf:datatype="http://www.w3.org/2001/XMLSchema#string">The relationships between a boundary (a 2D immaterial entity) and the material entity that it delimits.</fb:IAO_0000115>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">boundary of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0002002 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0002002">
+        <fb:IAO_0000115 rdf:datatype="http://www.w3.org/2001/XMLSchema#string">The relationship between a material entity and the boundary (2D immaterial entity) that delimits it.</fb:IAO_0000115>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">has boundary</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0002350 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0002350">
+        <rdfs:subPropertyOf rdf:resource="http://foo.bar/BFO_0000050"/>
+        <owl:inverseOf rdf:resource="http://foo.bar/RO_0002351"/>
+        <fb:IAO_0000112>An organism that is a member of a population of organisms</fb:IAO_0000112>
+        <fb:IAO_0000115>is member of is a mereological relation between a item and a collection.</fb:IAO_0000115>
+        <fb:IAO_0000118>is member of</fb:IAO_0000118>
+        <fb:IAO_0000118>member part of</fb:IAO_0000118>
+        <fb:IAO_0000119>SIO</fb:IAO_0000119>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">member of</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- http://foo.bar/RO_0002351 -->
+
+    <owl:ObjectProperty rdf:about="http://foo.bar/RO_0002351">
+        <rdfs:subPropertyOf rdf:resource="http://foo.bar/BFO_0000051"/>
+        <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#IrreflexiveProperty"/>
+        <fb:IAO_0000115>has member is a mereological relation between a collection and an item.</fb:IAO_0000115>
+        <fb:IAO_0000119>SIO</fb:IAO_0000119>
+        <fb:RO_0001900 rdf:resource="http://purl.obolibrary.org/obo/RO_0001901"/>
+        <rdfs:label xml:lang="en">has member</rdfs:label>
+    </owl:ObjectProperty>
+    
+
+
+    <!-- 
+    ///////////////////////////////////////////////////////////////////////////////////////
+    //
+    // Classes
+    //
+    ///////////////////////////////////////////////////////////////////////////////////////
+     -->
+
+    
+
+
+    <!-- http://foo.bar/BFO_0000002 -->
+
+    <owl:Class rdf:about="http://foo.bar/BFO_0000002"/>
+    
+
+
+    <!-- http://foo.bar/BFO_0000003 -->
+
+    <owl:Class rdf:about="http://foo.bar/BFO_0000003"/>
+    
+
+
+    <!-- http://foo.bar/BFO_0000004 -->
+
+    <owl:Class rdf:about="http://foo.bar/BFO_0000004"/>
+    
+
+
+    <!-- http://foo.bar/BFO_0000015 -->
+
+    <owl:Class rdf:about="http://foo.bar/BFO_0000015"/>
+    
+
+
+    <!-- http://foo.bar/BFO_0000019 -->
+
+    <owl:Class rdf:about="http://foo.bar/BFO_0000019"/>
+    
+
+
+    <!-- http://foo.bar/BFO_0000020 -->
+
+    <owl:Class rdf:about="http://foo.bar/BFO_0000020"/>
+    
+
+
+    <!-- http://foo.bar/BFO_0000023 -->
+
+    <owl:Class rdf:about="http://foo.bar/BFO_0000023"/>
+    
+
+
+    <!-- http://foo.bar/BFO_0000031 -->
+
+    <owl:Class rdf:about="http://foo.bar/BFO_0000031"/>
+</rdf:RDF>
+
+
+
+<!-- Generated by the OWL API (version 4.5.6) https://github.com/owlcs/owlapi -->
+
diff --git a/docs/examples/partial-rename.tsv b/docs/examples/partial-rename.tsv
new file mode 100644
index 00000000..b10e0bcc
--- /dev/null
+++ b/docs/examples/partial-rename.tsv
@@ -0,0 +1,2 @@
+Old IRI	New IRI
+http://purl.obolibrary.org/obo/	http://foo.bar/
\ No newline at end of file
diff --git a/docs/rename.md b/docs/rename.md
new file mode 100644
index 00000000..b3667004
--- /dev/null
+++ b/docs/rename.md
@@ -0,0 +1,83 @@
+# Rename
+
+The `rename` command allows you to rename entity IRIs in an ontology in two ways:
+
+#### Full
+
+Renames full IRIs (e.g. `obo:BFO_0000050` to `http://foo.bar/BFO_1234567`) in a file specified by `--mappings`:
+
+    robot rename --input test.owl \
+      --mappings full-rename.tsv \
+      --add-prefix "fb: http://foo.bar/"
+      --output results/full-rename.owl
+
+If two or more old IRIs are mapped to the same new IRI, these two entities will be merged. By default, ROBOT will throw an error if this happens. This behavior can be overridden by including `--allow-duplicates true`.
+
+#### Prefixes
+
+Renames the base IRIs of all matching entites (e.g. change the prefix `http://purl.obolibrary.org/obo/` to `http://foo.bar/`), based on mappings in a file specified by `--prefix-mappings`:
+
+    robot rename --input test.owl \
+      --prefix-mappings partial-rename.tsv \
+      --add-prefix "fb: http://foo.bar/"
+      --output results/partial-rename.owl
+      
+The `--add-prefix` option allows you to specify a prefix mapping in the same way as the [global prefix option](/global#prefixes). This will be added to the output ontology:
+
+```
+Prefix(fb:=<http://foo.bar/>)
+```
+
+The difference is that the global `--prefix` option does not include the prefix in the output ontology.
+
+### Mappings Files
+
+The mappings for renaming should be specified with the `--mappings` (for full renames) or `--prefix-mappings` (for renaming prefixes) option. These should be either comma- or tab-separated tables. Each row should have exactly two columns: on the left, the IRI to replace, and on the right, the IRI to replace it with. 
+
+For a full rename (you can use prefixes as long as they are defined by the defaults, `--prefix`, or `--add-prefix`):
+
+```
+Old IRI,New IRI
+obo:BFO_0000051,fb:BFO_1234567
+```
+
+For a prefix rename:
+
+```
+Old Base,New Base
+http://purl.obolibrary.org/obo/,http://foo.bar/
+```
+
+The `rename` command expects the first line to contain headers.
+
+---
+
+## Error Messages
+
+### Column Count Error
+
+Each row of the mapping file must have two columns: first, the old IRI, second, the new IRI. These must be separated by either a comma or a tab, depending on the file format.
+
+### Duplicate Mapping Error
+
+This error occurs when two rows have the same 'old IRI' value. This will cause two rename operations to occur for the same IRI, resulting in unexpected values. Make sure each 'old IRI' is only entered in the mappings once.
+
+### Duplicate Rename Error
+
+This error occurs when two rows have the same 'new IRI' value. This will cause a merge of the two old IRIs into the new IRI. If this is the intended behavior, use `--allow-duplicates true`.
+
+### File Format Error
+
+The mappings file must be comma-separated (ending in `.csv`) or tab-separated (ending in `.tsv` or `.txt`).
+
+### Missing Entity Error
+
+For a 'full' IRI replacement, the 'old IRI' must exist in the ontology. If not, nothing can be replaced and this error will be thrown.
+
+### Missing File Error
+
+This error occurs when the file provided for the `--mappings` or `--prefix-mappings` option does not exist. Check the path and try again.
+
+### Missing Mappings Error
+
+This error occurs when a `--mappings` or `--prefix-mappings` file is not provided.
diff --git a/robot-command/src/main/java/org/obolibrary/robot/CommandLineInterface.java b/robot-command/src/main/java/org/obolibrary/robot/CommandLineInterface.java
index da67c924..bdbecdcd 100644
--- a/robot-command/src/main/java/org/obolibrary/robot/CommandLineInterface.java
+++ b/robot-command/src/main/java/org/obolibrary/robot/CommandLineInterface.java
@@ -33,6 +33,7 @@ public class CommandLineInterface {
     m.addCommand("reduce", new ReduceCommand());
     m.addCommand("relax", new RelaxCommand());
     m.addCommand("remove", new RemoveCommand());
+    m.addCommand("rename", new RenameCommand());
     m.addCommand("repair", new RepairCommand());
     m.addCommand("report", new ReportCommand());
     m.addCommand("template", new TemplateCommand());
diff --git a/robot-command/src/main/java/org/obolibrary/robot/RenameCommand.java b/robot-command/src/main/java/org/obolibrary/robot/RenameCommand.java
new file mode 100644
index 00000000..7343645a
--- /dev/null
+++ b/robot-command/src/main/java/org/obolibrary/robot/RenameCommand.java
@@ -0,0 +1,245 @@
+package org.obolibrary.robot;
+
+import com.opencsv.CSVParserBuilder;
+import com.opencsv.CSVReader;
+import com.opencsv.CSVReaderBuilder;
+import java.io.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.semanticweb.owlapi.model.OWLOntology;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** */
+public class RenameCommand implements Command {
+
+  /** Logger. */
+  private static final Logger logger = LoggerFactory.getLogger(RenameCommand.class);
+
+  /** Namespace for error messages. */
+  private static final String NS = "rename#";
+
+  /** Error message when a row does not have exactly two columns. */
+  private static final String columnCountError =
+      NS + "COLUMN COUNT ERROR line %d in file '%s' must contain exactly two values.";
+
+  /** Error message when an old IRI value is duplicated in a mappings file. */
+  private static final String duplicateMappingError =
+      NS
+          + "DUPLICATE MAPPING ERROR line %d in file '%s' contains a duplicate mapping for value '%s'.";
+
+  /** Error message when a new IRI value is duplicated and fail-on-duplicates is true. */
+  private static final String duplicateRenameError = NS + "DUPLICATE RENAME ERROR line %d in file '%s' contains a duplicate rename for value '%s'";
+
+  /** Error message when a file is not in CSV or TSV/TXT format. */
+  private static final String fileFormatError =
+      NS + "FILE FORMAT ERROR the mappings file ('%s') must be a CSV or TSV/TXT file.";
+
+  /** Error message when a mappings file does not exist. */
+  private static final String missingFileError =
+      NS + "MISSING FILE ERROR mappings file '%s' does not exist.";
+
+  /** Error message when neither a full or prefix mappings file is provided. */
+  private static final String missingMappingsError =
+      NS
+          + "MISSING MAPPINGS ERROR either a --mappings or a --prefix-mappings file must be specified.";
+
+  /** Store the command-line options for the command. */
+  private Options options;
+
+  /** Initialze the command. */
+  public RenameCommand() {
+    Options o = CommandLineHelper.getCommonOptions();
+    o.addOption("i", "input", true, "load ontology from a file");
+    o.addOption("I", "input-iri", true, "load ontology from an IRI");
+    o.addOption("o", "output", true, "save ontology to a file");
+    o.addOption("m", "mappings", true, "table of mappings for renaming");
+    o.addOption("r", "prefix-mappings", true, "table of prefix mappings for renaming");
+    o.addOption("A", "add-prefix", true, "add a new prefix to ontology file header");
+    o.addOption("d", "allow-duplicates", true, "allow two or more terms to be renamed to the same full IRI");
+    options = o;
+  }
+
+  /**
+   * Name of the command.
+   *
+   * @return name
+   */
+  public String getName() {
+    return "rename";
+  }
+
+  /**
+   * Brief description of the command.
+   *
+   * @return description
+   */
+  public String getDescription() {
+    return "rename entities based on given mappings";
+  }
+
+  /**
+   * Command-line usage for the command.
+   *
+   * @return usage
+   */
+  public String getUsage() {
+    return "robot rename --input <file> " + "--mappings <file> " + "--output <file>";
+  }
+
+  /**
+   * Command-line options for the command.
+   *
+   * @return options
+   */
+  public Options getOptions() {
+    return options;
+  }
+
+  /**
+   * Handle the command-line and file operations.
+   *
+   * @param args strings to use as arguments
+   */
+  public void main(String[] args) {
+    try {
+      execute(null, args);
+    } catch (Exception e) {
+      CommandLineHelper.handleException(getUsage(), getOptions(), e);
+    }
+  }
+
+  /**
+   * Given an input state and command line arguments, rename the entity IRIs in the ontology. Save
+   * the ontology and return a new state with the updated ontology.
+   *
+   * @param state the state from the previous command, or null
+   * @param args the command-line arguments
+   * @return a new state with the new ontology
+   * @throws Exception on any problem
+   */
+  public CommandState execute(CommandState state, String[] args) throws Exception {
+    CommandLine line = CommandLineHelper.getCommandLine(getUsage(), getOptions(), args);
+    if (line == null) {
+      return null;
+    }
+
+    IOHelper ioHelper = CommandLineHelper.getIOHelper(line);
+    state = CommandLineHelper.updateInputOntology(ioHelper, state, line);
+    OWLOntology ontology = state.getOntology();
+
+    // Get additional prefixes to add to prefix manager
+    List<String> addPrefixes = CommandLineHelper.getOptionalValues(line, "add-prefix");
+    for (String pref : addPrefixes) {
+      ioHelper.addPrefix(pref);
+    }
+
+    String fullFile = CommandLineHelper.getOptionalValue(line, "mappings");
+    String prefixFile = CommandLineHelper.getOptionalValue(line, "prefix-mappings");
+    if (fullFile == null && prefixFile == null) {
+      throw new IOException(missingMappingsError);
+    }
+
+    boolean allowDuplicates = CommandLineHelper.getBooleanValue(line, "allow-duplicates", false);
+
+    char separator;
+    // Process full renames
+    if (fullFile != null) {
+      separator = getSeparator(fullFile);
+      Map<String, String> mappings = parseTableMappings(new File(fullFile), separator, allowDuplicates);
+      RenameOperation.renameFull(ontology, ioHelper, mappings);
+    }
+    // Process prefix renames (no need to fail on duplicates)
+    if (prefixFile != null) {
+      separator = getSeparator(prefixFile);
+      Map<String, String> mappings = parseTableMappings(new File(prefixFile), separator, true);
+      RenameOperation.renamePrefixes(ontology, ioHelper, mappings);
+    }
+
+    if (!addPrefixes.isEmpty()) {
+      ioHelper.addPrefixesAndSave(ontology, CommandLineHelper.getOutputFile(line), addPrefixes);
+    } else {
+      CommandLineHelper.maybeSaveOutput(line, ontology);
+    }
+
+    state.setOntology(ontology);
+    return state;
+  }
+
+  /**
+   * Given the file name of a table, return the separator character for cells based on the file
+   * extension (CSV = comma, TSV/TXT = tab).
+   *
+   * @param fileName name of file to get table separator for
+   * @return character separator, either tab or comma
+   * @throws IOException if file is not TSV/TXT or CSV
+   */
+  private static char getSeparator(String fileName) throws IOException {
+    if (fileName.endsWith(".tsv") || fileName.endsWith(".txt")) {
+      return '\t';
+    } else if (fileName.endsWith(".csv")) {
+      return ',';
+    }
+    throw new IOException(String.format(fileFormatError, fileName));
+  }
+
+  /**
+   * Given a file containing the mappings table and a character to separate cells, return the map of
+   * old values (left) to new values (right). Partial mappings can allow duplicate values, but full
+   * mappings should provide a warning and allow user to kill the process if there are duplicate
+   * values.
+   *
+   * @param mappingsFile File to parse mappings from
+   * @param separator character to separate cells in mapping file
+   * @param allowDuplicates boolean indicating if duplicate rename (new) should be allowed
+   * @return map of old values -> new values
+   * @throws Exception on any issue
+   */
+  private static Map<String, String> parseTableMappings(
+      File mappingsFile, char separator, boolean allowDuplicates) throws Exception {
+    Map<String, String> mappings = new HashMap<>();
+
+    if (!mappingsFile.exists()) {
+      throw new IOException(String.format(missingFileError, mappingsFile.getPath()));
+    }
+
+    try (CSVReader reader =
+        new CSVReaderBuilder(new FileReader(mappingsFile))
+            .withCSVParser(new CSVParserBuilder().withSeparator(separator).build())
+            .build()) {
+      int lineNum = 1;
+      // Remove the headers
+      reader.readNext();
+      for (String[] nextLine : reader) {
+        lineNum++;
+        if (nextLine.length != 2) {
+          throw new IOException(String.format(columnCountError, lineNum, mappingsFile.getPath()));
+        }
+
+        String oldIRI = nextLine[0];
+        String newIRI = nextLine[1];
+
+        // The OLD IRI has two distinct new IRIs
+        if (mappings.containsKey(oldIRI)) {
+          throw new IOException(
+              String.format(duplicateMappingError, lineNum, mappingsFile.getPath(), oldIRI));
+        }
+        // The new IRI is being used for one or more OLD IRI
+        // This results in a merge
+        if (mappings.containsValue(newIRI)) {
+          if (!allowDuplicates) {
+            throw new Exception(String.format(duplicateRenameError, lineNum, mappingsFile.getPath(), newIRI));
+          }
+          logger.warn(String.format("IRI '%s' will be used for two or more entities", newIRI));
+        }
+
+        mappings.put(oldIRI, newIRI);
+      }
+    }
+
+    return mappings;
+  }
+}
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 3d9dad2d..c3ac18c4 100644
--- a/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java
+++ b/robot-core/src/main/java/org/obolibrary/robot/IOHelper.java
@@ -28,12 +28,7 @@ import org.obolibrary.obo2owl.OWLAPIOwl2Obo;
 import org.obolibrary.oboformat.model.OBODoc;
 import org.obolibrary.oboformat.writer.OBOFormatWriter;
 import org.semanticweb.owlapi.apibinding.OWLManager;
-import org.semanticweb.owlapi.formats.FunctionalSyntaxDocumentFormat;
-import org.semanticweb.owlapi.formats.ManchesterSyntaxDocumentFormat;
-import org.semanticweb.owlapi.formats.OBODocumentFormat;
-import org.semanticweb.owlapi.formats.OWLXMLDocumentFormat;
-import org.semanticweb.owlapi.formats.RDFXMLDocumentFormat;
-import org.semanticweb.owlapi.formats.TurtleDocumentFormat;
+import org.semanticweb.owlapi.formats.*;
 import org.semanticweb.owlapi.model.IRI;
 import org.semanticweb.owlapi.model.OWLDataFactory;
 import org.semanticweb.owlapi.model.OWLDatatype;
@@ -164,6 +159,38 @@ public class IOHelper {
     setContext(jsonString);
   }
 
+  /**
+   * Given an ontology, a file, and a list of prefixes, save the ontology to the file and include
+   * the prefixes in the header.
+   *
+   * @param ontology OWLOntology to save
+   * @param outputFile File to save ontology to
+   * @param addPrefixes List of prefixes to add ("foo: http://foo.bar/")
+   * @throws IOException On issue parsing list of prefixes or saving file
+   */
+  public void addPrefixesAndSave(OWLOntology ontology, File outputFile, List<String> addPrefixes)
+      throws IOException {
+    OWLOntologyManager manager = ontology.getOWLOntologyManager();
+    OWLDocumentFormat df = getFormat(FilenameUtils.getExtension(outputFile.getPath()));
+
+    // If prefixes are not supported, just save the ontology without adding prefixes
+    if (!df.isPrefixOWLOntologyFormat()) {
+      logger.error("Prefixes are not supported in " + df.toString() + " (saving without prefixes)");
+      saveOntology(ontology, df, outputFile);
+      return;
+    }
+
+    PrefixDocumentFormat pf = df.asPrefixOWLOntologyFormat();
+    for (String pref : addPrefixes) {
+      String[] split = pref.split(": ");
+      if (split.length != 2) {
+        throw new IOException(String.format(invalidPrefixError, pref));
+      }
+      pf.setPrefix(split[0].trim(), split[1].trim());
+    }
+    saveOntology(ontology, df, outputFile);
+  }
+
   /**
    * Try to guess the location of the catalog.xml file. Looks in the directory of the given ontology
    * file for a catalog file.
diff --git a/robot-core/src/main/java/org/obolibrary/robot/RenameOperation.java b/robot-core/src/main/java/org/obolibrary/robot/RenameOperation.java
new file mode 100644
index 00000000..f59d0ec3
--- /dev/null
+++ b/robot-core/src/main/java/org/obolibrary/robot/RenameOperation.java
@@ -0,0 +1,87 @@
+package org.obolibrary.robot;
+
+import com.google.common.collect.Sets;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.semanticweb.owlapi.model.IRI;
+import org.semanticweb.owlapi.model.OWLOntology;
+import org.semanticweb.owlapi.model.OWLOntologyManager;
+import org.semanticweb.owlapi.util.OWLEntityRenamer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Rename entity IRIs in an ontology.
+ *
+ * @author <a href="mailto:rctauber@gmail.com">Becky Tauber</a>
+ */
+public class RenameOperation {
+
+  /** Logger. */
+  private static final Logger logger = LoggerFactory.getLogger(RenameOperation.class);
+
+  /** Namespace for error messages. */
+  private static final String NS = "rename#";
+
+  /** Error message when an entity to rename does not exist. */
+  private static final String missingEntityError =
+      NS + "MISSING ENTITY ERROR entity to rename ('%s') does not exist.";
+
+  /**
+   * Given an ontology, an IOHelper, and a map of old IRIs to new IRIs, rename each old IRI with the
+   * new IRI.
+   *
+   * @param ontology OWLOntology to rename entities in
+   * @param ioHelper IOHelper to create IRIs
+   * @param mappings map of old IRI -> new IRI
+   * @throws Exception if the old IRI in a mapping does not exist
+   */
+  public static void renameFull(
+      OWLOntology ontology, IOHelper ioHelper, Map<String, String> mappings) throws Exception {
+    OWLOntologyManager manager = ontology.getOWLOntologyManager();
+    OWLEntityRenamer entityRenamer = new OWLEntityRenamer(manager, Sets.newHashSet(ontology));
+    for (Map.Entry<String, String> mapping : mappings.entrySet()) {
+      IRI oldIRI = ioHelper.createIRI(mapping.getKey());
+      IRI newIRI = ioHelper.createIRI(mapping.getValue());
+      if (!ontology.containsEntityInSignature(oldIRI)) {
+        throw new Exception(String.format(missingEntityError, oldIRI.toString()));
+      }
+      manager.applyChanges(entityRenamer.changeIRI(oldIRI, newIRI));
+    }
+  }
+
+  /**
+   * Given an ontology, an IOHelper, and a map of old IRI bases to new IRI bases, rename each IRI
+   * with the 'old base' as a prefix, replacing it with the 'new base'.
+   *
+   * @param ontology OWLOntology to rename base prefixes in
+   * @param ioHelper IOHelper to create IRIs
+   * @param mappings map of old base -> new base
+   */
+  public static void renamePrefixes(
+      OWLOntology ontology, IOHelper ioHelper, Map<String, String> mappings) {
+    OWLOntologyManager manager = ontology.getOWLOntologyManager();
+    OWLEntityRenamer entityRenamer = new OWLEntityRenamer(manager, Sets.newHashSet(ontology));
+    Set<IRI> allIRIs = OntologyHelper.getIRIs(ontology);
+    for (Map.Entry<String, String> mapping : mappings.entrySet()) {
+      String oldBase = mapping.getKey();
+      String newBase = mapping.getValue();
+      Set<IRI> matchIRIs =
+          allIRIs
+              .stream()
+              .filter(iri -> iri.toString().startsWith(oldBase))
+              .collect(Collectors.toSet());
+      if (matchIRIs.isEmpty()) {
+        logger.warn(String.format("No entities with prefix '%s' to rename", oldBase));
+        continue;
+      }
+      for (IRI iri : matchIRIs) {
+        IRI newIRI = ioHelper.createIRI(iri.toString().replace(oldBase, newBase));
+        manager.applyChanges(entityRenamer.changeIRI(iri, newIRI));
+      }
+    }
+  }
+}


Test patch:
diff --git a/robot-core/src/test/java/org/obolibrary/robot/RenameOperationTest.java b/robot-core/src/test/java/org/obolibrary/robot/RenameOperationTest.java
new file mode 100644
index 00000000..6df01125
--- /dev/null
+++ b/robot-core/src/test/java/org/obolibrary/robot/RenameOperationTest.java
@@ -0,0 +1,46 @@
+package org.obolibrary.robot;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Test;
+import org.semanticweb.owlapi.model.OWLOntology;
+
+/** Tests for RenameOperation. */
+public class RenameOperationTest extends CoreTest {
+
+  /**
+   * Test renaming of full IRIs.
+   *
+   * @throws Exception on any problem
+   */
+  @Test
+  public void testFullRename() throws Exception {
+    OWLOntology ont = loadOntology("/simple.owl");
+    Map<String, String> mappings = new HashMap<>();
+    mappings.put(
+        "https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test1",
+        "http://foo.bar/test1");
+
+    RenameOperation.renameFull(ont, new IOHelper(), mappings);
+
+    assertIdentical("/rename_full.owl", ont);
+  }
+
+  /**
+   * Test renaming of partial IRIs.
+   *
+   * @throws Exception on any problem
+   */
+  @Test
+  public void testPartialRename() throws Exception {
+    OWLOntology ont = loadOntology("/simple.owl");
+    Map<String, String> mappings = new HashMap<>();
+    mappings.put(
+        "https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#",
+        "http://foo.bar/");
+
+    RenameOperation.renamePrefixes(ont, new IOHelper(), mappings);
+
+    assertIdentical("/rename_partial.owl", ont);
+  }
+}
diff --git a/robot-core/src/test/resources/rename_full.owl b/robot-core/src/test/resources/rename_full.owl
new file mode 100644
index 00000000..7689c688
--- /dev/null
+++ b/robot-core/src/test/resources/rename_full.owl
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<rdf:RDF xmlns="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl"
+     xml:base="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl"
+     xmlns:obo="http://purl.obolibrary.org/obo/"
+     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+     xmlns:foaf="http://xmlns.com/foaf/0.1/"
+     xmlns:owl="http://www.w3.org/2002/07/owl#"
+     xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
+     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+    <owl:Ontology rdf:about="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl"/>
+
+
+
+    <!--
+    ///////////////////////////////////////////////////////////////////////////////////////
+    //
+    // Classes
+    //
+    ///////////////////////////////////////////////////////////////////////////////////////
+     -->
+
+
+
+
+    <!-- http://foo.bar/test1 -->
+
+    <owl:Class rdf:about="http://foo.bar/test1">
+        <rdfs:label>test one</rdfs:label>
+        <rdfs:label>Test 1</rdfs:label>
+    </owl:Class>
+
+
+
+    <!-- https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test2 -->
+
+    <owl:Class rdf:about="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test2">
+        <rdfs:subClassOf rdf:resource="http://foo.bar/test1"/>
+    </owl:Class>
+</rdf:RDF>
+
diff --git a/robot-core/src/test/resources/rename_partial.owl b/robot-core/src/test/resources/rename_partial.owl
new file mode 100644
index 00000000..19af4dfc
--- /dev/null
+++ b/robot-core/src/test/resources/rename_partial.owl
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<rdf:RDF xmlns="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl"
+     xml:base="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl"
+     xmlns:obo="http://purl.obolibrary.org/obo/"
+     xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+     xmlns:foaf="http://xmlns.com/foaf/0.1/"
+     xmlns:owl="http://www.w3.org/2002/07/owl#"
+     xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
+     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+    <owl:Ontology rdf:about="https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl"/>
+
+
+
+    <!--
+    ///////////////////////////////////////////////////////////////////////////////////////
+    //
+    // Classes
+    //
+    ///////////////////////////////////////////////////////////////////////////////////////
+     -->
+
+
+
+
+    <!-- http://foo.bar/test1 -->
+
+    <owl:Class rdf:about="http://foo.bar/test1">
+        <rdfs:label>test one</rdfs:label>
+        <rdfs:label>Test 1</rdfs:label>
+    </owl:Class>
+
+
+
+    <!-- http://foo.bar/test2 -->
+
+    <owl:Class rdf:about="http://foo.bar/test2">
+        <rdfs:subClassOf rdf:resource="http://foo.bar/test1"/>
+    </owl:Class>
+</rdf:RDF>
+