Re: Direct nesting of PropertyShapes inside each other

Hello Phil,

Maybe it would help to have a little extra annotation?  I’ll add and mark a few lines.

```turtle
ex:PersonShape
                a sh:NodeShape ;
                sh:targetClass ex:Person ;
                sh:property [   # _:b1
                                a sh:PropertyShape ;  # AJN: This type statement is not required, but I’ve found it helpful for “self-documenting” code.
                                sh:path ex:address ;
                                sh:minCount 1 ;
                                sh:property [ # can we use sh:property here instead of an intervening sh:node?  AJN: Yes, but might look odd.
                                                                a sh:PropertyShape ;  # AJN: Again, type is not required; sh:path IS required.
                                                                sh:path ex:postalCode;
                                                                sh:maxCount 1
                                ]
] .  #AJN: Typo, second closing bracket needed.
```

This IS valid SHACL, and will get you what you want in terms of violation *counts*.  But, it might not get you what you want in terms of explainability of data issues.  Try running that shapes graph against this data graph:

```turtle
# Conformant.
ex:person-1
        a ex:Person ;
        ex:address [ ] ;
        .

# Conformant.
ex:person-2
        a ex:Person ;
        ex:address [
                ex:postalCode "12345" ;
        ] ;
        .

# Non-conformant.
ex:person-3
        a ex:Person ;
        ex:address [
                ex:postalCode "12345" ;
                ex:postalCode "54321" ;
        ] ;
        .
```

Contrast that with this graph, which uses the “Intervening” / intermediary `sh:node` you’d considered as an alternative:

```turtle
ex:PersonShapeWithInterveningNode
                a sh:NodeShape ;
                sh:targetClass ex:Person ;
                sh:property [   # _:b1
                                a sh:PropertyShape ;
                                sh:path ex:address ;
                                sh:minCount 1 ;
                                sh:node [
                                                a sh:NodeShape ;  # AJN: Again, type not necessary.
                                                sh:property [
                                                                a sh:PropertyShape ;
                                                                sh:path ex:postalCode ;
                                                                sh:maxCount 1 ;
                                                ] ;
                                ]
                ] .
```

Have a look at which shape-spelling gives you the `sh:focusNode` that would help you remedy data issues, just from looking at `sh:ValidationResult`s.  You should be able to run all 3 of these snippets in one shape-and-data graph evaluating itself, and my understanding of `sh:property` on a `sh:PropertyShape` is that the focus node might not be the most helpful in locating the actual triple in some cases.  I engineered one such case with the example individuals.
My understanding of what should happen is that your original graph flags the blank node attached to `ex:person-3` as the `sh:focusNode` in the validation result, but doesn’t necessarily note `ex:person-3`; so, rectifying the data may take a SPARQL query to find the node if the literals aren’t distinct enough.

Likely what you want instead is a qualified shape, which works linking either a node shape or property shape:

```turtle
ex:PersonShapeWithQualificationLinkingNS
                a sh:NodeShape ;
                sh:targetClass ex:Person ;
                sh:property [   # _:b1
                                a sh:PropertyShape ;
                                sh:path ex:address ;
                                sh:qualifiedMinCount 1 ;
                                sh:qualifiedValueShape [
                                        a sh:NodeShape ;  # AJN: Again, type not necessary.
                                        sh:property [
                                                                a sh:PropertyShape ;  # AJN: Again, type not necessary.
                                                                sh:path ex:postalCode ;
                                                                sh:maxCount 1 ;
                                        ] ;
                                ] ;
                ] .

ex:PersonShapeWithQualificationLinkingPS
                a sh:NodeShape ;
                sh:targetClass ex:Person ;
                sh:property [   # _:b1
                                a sh:PropertyShape ;
                                sh:path ex:address ;
                                sh:qualifiedMinCount 1 ;
                                sh:qualifiedValueShape [
                                        a sh:PropertyShape ;  # AJN: Again, type not necessary.
                                        sh:path ex:postalCode ;
                                        sh:maxCount 1 ;
                                ] ;
                ] .
```

I hope that helps.

--Alex


From: Harvey, Philip <philip.harvey@jpmorgan.com>
Date: Thursday, February 27, 2025 at 7:56 AM
To: public-shacl@w3.org <public-shacl@w3.org>
Subject: Direct nesting of PropertyShapes inside each other
I don’t fully understand SHACL’s semantics for nesting PropertyShapes and am hoping someone can clarify it for me.

There are some examples of nested properties in the spec, such as the Person/Address example in https://www.w3.org/TR/shacl/#NodeConstraintComponent (pasted below).

Is it legal to nest PropertyShape’s directly, i.e. can I rewrite that Person/Address example as:

-----
ex:PersonShape
                a sh:NodeShape ;
                sh:targetClass ex:Person ;
                sh:property [   # _:b1
                                sh:path ex:address ;
                                sh:minCount 1 ;
                                sh:property [ # can we use sh:property here instead of an intervening sh:node?
                                                                sh:path ex:postalCode;
                                                                sh:maxCount 1
                                ] .
-----

I assume this pattern is not legal, mainly because it never appears in the spec examples. The (non-normative) class diagram also suggests sh:property is only legal in NodeShapes (but shacl.ttl has gives sh:property a domain of sh:Shape, not NodeShape).

But perhaps more importantly I don’t understand at a conceptual level why this would not be allowed. I suspect this relates to how ‘value nodes’ are defined, but am not sure.

Thanks
Phil

This message is confidential and subject to terms at: https://www.jpmorgan.com/emaildisclaimer including on confidential, privileged or legal entity information, malicious content and monitoring of electronic messages. If you are not the intended recipient, please delete this message and notify the sender immediately. Any unauthorized use is strictly prohibited.

Received on Thursday, 27 February 2025 15:46:26 UTC