ISSUE-135: Proposed changes to implement syntax simplification

Several WG members supported the idea of allowing constraints to be used 
as values in places such as sh:or. I was asked to make some specific 
suggestions on what would need to be changed in the spec, so that the 
following syntax options would behave identically. (Both scenarios state 
that the values of schema:address must be string literals or instances 
of schema:Address):

a) Currently supported: sh:or can only be used with sh:NodeConstraints 
and operands of sh:or must be shapes

ex:MyShape
     a sh:Shape ;
     sh:constraint [
         sh:or (
             [ a sh:Shape ;
                 sh:property [
                     sh:predicate schema:address ;
                     sh:datatype xsd:string ;
                 ] ;
             ]
             [ a sh:Shape ;
                 sh:property [
                     sh:predicate schema:address ;
                     sh:class schema:Address ;
                 ] ;
             ]
         )
     ]

which lacks on multiple fronts - it is too verbose and also forces 
repetition of the predicate.

b) Proposed: generalize sh:or and values of sh:or may be constraints of 
the same kind as the surrounding constraint.

ex:MyShape
     a sh:Shape ;
     sh:property [
         sh:predicate schema:address ;
         sh:or (
             [ sh:datatype xsd:string ]
             [ sh:class schema:Address ]
         )
     ]

In this proposal, the members of the sh:or List may be 
sh:PropertyConstraints if sh:or is used within a sh:PropertyConstraint.

Required changes (all incremental to current spec):

1) Generalize sh:hasShape from sh:hasShape(?node, ?shape, ?shapesGraph) to

     sh:validateNode(?node, ?shapeOrConstraint, ?shapesGraph, 
?defaultConstraintType, ?defaultPredicate)

The two arguments at the end are optional, and are used to complement 
the provided ?shapeOrConstraint unless it is a sh:Shape. Legal values 
for ?defaultConstraintType would be sh:PropertyConstraint, 
sh:InversePropertyConstraint and sh:NodeConstraint. ?defaultPredicate is 
only supported if ?defaultConstraintType is given and != sh:NodeConstraint.

The algorithm would be

a) if ?shapeOrConstraint rdf:type sh:Shape, then behave as currently
b) otherwise, assume ?defaultConstraintType (unless the node has an 
rdf:type)
     and assume ?defaultPredicate for sh:predicate.
c) report failure if the node has rdf:type that is neither sh:Shape nor 
?defaultConstraintType.

While this function isn't pretty it's mostly used internally anyway and 
may therefore be regarded as an implementation detail. The name 
sh:validateNode is better than sh:hasShape because it may also return 
unbound.

2) Generalize sh:or to also have contexts: sh:PropertyConstraint and 
sh:InversePropertyConstraint

3) Add a sh:propertyValidator to sh:OrConstraint similar to what we have 
as sh:nodeValidator, but with the sh:validateNode function:

SELECT $this ?failure ...
WHERE {
   {
  $this $predicate ?value .
 }
  {
  SELECT (SUM(?s) AS ?count)
  WHERE {
   GRAPH $shapesGraph {
    $or rdf:rest*/rdf:first ?shape .
   }
   BIND (sh:validateNode(?value, ?shape, $shapesGraph, sh:PropertyConstraint, $predicate) AS ?valid) .
   BIND (IF(bound(?valid), IF(?valid, 1, 0), 'error') AS ?s) .
  }
 }
 BIND (!bound(?count) AS ?failure) .
 FILTER IF(?failure, true, ?count = 0) .
}


and similar for sh:inversePropertyValidator. The same approach would 
work for sh:and and sh:not. I guess also for sh:valueShape if that's 
desirable.

Regards,
Holger

Received on Thursday, 5 May 2016 02:50:31 UTC