@shexjs/validator
v1.0.0-alpha.30
Published
Shape Expressions Validator and schema index generator.
Readme
@shexjs/validator
Validator pattern for traversing ShExJ schemas
install
npm install --save @shexjs/validatorInvocation
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"
}
]
}
]
}Validation Proof
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"
}
}
]
}
]
}
]
}
}
]
}Specifying Shape Evaluator
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')
})External Shapes
One form of ShEx extensibility is the declaration of external shapes:
<S1> {
<p1> @<S2>
}
<S2> EXTERNALThese 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 functionTesting
Run this package's tests from packages/:
cd .. && npx mocha -C shex-validator/test/Validation-test.jsSelecting tests
Set TESTS to a regular expression matched against test ids, schema and data
file names to run a subset:
TESTS='vitals-RESTRICTS' npx mocha -C shex-validator/test/Validation-test.jsRegenerating reference results (REGEN=1)
Validation-test.js compares validation output against the reference results
in test/val/ (as mapped by test/val/test-result-map.json). When an
intentional change to the validator alters the ShExResults structures, set
REGEN=1 to rewrite the reference file of any test whose (canonicalized)
result no longer matches, instead of failing the assertion:
TESTS='(ExtendsRepeatedP-pass|2dot_fail-empty-err)' REGEN=1 npx mocha -C shex-validator/test/Validation-test.jsThe run reports the regenerated tests as passing; review the rewritten files
with git diff (or ediff) and commit the ones that reflect the intended
change. Always scope REGEN with TESTS to the tests you mean to regenerate —
an unscoped REGEN=1 run will absorb any mismatch, including real
regressions. Tests without an entry in test-result-map.json only check
conformance status and are unaffected.
Result names
When validating EXTENDS hierarchies, the first result for each extension/subgraph
pair carries a "resultName"; identical re-examinations in later partitions emit
{"type": "ResultReference", "ref": <resultName>} instead of repeating it. A
result name is the focus node followed by a
ShExPath expression addressing the
extension: a labeled extension by its shape-declaration selector,
<http://a.example/s>@<http://a.example/#B>an inline extension by a step into the extending shape's EXTENDS list
(…@<label>/extends/*[0] — extends selects the list, which is an item of its
own in ShExPath, /* steps into it and [0] picks the first out).
Only when the same node and extension are validated against a different
subgraph is a disambiguating #2, #3, … appended.
Lerna Monorepo
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/validatorfor validating Shapes, with tripleExpressions and EXTENDS etc.@shexjs/eval-simple-1err-- Implementation of@shexjs/eval-validator-apiwhich reports only one error.@shexjs/eval-threaded-nerr-- Implementation of@shexjs/eval-validator-apiwhich 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)

