Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error with your playground example: MaxCountConstraintComponent #118

Closed
benjaminaaron opened this issue Oct 26, 2023 · 3 comments
Closed

Comments

@benjaminaaron
Copy link

benjaminaaron commented Oct 26, 2023

I am getting Error: Cannot find validator for constraint component http://www.w3.org/ns/shacl#MaxCountConstraintComponent when running your playground example:

Screenshot 2023-10-26 at 11 24 58

This is my script.js:

const fs = require("fs")

async function importDependencies() {
    const [{ default: rdfExt }, { default: ParserN3 }, { default: SHACLValidator }] = await Promise.all([
        import("rdf-ext"),
        import("@rdfjs/parser-n3"),
        import("rdf-validate-shacl")
    ])
    return { factory: rdfExt, ParserN3, SHACLValidator }
}

async function loadDataset(filePath) {
    const { factory, ParserN3 } = await importDependencies()
    const stream = fs.createReadStream(filePath)
    const parser = new ParserN3()
    return factory.dataset().import(parser.import(stream))
}

async function run() {
    const { factory, SHACLValidator } = await importDependencies()
    const shapes = await loadDataset("shapes.ttl")
    const data = await loadDataset("data.ttl")

    const validator = new SHACLValidator(shapes, { factory })
    const report = await validator.validate(data)

    console.log(report)
}

run()

And this is my package.json:

{
  "dependencies": {
    "@rdfjs/parser-n3": "^2.0.1",
    "rdf-ext": "^2.4.0",
    "rdf-validate-shacl": "^0.5.1"
  }
}

I run it like this: node script.js.

👉 However, if I rewrite the SHACL shapes to not include blank nodes, it works:

@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix schema: <http://schema.org/> .

schema:PersonNamePropertyShape a sh:PropertyShape ;
    sh:path schema:name ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
.

schema:PersonAgePropertyShape a sh:PropertyShape ;
    sh:path schema:age ;
    sh:minCount 1 ;
    sh:minInclusive 18 ;
.

schema:Person
    a rdfs:Class, sh:NodeShape ;
    sh:property schema:PersonNamePropertyShape, schema:PersonAgePropertyShape ;
.

That makes me think that you might have an internal bug regarding blank nodes? Or am I doing something wrong? 🤔

@benjaminaaron
Copy link
Author

benjaminaaron commented Oct 26, 2023

One additional observation. If I reduce the conditions from 2 to 1 in the example it works ([] instead of [],[]). So maybe the problem has to do with blank node in combination with multiple conditions?

@tpluscode
Copy link
Collaborator

Thank you for getting in touch about this. I was able to replicate your issue

You were right about blank nodes. Internally, the shapes graph is combined with the SHACL triples themselves and this is where blank nodes get mixed up.

It is a common problem with RDF/JS stack, which has no easy solution. The easiest possible fix of your snippet would be to ensure the parsing happens using the same factory you later pass to the SHACL Engine

async function loadDataset(filePath) {
    const { factory, ParserN3 } = await importDependencies()
    const stream = fs.createReadStream(filePath)
+   const parser = new ParserN3()
+   const parser = new ParserN3({ factory })
    return factory.dataset().import(parser.import(stream))
}

Otherwise, I might suggest to simplify this code significantly by using the RDF Environment. You could keep rdf-ext, or try @zazuko/env-node, which comes with some extra bells and whistles.

import SHACLValidator from 'rdf-validate-shacl'
import factory from '@zazuko/env-node'

async function run() {
    // use factory to parse
    const shapes = await factory.dataset().import(factory.fromFile("shapes.ttl"))
    const data = await factory.dataset().import(factory.fromFile("data.ttl"))

    console.log(await shapes.serialize({ format: 'text/n3' }))

    const validator = new SHACLValidator(shapes, { factory })
    const report = await validator.validate(data)

    console.log(await report.dataset.serialize({ format: 'text/n3' }))
}

run()

factory.fromFile and dataset.serialize are additions only available in @zazuko/env-node. Else, the interface closely resembles rdf-ext

benjaminaaron added a commit to Citizen-Knowledge-Graph/citizen-knowledge-graph that referenced this issue Oct 26, 2023
@benjaminaaron
Copy link
Author

Great, thanks a lot @tpluscode! Your suggestion indeed makes it work 👍
I will also try your simplified approach, that looks much more compact 🤩

benjaminaaron added a commit to Citizen-Knowledge-Graph/citizen-knowledge-graph that referenced this issue Oct 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants