---
# System prepended metadata

title: SHACL
tags: [data, ontology, HN]

---

###### tags: `data` `ontology` `HN` 

SHACL 
===

excellente présentatino de T. Francart sur le sujet: 
https://rbdd.cnrs.fr/local/cache-zotspip/23D7N9G8/Francart%20SHApe%20Constraints%20Language.pdf


shacl définit des contraintes sur les triplet. 
Concrètement il définit des _sh:PropertyShape_ (les contraintes) sur des _sh:NodeShape_ (les classes)




## Node shapes
d'abord on définit des "nodeshapes". 
Ce sont des shapes qui contiennent les objets controlés.

__Valeurs__: 
`rdf:type`: sh:NodeShape forcément!
`sh:targetClass`: ensemble des objets controlés par cette shape
`sh:nodeKind`: sh:IRI signifie que l'on souhaite que les instances des classes de cette shape soit des IRI, pas des noeuds anonymes.
`sh:property`: ce sont les contraintes (_propertyshape_) voir plus bas attaché à la shape.
`sh:ignoredPropertie` : ce sont les propriétés owl qui ne seront pas vérifié en mode "closed shapes". On y met toujours au moins `rdf:type`mais aussi toutes les propriétés d'annotation (`rdfs:label`, `skos:prefLabel`, `skos:note`, etc.)

```sparql
myPrfx:shaclNode1
        rdf:type sh:NodeShape , 
        sh:targetClass crm:E67_Birth ;
        sh:property           
            crm:E67_Birth-P96_by_mother ,
            crm:E67_Birth-P98_brought_into_life , 
            crm:E67_Birth-P97_from_father .
```

shortcut: Si seule une classe est controlée on peut garder son IRI et ne pas renseigner de _sh:targetClass_. C'est ce que fait sparna.
L'exemple précéent peut être ré-écrit comme suit: 

```sparql
crm:E67_Birth
        rdf:type                     
            sh:NodeShape , 
            rdfs:Class ;
        sh:property           
            crm:E67_Birth-P96_by_mother ,
            crm:E67_Birth-P98_brought_into_life , 
            crm:E67_Birth-P97_from_father .
```


## Property shapes

Ensuite on définit les contraintes, ce sont les "propertyshape"
Chaque propertyshape est une nouvelle contrainte.
Dans l'exemple précédent, pour la classe`E67_BIrth` la _sh:property_ `<crm:E67_Birth-P96_by_mother>` est une contrainte que l'on va définir ici. 

__Valeurs__: 
`rdf:type`: sh:PropertyShape forcément!
`sh:path` : la propriété owl concernée
`sh:class`: classe attendue comme valeur de la propriété owl (si une seule)
`sh:or`: classes attendues comme valeurs de la propriété (si plusieurs)

ex: 

```sparql
crm:E67_Birth-P96_by_mother
        rdf:type  sh:PropertyShape ;
        sh:path   crm:P96_by_mother .
        sh:class  crm:E21_Person ;
```

## Conclusion pour domain range

on définit des contraintes pour chaque shape. 
Si je reprends mon exemple et que je met tout dans la même shape (je décloisonne) ça donne 

```sparql
crm:E67_Birth
        rdf:type                     
            sh:NodeShape , 
            rdfs:Class ;
        sh:property [
            sh:path     crm:P96_by_mother ;
            sh:class    crm:E21_Person ;
        ] .
```

## autre écriture
Il est possible de cible avec d'autres outils que `targetClass`par exemple avec `sh:targeSubjectOf`ou `sh:targObjectOf ` pour récupérer les sujets/objets des triplet associée à une propriété owl.

On peut alors écrire par exemple: 
```sparql
ex:p98shape
        rdf:type                sh:NodeShape;
        sh:targeSubjectOf       crm:P98_brought_into_life;
        sh:property             [
                                sh:class         crm:E67_Birth
                                ] .
```

## Pour d'autres contraintes

il est possible de définir d'autres contraintes sur les shapes. 


### cardinalité
Par exemple, on veut qu'il y ait 0 ou 1 mère seulement par Birth. 
on peut écrire: 
```sparql
crm:E67_Birth-P96_by_mother
        rdf:type  sh:PropertyShape ;
        sh:path   crm:P96_by_mother .
        sh:class  crm:E21_Person ;
        sh:maxCount 1
```


### type

#### IRI or not
On veut que le type de la mère soit un IRI (pas une chaine de char)


```sparql
crm:E67_Birth-P96_by_mother
        rdf:type  sh:PropertyShape ;
        sh:path   crm:P96_by_mother .
        sh:class  crm:E21_Person ;
        sh:maxCount 1
        sh:nodeKind sh:IRI
```

#### non IRI: autres types 
Par exemple on veut que la mère soit une chaine de char (et pas un IRI) et corresponde à un pattern

```sparql
crm:E67_Birth-P96_by_mother
        rdf:type  sh:PropertyShape ;
        sh:path   crm:P96_by_mother .
        sh:class  crm:E21_Person ;
        sh:maxCount 1
        sh:nodeKind sh:BlankNodeOrLiteral
        sh:datatype xsd:string
        sh:pattern "^[mM]adame .+$" ;
```