Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add labels option to diff #363

Merged
merged 2 commits into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)