@hydrofoil/shape-to-query

Living Document,

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

Abstract

Library for generating SPARQL from SHACL Shapes

1. Introduction

The library translates SHACL Node Shapes to SPARQL Queries in the form of CONSTRUCT and DELETE.

2. Getting started

2.1. Installation

The library is written in TypeScript and distributed as an NPM package:

npm i --save @hydrofoil/shape-to-query

2.2. Basic usage

import type { GraphPointer } from 'clownface'
import { constructQuery } from '@hydrofoil/shape-to-query'

let shape: GraphPointer

const queryString = constructQuery(shape).build()

2.3. About examples below

All the examples shown in this documentation are based on a toy dataset tbbt-ld which contains resources describing characters from the TV series The Big Bang Theory. To look nicer, the localhost URLs have been replaced with fictitious a tbbt.tv domain.

3. SHACL Constraints

Issue epic on GitHub [Issue #42]

3.1. Targets

Targets are used to match specific focus nodes of a given Node Shape. The most common, and natural way is to define a target of the root shape. However, targets declared in nested shapes, such as when using § 3.2.4 Logical Constraint Components or § 3.2.5.1 sh:node, can also be used to narrow down the query results.

Note: Multiple target types are combined with UNION

3.1.1. Node targets (sh:targetNode)

Note: SHACL spec: Shapes Constraint Language (SHACL) § targetNode

Whether there is one or multiple target nodes, a variable is used for the root focus node and the target nodes are provided as inline data using VALUES clause.

Multiple target nodes
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetNode tbbt:sheldon-cooper, tbbt:penny ;
  sh:property
    [
      sh:path schema:name ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT { ?resource1 schema:name ?resource2. }
WHERE {
  VALUES ?resource1 {
    <https://tbbt.tv/sheldon-cooper>
    <https://tbbt.tv/penny>
  }
  ?resource1 schema:name ?resource2.
}

3.1.2. Class-based Targets (sh:targetClass)

Note: SHACL spec: Shapes Constraint Language (SHACL) § targetClass

Single target class is directly matched with the focus node

Target resources of type schema:Person
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path schema:name ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 schema:name ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Person;
    schema:name ?resource2.
}

Multiple target classes are rendered as VALUES

Target resources of type schema:Person and foaf:Person
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person, foaf:Person ;
  sh:property
    [
      sh:path schema:name ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
CONSTRUCT {
  ?resource1 rdf:type ?resource2.
  ?resource1 schema:name ?resource3.
}
WHERE {
  ?resource1 rdf:type ?resource2.
  VALUES ?resource2 {
    schema:Person
    foaf:Person
  }
  ?resource1 schema:name ?resource3.
}

3.1.3. Subjects-of targets (sh:targetSubjectsOf)

Note: SHACL spec: Shapes Constraint Language (SHACL) § targetSubjectsOf

Targets resources which are the subject of a given predicate

Find resources which are parents
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetSubjectsOf schema:parent ;
  sh:property
    [
      sh:path schema:name ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:parent ?resource2.
  ?resource1 schema:name ?resource3.
}
WHERE {
  ?resource1 schema:parent ?resource2;
    schema:name ?resource3.
}

3.1.4. Subjects-of targets (sh:targetObjectsOf)

Note: SHACL spec: Shapes Constraint Language (SHACL) § targetObjectsOf

Targets resources which are the object of a given predicate

Find resources which are children
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetObjectsOf schema:children ;
  sh:property
    [
      sh:path schema:name ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource2 schema:children ?resource1.
  ?resource1 schema:name ?resource3.
}
WHERE {
  ?resource2 schema:children ?resource1.
  ?resource1 schema:name ?resource3.
}

3.2. Core Constraint Components

3.2.1. Value Type Constraint Components

3.2.1.1. sh:class

Note: SHACL spec: Shapes Constraint Language (SHACL) § ClassConstraintComponent

Restrict objects of a property to a specific class
PREFIX ch: <https://schema.ld.admin.ch/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass ch:Canton ;
  sh:property
    [
      sh:path schema:containsPlace ;
      sh:class ch:Municipality ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Canton>.
  ?resource1 schema:containsPlace ?resource2.
}
WHERE {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Canton>;
    schema:containsPlace ?resource2.
  ?resource2 rdf:type <https://schema.ld.admin.ch/Municipality>.
}
Restrict focus node to instances of a specific class
PREFIX ch: <https://schema.ld.admin.ch/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass ch:Canton ;
  sh:property
    [
      sh:path schema:containsPlace ;
      sh:node
        [
          sh:class ch:Municipality ;
          sh:property
            [
              sh:path schema:name ;
              sh:hasValue "Schwytz" ;
            ]
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Canton>.
  ?resource1 schema:containsPlace ?resource2.
  ?resource2 schema:name ?resource3.
}
WHERE {
  {
    SELECT ?resource1 ?resource2 WHERE {
      ?resource1 rdf:type <https://schema.ld.admin.ch/Canton>;
        schema:containsPlace ?resource2.
      {
        ?resource2 schema:name ?resource3.
        VALUES ?resource3 {
          "Schwytz"
        }
        ?resource6 rdf:type <https://schema.ld.admin.ch/Municipality>.
      }
    }
  }
  UNION
  {
    SELECT ?resource2 ?resource3 WHERE {
      ?resource1 rdf:type <https://schema.ld.admin.ch/Canton>;
        schema:containsPlace ?resource2.
      ?resource2 schema:name ?resource3.
      {
        ?resource2 schema:name ?resource3.
        VALUES ?resource3 {
          "Schwytz"
        }
        ?resource6 rdf:type <https://schema.ld.admin.ch/Municipality>.
      }
    }
  }
}

Note: Similar can be achieved using sh:targetClass but it is more natural to use sh:class when nesting shapes with sh:node

3.2.1.2. sh:datatype

Note: SHACL spec: Shapes Constraint Language (SHACL) § DatatypeConstraintComponent

Restrict objects of a property to a specific datatype
PREFIX ch: <https://schema.ld.admin.ch/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

[
  a sh:NodeShape ;
  sh:targetClass ch:Municipality ;
  sh:property
    [
      sh:path schema:name ;
      sh:datatype xsd:string ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
CONSTRUCT {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>.
  ?resource1 schema:name ?resource2.
}
WHERE {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>;
    schema:name ?resource2.
  FILTER((DATATYPE(?resource2)) = xsd:string)
}
3.2.1.3. sh:nodeKind
Use sh:nodeKind to restrict focus node and property nodes
PREFIX ch: <https://schema.ld.admin.ch/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass ch:Canton ;
  sh:nodeKind sh:IRI ;
  sh:property
    [
      sh:path schema:containsPlace ;
      sh:nodeKind sh:BlankNode ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Canton>.
  ?resource1 schema:containsPlace ?resource2.
}
WHERE {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Canton>;
    schema:containsPlace ?resource2.
  FILTER(ISBLANK(?resource2))
  FILTER(ISIRI(?resource1))
}

3.2.2. Value Range Constraint Components

3.2.2.1. sh:minExclusive

Note: SHACL spec: Shapes Constraint Language (SHACL) § MinExclusiveConstraintComponent

Restrict objects of a property to a specific range
PREFIX ch: <https://schema.ld.admin.ch/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

[
  a sh:NodeShape ;
  sh:targetClass ch:Municipality ;
  sh:property
    [
      sh:path schema:identifier ;
      sh:minExclusive 250 ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>.
  ?resource1 schema:identifier ?resource2.
}
WHERE {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>;
    schema:identifier ?resource2.
  FILTER(?resource2 > 250 )
}
3.2.2.2. sh:minInclusive

Note: SHACL spec: Shapes Constraint Language (SHACL) § MinInclusiveConstraintComponent

Restrict objects of a property to a specific range
PREFIX ch: <https://schema.ld.admin.ch/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

[
  a sh:NodeShape ;
  sh:targetClass ch:Municipality ;
  sh:property
    [
      sh:path schema:identifier ;
      sh:minInclusive 250 ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>.
  ?resource1 schema:identifier ?resource2.
}
WHERE {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>;
    schema:identifier ?resource2.
  FILTER(?resource2 >= 250 )
}
3.2.2.3. sh:maxExclusive

Note: SHACL spec: Shapes Constraint Language (SHACL) § MaxExclusiveConstraintComponent

Restrict objects of a property to a specific range
PREFIX ch: <https://schema.ld.admin.ch/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

[
  a sh:NodeShape ;
  sh:targetClass ch:Municipality ;
  sh:property
    [
      sh:path schema:identifier ;
      sh:maxExclusive 250 ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>.
  ?resource1 schema:identifier ?resource2.
}
WHERE {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>;
    schema:identifier ?resource2.
  FILTER(?resource2 < 250 )
}
3.2.2.4. sh:maxInclusive

Note: SHACL spec: Shapes Constraint Language (SHACL) § MaxInclusiveConstraintComponent

Restrict objects of a property to a specific range
PREFIX ch: <https://schema.ld.admin.ch/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

[
  a sh:NodeShape ;
  sh:targetClass ch:Municipality ;
  sh:property
    [
      sh:path schema:identifier ;
      sh:maxInclusive 250 ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>.
  ?resource1 schema:identifier ?resource2.
}
WHERE {
  ?resource1 rdf:type <https://schema.ld.admin.ch/Municipality>;
    schema:identifier ?resource2.
  FILTER(?resource2 <= 250 )
}

3.2.3. String-based Constraint Components

3.2.3.1. sh:pattern

Note: SHACL spec: Shapes Constraint Language (SHACL) § PatternConstraintComponent

Filter only those resources whose family name starts with "B" or "C", case-insensitive
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:property
    [ sh:path schema:givenName ],
    [
      sh:path schema:familyName ;
      sh:pattern "^[bc]" ;
      sh:flags "i" ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:givenName ?resource2.
  ?resource1 schema:familyName ?resource3.
}
WHERE {
  OPTIONAL { ?resource1 schema:givenName ?resource2. }
  ?resource1 schema:familyName ?resource3.
  FILTER(REGEX(?resource3, "^[bc]", "i"))
}
3.2.3.2. sh:languageIn

Note: SHACL spec: Shapes Constraint Language (SHACL) § LanguageInConstraintComponent

Filter job titles to English and German
PREFIX ex: <http://example.org/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX sparql: <http://datashapes.org/sparql#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path schema:jobTitle ;
      sh:languageIn ( "de" "en" ) ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 schema:jobTitle ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Person;
    schema:jobTitle ?resource2.
  FILTER(LANG(?resource2) IN("de", "en"))
}

3.2.4. Logical Constraint Components

The elements of a sh:or list are shapes and thus, they can be used both to define alternative paths to construct in the constructed graph, or add filters to filter out according to the shapes' constraints.

3.2.4.1. sh:and

Note: SHACL spec: Shapes Constraint Language (SHACL) § AndConstraintComponent

Combines all paths and constraints from the list of shapes.

Filter characters who know Sheldon Cooper and are a microbiologist
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:and
    (
      [
        sh:property
          [
            sh:path schema:knows ;
            sh:hasValue tbbt:sheldon-cooper ;
          ]
      ]
      [
        sh:property
          [
            sh:path schema:jobTitle ;
            sh:hasValue "microbiologist" ;
          ]
      ]
    )
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:knows ?resource2.
  ?resource1 schema:jobTitle ?resource3.
}
WHERE {
  ?resource1 schema:knows ?resource2;
    schema:jobTitle ?resource3.
  VALUES ?resource2 {
    <https://tbbt.tv/sheldon-cooper>
  }
  VALUES ?resource3 {
    "microbiologist"
  }
}
3.2.4.2. sh:or

Note: SHACL spec: Shapes Constraint Language (SHACL) § OrConstraintComponent

Get schema:givenName and schema:familyName but only of those resources which have either schema:parent or schema:children properties
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:or
    (
      [ sh:property [ sh:path schema:parent ] ]
      [ sh:property [ sh:path schema:children ] ]
    ) ;
  sh:property
    [ sh:path schema:givenName ],
    [ sh:path schema:familyName ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:givenName ?resource2.
  ?resource1 schema:familyName ?resource3.
  ?resource1 schema:parent ?resource4.
  ?resource1 schema:children ?resource5.
}
WHERE {
  { ?resource1 schema:givenName ?resource2. }
  UNION
  { ?resource1 schema:familyName ?resource3. }
  { ?resource1 schema:parent ?resource4. }
  UNION
  { ?resource1 schema:children ?resource5. }
  
}

Add example of sh:or used in sh:property when more useful constraints are implemented

3.2.5. Shape-based Constraint Components

3.2.5.1. sh:node

When added to a shape, sh:node allows to restrict a given value node to another shape.

The is most commonly use case is describing deep graph structures (as an alternative to complex SHACL Property Paths).

Find names of the root focus node(s) and objects of their schema:knows property
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:property
    [ sh:path schema:givenName ],
    [
      sh:path schema:knows ;
      sh:node
        [
          sh:property [ sh:path schema:givenName ]
        ] ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:givenName ?resource2.
  ?resource1 schema:knows ?resource3.
  ?resource3 schema:givenName ?resource4.
}
WHERE {
  {
    SELECT ?resource1 ?resource2 ?resource3 WHERE {
      { ?resource1 schema:givenName ?resource2. }
      UNION
      { ?resource1 schema:knows ?resource3. }
    }
  }
  UNION
  {
    SELECT ?resource3 ?resource4 WHERE {
      ?resource1 schema:knows ?resource3.
      ?resource3 schema:givenName ?resource4.
    }
  }
}

By reusing a shape, it is also possible to apply it to multiple subgraphs.

Describes the root focus node and objects of schema:parent and schema:children using the same PersonShape
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:node <PersonShape> ;
  sh:property
    [
      sh:path schema:parent ; sh:node <PersonShape> ;
    ] ,
    [
      sh:path schema:children ; sh:node <PersonShape> ;
    ] ;
] .

<PersonShape>
  sh:property
    [
      sh:path schema:givenName ;
    ],
    [
      sh:path schema:familyName ;
    ] ;
.
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:parent ?resource2.
  ?resource1 schema:children ?resource6.
  ?resource2 schema:givenName ?resource3.
  ?resource2 schema:familyName ?resource4.
  ?resource6 schema:givenName ?resource7.
  ?resource6 schema:familyName ?resource8.
}
WHERE {
  {
    SELECT ?resource1 ?resource2 ?resource6 WHERE {
      { ?resource1 schema:parent ?resource2. }
      UNION
      { ?resource1 schema:children ?resource6. }
    }
  }
  UNION
  {
    SELECT ?resource2 ?resource3 ?resource4 WHERE {
      ?resource1 schema:parent ?resource2.
      { ?resource2 schema:givenName ?resource3. }
      UNION
      { ?resource2 schema:familyName ?resource4. }
    }
  }
  UNION
  {
    SELECT ?resource6 ?resource7 ?resource8 WHERE {
      ?resource1 schema:children ?resource6.
      { ?resource6 schema:givenName ?resource7. }
      UNION
      { ?resource6 schema:familyName ?resource8. }
    }
  }
}

Support recursive shapes using sh:node [Issue #99]

3.2.6. Other Constraint Components

3.2.6.1. sh:hasValue

Note: SHACL spec: Shapes Constraint Language (SHACL) § HasValueConstraintComponent

Filters nodes whose property has the exact set of objects

Get schema:givenName and schema:familyName but only of those resources who know both Sheldon Cooper and Stuart Bloom
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:property
    [ sh:path schema:givenName ],
    [ sh:path schema:familyName ] ,
    [
      sh:path schema:knows ;
      sh:hasValue tbbt:sheldon-cooper, tbbt:stuart-bloom ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:givenName ?resource2.
  ?resource1 schema:familyName ?resource3.
  ?resource1 schema:knows ?resource4.
}
WHERE {
  { ?resource1 schema:givenName ?resource2. }
  UNION
  { ?resource1 schema:familyName ?resource3. }
  ?resource1 schema:knows ?resource4.
  FILTER(EXISTS { ?resource1 schema:knows <https://tbbt.tv/sheldon-cooper>, <https://tbbt.tv/stuart-bloom>. })
}

sh:hasValue is not currently supported as property of the root node shape and will be ignored in such case

3.2.6.2. sh:in

Note: SHACL spec: Shapes Constraint Language (SHACL) § InConstraintComponent

Similar to § 3.2.6.1 sh:hasValue but filters focus nodes whose property has values from the given set and no others.

Get schema:givenName and schema:familyName but only of those resources who know Sheldon Cooper or Stuart Bloom
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:property
    [ sh:path schema:givenName ],
    [ sh:path schema:familyName ],
    [
      sh:path schema:knows ;
      sh:in ( tbbt:sheldon-cooper tbbt:stuart-bloom ) ;
    ]
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:givenName ?resource2.
  ?resource1 schema:familyName ?resource3.
  ?resource1 schema:knows ?resource4.
}
WHERE {
  { ?resource1 schema:givenName ?resource2. }
  UNION
  { ?resource1 schema:familyName ?resource3. }
  ?resource1 schema:knows ?resource4.
  FILTER(?resource4 IN(<https://tbbt.tv/sheldon-cooper>, <https://tbbt.tv/stuart-bloom>))
}

sh:in is not currently supported as property of the root node shape and will be ignored in such case

4. SHACL Advanced Features

This section uses the currently published SHACL Advanced Features spec as well as parts of the Community Group Draft. The implementation may become outdated in time or deviate from the spec to accommodate for the specifics of generating queries.

Issue epic on GitHub [Issue #19]

4.1. Node expressions

The core of the support for node expressions is the new sh:values predicate, which allows the query generator to provide values for the predicate. Rather than following the sh:path to find the match the RDF terms, the node expressions are define the objects of the property. Different kinds of node expressions can be used to generate subselects or computed properties.

Note: Because the result must be a triple patterns where the node expression’s output is the subject or object, only Predicate Path and Inverse Path can be used with sh:values.

Multiple objects of sh:values should form a UNION [Issue #20]

4.1.1. Focus Node Expression

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § node-expressions-focus

The object of the property at sh:path is the current focus node

Focus node expressions
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetNode tbbt:sheldon-cooper ;
  sh:property
    [
      sh:path schema:knows ;
      sh:values sh:this ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT { ?resource1 schema:knows ?resource2. }
WHERE {
  VALUES ?resource1 {
    <https://tbbt.tv/sheldon-cooper>
  }
  BIND(?resource1 AS ?resource2)
}

Note: For a pragmatic use of Focus Node Expression, see § 5.1.1 Node Expression Target.

4.1.2. Constant Term Expression

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § node-expressions-constant

The objects of sh:values become directly asserted as the objects of the property.

Two properties with constant values
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetNode tbbt:sheldon-cooper ;
  sh:property
    [
      sh:path schema:givenName ;
      sh:values "Sheldon" ;
    ],
    [
      sh:path schema:familyName ;
      sh:values "Cooper" ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:givenName ?resource2.
  ?resource1 schema:familyName ?resource3.
}
WHERE {
  VALUES ?resource1 {
    <https://tbbt.tv/sheldon-cooper>
  }
  { BIND("Sheldon" AS ?resource2) }
  UNION
  { BIND("Cooper" AS ?resource3) }
}

4.1.3. Filter Shape Expressions

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § node-expressions-filter-shape

Filter shapes restricts the selected values to only those conforming to the shape set to sh:filterShape property.

The expression requires the presence of exactly on value of sh:filterShape property, value of which must be SHACL Shape. It will be used to filter the values of said property to only those conforming to that shape.

PREFIX ex: <http://example.org/>
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path schema:knows ;
      sh:values
        [
          sh:filterShape
            [
              sh:property
                [
                  sh:path ( schema:address schema:addressRegion ) ;
                  sh:hasValue "CA" ;
                ] ;
            ] ;
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 schema:knows ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Person;
    (schema:address/schema:addressRegion) ?resource3.
  VALUES ?resource3 {
    "CA"
  }
}

Note: For a practical use of Filter Shape Expression using a § 4.1.1 Focus Node Expression (without sh:nodes), see § 5.1.1 Node Expression Target.

Additionally, sh:nodes property can be used to select different set of values nodes for that property.

Calculates separate properties for parents' names by filtering on their respective gender
PREFIX ex: <http://example.org/>
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path ex:motherName ;
      sh:values
        [
          sh:path schema:givenName ;
          sh:nodes
            [
              sh:nodes [ sh:path schema:parent ] ;
              sh:filterShape
                [
                  sh:property
                    [
                      sh:path schema:gender ;
                      sh:hasValue schema:Female ;
                    ] ;
                ] ;
            ] ;
        ] ;
    ],
    [
      sh:path ex:fatherName ;
      sh:values
        [
          sh:path schema:givenName ;
          sh:nodes
            [
              sh:nodes [ sh:path schema:parent ] ;
              sh:filterShape
                [
                  sh:property
                    [
                      sh:path schema:gender ;
                      sh:hasValue schema:Male ;
                    ] ;
                ] ;
            ] ;
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 <http://example.org/motherName> ?resource2.
  ?resource1 <http://example.org/fatherName> ?resource6.
}
WHERE {
  ?resource1 rdf:type schema:Person.
  {
    ?resource1 schema:parent ?resource3.
    ?resource3 schema:gender ?resource5.
    VALUES ?resource5 {
      schema:Female
    }
    ?resource3 schema:givenName ?resource2.
  }
  UNION
  {
    ?resource1 schema:parent ?resource7.
    ?resource7 schema:gender ?resource9.
    VALUES ?resource9 {
      schema:Male
    }
    ?resource7 schema:givenName ?resource6.
  }
}

4.1.4. Function Expressions

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § node-expressions-function

Contrary to the name, function expressions are used to represent not only function calls but also other kinds of expressions:

NOTE: Read Conceptual Guides § additive-expressions to learn more about how shape-to-query handles mathematical operations.

NOTE: Read How-Tos § custom-functions to learn how to add register custom functions with shape-to-query.

Calculate the person’s ex:drivingExperienceYears property as the difference between the current year and the year when that person had their driving license issued
PREFIX schema: <http://schema.org/>
PREFIX sparql: <http://datashapes.org/sparql#>
PREFIX ex: <http://example.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path ex:drivingExperienceYears ;
      sh:values
        [
          sparql:subtract
            (
              [ sparql:year ( [ sparql:now () ] )]
              [ sparql:year ( [ sh:path (ex:drivingLicense ex:issueDate) ] )]
            ) ;
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 <http://example.org/drivingExperienceYears> ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Person;
    (<http://example.org/drivingLicense>/<http://example.org/issueDate>) ?resource3.
  BIND((YEAR(NOW())) - (YEAR(?resource3)) AS ?resource2)
}

4.1.5. Path Expressions

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § node-expressions-path

Path expression is the simplest possible expression which select focus node objects at a specified path.

Find resource’s parent names
PREFIX ex: <http://example.org/>
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path ex:parentNames ;
      sh:values
        [
          sh:path ( schema:parent schema:givenName ) ;
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 <http://example.org/parentNames> ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Person;
    (schema:parent/schema:givenName) ?resource2.
}

Optionally, a path expression can have one value of sh:nodes property which defines the set of subjects for the path.

Find the people known to parents and spouse
PREFIX ex: <http://example.org/>
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path ex:familyFriend ;
      sh:values
        [
          sh:nodes
            [
              sh:path
                [
                  sh:alternativePath ( schema:parent schema:spouse ) ;
                ] ;
            ] ;
          sh:path schema:knows
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 <http://example.org/familyFriend> ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Person;
    (schema:parent|schema:spouse) ?resource3.
  ?resource3 schema:knows ?resource2.
}

4.1.6. Distinct Expressions

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § distinct

Select only unique values of
PREFIX ex: <http://example.org/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Organization ;
  sh:property
    [
      sh:path ex:contact ;
      sh:values
        [
          sh:distinct
            [
              sh:path [ sh:alternativePath ( ex:customer ex:client ) ]
            ] ;
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Organization.
  ?resource1 <http://example.org/contact> ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Organization.
  {
    SELECT DISTINCT ?resource1 ?resource2 WHERE {
      ?resource1 (<http://example.org/customer>|<http://example.org/client>) ?resource2;
        rdf:type schema:Organization.
    }
  }
}

4.1.7. Count Expressions

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § count

Count the number of articles
PREFIX ex: <http://example.org/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Periodical ;
  sh:property
    [
      sh:path ex:numberOfArticles ;
      sh:values
        [
          sh:count [ sh:path schema:publication ] ;
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Periodical.
  ?resource1 <http://example.org/numberOfArticles> ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Periodical.
  {
    SELECT (COUNT(?resource3) AS ?resource2) WHERE {
      ?resource1 schema:publication ?resource3;
        rdf:type schema:Periodical.
    }
  }
}

4.1.8. OrderBy Expressions

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § orderBy

Use sh:orderBy to sort a set of focus nodes by a property from the specific path

Find 10 most recent articles
PREFIX ex: <http://example.org/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:property
    [
      sh:path ex:latestArticles ;
      sh:values
        [
          sh:limit 10 ;
          sh:nodes
            [
              sh:nodes [ sh:path schema:publication ] ;
              sh:orderBy [ sh:path schema:datePublished ] ;
              sh:desc true ;
            ] ;
        ] ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT { ?resource1 <http://example.org/latestArticles> ?resource2. }
WHERE {
  {
    SELECT ?resource1 ?resource2 WHERE {
      ?resource1 schema:publication ?resource2.
      OPTIONAL { ?resource2 schema:datePublished ?resource3. }
    }
    ORDER BY DESC (?resource3)
    LIMIT 10
  }
}

Note: sh:desc is optional and defaults to false

4.1.9. Limit Expressions

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § limit

Returns the first N nodes from the inner node expression

Select only one value of a resource’s schema:parent property
PREFIX schema: <http://schema.org/>
PREFIX ex: <http://example.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path ex:oneParent ;
      sh:values
        [
          sh:limit 1 ;
          sh:nodes [ sh:path schema:parent ] ;
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 <http://example.org/oneParent> ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Person.
  {
    SELECT ?resource1 ?resource2 WHERE {
      ?resource1 schema:parent ?resource2;
        rdf:type schema:Person.
    }
    LIMIT 1
  }
}

Note: sh:limit makes most sense when combined with sh:orderBy or sh:select

4.1.10. Offset Expressions

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § offset

Skips a number of nodes from the inner node expression

Select only one value of a resource’s schema:parent property
PREFIX schema: <http://schema.org/>
PREFIX ex: <http://example.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path ex:oneParent ;
      sh:values
        [
          sh:offset 1 ;
          sh:nodes [ sh:path schema:parent ] ;
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 <http://example.org/oneParent> ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Person.
  {
    SELECT ?resource1 ?resource2 WHERE {
      ?resource1 schema:parent ?resource2;
        rdf:type schema:Person.
    }
    OFFSET 1
  }
}

Note: sh:offset makes most sense when combined with sh:limit and sh:orderBy or sh:select

4.2. Expression Constraints

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § ExpressionConstraintComponent

Constrains focus nodes by evaluating § 4.1 Node expressions.

Select only one people who have a job title containing the word "physicist"
PREFIX ex: <http://example.org/>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX sparql: <http://datashapes.org/sparql#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path schema:jobTitle ;
    ] ;
  sh:expression
    [
      sparql:contains
        (
          [ sh:path schema:jobTitle ]
          "physicist"
        ) ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 schema:jobTitle ?resource2.
}
WHERE {
  ?resource1 rdf:type schema:Person;
    schema:jobTitle ?resource2, ?resource4.
  FILTER(CONTAINS(?resource4, "physicist"))
}

4.3. SHACL Rules

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § rules

SHACL Rules provide a way insert computed data (triples) into the data graph.

Any rule with sh:deactivated true will be ignored.

4.3.1. Triple Rules

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § TripleRule

Triple rules are a generalised way to assert new statements in the data graph. They require the subject, predicate and object being provided as § 4.1 Node expressions.

Construct new relatedTo triples for all resources linked by the children, parent, or spouse predicates
PREFIX sparql: <http://datashapes.org/sparql#>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:rule
    [
      sh:subject
        [
          sh:path [ sh:alternativePath ( schema:spouse schema:children schema:parent ) ]
        ] ;
      sh:predicate schema:relatedTo ;
      sh:object sh:this ;
    ] ,
    [
      sh:subject sh:this ;
      sh:predicate schema:relatedTo ;
      sh:object
        [
          sh:path [ sh:alternativePath ( schema:spouse schema:children schema:parent ) ]
        ] ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource2 ?resource3 ?resource4.
  ?resource5 ?resource6 ?resource7.
}
WHERE {
  ?resource1 rdf:type schema:Person.
  {
    ?resource1 rdf:type schema:Person;
      (schema:spouse|schema:children|schema:parent) ?resource2.
    BIND(schema:relatedTo AS ?resource3)
    BIND(?resource1 AS ?resource4)
  }
  UNION
  {
    ?resource1 rdf:type schema:Person.
    BIND(?resource1 AS ?resource5)
    BIND(schema:relatedTo AS ?resource6)
    ?resource1 (schema:spouse|schema:children|schema:parent) ?resource7.
  }
}

Because any arbitrary node expressions can be used, the resulting triples can be unrelated to the focus nodes itself.

In addition to triples about each Person, also return a new collection resource ex:JobTitles which gathers all values of their respective jobTitle properties.
PREFIX hydra: <http://www.w3.org/ns/hydra/core#>
PREFIX ex: <http://example.org/>
PREFIX sparql: <http://datashapes.org/sparql#>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property [ sh:path schema:givenName ] , [ sh:path schema:familyName ] ;
  sh:rule
    [
      sh:subject ex:JobTitles ;
      sh:predicate hydra:member ;
      sh:object
      [
        sh:path schema:jobTitle ;
      ];
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
PREFIX hydra: <http://www.w3.org/ns/hydra/core#>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 schema:givenName ?resource2.
  ?resource1 schema:familyName ?resource3.
  ?resource4 ?resource5 ?resource6.
}
WHERE {
  ?resource1 rdf:type schema:Person.
  {
    { ?resource1 schema:givenName ?resource2. }
    UNION
    { ?resource1 schema:familyName ?resource3. }
  }
  UNION
  {
    ?resource1 rdf:type schema:Person.
    BIND(<http://example.org/JobTitles> AS ?resource4)
    BIND(hydra:member AS ?resource5)
    ?resource1 schema:jobTitle ?resource6.
  }
}

Note: That is a major difference from § 4.3.2 Property Value Rules, which is equivalent of using sh:this as subject.

4.3.2. Property Value Rules

Note: SHACL-AF spec: SHACL Advanced Features 1.1 (draft) § PropertyValueRule

Used throughout the § 4.1 Node expressions examples, the sh:values is a specialised kind of triple rule which binds computed values to triples with the current focus node subject and property being the value of sh:path.

Note: An error will be thrown when the sh:path is not an IRI

5. Extensions

The shape-to-query library introduces some additional constructs which handle specific scenarios unique to generated SPARQL queries which cannot be otherwise handled with terms defined in SHACL and SHACL-AF.

ALl extensions use the namespace https://hypermedia.app/shape-to-query#. The preferred prefix is s2q:.

5.1. Targets

5.1.1. Node Expression Target

Custom targets, which are instances of s2q:NodeExpressionTarget ar called Node Expression Targets. They are used to define the focus nodes of a shape using Node Expressions.

Any of the simple expressions will generate SPARQL patterns directly in the query.

Find names of resources which are elements of ex:prop lists
PREFIX ex: <http://example.org/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX s2q: <https://hypermedia.app/shape-to-query#>

[
  a sh:NodeShape ;
  sh:target [
    a s2q:NodeExpressionTarget ;
    sh:expression [
      sh:path ( ex:prop [ sh:zeroOrMorePath rdf:rest] rdf:first ) ;
    ] ;
  ] ;
  sh:property
    [
      sh:path schema:name ;
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT { ?resource1 schema:name ?resource4. }
WHERE {
  { SELECT (?resource3 AS ?resource1) WHERE { ?resource2 (<http://example.org/prop>/(rdf:rest*)/rdf:first) ?resource3. } }
  ?resource1 schema:name ?resource4.
}

Node Expression Targets become especially useful when combined with § 4.1.9 Limit Expressions, § 4.1.10 Offset Expressions and § 4.1.8 OrderBy Expressions to paginate the results and only select a subset of candidate focus nodes, which cannot be achieved by other means of SHACL-AF. Such as in the example below, where the Node Expression generates a subselect.

Find names of resources which are elements of ex:prop lists
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX s2q: <https://hypermedia.app/shape-to-query#>

[
  a sh:NodeShape ;
  sh:target
    [
      a s2q:NodeExpressionTarget ;
      sh:expression
        [
          # 3. Select 10 first results
          sh:limit 10 ;
          sh:nodes
            [
              # 2. Order by position
              sh:orderBy
                [
                  sh:path schema:position ;
                ] ;
              sh:nodes
                [
                  # 1. Find all people named John
                  sh:filterShape
                    [
                      sh:property
                        [
                          sh:path schema:name ;
                          sh:pattern "John" ;
                        ] ;
                      sh:property
                        [
                          sh:path rdf:type ;
                          sh:hasValue schema:Person ;
                        ] ;
                    ] ;
                ] ;
            ]
        ] ;
    ] ;
  sh:property
    [
      sh:path schema:name ;
    ] ;
] .
PREFIX schema: <http://schema.org/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
CONSTRUCT { ?resource1 schema:name ?resource7. }
WHERE {
  {
    SELECT ?resource2 (?resource2 AS ?resource1) WHERE {
      ?resource2 schema:name ?resource4.
      FILTER(REGEX(?resource4, "John"))
      ?resource2 rdf:type ?resource5.
      VALUES ?resource5 {
        schema:Person
      }
      OPTIONAL { ?resource2 schema:position ?resource6. }
    }
    ORDER BY (?resource6)
    LIMIT 10
  }
  ?resource1 schema:name ?resource7.
}

5.2. Node Expressions

5.2.1. Optional Expression

An optional expression is a blank node which has a single object of the s2q:optional property which is a well-formed Node Expression.

Find people who do not have an address region or whose address region is Texas
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX s2q: <https://hypermedia.app/shape-to-query#>
PREFIX sparql: <http://datashapes.org/sparql#>

[
  a sh:NodeShape ;
  sh:property
    [ sh:path schema:givenName ],
    [ sh:path schema:familyName ] ;
  sh:expression
    [
      sparql:or
        (
          [ sparql:not ( [ sparql:bound ( _:addressLocation ) ] ) ]
          [ sparql:eq ( _:addressLocation "TX" ) ]
        ) ;
    ] ;
] .

_:addressLocation
  s2q:optional
    [
      sh:path ( schema:address schema:addressRegion )
    ] .
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 schema:givenName ?resource2.
  ?resource1 schema:familyName ?resource3.
}
WHERE {
  { ?resource1 schema:givenName ?resource2. }
  UNION
  { ?resource1 schema:familyName ?resource3. }
  OPTIONAL { ?resource1 (schema:address/schema:addressRegion) ?resource5. }
  OPTIONAL { ?resource1 (schema:address/schema:addressRegion) ?resource5. }
  FILTER((!(BOUND(?resource5))) || (?resource5 = "TX"))
}

5.3. Custom rules

5.3.1. SPO rule

An SPO rule is a blank node with the RDF type s2q:SPORule. It can optionally have the properties s2q:predicateFilter and s2q:objectFilter, value of which must be a well-formed Node Expression.

This rule can be used to mimic a behavior of DESCRIBE queries which would return all direct properties of the given focus node, which is otherwise not possible with other SHACL constructs.

Return all information about Sheldon Cooper
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX s2q: <https://hypermedia.app/shape-to-query#>
PREFIX sparql: <http://datashapes.org/sparql#>

[
  a sh:NodeShape ;
  sh:targetNode tbbt:sheldon-cooper ;
  sh:rule [
    a s2q:SPORule ;
  ]
] .
CONSTRUCT { ?resource1 ?resource2 ?resource3. }
WHERE {
  VALUES ?resource1 {
    <https://tbbt.tv/sheldon-cooper>
  }
  ?resource1 ?resource2 ?resource3.
}

Additionally, node expressions can be used to limit the predicates and objects. sh:this in those expressions refers to the predicate and object itself and not the subject

Return all information about Sheldon Cooper except for schema:knows property and values which are blank nodes
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX s2q: <https://hypermedia.app/shape-to-query#>
PREFIX sparql: <http://datashapes.org/sparql#>

[
  a sh:NodeShape ;
  sh:targetNode tbbt:sheldon-cooper ;
  sh:rule [
    a s2q:SPORule ;
    s2q:predicateFilter [
      sparql:not ( [ sparql:eq ( sh:this schema:knows ) ] ) ;
    ] ;
    s2q:objectFilter [
      sh:filterShape [
        sh:nodeKind sh:IRIOrLiteral ;
      ] ;
    ] ;
  ]
] .
PREFIX schema: <http://schema.org/>
CONSTRUCT { ?resource1 ?resource2 ?resource3. }
WHERE {
  VALUES ?resource1 {
    <https://tbbt.tv/sheldon-cooper>
  }
  ?resource1 ?resource2 ?resource3.
  FILTER(!(?resource2 = schema:knows))
  FILTER((ISIRI(?resource3)) || (ISLITERAL(?resource3)))
}

Note: In many cases, nested node shapes with expressions and constraints are a more fitting way to represent such filters.

Expanding on the example above, sh:filterShape can be used to further restrict the objects in an SPO pattern by their respective properties

Find values of people’s schema:knows property but only where that other person is a physicist.
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX s2q: <https://hypermedia.app/shape-to-query#>
PREFIX sparql: <http://datashapes.org/sparql#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:rule [
    a s2q:SPORule ;
    s2q:predicateFilter [
      sparql:eq ( sh:this schema:knows ) ;
    ] ;
    s2q:objectFilter [
      sh:filterShape [
        sh:property [
          sh:path schema:jobTitle ;
          sh:pattern "physicist" ;
        ] ;
      ] ;
    ] ;
  ]
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 ?resource2 ?resource3.
}
WHERE {
  ?resource1 rdf:type schema:Person;
    ?resource2 ?resource3.
  FILTER(?resource2 = schema:knows)
  ?resource3 schema:jobTitle ?resource4.
  FILTER(REGEX(?resource4, "physicist"))
}

Finally, SPORule can also be used inside sh:node expression to select the values of any nested focus node

Find people with address and all properties of said address
PREFIX schema: <http://schema.org/>
PREFIX tbbt: <https://tbbt.tv/>
PREFIX sh: <http://www.w3.org/ns/shacl#>
PREFIX s2q: <https://hypermedia.app/shape-to-query#>
PREFIX sparql: <http://datashapes.org/sparql#>

[
  a sh:NodeShape ;
  sh:targetClass schema:Person ;
  sh:property
    [
      sh:path schema:address ;
      sh:node
        [
          sh:rule
            [
              a s2q:SPORule ;
            ] ;
        ]
    ] ;
] .
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <http://schema.org/>
CONSTRUCT {
  ?resource1 rdf:type schema:Person.
  ?resource1 schema:address ?resource2.
  ?resource2 ?resource3 ?resource4.
}
WHERE {
  {
    SELECT ?resource1 ?resource2 WHERE {
      ?resource1 rdf:type schema:Person;
        schema:address ?resource2.
    }
  }
  UNION
  {
    SELECT ?resource2 ?resource3 ?resource4 WHERE {
      ?resource1 rdf:type schema:Person;
        schema:address ?resource2.
      ?resource2 ?resource3 ?resource4.
    }
  }
}

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-CONCEPTS]
Richard Cyganiak; David Wood; Markus Lanthaler. RDF 1.1 Concepts and Abstract Syntax. 25 February 2014. REC. URL: https://www.w3.org/TR/rdf11-concepts/
[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
[SHACL]
Holger Knublauch; Dimitris Kontokostas. Shapes Constraint Language (SHACL). URL: https://w3c.github.io/data-shapes/shacl/
[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/
[SPARQL11-OVERVIEW]
The W3C SPARQL Working Group. SPARQL 1.1 Overview. 21 March 2013. REC. URL: https://www.w3.org/TR/sparql11-overview/
[SPARQL11-QUERY]
Steven Harris; Andy Seaborne. SPARQL 1.1 Query Language. 21 March 2013. REC. URL: https://www.w3.org/TR/sparql11-query/
[SPARQL11-UPDATE]
Paula Gearon; Alexandre Passant; Axel Polleres. SPARQL 1.1 Update. 21 March 2013. REC. URL: https://www.w3.org/TR/sparql11-update/

Informative References

[S2Q-CONCEPTS]
Conceptual Guides. URL: ../concepts
[S2Q-HOW-TOS]
How-Tos. URL: ../how-tos

Issues Index

Issue epic on GitHub [Issue #42]
Add example of sh:or used in sh:property when more useful constraints are implemented
Support recursive shapes using sh:node [Issue #99]
Issue epic on GitHub [Issue #19]
Multiple objects of sh:values should form a UNION [Issue #20]