w3c / shacl

SHACL Community Group (Post-REC activitities)
27 stars 4 forks source link

SHACL constraint example for nested lists? #17

Closed devonsparks closed 7 months ago

devonsparks commented 1 year ago

Does anyone have a snippet showing how to validate lists of lists? TopQuadrant gives a nice example for single lists:

ex:TrafficLightShape
    a sh:NodeShape ;
    sh:targetClass ex:TrafficLight ;
    sh:property [
        sh:path ex:colors ;
        sh:node dash:ListShape ;
        sh:property [
            sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ;
            sh:datatype xsd:string ;
            sh:minLength 1 ;
            sh:minCount 2 ;
            sh:maxCount 3 ;
        ]
    ] .

For example, suppose I want to validate a list of lists, such that:

My initial instinct was that the sh:property within sh:path should itself have an sh:property, but this isn't giving the result I expected. Something like

ex:TrafficLightShape
    sh:targetClass ex:TrafficLight ;
    sh:property [
        sh:path ex:colors ;
        sh:property [
            sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ;

            sh:minCount 2 ;
            sh:maxCount 2 ;

             sh:property [
                sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ;
                sh:datatype xsd:string ;
                sh:minLength 1 ;
                sh:minCount 3 ;
                sh:maxCount 3 ;
            ]
        ]
    ] .

The correspondence instance data would look like:

@prefix ex: <http://example.com/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dash: <http://datashapes.org/dash#> .

ex:MyTrafficLight
    a ex:TrafficLight ;
    ex:colors ( ( "red" "yellow" "green") ("blue" "purple" "black" ) ) .

Does anyone have an instinct how to write SHACL constraints for nested lists? Thanks!

lucascool12 commented 8 months ago

In your ex:MyTrafficLight shape the property shape that would constrain the nested lists is missing a rdf:first in the sequence path. If you create the rdf list without the syntactic sugar from turtle like in the data graph below you can see why. Do note that for some reason the zazuko shacl validator says the data graph does not conform to the shape graph. Whilst pyshacl saying it does and my own reasoning engine (my brain) does not see the reason why this would not validate.

edit 2: uuhm this does not seem to be a valid answer to your question, pyshacl says it conforms but when changing the minCount to something higher than 3 I would expect it to not conform but this is not the case. This shapes graph does not seem to be malformed SHACL as far as I and shacl-shacl is aware so I have no clue what is going on here,

Shape graph:

@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix schema: <http://schema.org/> .
@prefix ex: <http://example.org/> .
@prefix dash: <http://datashapes.org/dash#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ex:TrafficLightShape
    a sh:NodeShape ;
    sh:targetClass ex:TrafficLight ;
    sh:property [
        sh:path ex:colors ;
        # sh:node dash:ListShape ;
        sh:property [
            sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ;
            sh:property [
              sh:path ( rdf:first [ sh:zeroOrMorePath rdf:rest ] rdf:first );
              sh:datatype xsd:string;
              sh:minCount 2;
        ];
            # sh:minLength 1 ;
            sh:minCount 2 ;
        ]
    ] .

Data graph:

@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix schema: <http://schema.org/> .
@prefix ex: <http://example.org/> .
@prefix dash: <http://datashapes.org/dash#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ex:t a ex:TrafficLight;
    # ex:colors (("a" "b" "c") ("d" "e" "f")).
    ex:colors _:a .

_:a rdf:first _:b ;
    rdf:rest _:c .

_:b rdf:first "a" ;
    rdf:rest _:f .

_:f rdf:first "b";
    rdf:rest _:g .

_:g rdf:first "c";
    rdf:rest rdf:nil .

_:c rdf:first _:d ;
    rdf:rest rdf:nil .

_:d rdf:first "d" ;
    rdf:rest _:i .

_:i rdf:first "e";
    rdf:rest _:j .

_:j rdf:first "f";
    rdf:rest rdf:nil .

edit: weird formatting

lucascool12 commented 8 months ago

I revisited this, your own answer seems to work like I expected it would. Maybe the validator you were using was having some issues?

devonsparks commented 7 months ago

Yes, strange. Revisiting this a year later, the original sample seems to work fine. It may have been the validator's conformance at the time. Appreciate the consult :)