mdesalvo/RDFSharp

Creating NodeShapes with connected PropertyShapes

Closed this issue · 2 comments

Hello!

A few colleagues and I are currently working on creating SHACL shapes graphs to validate local RDF/XML files. We are using RDFSharp to create the necessary shapes, but are having problems with some of the rules we want to create.

Our goal is to create "closed" NodeShapes with defined properties (PropertyShapes), but have't found a way to connect a RDFNodeShape to a set of RDFPropertyShapes. (see example here: Shapes Constraint Language - Shapes Graph Example)

SHACL Shapes Graph Example

ex:PersonShape
	a sh:NodeShape ;
	sh:targetClass ex:Person ;    # Applies to all persons
	sh:property [                        # _:b1
		sh:path ex:ssn ;            # constrains the values of ex:ssn
		sh:maxCount 1 ;
		sh:datatype xsd:string ;
		sh:pattern "^\\d{3}-\\d{2}-\\d{4}$" ;
	] ;
	sh:property [                 # _:b2
		sh:path ex:worksFor ;
		sh:class ex:Company ;
		sh:nodeKind sh:IRI ;
	] ;
	sh:closed true ;
	sh:ignoredProperties ( rdf:type ) .

Questions

  • Is it possible to create RDFNodeShapes with a list of attached RDFPropertyShapes in the current implementation of the library? We are currently using a workaround to implement this (see below).
  • Is it possible to contribute to the library? If yes, is there any preferred way of doing it?

Current Workaround

  1. Create RDFNodeShape
  2. Create RDFPropertyShape
  3. Create an RDFShapes Graph
  4. Attach both shapes to the graph
  5. Convert the graph to an RDFGraph
  6. Attach an RDFTriple to the graph, that connects the PropertyShape as "property" to the NodeShape
  7. Save everything to a .ttl file and/or use the graph to validate data graphs
var Graph = new RDFShapesGraph();
var nodeShape = new RDFNodeShape(new RDFResource("http://iec.ch/TC57/2013/CIM-schema-cim16#CoordinateSystem"));
var PropertyShape = new RDFPropertyShape(new RDFResource("http://iec.ch/TC57/2013/CIM-schema-cim16#CoordinateSystem.crsUrn"), new RDFResource("http://iec.ch/TC57/2013/CIM-schema-cim16#CoordinateSystem.crsUrn"));

Graph.AddShape(nodeShape);
Graph.AddShape(PropertyShape);

var rdfGraph = Graph.ToRDFGraph();

rdfGraph.AddTriple(new RDFTriple(
    new RDFResource("http://iec.ch/TC57/2013/CIM-schema-cim16#CoordinateSystem"),
    new RDFResource("http://www.w3.org/ns/shacl#property"),
    new RDFResource("http://iec.ch/TC57/2013/CIM-schema-cim16#CoordinateSystem.crsUrn")));

rdfGraph.ToFile(RDFModelEnums.RDFFormats.Turtle, path_shacl_rules);

Result from Workaround

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix sh: <http://www.w3.org/ns/shacl#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@base <https://rdfsharp.codeplex.com/>.

<http://iec.ch/TC57/2013/CIM-schema-cim16#CoordinateSystem> a sh:NodeShape; 
                                                            sh:deactivated "false"^^xsd:boolean; 
                                                            sh:property <http://iec.ch/TC57/2013/CIM-schema-cim16#CoordinateSystem.crsUrn>; 
                                                            sh:severity sh:Violation. 
<http://iec.ch/TC57/2013/CIM-schema-cim16#CoordinateSystem.crsUrn> a sh:PropertyShape; 
                                                                   sh:deactivated "false"^^xsd:boolean; 
                                                                   sh:path <http://iec.ch/TC57/2013/CIM-schema-cim16#CoordinateSystem.crsUrn>; 
                                                                   sh:severity sh:Violation. 

Wanted Features

We would love to have a way to directly add RDFPropertyShapes to RDFNodeShapes and to convert the resulting ShapesGraph to RDF etc..

Hi Stephan,
here is an implementation of the example turtle file showing usage of constraints and targets:

var shapesGraph = new RDFShapesGraph();

var nodeShape = new RDFNodeShape(new RDFResource("ex:PersonShape"));
nodeShape.AddTarget(new RDFTargetClass(new RDFResource("ex:Person")));
nodeShape.AddConstraint(new RDFPropertyConstraint(new RDFResource("ex:PropertyShapeSSN")));
nodeShape.AddConstraint(new RDFPropertyConstraint(new RDFResource("ex:PropertyShapeWorksFor")));
nodeShape.AddConstraint(new RDFClosedConstraint(true).AddIgnoredProperty(RDFVocabulary.RDF.TYPE));

var propertyShapeSSN = new RDFPropertyShape(new RDFResource("ex:PropertyShapeSSN"), new RDFResource("ex:ssn"));
propertyShapeSSN.AddConstraint(new RDFMaxCountConstraint(1));
propertyShapeSSN.AddConstraint(new RDFDatatypeConstraint(RDFModelEnums.RDFDatatypes.XSD_STRING));
propertyShapeSSN.AddConstraint(new RDFPatternConstraint(new Regex("^\\d{3}-\\d{2}-\\d{4}$")));

var PropertyShapeWorksFor = new RDFPropertyShape(new RDFResource("ex:PropertyShapeWorksFor"), new RDFResource("ex:worksFor"));
PropertyShapeWorksFor.AddConstraint(new RDFClassConstraint(new RDFResource("ex:Company")));
PropertyShapeWorksFor.AddConstraint(new RDFNodeKindConstraint(RDFValidationEnums.RDFNodeKinds.IRI));

shapesGraph.AddShape(nodeShape);
shapesGraph.AddShape(propertyShapeSSN);
shapesGraph.AddShape(PropertyShapeWorksFor);

It is of course possible to contribute to the library: posting questions, signalling issues, requesting new capabilities, also submitting PRs for targeting bugs or delivering new features.

Let me know if this coding example clarifies your doubts about usage of the library.
Regards,
marco

Hello Marco,

You are a live-safer, this is exactly what I was looking for.
Thanks for the very quick response and good example how to connect this. I never considered that "RDFPropertyConstraint" is used for this.

I do hope that we can contribute further, we will continue to use the library and post questions that we find or oddities that we notice.

Best Regards
Stephan