Testing contingent properties in SHACL

20 views
Skip to first unread message

Gary Murphy

unread,
Feb 19, 2020, 4:31:38 PM2/19/20
to TopBraid Suite Users
I have an application where I use the validation sh:resultPath to display violation messages, but I've hit a conundrum with dependent/contingent properties

a simple example: schema:AggregateRating can have either or both of ratingCount and reviewCount, with a structure as follows:

  {
    "@context": { "@vocab": "http://schema.org/" },
   "@type": "AggregateRating",
    "ratingCount": 25,
    "ratingValue": "3.5",
    "reviewCount": 5,
    "@id": "http://schemaapp.com/db/SchemaApp#AggregateRating"
}

what I would like to do is to attach a PropertyShape with a sh:path schema:reviewCount that will pass if either (or both) properties are present, but return a violation (with sh:resultPath schema:reviewCount) if both are missing

It was very easy to phrase using sh:alternativePath in a NodeShape, but that gives the sh:alternativePath blank node as the resultPath.  I might be stuck with that, but hoping there's a way to do it the way I need
--
Gary Lawrence Murphy <ga...@schemaapp.com> - Hunch Manifest, 15 Wyndham N 'C', Guelph

Holger Knublauch

unread,
Feb 19, 2020, 8:21:45 PM2/19/20
to topbrai...@googlegroups.com

I think a path of ratingCount|reviewCount with sh:minCount 1 is the cleanest approach. So if the blank node isn't very meaningful yet, maybe you'd need to adjust the results display accordingly? You could also specify a nice sh:message to explain what's really going on at the property shape.

ex:AggregateRatingShape
    a sh:NodeShape ;
    sh:targetClass schema:AggregateRating ;
    sh:property [
        sh:path [ sh:alternativePath ( schema:ratingCount schema:reviewCount ) ] ;
        sh:minCount 1 ;
        sh:message "AggregateRating can have either or both of ratingCount and reviewCount" ;
    ] .

Of course you'd also need the individual property shapes for the two properties, with no sh:minCount.

Alternatively, use sh:or at the node shape, yet that might even be more complicating.

Holger

--
You received this message because you are subscribed to the Google Groups "TopBraid Suite Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to topbraid-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/topbraid-users/CADnyxpsmyhQ7j7-qYDdu87iPvQ6Fo09je97%3DStwqzK3cj5N55Q%40mail.gmail.com.

Gary Murphy

unread,
Feb 20, 2020, 9:25:16 AM2/20/20
to TopBraid Suite Users
Yes, that was my original approach, but since the path is reported as a blank node, the alternativePath itself, and not the specific alternative that tripped the violation, I've lost the path information.  I know it is an unusual and extraneous demand, but legacy code wants to know ....

using the message to decide is an awkward possibility. It means dual-purposing a data item and it also forms a technical debt should the application someday support other languages.

I also tried convoluted paths in hopes of chaining inversePath with the alternate as a path list, and then using that in an sh:or like 

sh:path schema:ratingCount ;
sh:or ( 
    [ sh:path ( [ sh:inversePath schema:ratingCount ] schema:reviewCount ) ; minCount 1 ]
    [ sh:minCount 1 ]
);

but needless to say that didn't work either.  It seemed like a good idea at the time, and I'm not at all certain I fully understand inversePath, but when the engine gets to the second sh:or case I think it is saying that it doesn't know who this minCount is referencing.

Gary Murphy

unread,
Feb 20, 2020, 3:04:43 PM2/20/20
to TopBraid Suite Users
Just to follow up on that last example, which even I don't think should ever work, here's another that I was nearly certain would do something:

ex:AggregateRatingShape
  a sh:NodeShape ;
  sh:property [
      sh:path schema:reviewCount ;
      sh:or (
        [ sh:minCount 1 ]
        [ sh:node [
            sh:property [
              sh:path (
                [ sh:inversePath schema:reviewCount ]
                schema:ratingCount );
              sh:minCount 1 ;
            ] ;
          ];
        ]      
      ) ;
    ];
  sh:targetClass schema:AggregateRating ;
.

And this is where I'd like to ask some naive questions about sh:inversePath

in the parent/child example, the schema:children triple doesn't actually exist however the value is inferred, given sh:values by tracing an incoming sh:inversePath schema:parent.  Is it fair to say that a sh:property (or PropertyShape) uses sh:path to "place the context pointer" at the Object value? (ie ?s ?path ?Object)  and so we test datatype, class etc of that graph node, and sh:node would place us also at that Object?  I had hoped that from sh:node I could draw a sh:inversePath back to give me the ?s of this triple, ie the instance of the class that the NodeShape lists as sh:targetClass, and so, from there, I had hoped to draw a new sh:path out to that alternate schema:ratingCount value to test for a minCount.  I get confused just describing it.

if I use sh:inversePath at the sh:NodeShape level (outside of sh:property blocks) does this make the context now some subject ?s that links to this sh:targetClass instance via the property provided as the 'argument' to sh:inversePath, while using it within sh:PropertyShape it is referring to ?Object indicated by the shape's sh:path?

I'm thinking that what I really want to do is use sh:sparql or sh:ask ...

Holger Knublauch

unread,
Feb 20, 2020, 9:59:28 PM2/20/20
to topbrai...@googlegroups.com


On 21/02/2020 06:04, Gary Murphy wrote:
Just to follow up on that last example, which even I don't think should ever work, here's another that I was nearly certain would do something:

ex:AggregateRatingShape
  a sh:NodeShape ;
  sh:property [
      sh:path schema:reviewCount ;
      sh:or (
        [ sh:minCount 1 ]
        [ sh:node [
            sh:property [
              sh:path (
                [ sh:inversePath schema:reviewCount ]
                schema:ratingCount );
              sh:minCount 1 ;
            ] ;
          ];
        ]      
      ) ;
    ];
  sh:targetClass schema:AggregateRating ;
.

And this is where I'd like to ask some naive questions about sh:inversePath

in the parent/child example, the schema:children triple doesn't actually exist however the value is inferred, given sh:values by tracing an incoming sh:inversePath schema:parent.  Is it fair to say that a sh:property (or PropertyShape) uses sh:path to "place the context pointer" at the Object value? (ie ?s ?path ?Object)  and so we test datatype, class etc of that graph node, and sh:node would place us also at that Object?  I had hoped that from sh:node I could draw a sh:inversePath back to give me the ?s of this triple, ie the instance of the class that the NodeShape lists as sh:targetClass, and so, from there, I had hoped to draw a new sh:path out to that alternate schema:ratingCount value to test for a minCount.  I get confused just describing it.

if I use sh:inversePath at the sh:NodeShape level (outside of sh:property blocks) does this make the context now some subject ?s that links to this sh:targetClass instance via the property provided as the 'argument' to sh:inversePath, while using it within sh:PropertyShape it is referring to ?Object indicated by the shape's sh:path?

I'm thinking that what I really want to do is use sh:sparql or sh:ask ...

Yes, I agree with the latter statement. That's what SHACL-SPARQL was added for, and you don't need to artificially try to get inferences, path expressions and target statements right. Note that sh:values rules are not applied by default during validation.

Holger


Reply all
Reply to author
Forward
0 new messages