Skip to content
This repository has been archived by the owner on Feb 22, 2020. It is now read-only.

Commit

Permalink
eclipse-rdf4j/rdf4j#1109 support for language in
Browse files Browse the repository at this point in the history
Signed-off-by: Håvard Ottestad <[email protected]>
  • Loading branch information
hmottestad committed Jan 19, 2019
1 parent e279a2d commit dae8c16
Show file tree
Hide file tree
Showing 21 changed files with 369 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*******************************************************************************
* Copyright (c) 2018 Eclipse RDF4J contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*******************************************************************************/
package org.eclipse.rdf4j.sail.shacl.AST;


import org.eclipse.rdf4j.common.iteration.Iterations;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.vocabulary.SHACL;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection;
import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection;
import org.eclipse.rdf4j.sail.shacl.planNodes.LanguageInFilter;
import org.eclipse.rdf4j.sail.shacl.planNodes.PlanNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* @author Håvard Ottestad
*/
public class LanguageInPropertyShape extends PathPropertyShape {

private final List<String> languageIn;
private static final Logger logger = LoggerFactory.getLogger(LanguageInPropertyShape.class);

LanguageInPropertyShape(Resource id, SailRepositoryConnection connection, NodeShape nodeShape) {
super(id, connection, nodeShape);

try (Stream<Statement> stream = Iterations.stream(connection.getStatements(id, SHACL.LANGUAGE_IN, null, true))) {
Resource orList = stream.map(Statement::getObject).map(v -> (Resource) v).findAny().orElseThrow(() -> new RuntimeException("Expected to find sh:languageIn on " + id));
languageIn = toList(connection, orList).stream().map(Value::stringValue).collect(Collectors.toList());
}

}


@Override
public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeShape, boolean printPlans, boolean assumeBaseSailValid) {

PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan(
shaclSailConnection,
nodeShape,
(parent, trueNode, falseNode) -> new LanguageInFilter(parent, trueNode, falseNode, languageIn),
this
);

if (printPlans) {
String planAsGraphvizDot = getPlanAsGraphvizDot(invalidValues, shaclSailConnection);
logger.info(planAsGraphvizDot);
}

return invalidValues;

}

@Override
public boolean requiresEvaluation(Repository addedStatements, Repository removedStatements) {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,8 @@ public class OrPropertyShape extends PropertyShape {

}

private static List<Value> toList(SailRepositoryConnection connection, Resource orList) {
List<Value> ret = new ArrayList<>();
while (!orList.equals(RDF.NIL)) {
try (Stream<Statement> stream = Iterations.stream(connection.getStatements(orList, RDF.FIRST, null))) {
Value value = stream.map(Statement::getObject).findAny().get();
ret.add(value);
}

try (Stream<Statement> stream = Iterations.stream(connection.getStatements(orList, RDF.REST, null))) {
orList = stream.map(Statement::getObject).map(v -> (Resource) v).findAny().get();
}

}


return ret;


}


@Override
public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeShape, boolean printPlans, boolean assumeBaseSailValid) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.eclipse.rdf4j.common.iteration.Iterations;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.model.vocabulary.SHACL;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection;
Expand Down Expand Up @@ -82,6 +84,26 @@ public String getPlanAsGraphvizDot(PlanNode planNode, ShaclSailConnection shaclS

}

static List<Value> toList(SailRepositoryConnection connection, Resource orList) {
List<Value> ret = new ArrayList<>();
while (!orList.equals(RDF.NIL)) {
try (Stream<Statement> stream = Iterations.stream(connection.getStatements(orList, RDF.FIRST, null))) {
Value value = stream.map(Statement::getObject).findAny().get();
ret.add(value);
}

try (Stream<Statement> stream = Iterations.stream(connection.getStatements(orList, RDF.REST, null))) {
orList = stream.map(Statement::getObject).map(v -> (Resource) v).findAny().get();
}

}


return ret;


}

static class Factory {

static List<PropertyShape> getPropertyShapes(Resource ShapeId, SailRepositoryConnection connection, NodeShape nodeShape) {
Expand Down Expand Up @@ -131,6 +153,10 @@ static List<PropertyShape> getPropertyShapesInner(SailRepositoryConnection conne
if (hasPattern(propertyShapeId, connection)) {
propertyShapes.add(new PatternPropertyShape(propertyShapeId, connection, nodeShape));
}

if (hasLanguageIn(propertyShapeId, connection)) {
propertyShapes.add(new LanguageInPropertyShape(propertyShapeId, connection, nodeShape));
}
return propertyShapes;
}

Expand Down Expand Up @@ -162,6 +188,9 @@ private static boolean hasMaxLength(Resource id, SailRepositoryConnection connec
private static boolean hasPattern(Resource id, SailRepositoryConnection connection) {
return connection.hasStatement(id, SHACL.PATTERN, null, true);
}
private static boolean hasLanguageIn(Resource id, SailRepositoryConnection connection) {
return connection.hasStatement(id, SHACL.LANGUAGE_IN, null, true);
}


}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*******************************************************************************
* Copyright (c) 2018 Eclipse RDF4J contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*******************************************************************************/

package org.eclipse.rdf4j.sail.shacl.planNodes;


import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Resource;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
* @author Håvard Ottestad
*/
public class LanguageInFilter extends FilterPlanNode {

private final List<String> languageIn;

public LanguageInFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, List<String> languageIn) {
super(parent, trueNode, falseNode);
this.languageIn = languageIn;
}

@Override
boolean checkTuple(Tuple t) {
if(! (t.line.get(1) instanceof Literal)) return false;

Optional<String> language = ((Literal) t.line.get(1)).getLanguage();
if(!language.isPresent()) return false;

return languageIn.contains(language.get());

}


@Override
public String toString() {
return "LanguageInFilter{" +
"languageIn=" + Arrays.toString(languageIn.toArray()) +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class ShaclTest {
"test-cases/minLength/simple",
"test-cases/maxLength/simple",
"test-cases/pattern/simple",
"test-cases/languageIn/simple",
"test-cases/minCount/simple",
"test-cases/maxCount/simple",
"test-cases/or/inheritance",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1 a ex:Person ;
ex:label "människa"@se.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1 a ex:Person ;
ex:label "human"@en.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1 ex:label "människa"@se.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1 ex:label "människa"@se.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1 a ex:Person .

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1 ex:label "människa"@se.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1
ex:label "human"@en ;
a ex:Person .

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1 ex:label "människa"@se.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1
ex:label "human"@en ;
a ex:Person .

ex:validPerson2
ex:label "human"@en ;
a ex:Person .

}
16 changes: 16 additions & 0 deletions shacl/src/test/resources/test-cases/languageIn/simple/shacl.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@base <http://example.com/ns> .
@prefix ex: <http://example.com/ns#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ex:PersonShape
a sh:NodeShape ;
sh:targetClass ex:Person ;
sh:property [
sh:path ex:label ;
sh:languageIn ( "en" "no" ) ;
] .

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1 a ex:Person ;
ex:label "human"@en, "menneske"@no.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
PREFIX ex: <http://example.com/ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

INSERT DATA {

ex:validPerson1 a ex:Person ;
ex:label "human"@en.

}
Loading

0 comments on commit dae8c16

Please sign in to comment.