Skip to content

Commit

Permalink
Lax comparison of language tags (WIP).
Browse files Browse the repository at this point in the history
As discussed in INCATools/kgcl#60, when trying
to find an annotation value (e.g. to rename a class, we need to find the
annotation corresponding to the old label), language tags should be
compared in a relaxed fashion. We should not fail to find an annotation
just because the annotation has a language tag and the KGCL command did
not specify any language tag at all.

This necessitates some pretty important refactoring, because this means,
among other things, that more than one annotation values may match (if
several annotations have the same literal value but different language
tags, or one has a language tag and another does not).

This is still a work in progress. For now, this is implemented
specifically for the NodeRename operation. After more testing, this will
be generalized to all other operations that involve finding an existing
annotation value (e.g. RemoveDefinition, ChangeDefinition,
SynonymReplacement, etc.).
  • Loading branch information
gouttegd committed Mar 10, 2024
1 parent 488f78a commit 21abbf0
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,80 @@ private boolean compareValue(OWLAnnotationValue value, String changeText, String
return valueLang.equals(changeLang);
}

/*
* Helper method to find the annotations whose value matches what a change
* expects.
*/
private Set<OWLAnnotationAssertionAxiom> findMatchingAnnotations(IRI property, IRI entity, String text, String lang,
String datatype, String newLang) {
HashSet<OWLAnnotationAssertionAxiom> axioms = new HashSet<OWLAnnotationAssertionAxiom>();
OWLAnnotationAssertionAxiom langLessAxiom = null;
for ( OWLAnnotationAssertionAxiom ax : ontology.getAnnotationAssertionAxioms(entity) ) {
if ( !ax.getProperty().getIRI().equals(property) ) {
continue;
}

OWLAnnotationValue value = ax.getValue();
if ( !value.isLiteral() ) {
continue;
}

String valueText = value.asLiteral().get().getLiteral();
if ( !valueText.equals(text) ) {
continue;
}

String valueLang = value.asLiteral().get().getLang();
if ( valueLang.isEmpty() ) {
// We'll decide later what to do with this one
langLessAxiom = ax;
continue;
}

// If we are expecting a given language, the language of the value must match.
if ( lang != null && !valueLang.equals(lang) ) {
continue;
}

// If the new value has an explicit language tag, then even if no language tag
// has been explicitly specified for the old value, we can only accept a value
// with the same language as the new value.
if ( newLang != null && !valueLang.equals(newLang) ) {
continue;
}

// At this point both the text and the language match.
axioms.add(ax);
}

if ( langLessAxiom != null ) {
// We accept the langless axiom only if:
// - no language tag was explicitly specified on the old value
// - if alanguage tag was explicitly specified on the new value, we didn't find
// any annotation in that language
// - if a datatype was explicitly specified, it matches the datatype of the
// langless axiom's value
if ( lang == null && (newLang == null || axioms.isEmpty()) && (datatype == null || langLessAxiom.getValue()
.asLiteral().get().getDatatype().getIRI().toString().equals(datatype)) ) {
axioms.add(langLessAxiom);
}
}

return axioms;
}

private OWLLiteral getLiteral(NodeChange change) {
return getLiteral(change, null);
}

private OWLLiteral getLiteral(NodeChange change, String oldLang) {
if ( change.getNewLanguage() != null ) {
return factory.getOWLLiteral(change.getNewValue(), change.getNewLanguage());
} else if ( change.getNewDatatype() != null ) {
return factory.getOWLLiteral(change.getNewValue(),
factory.getOWLDatatype(IRI.create(change.getNewDatatype())));
} else if ( oldLang != null ) {
return factory.getOWLLiteral(change.getNewValue(), oldLang);
} else {
return factory.getOWLLiteral(change.getNewValue());
}
Expand Down Expand Up @@ -261,27 +329,25 @@ public List<OWLOntologyChange> visit(NodeRename v) {
return empty;
}

OWLAnnotationAssertionAxiom oldLabelAxiom = null;
for ( OWLAnnotationAssertionAxiom ax : ontology
.getAnnotationAssertionAxioms(IRI.create(v.getAboutNode().getId())) ) {
if ( ax.getProperty().getIRI().equals(OWLRDFVocabulary.RDFS_LABEL.getIRI()) ) {
if ( compareValue(ax.getValue(), v.getOldValue(), v.getOldLanguage()) ) {
oldLabelAxiom = ax;
}
}
}
IRI nodeIRI = IRI.create(v.getAboutNode().getId());
Set<OWLAnnotationAssertionAxiom> matches = findMatchingAnnotations(OWLRDFVocabulary.RDFS_LABEL.getIRI(),
nodeIRI, v.getOldValue(), v.getOldLanguage(), v.getOldDatatype(), v.getNewLanguage());

if ( oldLabelAxiom == null ) {
if ( matches.isEmpty() ) {
onReject(v, "Label \"%s\" not found on <%s>", v.getOldValue(), v.getAboutNode().getId());
return empty;
}

AddAxiom addNewLabel = new AddAxiom(ontology,
factory.getOWLAnnotationAssertionAxiom(
factory.getOWLAnnotationProperty(OWLRDFVocabulary.RDFS_LABEL.getIRI()),
IRI.create(v.getAboutNode().getId()), getLiteral(v)));
ArrayList<OWLOntologyChange> changes = new ArrayList<OWLOntologyChange>();
for ( OWLAnnotationAssertionAxiom match : matches ) {
changes.add(removeAxiom(match));
changes.add(new AddAxiom(ontology,
factory.getOWLAnnotationAssertionAxiom(
factory.getOWLAnnotationProperty(OWLRDFVocabulary.RDFS_LABEL.getIRI()), nodeIRI,
getLiteral(v, match.getValue().asLiteral().get().getLang()))));
}

return makeList(removeAxiom(oldLabelAxiom), addNewLabel);
return changes;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,82 @@ void testNodeRename() {
testChange(change, expected, null);
}

@Test
void testNodeRenameNoLangTags() {
NodeRename change = new NodeRename();
setAboutNode(change, "LaReine");
setValue(change, "LaReine", null, true);
setValue(change, "TheQueen", null);

// LaReine has two identical labels in both English and Portuguese; since we
// have not specified any language tags, both should be renamed and the original
// language tags should be preserved.

ArrayList<OWLOntologyChange> expected = new ArrayList<OWLOntologyChange>();
expected.add(new RemoveAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "LaReine", "en")));
expected.add(new RemoveAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "LaReine", "pt")));
expected.add(new AddAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "TheQueen", "en")));
expected.add(new AddAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "TheQueen", "pt")));

testChange(change, expected, null);
}

@Test
void testNodeRenameNoOldLangTag() {
NodeRename change = new NodeRename();
setAboutNode(change, "LaReine");
setValue(change, "LaReine", null, true);
setValue(change, "TheQueen", "en");

// Here, since we have specified English as the NEW language tag, only the
// original English label should be renamed; the Portuguese one should be left
// untouched, even if its literal value is the same as the English label.

ArrayList<OWLOntologyChange> expected = new ArrayList<OWLOntologyChange>();
expected.add(new RemoveAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "LaReine", "en")));
expected.add(new AddAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "TheQueen", "en")));

testChange(change, expected, null);
}

@Test
void testNodeRenameNoNewLangTag() {
NodeRename change = new NodeRename();
setAboutNode(change, "LaReine");
setValue(change, "LaReine", "en", true);
setValue(change, "TheQueen", null);

// Only the English label should be modified since we have explicitly specified
// a language tag on the old value; furthermore, even if the new value has no
// language tag, the original tag should be carried over.

ArrayList<OWLOntologyChange> expected = new ArrayList<OWLOntologyChange>();
expected.add(new RemoveAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "LaReine", "en")));
expected.add(new AddAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "TheQueen", "en")));

testChange(change, expected, null);
}

@Test
void testNodeRenameExplicitNewDatatype() {
NodeRename change = new NodeRename();
setAboutNode(change, "LaReine");
setValue(change, "LaReine", "en", true);
change.setNewValue("TheQueen");
change.setNewDatatype(XSDVocabulary.STRING.toString());

// Only the English label should be modified since we have explicitly specified
// a language tag on the old value; we have also explicitly set a xsd:string
// datatype on the new value, so the old language tag should NOT be carried
// over.

ArrayList<OWLOntologyChange> expected = new ArrayList<OWLOntologyChange>();
expected.add(new RemoveAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "LaReine", "en")));
expected.add(new AddAxiom(ontology, getAnnotation(LABEL_IRI, "LaReine", "TheQueen", null)));

testChange(change, expected, null);
}

@Test
void testRejectedNodeRename() {
NodeRename change = new NodeRename();
Expand Down

0 comments on commit 21abbf0

Please sign in to comment.