在Apache Jena中使用DASH执行SHACL验证时出现异常约束错误的问题
我尝试在Apache Jena中使用DASH形状词汇对本体进行SHACL验证,编写代码如下:
String SHAPES = """ @prefix : <https://example.com/> . @prefix sh: <http://www.w3.org/ns/shacl#> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix owl: <http://www.w3.org/2002/07/owl#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @prefix dash: <http://datashapes.org/dash#> . <https://example.com/> a owl:Ontology ; owl:imports <http://datashapes.org/dash> . :person a sh:NodeShape ; a rdfs:Class ; dash:closedByTypes true ; sh:ignoredProperties ( rdf:type ) ; sh:property [ sh:path :name ; ] . """; String DATA = """ @prefix : <https://example.com/> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . :person-1 a :person ; :name "John"^^xsd:string ; . """; RDFParser shapesTurtleParser = RDFParser.source(new ByteArrayInputStream(SHAPES.toString().getBytes(StandardCharsets.UTF_8))) .forceLang(Lang.TTL) .build(); Graph shapesGraph = shapesTurtleParser.toGraph(); // 不加这行验证能通过 shapesGraph = Imports.withImports(shapesGraph); RDFParser dataTurtleParser = RDFParser.source(new ByteArrayInputStream(DATA.toString().getBytes(StandardCharsets.UTF_8))) .forceLang(Lang.TTL) .build(); Graph dataGraph = dataTurtleParser.toGraph(); ValidationReport report = ShaclValidator.get().validate(shapesGraph, dataGraph); RDFDataMgr.write(System.out, report.getModel(), Lang.TTL);
验证结果输出:
@prefix : <https://example.com/> . @prefix dash: <http://datashapes.org/dash#> . @prefix owl: <http://www.w3.org/2002/07/owl#> . @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . @prefix sh: <http://www.w3.org/ns/shacl#> . @prefix tosh: <http://topbraid.org/tosh#> . @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . [ rdf:type sh:ValidationReport; sh:conforms false; sh:result [ rdf:type sh:ValidationResult; sh:focusNode :person-1; sh:resultMessage "Property <https://example.com/name> is not among those permitted for any of the types"; sh:resultPath :name; sh:resultSeverity sh:Violation; sh:sourceConstraintComponent dash:ClosedByTypesConstraintComponent; sh:sourceShape :person; sh:value "John" ] ] .
明明:name属性已经在Shape中声明,却得到了dash:ClosedByTypesConstraintComponent的验证错误,请问问题出在哪里?
原因分析
dash:closedByTypes的核心逻辑是仅允许目标类在本体中定义的属性,而非Shape里sh:property声明的属性。你的代码中:name没有被关联为:person类的属性(比如通过rdfs:domain),因此导入DASH本体后,验证器会检查数据图中:person-1的属性是否属于:person类允许的属性集合,:name不在这个集合内,所以触发错误。
另外,不调用Imports.withImports(shapesGraph)时,DASH的约束组件未被正确加载,dash:closedByTypes并未生效,所以验证能通过,但这属于未启用约束的无效状态。
解决方案
有两种可行的修复方式:
为
:name属性关联:person类
在SHAPES的Turtle代码中添加:name的领域声明,明确它属于:person类的合法属性::name a rdf:Property ; rdfs:domain :person ; .这样
dash:closedByTypes会识别:name是:person允许的属性,验证即可通过。改用SHACL标准的
sh:closed约束
如果你不需要基于本体类的属性闭合验证,而是想基于Shape中声明的属性做检查,直接使用SHACL原生的sh:closed即可,无需依赖DASH::person a sh:NodeShape ; a rdfs:Class ; sh:closed true ; sh:ignoredProperties ( rdf:type ) ; sh:property [ sh:path :name ] ; .这种方式下,验证器只会检查数据中的属性是否都在Shape的
sh:property列表中,符合你的预期。
内容的提问来源于stack exchange,提问作者sha

