Rule Execution With SHACL

DZone 's Guide to

Rule Execution With SHACL

A quick, but in-depth look into using SHACL for performing rule execution on RDF data, and some example code to get you started!

· Big Data Zone ·
Free Resource

In my previous post, Using Jena and SHACL to validate RDF Data, I looked at how RDF data can be validated using SHACL. A closely related concern to constraints checking is rule execution, for which SHACL also can be used.

A SHACL Rule Example

We will again use an example from the SHACL specification. Assume we have a file rectangles.ttl   that contains the following data:

@prefix ex: <http://example.com/ns#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

  a ex:Rectangle .

  a ex:Rectangle ;
  ex:height 2 ;
  ex:width 3 .

  a ex:Rectangle ;
  ex:height 4 ;
  ex:width 4 .

Assuming we want to infer that when the height and width of a rectangle are equal, the rectangle represents a square, the following SHACL rule specification can be used (which we will store in  rectangleRules.ttl ):

@prefix ex: <http://example.com/ns#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix dash: <http://datashapes.org/dash#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

  a rdfs:Class, sh:NodeShape ;
  rdfs:label "Rectangle" ;
  sh:property [
    sh:path ex:height ;
    sh:datatype xsd:integer ;
    sh:maxCount 1 ;
    sh:minCount 1 ;
    sh:name "height" ;
  ] ;
  sh:property [
    sh:path ex:width ;
    sh:datatype xsd:integer ;
    sh:maxCount 1 ;
    sh:minCount 1 ;
    sh:name "width" ;
  ] ;
  sh:rule [
    a sh:TripleRule ;
    sh:subject sh:this ;
    sh:predicate rdf:type ;
    sh:object ex:Square ;
    sh:condition ex:Rectangle ;
    sh:condition [
      sh:property [
        sh:path ex:width ;
        sh:equals ex:height ;
      ] ;
    ] ;
  ] .

A Code Example Using Jena

Naturally, you will need to add SHACL to your Maven pom dependencies. Then the following code will execute your SHACL rules:

package org.shacl.tutorial;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.apache.jena.rdf.model.Model;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RDFFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import org.topbraid.shacl.rules.RuleUtil;
import org.topbraid.spin.util.JenaUtil;

public class ShaclRuleExecution {
  private static Logger logger = LoggerFactory.getLogger(ShaclValidation.class);
  // Why This Failure marker
  private static final Marker WTF_MARKER = MarkerFactory.getMarker("WTF");

  public static void main(String[] args) {
    try {   
      Path path = Paths.get(".").toAbsolutePath().normalize();
      String data = "file:" + path.toFile().getAbsolutePath() + 
      String shape = "file:" + path.toFile().getAbsolutePath() + 

      Model dataModel = JenaUtil.createDefaultModel();
      Model shapeModel = JenaUtil.createDefaultModel();
      Model inferenceModel = JenaUtil.createDefaultModel();

      inferenceModel = RuleUtil.executeRules(dataModel, shapeModel, 
        inferenceModel, null);

      String inferences = path.toFile().getAbsolutePath() + 
      File inferencesFile = new File(inferences);
      OutputStream reportOutputStream = new FileOutputStream(inferencesFile);

      RDFDataMgr.write(reportOutputStream, inferenceModel, RDFFormat.TTL);        
    } catch (Throwable t) {
      logger.error(WTF_MARKER, t.getMessage(), t);

Running the Code

Running the code will cause an inferences.ttl file to be written out to $Project/src/main/resources/. It contains the following output:

@prefix owl:   <http://www.w3.org/2002/07/owl#> .
@prefix rdf:   <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs:  <http://www.w3.org/2000/01/rdf-schema#> .

  a  <http://example.com/ns#Square> .

Note that ex:InvalidRectangle has been ignored because it does not adhere to  sh:condition ex:Rectangle, since it does not have ex:height and ex:width properties. Also, ex:NonSquareRectangle is a rectangle, not a square.


In this post, I gave a brief overview of how SHACL can be used to implement rules on RDF data. This code example is available at GitHub.

big data, jena, rdf, rule execution, shacl

Published at DZone with permission of Henriette Harmse , DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}