1. Conceptual Guides
1.1. Shape reuse
While working with [SHACL-AF] you may sometimes find repeatable patterns which deal with similar data. Such scenarios can easily lead to duplication as seen below.
hydra:member
and hydra:totalItems
properties of a collection
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX schema: <http://schema.org/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX hydra: <http://www.w3.org/ns/hydra/core#> PREFIX sh: <http://www.w3.org/ns/shacl#> <http://example.com/people> a hydra : Collection ; hydra : memberAssertion [ hydra : property rdf : type ; hydra : object schema : Person ; ] ; . [ a sh : NodeShape ; sh : targetNode <http://example.com/people> ; sh : property [ sh : path hydra : member ; sh : values [ sh : path [ sh : inversePath rdf : type ] ; sh : nodes [ sh : path hydra : object ; sh : nodes [ sh : filterShape [ sh : property [ sh : path hydra : property ; sh : hasValue rdf : type ] ; ] ; sh : nodes [ sh : path ( [ sh : zeroOrMorePath rdf : type ] hydra : memberAssertion ) ; ] ; ] ; ] ; ] ; ], [ sh : path hydra : totalItems ; sh : values [ rdfs : label "count" ; sh : count [ sh : path [ sh : inversePath rdf : type ] ; sh : nodes [ sh : path hydra : object ; sh : nodes [ sh : filterShape [ sh : property [ sh : path hydra : property ; sh : hasValue rdf : type ] ; ] ; sh : nodes [ sh : path ( [ sh : zeroOrMorePath rdf : type ] hydra : memberAssertion ) ; ] ; ] ; ] ; ] ; ] ; ] ; ] .
PREFIX rdf : <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX hydra : <http://www.w3.org/ns/hydra/core#> CONSTRUCT { ?resource1 hydra : member ?resource2 . ?resource1 hydra : totalItems ?resource7 . } WHERE { VALUES ?resource1 { <http://example.com/people> } { ?resource1 (( rdf : type * ) / hydra : memberAssertion ) ?resource4 . ?resource4 hydra : property ?resource6 . VALUES ?resource6 { rdf : type } ?resource4 hydra : object ?resource3 . ?resource3 ^ rdf : type ?resource2 . } UNION { SELECT ( COUNT ( ?resource8 ) AS ?resource7 ) WHERE { ?resource1 (( rdf : type * ) / hydra : memberAssertion ) ?resource10 . ?resource10 hydra : property ?resource12 . VALUES ?resource12 { rdf : type } ?resource10 hydra : object ?resource9 . ?resource9 ^ rdf : type ?resource8 . VALUES ?resource1 { <http://example.com/people> } } } }
In this not so trivial example you can see how many triples need to be duplicated to represent the node expression which retrieves all elements of a collection. Once, used to find the actual members of that collection (people) and second time to get their count.
This can be reduced by extracting the common node expression into a separate blank node and referencing it in the two properties.
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX schema: <http://schema.org/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX hydra: <http://www.w3.org/ns/hydra/core#> PREFIX sh: <http://www.w3.org/ns/shacl#> <http://example.com/people> a hydra : Collection ; hydra : memberAssertion [ hydra : property rdf : type ; hydra : object schema : Person ; ] ; . [ a sh : NodeShape ; sh : targetNode <http://example.com/people> ; sh : property [ sh : path hydra : member ; sh : values _: collectionMembers ; ], [ sh : path hydra : totalItems ; sh : values [ sh : count _: collectionMembers ] ; ] ; ] . _: collectionMembers sh : path [ sh : inversePath rdf : type ] ; sh : nodes [ sh : path hydra : object ; sh : nodes [ sh : filterShape [ sh : property [ sh : path hydra : property ; sh : hasValue rdf : type ] ; ] ; sh : nodes [ sh : path ( [ sh : zeroOrMorePath rdf : type ] hydra : memberAssertion ) ] ; ] ; ] ; .
PREFIX rdf : <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX hydra : <http://www.w3.org/ns/hydra/core#> CONSTRUCT { ?resource1 hydra : member ?resource2 . ?resource1 hydra : totalItems ?resource7 . } WHERE { VALUES ?resource1 { <http://example.com/people> } { ?resource1 (( rdf : type * ) / hydra : memberAssertion ) ?resource4 . ?resource4 hydra : property ?resource6 . VALUES ?resource6 { rdf : type } ?resource4 hydra : object ?resource3 . ?resource3 ^ rdf : type ?resource2 . } UNION { SELECT ( COUNT ( ?resource8 ) AS ?resource7 ) WHERE { ?resource1 (( rdf : type * ) / hydra : memberAssertion ) ?resource10 . ?resource10 hydra : property ?resource12 . VALUES ?resource12 { rdf : type } ?resource10 hydra : object ?resource9 . ?resource9 ^ rdf : type ?resource8 . VALUES ?resource1 { <http://example.com/people> } } } }
1.2. Creating a more efficient DSL on top of SHACL-AF
1.3. SHACL Function metadata
describe function properties based on https://datashapes.org/sparql