@hydrofoil/shape-to-query Conceptual Guides

Living Document,

This version:
https://shape-to-query.hypermedia.app/concepts/
Issue Tracking:
GitHub
Inline In Spec
Editor:
Tomasz Pluskiewicz

Abstract

This document explains patterns useful when building shapes using SHACL Advanced Features

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.

Using Property Value Expression to populate 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.

Node expression reused
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

TODO

1.3. SHACL Function metadata

describe function properties based on https://datashapes.org/sparql

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

References

Normative References

[RDF11-PRIMER]
Guus Schreiber; Yves Raimond. RDF 1.1 Primer. 24 June 2014. NOTE. URL: https://www.w3.org/TR/rdf11-primer/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119

Informative References

[SHACL-AF]
Holger Knublauch; Dean Allemang; Simon Steyskal. SHACL Advanced Features 1.1 (draft). 8 March 2024. Community Group Draft Report. URL: https://w3c.github.io/shacl/shacl-af/

Issues Index

TODO
describe function properties based on https://datashapes.org/sparql