Skip to content

Commit

Permalink
Merge pull request #363 from rctauber/diff-update
Browse files Browse the repository at this point in the history
Add labels option to diff
  • Loading branch information
jamesaoverton authored Sep 20, 2018
2 parents 93a64ad + 53726c1 commit fd906a0
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 15 deletions.
2 changes: 2 additions & 0 deletions docs/diff.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ If `--output` is provided then a report will be written with any differences bet

See <a href="/examples/release-diff.txt" target="_blank">`release-diff.txt`</a> for an example. In the output, 'Ontology 1' corresponds to your `--left` input and 'Ontology 2' corresponds to your `--right` input.

The output is in OWL Manchester syntax, but you can include entity labels with `--labels true`.

You can also compare ontologies by IRI with `--left-iri` and `--right-iri`. You may want to compare a local file to a release, in which case:
<!-- DO NOT TEST -->
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.semanticweb.owlapi.model.IRI;
Expand Down Expand Up @@ -45,6 +47,7 @@ public DiffCommand() {
o.addOption("r", "right", true, "load right ontology from file");
o.addOption("R", "right-iri", true, "load right ontology from IRI");
o.addOption("o", "output", true, "save results to file");
o.addOption(null, "labels", true, "if true, use labels in place of entity IRIs");
options = o;
}

Expand Down Expand Up @@ -145,7 +148,10 @@ public CommandState execute(CommandState state, String[] args) throws Exception
writer = new PrintWriter(System.out);
}

DiffOperation.compare(leftOntology, rightOntology, writer);
Map<String, String> options = new HashMap<>();
options.put("labels", CommandLineHelper.getDefaultValue(line, "labels", "false"));

DiffOperation.compare(leftOntology, rightOntology, ioHelper, writer, options);
writer.flush();
writer.close();

Expand Down
98 changes: 84 additions & 14 deletions robot-core/src/main/java/org/obolibrary/robot/DiffOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@

import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.util.DefaultPrefixManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -30,6 +25,17 @@ public class DiffOperation {
/** A pattern for matching IRI strings. */
private static Pattern iriPattern = Pattern.compile("<(http\\S+)>");

/**
* Return default diff options.
*
* @return diff options
*/
public static Map<String, String> getDefaultOptions() {
Map<String, String> options = new HashMap<>();
options.put("labels", "false");
return options;
}

/**
* Given two ontologies, compare their sets of axiom strings, returning true if they are identical
* and false otherwise.
Expand Down Expand Up @@ -58,9 +64,33 @@ public static boolean equals(OWLOntology ontology1, OWLOntology ontology2) {
*/
public static boolean compare(OWLOntology ontology1, OWLOntology ontology2, Writer writer)
throws IOException {
return compare(ontology1, ontology2, new IOHelper(), writer, getDefaultOptions());
}

// Map<IRI, String> labels = OntologyHelper.getLabels(ontology1);
// labels.putAll(OntologyHelper.getLabels(ontology2));
/**
* Given two ontologies, a Writer, and a set of diff options, get the differences between axiom
* strings and write then to the writer. The ontologies are not changed.
*
* @param ontology1 the first ontology
* @param ontology2 the second ontology
* @param ioHelper IOHelper to use for prefixes
* @param writer the Writer for the report, or null
* @param options diff options
* @return true if the ontologies are the same, false otherwise
* @throws IOException on writer failure
*/
public static boolean compare(
OWLOntology ontology1,
OWLOntology ontology2,
IOHelper ioHelper,
Writer writer,
Map<String, String> options)
throws IOException {

boolean useLabels = OptionsHelper.optionIsTrue(options, "labels");

Map<IRI, String> labels = OntologyHelper.getLabels(ontology1);
labels.putAll(OntologyHelper.getLabels(ontology2));

Set<String> strings1 = getAxiomStrings(ontology1);
Set<String> strings2 = getAxiomStrings(ontology2);
Expand All @@ -85,7 +115,11 @@ public static boolean compare(OWLOntology ontology1, OWLOntology ontology2, Writ
writer.write(strings1minus2.size() + " axioms in Ontology 1 but not in Ontology 2:\n");
sorted = new TreeSet<>();
for (String axiom : strings1minus2) {
sorted.add("- " + axiom + "\n");
if (useLabels) {
sorted.add("- " + addLabels(ioHelper, labels, axiom) + "\n");
} else {
sorted.add("- " + axiom + "\n");
}
}
for (String axiom : sorted) {
writer.write(axiom);
Expand All @@ -96,7 +130,11 @@ public static boolean compare(OWLOntology ontology1, OWLOntology ontology2, Writ
writer.write(strings2minus1.size() + " axioms in Ontology 2 but not in Ontology 1:\n");
sorted = new TreeSet<>();
for (String axiom : strings2minus1) {
sorted.add("+ " + axiom + "\n");
if (useLabels) {
sorted.add("+ " + addLabels(ioHelper, labels, axiom) + "\n");
} else {
sorted.add("+ " + axiom + "\n");
}
}
for (String axiom : sorted) {
writer.write(axiom);
Expand All @@ -120,9 +158,9 @@ public static String addLabels(Map<IRI, String> labels, String axiom) {
IRI iri = IRI.create(matcher.group(1));
String id = iri.toString();
if (id.startsWith(oboBase)) {
id = id.substring(oboBase.length());
id = id.substring(oboBase.length()).replace("_", ":");
}
String replacement = "<" + iri + ">";
String replacement = "<" + id + ">";
if (labels.containsKey(iri)) {
replacement = "<" + id + ">[" + labels.get(iri) + "]";
}
Expand All @@ -132,6 +170,38 @@ public static String addLabels(Map<IRI, String> labels, String axiom) {
return sb.toString();
}

/**
* Given an IOHelper to get short form of IRIs, a map from IRIs to labels, and an axiom string,
* add labels next to any IRIs in the string, shorten OBO IRIs, and return the updated string.
*
* @param ioHelper IOHelper to use for prefixes
* @param labels a map from IRIs to label strings
* @param axiom a string representation of an OWLAxiom
* @return a string with labels inserted next to CURIEs
*/
public static String addLabels(IOHelper ioHelper, Map<IRI, String> labels, String axiom) {
DefaultPrefixManager pm = ioHelper.getPrefixManager();
Matcher matcher = iriPattern.matcher(axiom);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
IRI iri = IRI.create(matcher.group(1));
String id = pm.getShortForm(iri);
if (id.startsWith("obo:")) {
id = id.substring(4).replace("_", ":");
}
if (!id.startsWith("<") && !id.endsWith(">")) {
id = "<" + id + ">";
}
String replacement = id;
if (labels.containsKey(iri)) {
replacement = id + "[" + labels.get(iri) + "]";
}
matcher.appendReplacement(sb, replacement);
}
matcher.appendTail(sb);
return sb.toString();
}

/**
* Given an ontology, return a list of strings for all the axioms of that ontology.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
Expand Down Expand Up @@ -54,4 +56,25 @@ public void testCompareModified() throws IOException, OWLOntologyCreationExcepti
String expected = IOUtils.toString(this.getClass().getResourceAsStream("/simple1.diff"));
assertEquals(expected, writer.toString());
}

/**
* Compare one ontology to a modified copy with labels in output.
*
* @throws IOException on file problem
* @throws OWLOntologyCreationException on ontology problem
*/
@Test
public void testCompareModifiedWithLabels() throws IOException, OWLOntologyCreationException {
OWLOntology simple = loadOntology("/simple.owl");
OWLOntology elk = loadOntology("/simple_elk.owl");

StringWriter writer = new StringWriter();
Map<String, String> options = new HashMap<>();
options.put("labels", "true");
boolean actual = DiffOperation.compare(simple, elk, new IOHelper(), writer, options);
System.out.println(writer.toString());
assertFalse(actual);
String expected = IOUtils.toString(this.getClass().getResourceAsStream("/simple.diff"));
assertEquals(expected, writer.toString());
}
}
4 changes: 4 additions & 0 deletions robot-core/src/test/resources/simple.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
0 axioms in Ontology 1 but not in Ontology 2:

1 axioms in Ontology 2 but not in Ontology 1:
+ SubClassOf(<https://github.com/ontodev/robot/robot-core/src/test/resources/simple.owl#test1>[Test 1] owl:Thing)

0 comments on commit fd906a0

Please sign in to comment.