My solution was to just break up the list-lookup part of the SPARQL query into two elements:

$this $listPredicate ?listHead .
?listHead rdf:rest*/rdf:first ?missing .

Easy enough!

On 8/23/21 12:11 PM, Patrick Golden wrote:
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

Reply via email to