Skip to content

Commit

Permalink
Language specification support - load only values with correct langua…
Browse files Browse the repository at this point in the history
…ge tag in Owlapi driver, part I.
  • Loading branch information
ledsoft committed Jun 2, 2017
1 parent 38b7c83 commit 314eefd
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/**
* Copyright (C) 2016 Czech Technical University in Prague
*
* <p>
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
Expand All @@ -14,11 +14,11 @@
*/
package cz.cvut.kbss.ontodriver.owlapi;

import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot;
import cz.cvut.kbss.ontodriver.owlapi.util.OwlapiUtils;
import cz.cvut.kbss.ontodriver.model.Assertion;
import cz.cvut.kbss.ontodriver.model.Axiom;
import cz.cvut.kbss.ontodriver.model.NamedResource;
import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot;
import cz.cvut.kbss.ontodriver.owlapi.util.OwlapiUtils;
import org.semanticweb.owlapi.model.*;

import java.net.URI;
Expand All @@ -36,6 +36,7 @@ class ExplicitAxiomLoader implements AxiomLoader {

private final OwlapiAdapter adapter;
private final AxiomAdapter axiomAdapter;
private final String language;

private Set<Assertion> assertions;
private Set<URI> assertionUris;
Expand All @@ -45,6 +46,7 @@ class ExplicitAxiomLoader implements AxiomLoader {
this.ontology = snapshot.getOntology();
this.dataFactory = snapshot.getDataFactory();
this.axiomAdapter = new AxiomAdapter(dataFactory, adapter.getLanguage());
this.language = adapter.getLanguage();
}

@Override
Expand All @@ -71,28 +73,34 @@ public Collection<Axiom<?>> loadAxioms(NamedResource subject, Set<Assertion> ass

private Collection<Axiom<?>> dataPropertyValuesToAxioms(NamedResource subject,
Collection<OWLDataPropertyAssertionAxiom> axioms) {
return axioms.stream().filter(axiom ->
assertions.contains(UNSPECIFIED_ASSERTION) ||
assertionUris.contains(axiom.getProperty().asOWLDataProperty().getIRI().toURI()))
.map(axiom -> axiomAdapter.toAxiom(subject, axiom, false))
return axioms.stream().filter(axiom -> {
final OWLLiteral value = axiom.getObject();
final boolean propertyExists = doesPropertyExist(axiom.getProperty().asOWLDataProperty().getIRI());
return propertyExists && OwlapiUtils.doesLanguageMatch(value, language);
}).map(axiom -> axiomAdapter.toAxiom(subject, axiom, false))
.collect(Collectors.toList());
}

private boolean doesPropertyExist(IRI o) {
return assertions.contains(UNSPECIFIED_ASSERTION) || assertionUris.contains(o.toURI());
}

private Collection<Axiom<?>> objectPropertyValuesToAxioms(NamedResource subject,
Collection<OWLObjectPropertyAssertionAxiom> axioms) {
return axioms.stream().filter(axiom ->
assertions.contains(UNSPECIFIED_ASSERTION) ||
assertionUris.contains(axiom.getProperty().asOWLObjectProperty().getIRI().toURI()))
doesPropertyExist(axiom.getProperty().asOWLObjectProperty().getIRI()))
.map(axiom -> axiomAdapter.toAxiom(subject, axiom, false))
.collect(Collectors.toList());
}

private Collection<Axiom<?>> annotationPropertyValuesToAxioms(NamedResource subject,
Collection<OWLAnnotationAssertionAxiom> axioms) {
return axioms.stream().filter(axiom ->
assertions.contains(UNSPECIFIED_ASSERTION) ||
assertionUris.contains(axiom.getProperty().asOWLAnnotationProperty().getIRI().toURI()))
.map(axiom -> axiomAdapter.toAxiom(subject, axiom, false))
return axioms.stream().filter(axiom -> {
final OWLAnnotationValue value = axiom.getValue();
final boolean propertyExists = doesPropertyExist(axiom.getProperty().asOWLAnnotationProperty().getIRI());
return propertyExists && (!value.asLiteral().isPresent() ||
OwlapiUtils.doesLanguageMatch(value.asLiteral().get(), language));
}).map(axiom -> axiomAdapter.toAxiom(subject, axiom, false))
.collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@
package cz.cvut.kbss.ontodriver.owlapi.util;

import cz.cvut.kbss.ontodriver.model.NamedResource;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.vocab.OWL2Datatype;

import java.net.URI;
Expand All @@ -35,6 +32,10 @@ public class OwlapiUtils {

private static final String DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS";

private OwlapiUtils() {
throw new AssertionError("Can't create instance.");
}

/**
* Creates OWLLiteral from the specified Java instance.
*
Expand Down Expand Up @@ -112,6 +113,26 @@ public static Object owlLiteralToValue(final OWLLiteral literal) {
throw new IllegalArgumentException("Unsupported datatype: " + literal.getDatatype());
}

/**
* Checks whether the specified literal matches to the specified language.
* <p>
* If the literal is not a string, it automatically matches. If it is a string, it matches if {@code language} is
* not specified, it is without language tag or if the language tag matches the specified language.
*
* @param literal Literal to check
* @param language Expected language, possibly {@code null}
* @return {@code true} if the literal matches the language, {@code false} otherwise
*/
public static boolean doesLanguageMatch(OWLLiteral literal, String language) {
assert literal != null;

final OWLDatatype datatype = literal.getDatatype();
if (datatype.isBuiltIn() && datatype.isString() || datatype.isRDFPlainLiteral()) {
return language == null || literal.getLang().isEmpty() || literal.getLang().equals(language);
}
return true;
}

/**
* Gets OWLNamedIndividual for the specified named resource.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/**
* Copyright (C) 2016 Czech Technical University in Prague
*
* <p>
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
Expand All @@ -14,10 +14,10 @@
*/
package cz.cvut.kbss.ontodriver.owlapi;

import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot;
import cz.cvut.kbss.ontodriver.owlapi.exception.ReasonerNotAvailableException;
import cz.cvut.kbss.ontodriver.descriptor.AxiomDescriptor;
import cz.cvut.kbss.ontodriver.model.*;
import cz.cvut.kbss.ontodriver.owlapi.connector.OntologySnapshot;
import cz.cvut.kbss.ontodriver.owlapi.exception.ReasonerNotAvailableException;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
Expand All @@ -36,15 +36,14 @@
import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;

public class MainAxiomLoaderTest {

private static final NamedResource SUBJECT = NamedResource.create("http://krizik.felk.cvut.cz/Individual");
private static final String LANG = "en";

@Mock
private OwlapiAdapter adapterMock;
Expand All @@ -69,6 +68,7 @@ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
final OntologySnapshot snapshot = new OntologySnapshot(ontologyMock, managerMock, dataFactory,
reasonerMock);
when(adapterMock.getLanguage()).thenReturn(LANG);
this.axiomLoader = new MainAxiomLoader(adapterMock, snapshot);
this.individual = dataFactory.getOWLNamedIndividual(IRI.create(SUBJECT.getIdentifier()));
when(ontologyMock.containsIndividualInSignature(individual.getIRI())).thenReturn(true);
Expand Down Expand Up @@ -281,4 +281,44 @@ public void skipsExplicitAssertionValueIfThereIsTheSameAssertionAlsoWithInferenc
assertEquals(opInferred, ax.getAssertion());
}
}

@Test
public void loadsStringLiteralValueForExplicitAnnotationPropertyWithCorrectLanguageTag() throws Exception {
final Set<OWLAnnotationAssertionAxiom> axioms = new HashSet<>();
final String propertyUri = "http://www.w3.org/2000/01/rdf-schema#label";
final OWLNamedIndividual individual = dataFactory.getOWLNamedIndividual(IRI.create(SUBJECT.getIdentifier()));
final OWLAnnotationProperty property = dataFactory.getOWLAnnotationProperty(IRI.create(propertyUri));
axioms.add(dataFactory.getOWLAnnotationAssertionAxiom(property, individual.getIRI(),
dataFactory.getOWLLiteral("a", LANG)));
axioms.add(dataFactory.getOWLAnnotationAssertionAxiom(property, individual.getIRI(),
dataFactory.getOWLLiteral("b", "cs")));
when(ontologyMock.getAnnotationAssertionAxioms(individual.getIRI())).thenReturn(axioms);

final Collection<Axiom<?>> result = axiomLoader
.findAxioms(descriptor(Assertion.createAnnotationPropertyAssertion(URI.create(propertyUri), false)));
assertEquals(1, result.size());
final Axiom<?> ax = result.iterator().next();
assertEquals("a", ax.getValue().getValue());
}

@Test
public void loadsStringLiteralValueForExplicitDataPropertyWithCorrectLanguageTag() throws Exception {
final Set<OWLDataPropertyAssertionAxiom> axioms = new HashSet<>();
final String propertyUri = "http://krizik.felk.cvut.cz/dataPropertyOne";
final OWLNamedIndividual individual = dataFactory.getOWLNamedIndividual(IRI.create(SUBJECT.getIdentifier()));
final OWLDataProperty property = dataFactory.getOWLDataProperty(IRI.create(propertyUri));
axioms.add(dataFactory
.getOWLDataPropertyAssertionAxiom(property, individual, dataFactory.getOWLLiteral("a", LANG)));
axioms.add(dataFactory
.getOWLDataPropertyAssertionAxiom(property, individual, dataFactory.getOWLLiteral("b", "cs")));
when(ontologyMock.getDataPropertyAssertionAxioms(individual)).thenReturn(axioms);

final Collection<Axiom<?>> result = axiomLoader
.findAxioms(descriptor(Assertion.createDataPropertyAssertion(URI.create(propertyUri), false)));
assertEquals(1, result.size());
final Axiom<?> ax = result.iterator().next();
assertEquals("a", ax.getValue().getValue());
}

// TODO Do the language checks also for inferred values
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cz.cvut.kbss.ontodriver.owlapi.util;

import org.junit.Test;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLLiteral;
import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;

import static org.junit.Assert.*;

public class OwlapiUtilsTest {

private static final String LANG = "en";

private OWLDataFactory dataFactory = new OWLDataFactoryImpl();

@Test
public void doesLanguageMatchReturnsTrueWhenLanguageTagMatches() {
final OWLLiteral literal = dataFactory.getOWLLiteral("test", LANG);
assertTrue(OwlapiUtils.doesLanguageMatch(literal, LANG));
}

@Test
public void doesLanguageMatchReturnsFalseWhenLanguageTagDoesNotMatch() {
final OWLLiteral literal = dataFactory.getOWLLiteral("test", LANG);
assertFalse(OwlapiUtils.doesLanguageMatch(literal, "cs"));
}

@Test
public void doesLanguageMatchReturnsTrueWhenLanguageIsNotSpecified() {
final OWLLiteral literal = dataFactory.getOWLLiteral("test", LANG);
assertTrue(OwlapiUtils.doesLanguageMatch(literal, null));
}

@Test
public void doesLanguageMatchReturnsTrueWhenLiteralHasNoLanguageTag() {
final OWLLiteral literal = dataFactory.getOWLLiteral("test");
assertTrue(OwlapiUtils.doesLanguageMatch(literal, LANG));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ private Object toObject(Value val) {
return null;
}
if (val instanceof Literal) {
return SesameUtils.getDataPropertyValue((Literal) val, null).get();
return SesameUtils.getDataPropertyValue((Literal) val);
} else if (val instanceof IRI) {
return SesameUtils.toJavaUri((IRI) val);
} else {
Expand Down Expand Up @@ -245,7 +245,7 @@ private <T> T toObject(Value val, Class<T> cls) throws OntoDriverException {
}
Object ob = null;
if (val instanceof Literal) {
ob = SesameUtils.getDataPropertyValue((Literal) val, null).get();
ob = SesameUtils.getDataPropertyValue((Literal) val);
} else if (val instanceof IRI) {
ob = SesameUtils.toJavaUri((IRI) val);
}
Expand All @@ -260,12 +260,12 @@ private <T> T toObject(Value val, Class<T> cls) throws OntoDriverException {
* Searches for a suitable constructor and creates a new instance of class {@code cls}. </p>
* <p>
* The type has to have single-argument constructor, which takes either {@code Value} or its subtypes or type of
* instance returned by {@link SesameUtils#getDataPropertyValue(Literal, String)}.
* instance returned by {@link SesameUtils#getDataPropertyValue(Literal)}.
*
* @param cls The return type
* @param val Raw value
* @param ob Either raw value (if it is a resource) or instance returned by {@link
* SesameUtils#getDataPropertyValue(Literal, String)} on passing the literal {@code val}
* SesameUtils#getDataPropertyValue(Literal)} on passing the literal {@code val}
* @return The new instance
* @throws OntoDriverException If no suitable constructor is found or the instance cannot be created
*/
Expand Down Expand Up @@ -322,7 +322,7 @@ public String getString(String columnLabel) throws OntoDriverException {

private String getStringImpl(Value val) {
if (val instanceof Literal) {
return SesameUtils.getDataPropertyValue((Literal) val, null).get().toString();
return SesameUtils.getDataPropertyValue((Literal) val).toString();
} else {
return val.toString();
}
Expand Down Expand Up @@ -353,15 +353,15 @@ private Object getLiteralValue(int columnIndex) throws OntoDriverException {
if (!(val instanceof Literal)) {
throw new OntoDriverException("Expected value " + val + " to be a literal.");
}
return SesameUtils.getDataPropertyValue((Literal) val, null).get();
return SesameUtils.getDataPropertyValue((Literal) val);
}

private Object getLiteralValue(String columnName) throws OntoDriverException {
final Value val = getCurrent(columnName);
if (!(val instanceof Literal)) {
throw new OntoDriverException("Expected value " + val + " to be a literal.");
}
return SesameUtils.getDataPropertyValue((Literal) val, null).get();
return SesameUtils.getDataPropertyValue((Literal) val);
}

private Value getCurrent(int columnIndex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,10 @@ private Assertion resolveAssertion(IRI predicate) {
private Optional<Value<?>> createValue(Assertion.AssertionType assertionType, org.eclipse.rdf4j.model.Value value) {
switch (assertionType) {
case DATA_PROPERTY:
if (!(value instanceof Literal)) {
if (!(value instanceof Literal) || !SesameUtils.doesLanguageMatch((Literal) value, language)) {
return Optional.empty();
}
final Optional<Object> val = SesameUtils.getDataPropertyValue((Literal) value, language);
return val.map(Value::new);
return Optional.of(new Value<>(SesameUtils.getDataPropertyValue((Literal) value)));
case CLASS:
if (!(value instanceof Resource)) {
return Optional.empty();
Expand All @@ -101,7 +100,10 @@ private Optional<Value<?>> createValue(Assertion.AssertionType assertionType, or

private Optional<Value<?>> resolveValue(org.eclipse.rdf4j.model.Value object) {
if (object instanceof Literal) {
return SesameUtils.getDataPropertyValue((Literal) object, language).map(Value::new);
if (!SesameUtils.doesLanguageMatch((Literal) object, language)) {
return Optional.empty();
}
return Optional.of(new Value<>(SesameUtils.getDataPropertyValue((Literal) object)));
} else {
return Optional.of(new Value<>(NamedResource.create(object.stringValue())));
}
Expand Down
Loading

0 comments on commit 314eefd

Please sign in to comment.