TopQuadrant / shacl

SHACL API in Java based on Apache Jena
Apache License 2.0
214 stars 61 forks source link

Custom ConstraintComponents not triggered when used in sh:or ? #106

Closed tfrancart closed 3 years ago

tfrancart commented 3 years ago

Hello

I have the feeling that custom constraint components are not triggered properly when used inside sh:or. Given a custom SPARQL Constraint Component with parameter ex:parameter :

ex:MyConstraintComponent
  rdf:type sh:ConstraintComponent ;
  rdfs:label "Sample" ;
  sh:parameter [
      sh:path ex:parameter ;
    ] ;
  sh:propertyValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "..." ;
      sh:select """
            SELECT ?this ?value WHERE { ... }
            """ ;
    ] ;
.

The following works and triggers a violation :

ex:ShapeThatWorksAsExpected
    a sh:NodeShape ;
    sh:property [
        sh:path ex:myProperty ;
        ex:parameter ex:foo ;
    ]
.

But the following does not :

ex:ShapeThatDoesNotWorksAsExpected
    a sh:NodeShape ;
    sh:property [
        sh:path ex:myProperty ;
        sh:or (
            [ ex:parameter ex:foo ; ]
            [ ex:parameter ex:bar ; ]
        ) ;
    ]
.

The violation is simply not triggered anymore.

Could this be the case ? given that the constraint components expects a binding for $PATH, do we need to be more explicit in the alternatives of the sh:or and respecify the sh:path explicitely ?

tfrancart commented 3 years ago

OK, this works :

ex:ShapeThatWorksAlso
    a sh:NodeShape ;
    sh:or (
        [ sh:path ex:myProperty; ex:parameter ex:foo;]
        [ sh:path ex:myProperty; ex:parameter ex:bar;]
    )
.

Isn't it strange, as one does not need to use this workaround for core constraint components on property shapes, as shown in the second example of spec at https://www.w3.org/TR/shacl/#OrConstraintComponent ?

HolgerKnublauch commented 3 years ago

I think the implementation is correct. If you are using sh:or then the sh:path of the surrounding sh:property is NOT propagated into the nested property shapes of the or. In your first example with sh:or ( [ ex:parameter ex:foo ] ) the inner [] is a node shape, and that node shape cannot be executed if only a sh:propertyValidator is provided. The node shape will be validated against each value node. So for example sh:or ( [ sh:datatype xsd:string ] ) can work OK, because sh:datatype can also be executed as a node shape against individual values.

However, in the second example each nested shape in the sh:or is a property shape because it has a sh:path, and that sh:path is required to make it work.

tfrancart commented 3 years ago

Thank you, a bit odd at first, but this makes sense. without an sh:path, the members of the sh:or are NodeShapes, so a custom constraint component need to use sh:nodeValidator and not sh:propertyValidator.

The confusing thing is that when using an sh:or inside a propertyShape, the shapes inside are not property shapes anymore, but node shapes...

So actually if my custom constraint validator needs to be used at both places (inside sh:or or not), it needs to provide both a sh:propertyValidator and a sh:nodeValidator.