Hello,
I'm trying to write a sh:ConstraintComponent that validates whether two
predicates have the same objects. One predicate has multiple objects and
the other has an object with an ordered RDF list of those same nodes. In
Turtle, a valid graph looks like:
@prefix ex: <http://example.org/> .
ex:Thing
ex:p1 ex:a, ex:b, ex:c ;
ex:p2 ( ex:a ex:b ex:c ) .
I can create a SPARQL constraint that expresses this:
:ListPredEqualityConstraint
a sh:SPARQLConstraint ;
sh:prefixes [
sh:declare
[
sh:prefix "ex" ;
sh:namespace "http://example.org/"^^xsd:anyURI
] ,
]
sh:select """
SELECT $this ?missing
WHERE {
{
$this ex:p2/rdf:rest*/rdf:first ?missing
MINUS
{ $this ex:p1 ?missing }
}
UNION
{
$this ex:p1 ?missing
MINUS
{ $this ex:p2/rdf:rest*/rdf:first ?missing }
}
}
""" .
I have multiple pairs of predicates to which this constraint can apply,
so I wanted to make a generic constraint component which can take each
of the two predicates as parameters. This is how I tried to model that:
:ListMatchConstraintComponent
a sh:ConstraintComponent ;
sh:parameter [
sh:path ex:unorderedPredicate ;
] ;
sh:parameter [
sh:path ex:listPredicate ;
] ;
sh:nodeValidator [
a sh:SPARQLSelectValidator ;
sh:select """
SELECT $this ?missing
WHERE {
{
$this $listPredicate/rdf:rest*/rdf:first ?missing
MINUS
{ $this $unorderedPredicate ?missing }
}
UNION
{
$this $unorderedPredicate ?missing
MINUS
{ $this $listPredicate/rdf:rest*/rdf:first ?missing }
}
}
"""
] .
For each predicate pair constraint, I create a shape like this:
:P1P2ListMatchConstraint
a sh:NodeShape ;
:unorderedPredicate ex:p1 ;
:listPredicate ex:p2 .
However, when I run `shacl validate` for the graph against this shape, I
see the result:
$ shacl v -s shape.ttl -d graph.ttl
org.apache.jena.shacl.parser.ShaclParseException: Bad query: Encountered
" "/" "/ "" at line 8, column 27.
Was expecting one of:
<IRIref> ...
<PNAME_NS> ...
<PNAME_LN> ...
<BLANK_NODE_LABEL> ...
<VAR1> ...
<VAR2> ...
"true" ...
"false" ...
<INTEGER> ...
<DECIMAL> ...
<DOUBLE> ...
<INTEGER_POSITIVE> ...
<DECIMAL_POSITIVE> ...
<DOUBLE_POSITIVE> ...
<INTEGER_NEGATIVE> ...
<DECIMAL_NEGATIVE> ...
<DOUBLE_NEGATIVE> ...
<STRING_LITERAL1> ...
<STRING_LITERAL2> ...
<STRING_LITERAL_LONG1> ...
<STRING_LITERAL_LONG2> ...
"(" ...
<NIL> ...
"[" ...
<ANON> ...
"<<" ...
I am guessing that the values for the parameters in the constraint
($unorderedPredicate, $listPredicate) are not allowed to be in SPARQL
property paths (e.g. $this $listPredicate/rdf:rest*/rdf:first ?missing).
Is that the case? Are there alternative ways to achieve what I'm trying
to do?
Thank you,
Patrick