Validator pattern for traversing ShExJ schemas
npm install --save @shexjs/validator
Using Partition(<schema>, [<URL>s])
as an example, an illustrative way to invoke from it from the command line uses @shexjs/parser
and N3.js
:
const ShExParser = require('@shexjs/parser');
const { ctor: RdfJsDb } = require('@shexjs/neighborhood-rdfjs')
const {ShExValidator} = require('@shexjs/validator');
const {Parser: N3Parser, Store: N3Store} = require('n3');
const base = 'http://a.example/';
const shexc = `
<S1> {
<p1> . ;
<p2> . ;
}`;
const turtle = `
<n1> <p1> 1 ; <p3> 2 . # missing p2
<n2> <p4> 1 ; <p2> 2 . # missing p1
`;
const schema = ShExParser.construct(base)
.parse(shexc);
const g = new N3Store();
new N3Parser({baseIRI: base}).parse(turtle, (error, quad, prefixes) => {
if (quad)
g.addQuad(quad);
else
console.log(JSON.stringify(
new ShExValidator(schema, RdfJsDb(g))
.validate([{node: base + 'n1', shape: base + 'S1'},
{node: base + 'n2', shape: base + 'S1'}]),
null, 2 # stringify args
));
});
The result is a JSON structure which reports the expected errors
{
"type": "FailureList",
"errors": [
{
"type": "Failure",
"node": "http://a.example/n1",
"shape": "http://a.example/S1",
"errors": [
{
"type": "MissingProperty",
"property": "http://a.example/p2"
}
]
},
{
"type": "Failure",
"node": "http://a.example/n2",
"shape": "http://a.example/S1",
"errors": [
{
"type": "MissingProperty",
"property": "http://a.example/p1"
}
]
}
]
}
If we correct the two errors in the above Turtle:
<n1> <p1> 1 ; <p2> 2 . # fixed missing p2
<n2> <p1> 3 ; <p2> 4 . # fixed missing p1
, the validator gives us a proof of conformance:
{
"type": "SolutionList",
"solutions": [
{
"type": "ShapeTest",
"node": "http://a.example/n1",
"shape": "http://a.example/S1",
"solution": {
"type": "EachOfSolutions",
"solutions": [
{
"type": "EachOfSolution",
"expressions": [
{
"type": "TripleConstraintSolutions",
"predicate": "http://a.example/p1",
"solutions": [
{
"type": "TestedTriple",
"subject": "http://a.example/n1",
"predicate": "http://a.example/p1",
"object": {
"value": "1",
"type": "http://www.w3.org/2001/XMLSchema#integer"
}
}
]
},
{
"type": "TripleConstraintSolutions",
"predicate": "http://a.example/p2",
"solutions": [
{
"type": "TestedTriple",
"subject": "http://a.example/n1",
"predicate": "http://a.example/p2",
"object": {
"value": "2",
"type": "http://www.w3.org/2001/XMLSchema#integer"
}
}
]
}
]
}
]
}
},
{
"type": "ShapeTest",
"node": "http://a.example/n2",
"shape": "http://a.example/S1",
"solution": {
"type": "EachOfSolutions",
"solutions": [
{
"type": "EachOfSolution",
"expressions": [
{
"type": "TripleConstraintSolutions",
"predicate": "http://a.example/p1",
"solutions": [
{
"type": "TestedTriple",
"subject": "http://a.example/n2",
"predicate": "http://a.example/p1",
"object": {
"value": "3",
"type": "http://www.w3.org/2001/XMLSchema#integer"
}
}
]
},
{
"type": "TripleConstraintSolutions",
"predicate": "http://a.example/p2",
"solutions": [
{
"type": "TestedTriple",
"subject": "http://a.example/n2",
"predicate": "http://a.example/p2",
"object": {
"value": "4",
"type": "http://www.w3.org/2001/XMLSchema#integer"
}
}
]
}
]
}
]
}
}
]
}
The triple expression in a Shape is essentially a fancy regular expression. shex.js ships with two evaluators:
- eval-threaded-nerr (default) - Exhaustively enumerate combinations of ways the data fails to satisfy a shape's expression.
- eval-simple-1err - Report only one error.
You can specify which module to use with the schema options parameter to the validator constructor:
new ShExValidator(schema, RdfJsDb(g), {
regexModule: require('@shexjs/eval-simple-1err')
})
One form of ShEx extensibility is the declaration of external shapes:
<S1> {
<p1> @<S2>
}
<S2> EXTERNAL
These must be supplied to your validator but the ShEx specification does not specify how. In ShExJS, these must be supplied as a constructor argument:
new ShExValidator(schema, RdfJsDb(g), {
regexModule: require('@shexjs/eval-simple-1err'),
validateExtern: myValidator
})
function myValidator (point, shapeLabel, ctx) { // (RdfJs.Term, string, ShapeExprValidationContext) -> ShExV.shapeExprTest
if (shapeLabel === "http://a.example/S2") {
const p2z = g.getQuads(point, 'http://a.example/p2', null);
if (p2z.length === 1) {
return {
"type": "ShapeTest",
"node": "_:b0",
"shape": "http://a.example/S2",
"solution": {
"type": "TripleConstraintSolutions",
"predicate": "http://a.example/p2",
"solutions": [
{
"type": "TestedTriple",
"subject": point,
"predicate": "http://a.example/p2",
"object": p2z[0].object.value
}
]
}
};
}
}
}
Failure to supply an external validator function when validating a schema with external shapes will result in an exception:
TypeError: this.options.validateExtern is not a function
This repo uses lerna to manage multiple NPM packages. These packages are located in packages/*
:
shape-map
-- a ShapeMap parser@shexjs/parser
-- parse ShExC into ShExJ@shexjs/writer
-- serialize ShExK as ShExC@shexjs/term
-- RDF terms uses in ShEx@shexjs/util
-- some utilities for transforming schemas or validation output@shexjs/visitor
-- a visitor for schemas@shexjs/validator
-- validate nodes in an RDF graph against shapes in a schema@shexjs/eval-validator-api
-- API called by@shexjs/validator
for validating Shapes, with tripleExpressions and EXTENDS etc.@shexjs/eval-simple-1err
-- Implementation of@shexjs/eval-validator-api
which reports only one error.@shexjs/eval-threaded-nerr
-- Implementation of@shexjs/eval-validator-api
which exhaustively enumerate combinations of ways the data fails to satisfy a shape's expression.@shexjs/loader
-- an API for loading and using ShEx schemas@shexjs/node
-- additional API functionality for a node environment@shexjs/cli
-- a set of command line tools for transformaing and validating with schemas@shexjs/webapp
-- the shex-simple WEBApp@shexjs/shape-path-query
-- traverse ShEx schemas with a path language@shexjs/extension-test
-- a small language for testing semantic actions in ShEx implementations (more)@shexjs/extension-map
-- an extension for transforming data from one schema to another (more)@shexjs/extension-eval
-- simple extension which evaluates Javascript semantic action code (more)