I am trying to utilize SHACL-JS to access external JavaScript functions and perform constraint validation on an RDF graph. The reason for using external functions is I need to perform some complex mathematical operations, which cannot be performed directly within SHACL-SPARQL.
The shape graph I used is as follows:
PREFIX CSRO: <http://www.semanticweb.org/aagr657/ontologies/2023/9/CraneSpaceRepresentationOntology#>
PREFIX LinkOnt: <http://purl.org/ConstructLinkOnt/LinkOnt#>
PREFIX bot: <https://w3id.org/bot#>
PREFIX expr: <https://w3id.org/express#>
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
PREFIX geom: <http://rdf.bg/geometry.ttl#>
PREFIX ifc: <https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#>
PREFIX inst: <https://www.ugent.be/myAwesomeFirstBIMProject#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX sf: <http://www.opengis.net/ont/sf#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX omg: <https://w3id.org/omg#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX lbd: <https://linkedbuildingdata.org/LBD#>
PREFIX props: <http://lbd.arch.rwth-aachen.de/props#>
PREFIX unit: <http://qudt.org/vocab/unit/>
PREFIX IFC4-PSD: <https://www.linkedbuildingdata.net/IFC4-PSD#>
PREFIX smls: <https://w3id.org/def/smls-owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX fog: <https://w3id.org/fog#>
PREFIX vann: <http://purl.org/vocab/vann/>
PREFIX express: <https://w3id.org/express#>
PREFIX dce: <http://purl.org/dc/elements/1.1/>
PREFIX cc: <http://creativecommons.org/ns#>
PREFIX sh: <http://www.w3.org/ns/shacl#>
inst:
sh:declare [
sh:prefix "inst";
sh:namespace "https://www.ugent.be/myAwesomeFirstBIMProject#"^^xsd:anyURI ;
];
sh:declare [
sh:prefix "ifc";
sh:namespace "https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#"^^xsd:anyURI ;
];
sh:declare [
sh:prefix "owl";
sh:namespace "http://www.w3.org/2002/07/owl#"^^xsd:anyURI ;
];
sh:declare [
sh:prefix "LinkOnt";
sh:namespace "http://purl.org/ConstructLinkOnt/LinkOnt#"^^xsd:anyURI ;
];
sh:declare [
sh:prefix "CSRO";
sh:namespace "http://www.semanticweb.org/aagr657/ontologies/2023/9/CraneSpaceRepresentationOntology#"^^xsd:anyURI ;
];
sh:declare [
sh:prefix "bot";
sh:namespace "https://w3id.org/bot#"^^xsd:anyURI ;
];
sh:declare [
sh:prefix "geo";
sh:namespace "http://www.opengis.net/ont/geosparql#"^^xsd:anyURI ;
];
sh:declare [
sh:prefix "sf";
sh:namespace "http://www.opengis.net/ont/sf#"^^xsd:anyURI ;
];
sh:declare [
sh:prefix "rdfs";
sh:namespace "http://www.w3.org/2000/01/rdf-schema#"^^xsd:anyURI ;
];
sh:declare [
sh:prefix "rdf";
sh:namespace "http://www.w3.org/1999/02/22-rdf-syntax-ns#"^^xsd:anyURI ;
].
inst:checkCollision
rdf:type sh:JSFunction ;
sh:parameter [
sh:path inst:surface1;
sh:datatype geo:wktLiteral;
];
sh:parameter [
sh:path inst:surface2;
sh:datatype geo:wktLiteral;
];
sh:returnType xsd:boolean;
sh:jsLibrary [ sh:jsLibraryURL "http://localhost:8000/Constraint_Checking_Functions.js"^^xsd:anyURI ] ;
sh:jsFunctionName "checkEquality" .
inst:boundingBoxIntersectionDetection
rdf:type sh:NodeShape ;
sh:target [
rdf:type sh:SPARQLTarget ;
sh:prefixes inst: ;
sh:select """
SELECT $this
WHERE {
$this rdf:type ifc:IfcTask;
LinkOnt:TaskLevel LinkOnt:SubActivity.
}
""";
];
sh:sparql [
rdf:type sh:SPARQLConstraint ;
sh:message "Space constraint is violated" ;
sh:prefixes inst: ;
sh:select"""
SELECT $this
WHERE {
$this LinkOnt:HasResource ?resource.
?resource rdf:type LinkOnt:Resource;
LinkOnt:ResourceType LinkOnt:Equipment;
owl:sameAs ?crane.
?crane rdf:type CSRO:CrawlerCrane;
CSRO:hasComponent ?craneComponent.
?craneComponent CSRO:hasBoundingBox ?polyhedralsurface1.
?polyhedralsurface1 rdf:type sf:PolyhedralSurface;
geo:asWKT ?surfaceValue1.
?siteElement rdf:type bot:Element;
CSRO:hasBoundingBox ?polyhedralsurface2.
?polyhedralsurface2 rdf:type sf:PolyhedralSurface;
geo:asWKT ?surfaceValue2.
BIND (inst:checkCollision(?surfaceValue1, ?surfaceValue2) AS ?result).
FILTER (?result = "true")
}
""";
].
This is a sample shape, which I am using just for testing purpose. The objective of this shape is just to validate that no two bounding boxes in the RDF data are equal (as I said, this is just for testing purpose, just to get the approach right. I’ll be developing shape and JS functions for more complex operations).
The JS function checkEquality is as follows:
function checkEQuality ($surfaceValue1, $surfaceValue2) {
if ($surfaceValue1 = $surfaceValue2) {
return "true";
}
}
The link to the datagraph is (sharing the link as it is a large file) –
https://drive.google.com/file/d/1Dz8M0obbajLOWvy8RYGzXgL3LSRsVEHl/view?usp=sharing
For validation, I used two approaches – One using PySHACL and the Second using Apache Jena SHACl.
- PySHACL – The code used for validation is as follows :
from pyshacl import validate
conforms, v_graph, v_text = validate(data_graph, shacl_graph=shape_graph, ont_graph = None, advanced = True, inference='rdfs', js=True)
Where, the data graph and shape_graph point to the turtle files containing the data graph and shape graph respectively.
2. Apache Jena CLI –
shacl validate --shapes=path_to_shape_graph_file --data=path_to_data_graph_file
However, using both the approaches, the validation result always comes to be true.
The validation result for PySHACL is as follows –
True
Validation Report
Conforms: True
The validation result for Apache jena is as follows –
[ rdf:type sh:ValidationReport;
sh:conforms true
] .
The problem is, I am not sure if the shape is actually accessing the external function or not. This is because, for the FILTER statement in the SPARQL constraint, whatever value of the string I use in FILTER (?result = "true")
in place of “true”, the validation result is always true, which should not be the case. I think there is something wrong with the way the JS function is being accessed and the arguments are being passed.
Could anyone please suggest if what I am trying is the right way of accessing the JavaScript functions from SHACL_JS and passing the arguments? What changes should be made to the shape so that I can pass the arguments to the external JS function and use the computation results for constraint checking. I searched a lot online, but not much of the information is available, other than the official W3C SHACL-JS documentation.
(I am not sure about Apache Jena CLI, but PySHACL supports SHACL-JS. So I think support of SHACL-JS should not be a problem).
Thanks.