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

1 no link to concept scheme #2

Merged
merged 6 commits into from
Jan 31, 2023
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
10 changes: 10 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

on: push

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Validate with script
run: ${GITHUB_WORKSPACE}/scripts/test.sh
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,20 @@ To use this shape with [Apache Jena](https://jena.apache.org/download/index.cgi)
To validate with the help of a docker container, you can run the following (run from current directory or adjust the respective paths to shape and your file):

`docker run --rm -v $(pwd)/skos.shacl.ttl:/rdf/shape.ttl -v $(pwd)/YOUR_SKOS_FILE.ttl:/rdf/file.ttl skohub/jena:4.6.1 shacl v -s /rdf/shape.ttl -d /rdf/file.ttl`

## Tests

There is some basis test functionality provided to test the shape.
Currently there are not many tests provided, but the general idea is as follows:
- build a small valid Concept Scheme for a node shape
- build a small invalid Concept Scheme for a node shape
- put these in the appropriate folders under `test/`
- check if it works with [`scripts/test.sh`](scripts/test.sh)

These tests are also run on every push via GitHub Actions.

It is very basic, but works like this:
- all files in the valid folder are run against the shape. If the validation script exits with `exit 1` it returns an error
- all files in the invalid folder are run against the shape. If the validation script exits with `exit 0` it returns an error

Feel free to suggest improvements or add more tests!
23 changes: 23 additions & 0 deletions scripts/checkForBoth.rq
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
prefix : <http://skohub.io/skohub-shacl>
prefix sh: <http://www.w3.org/ns/shacl#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix xml: <http://www.w3.org/XML/1998/namespace>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix skos: <http://www.w3.org/2004/02/skos/core#>
prefix dct: <http://purl.org/dc/terms/>


SELECT ?focusNode ?resultMessage ?value ?sourceShape ?resultPath ?sourceConstraintComponent
WHERE {
?result a sh:ValidationResult ;
{ ?result sh:resultSeverity sh:Warning . }
UNION
{ ?result sh:resultSeverity sh:Violation . }
?result sh:focusNode ?focusNode ;
sh:sourceShape ?sourceShape ;
sh:resultMessage ?resultMessage ;
OPTIONAL { ?result sh:resultPath ?resultPath }
OPTIONAL { ?result sh:value ?value}
}
21 changes: 21 additions & 0 deletions scripts/checkForViolation.rq
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
prefix : <http://skohub.io/skohub-shacl>
prefix sh: <http://www.w3.org/ns/shacl#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix xml: <http://www.w3.org/XML/1998/namespace>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix skos: <http://www.w3.org/2004/02/skos/core#>
prefix dct: <http://purl.org/dc/terms/>


SELECT ?focusNode ?resultMessage ?value ?sourceShape ?resultPath ?sourceConstraintComponent
WHERE {
?result a sh:ValidationResult ;
sh:resultSeverity sh:Violation .
?result sh:focusNode ?focusNode ;
sh:sourceShape ?sourceShape ;
sh:resultMessage ?resultMessage ;
OPTIONAL { ?result sh:resultPath ?resultPath }
OPTIONAL { ?result sh:value ?value}
}
21 changes: 21 additions & 0 deletions scripts/checkForWarning.rq
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
prefix : <http://skohub.io/skohub-shacl>
prefix sh: <http://www.w3.org/ns/shacl#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix xml: <http://www.w3.org/XML/1998/namespace>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix skos: <http://www.w3.org/2004/02/skos/core#>
prefix dct: <http://purl.org/dc/terms/>


SELECT ?focusNode ?resultMessage ?value ?sourceShape ?resultPath ?sourceConstraintComponent
WHERE {
?result a sh:ValidationResult ;
sh:resultSeverity sh:Warning .
?result sh:focusNode ?focusNode ;
sh:sourceShape ?sourceShape ;
sh:resultMessage ?resultMessage ;
OPTIONAL { ?result sh:resultPath ?resultPath }
OPTIONAL { ?result sh:value ?value}
}
28 changes: 28 additions & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash
error=false
# for files in tests/valid no output should be given
FILES="$(pwd)/tests/valid/*"
for f in $FILES
do
echo "Processing $f ..."
# take action on each file. $f store current file name
scripts/validate-skos.sh -f "$f" -s skos.shacl.ttl -l both 2>/dev/null
if test $? -eq 1; then echo "Error: $f should be valid, but is invalid"; error=true; fi;
done

# for files in tests/invalid output should be received
FILES="$(pwd)/tests/invalid/*"
for f in $FILES
do
echo "Processing $f ..."
# validate with script and log error messages to dev null
scripts/validate-skos.sh -f "$f" -s skos.shacl.ttl -l both 2>/dev/null
if test $? -eq 0; then echo "Error: $f should be invalid, but is valid"; error=true; fi
done

if test "$error" = true;
then
echo "There were errors in your tests!" && rm $(pwd)/result.ttl ; exit 1
else
rm $(pwd)/result.ttl
fi
48 changes: 48 additions & 0 deletions scripts/validate-skos.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash

#############
## No return message means everything is fine
##
#############

while getopts f:s:l: flag
do
case "${flag}" in
f) file=${OPTARG};;
s) shape=${OPTARG};;
l) severity=${OPTARG};; # not used right now
esac
done

# fail if any other exit status than 0
set -e

# make path absolute if no absolute path is given
# docker does not like relative paths
if [[ ! "$file" = /* ]];
then
file="$(pwd)/$file"
fi

# check file is not empty
test $(wc -l $file | awk '{print $1}') -gt 0 || (echo "file has no lines, aborting"; exit 1)

docker run --rm -v $(pwd)/$shape:/rdf/shape.ttl -v $file:/rdf/file.ttl skohub/jena:4.6.1 shacl v -s /rdf/shape.ttl -d /rdf/file.ttl > $(pwd)/result.ttl

if [[ $severity == "warning" ]]
then
SEVERITY_FILE="$(pwd)/scripts/checkForWarning.rq"
elif [[ $severity == "both" ]]
then
SEVERITY_FILE="$(pwd)/scripts/checkForBoth.rq"
else
SEVERITY_FILE="$(pwd)/scripts/checkForViolation.rq"
fi

validationResult="$(docker run --rm -v $SEVERITY_FILE:/rdf/checkForViolation.rq --mount type=bind,source=$(pwd)/result.ttl,target=/rdf/result.ttl skohub/jena:4.6.1 arq --data /rdf/result.ttl --query /rdf/checkForViolation.rq)"

lines=$(echo "$validationResult" | wc -l )

# an empty result, i.e. a correct validation has 4 lines of output
test ${lines} -eq 4 || (>&2 echo "validation errors, check output" ; >&2 echo "$validationResult"; exit 1)
exit 0
44 changes: 16 additions & 28 deletions skos.shacl.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -153,54 +153,42 @@ skos:
] ;
.

:NoLinkToConceptScheme
a sh:NodeShape ;
sh:targetClass skos:Concept ;
sh:message "Orphaned concepts that are not linked to the ConceptScheme are not allowed." ;
sh:sparql [
a sh:SPARQLConstraint ;
sh:prefixes skos: ;
sh:select """
SELECT $this
WHERE {
$this a skos:Concept ;
FILTER (NOT EXISTS {
{$this skos:topConceptOf ?a }
UNION
{$this skos:inScheme ?a }
})
.
}""" ;
] ;
.


:OrphanConcepts
a sh:NodeShape ;
sh:targetClass skos:Concept ;
sh:severity sh:Warning ;
sh:sparql [
a sh:SPARQLConstraint ; # This triple is optional
a sh:SPARQLConstraint ;
sh:prefixes skos: ;
rdfs:comment "Orphan Concept" ;
sh:description "An orphan concept is a concept without any associative or hierarchical relations. It might have attached literals like e.g., labels, but is not connected to any other resource, lacking valuable context information. A controlled vocabulary that contains many orphan concepts is less usable for search and retrieval use cases, because, e.g., no hierarchical query expansion can be performed on search terms to find documents with more general content." ;
sh:message "The concept is not a top concept of a Concept Scheme and neither has a broader or related concept. If it is a topConcept link it with skos:topConceptOf. Otherwise use one of the other relations." ;
sh:description """
An orphan concept is a concept without any associative or hierarchical
relations. It might have attached literals like e.g., labels, but is
not connected to any other resource, lacking valuable context information.
A controlled vocabulary that contains many orphan concepts is less
usable for search and retrieval use cases, because, e.g., no hierarchical
query expansion can be performed on search terms to find documents with
more general content.
""" ;
sh:message "The concept is not linked from a Concept Scheme or has no link to a Concept Scheme. Neither it has a relation to another concept. If it is a topConcept link it with skos:topConceptOf. Otherwise use one of the other relations." ;
sh:severity sh:Info ;
sh:select """
SELECT $this
WHERE {
$this a skos:Concept .
FILTER NOT EXISTS {
?this skos:topConceptOf ?cs .
?this skos:topConceptOf | skos:inScheme ?cs .
}
FILTER NOT EXISTS {
?cs skos:hasTopConcept ?this .
}
FILTER NOT EXISTS {
?this skos:broader | skos:broaderTransitive | skos:related ?other .
{?this skos:broader | skos:broaderTransitive | skos:related | skos:narrower | skos:narrowerTransitive ?other .}
}
}""" ;
] ;
.


:AmbiguousNotatation
a sh:NodeShape ;
sh:severity sh:Warning ;
Expand Down
26 changes: 26 additions & 0 deletions tests/invalid/ConceptShape.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@prefix : <https://example.org/> .
@prefix dct: <http://purl.org/dc/terms/>.
@prefix skos: <http://www.w3.org/2004/02/skos/core#>.


:cs1 a skos:ConceptScheme;
dct:title "Test"@de ;
skos:hasTopConcept :c1 ;
.

:c1 a skos:Concept;
skos:prefLabel "1"@de, "2"@de ;
skos:altLabel "1"@de ;
skos:inScheme : ;
.


:cs2 a skos:ConceptScheme;
dct:title "Test"@de ;
skos:hasTopConcept :c2 ;
.

:c2 a skos:Concept;
skos:prefLabel "2"@de ;
.

17 changes: 17 additions & 0 deletions tests/invalid/OrphanConcepts.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@prefix : <https://example.org/> .
@prefix dct: <http://purl.org/dc/terms/>.
@prefix skos: <http://www.w3.org/2004/02/skos/core#>.


: a skos:ConceptScheme;
dct:title "Test"@de ;
skos:hasTopConcept :1 ;
.

:1 a skos:Concept;
skos:prefLabel "1"@de ;
.

:2 a skos:Concept ;
skos:prefLabel "2"@de ;
.
25 changes: 25 additions & 0 deletions tests/valid/ConceptShape.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@prefix : <https://example.org/> .
@prefix dct: <http://purl.org/dc/terms/>.
@prefix skos: <http://www.w3.org/2004/02/skos/core#>.


:cs1 a skos:ConceptScheme;
dct:title "Test"@de ;
skos:hasTopConcept :c1 ;
.

:c1 a skos:Concept;
skos:prefLabel "1"@de ;
skos:inScheme : ;
.


:cs2 a skos:ConceptScheme;
dct:title "Test"@de ;
skos:hasTopConcept :c2 ;
.

:c2 a skos:Concept;
skos:prefLabel "2"@de ;
.

25 changes: 25 additions & 0 deletions tests/valid/OrphanConcepts.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@prefix : <https://example.org/> .
@prefix dct: <http://purl.org/dc/terms/>.
@prefix skos: <http://www.w3.org/2004/02/skos/core#>.


:cs1 a skos:ConceptScheme;
dct:title "Test"@de ;
skos:hasTopConcept :c1 ;
.

:c1 a skos:Concept;
skos:prefLabel "1"@de ;
skos:inScheme : ;
.


:cs2 a skos:ConceptScheme;
dct:title "Test"@de ;
skos:hasTopConcept :c2 ;
.

:c2 a skos:Concept;
skos:prefLabel "2"@de ;
.