Stand-alone Shapes and oslc:valueRange implemented in SPIN

[Starting a new thread on this specific solution, extending on [1] ]

I have implemented a new SPIN property function spin:constructViolations 
and a helper function spl:violatesConstraints, and those have allowed me 
to implement oslc:valueRange as defined by the Resource Shapes 2.0 spec. 
The implementation and an example file are attached.

In the example, we have :Issue pointing at :Person via two properties 
:assignedTo and :submittedBy. Both are Persons, but submitters may not 
have last name or email, but assignees must have those. This is modeled via

   rdf:type owl:Class ;
   spin:constraint [
       rdf:type oslc:Property ;
       oslc:propertyDefinition oslc_issue:assignedTo ;
       oslc:range oslc_issue:Person ;
       oslc:valueRange oslc_issue:Assignee ;
     ] ;
   spin:constraint [
       rdf:type oslc:Property ;
       oslc:propertyDefinition oslc_issue:submittedBy ;
       oslc:range oslc_issue:Person ;
       oslc:valueRange oslc_issue:Submitter ;
     ] ;
   rdfs:label "Issue"^^xsd:string ;
   rdfs:subClassOf owl:Thing .

which means although the range of both properties is Person, different 
additional constraints are used depending on the context. Here is Assignee:

   rdf:type owl:Class ;
   spin:constraint [
       rdf:type oslc:Property ;
       oslc:occurs oslc:Exactly-one ;
       oslc:propertyDefinition oslc_issue:email ;
     ] ;
   spin:constraint [
       rdf:type oslc:Property ;
       oslc:occurs oslc:Exactly-one ;
       oslc:propertyDefinition oslc_issue:lastName ;
     ] ;
   rdfs:comment "All assignees must have an email and a last 
name."^^xsd:string ;
   rdfs:label "Assignee"^^xsd:string ;
   rdfs:subClassOf oslc_issue:Person .

This :Assignee class doesn't need to be part of the actual ontology - it 
may just live in a SPIN file that isn't visible to end users.

The actual context-sensitive check behind oslc:valueRange is implemented 

         CONSTRUCT {
             _:cv a spin:ConstraintViolation ;
                 spin:violationRoot ?this ;
                 spin:violationPath ?propertyDefinition ;
                 rdfs:label ?label .
             ?s ?p ?o .
         WHERE {
             ?this ?propertyDefinition ?value .
             (?value ?valueRange) spin:constructViolations (?s ?p ?o)
             BIND (CONCAT("Value ", xsd:string(?value), " of property ",
                  xsd:string(?propertyDefinition), " does not match the 
shape ",
                  xsd:string(?valueRange)) AS ?label) .

where spin:constraintViolations essentially spawns off a recursive 
constraint checking engine to verify that the given ?value meets all 
constraints defined at the class ?valueRange. Any nested constraint 
violations get propagated forward in the surrounding CONSTRUCT. But 
nobody needs to look into those details - they can be solved by a shapes 

The cost of this solution is that engines who want to support this would 
need to implement the spin:constructViolations property function. There 
is currently no official extension mechanism in SPARQL for property 
functions, but many SPARQL databases actually have this implemented as a 
de-facto standard. Yet we would need to somehow specify this. If we 
cannot use property functions (aka magic properties) then we could make 
it a normal SPARQL function that returns a temporary named graph or 
maybe just a boolean, so it will definitely work even with the current 
SPARQL language spec in one way or another.

Anyway, the extension above is now in the TopBraid code base and will go 
into the next SPIN API for Jena too.

This means that SPIN can now be used to check an instance against a 
certain "shape" even if the instance doesn't have a corresponding rdf:type.

I would appreciate feedback from those in the Shapes/ShEx camp. What 
else is needed?



Received on Thursday, 20 November 2014 00:52:09 UTC