【问题标题】:Validating that every subject has a type of class验证每个主题都有一个类型的类
【发布时间】:2020-04-13 14:47:03
【问题描述】:

我有以下数据和形状图。

@prefix hr: <http://learningsparql.com/ns/humanResources#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix schema: <http://schema.org/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

hr:Employee a rdfs:Class .
hr:BadThree rdfs:comment "some comment about missing" .
hr:BadTwo a hr:BadOne .
hr:YetAnother a hr:Another .
hr:YetAnotherName a hr:AnotherName .
hr:Another a hr:Employee .
hr:AnotherName a hr:name .
hr:BadOne a hr:Dangling .
hr:name a rdf:Property .

schema:SchemaShape
    a sh:NodeShape ;
    sh:target [
        a sh:SPARQLTarget ;
        sh:prefixes hr: ;
        sh:select """
            SELECT ?this
            WHERE {
                ?this ?p ?o .
            }
            """ ;
    ] ; 

    sh:property [                
        sh:path rdf:type ;
        sh:nodeKind sh:IRI ;
        sh:hasValue rdfs:Class
    ] ; 
.

使用pySHACL

import rdflib

from pyshacl import validate

full_graph = open( "/Users/jamesh/jigsaw/shacl_work/data_graph.ttl", "r" ).read()

g = rdflib.Graph().parse( data = full_graph, format = 'turtle' )

report = validate( g, inference='rdfs', abort_on_error = False, meta_shacl = False, debug = False )
print( report[2] )

我认为应该发生的是基于 SPARQL 的目标应该选择数据图中的每个主题,然后验证是否存在 rdf:type 的路径,其值为 rdfs:Class。

我得到以下结果:

Validation Report
Conforms: True

预期的验证错误应仅包括以下主题:

| <http://learningsparql.com/ns/humanResources#BadOne>         |
| <http://learningsparql.com/ns/humanResources#BadTwo>         |
| <http://learningsparql.com/ns/humanResources#BadThree>       |
| <http://learningsparql.com/ns/humanResources#AnotherName>    |
| <http://learningsparql.com/ns/humanResources#name>           |
| <http://learningsparql.com/ns/humanResources#YetAnotherName> |

SHACL 可以做到这一点吗?如果是这样,形状文件应该是什么?

【问题讨论】:

  • 基于 SPARQL 的目标需要启用高级功能,因为这不是 SHACL 核心的一部分。尝试将advanced = True 添加到 validate 方法中。至少这是问题之一,不确定您的总体形状。
  • 这确实有助于我现在得到验证错误。但是,它会为 hr:Another 生成验证错误,因为它不是 rdfs:Class 类型。但它不应该是验证错误,因为它是 hr:Employee 的子类,其类型为 rdfs:Class。我在sh:focusNode "some comment about missing" ; 和其他不应该出现的验证错误上也遇到了奇怪的错误。我可以直接使用 SPARQL 进行此验证,并且很想知道如何使用 SHACL 进行验证。
  • 将当前验证错误放在gist.github.com/James-Hudson3010/…
  • 我还是不明白你的数据建模,但是如果你想遵循任意路径,你还必须在 SHACL 形状中说明这一点,所以使用sh:path ( rdf:type [ sh:zeroOrMorePath rdf:type ] )
  • hr:YetAnother 是 hr:Another 的子类,它是 hr:Employee 的子类,它是 rdfs:Class 的子类。他们都应该验证。其他一切都不应该因为没有 rdfs:Class 的 rdf:type 属性路径。形状文件应该如何报告未验证的主题?我将看看 sh:zeroOrMorePath。谢谢。

标签: sparql rdf turtle-rdf shacl


【解决方案1】:

接下来会导致预期的验证错误,但是,我仍然有几件事不明白。

  1. 不需要sh:prefixes hr: ;designed 为 SPARQL 目标 SELECT 语句本身提供前缀,仅此而已。

  2. Inference 需要被禁用。它正在插入三元组并尝试验证它们。在这个用例中,这不是我们想要的。应该验证的是架构中的内容,仅此而已。

  3. 我还认为,基于显然对 https://github.com/RDFLib/pySHACL/issues/46 的误解将所有内容放入单个图表中不会有问题。

graph_data = """
@prefix hr: <http://learningsparql.com/ns/humanResources#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix schema: <http://schema.org/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

hr:Employee a rdfs:Class .
hr:BadThree rdfs:comment "some comment about missing" .
hr:BadTwo a hr:BadOne .
hr:YetAnother a hr:Another .
hr:YetAnotherName a hr:AnotherName .
hr:Another a hr:Employee .
hr:AnotherName a hr:name .
hr:BadOne a hr:Dangling .
hr:name a rdf:Property .
"""

shape_data = '''
@prefix hr: <http://learningsparql.com/ns/humanResources#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix schema: <http://schema.org/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

schema:SchemaShape
    a sh:NodeShape ;
    sh:target [
        a sh:SPARQLTarget ;
        sh:prefixes hr: ;
        sh:select """
            SELECT ?this
            WHERE {
                ?this ?p ?o .
            }
            """ ;
    ] ; 

    sh:property [                
        sh:path ( rdf:type [ sh:zeroOrMorePath rdf:type ] ) ;
        sh:nodeKind sh:IRI ;
        sh:hasValue rdfs:Class
    ] ; 
.
'''

data  = rdflib.Graph().parse( data = graph_data, format = 'turtle' )
shape = rdflib.Graph().parse( data = shape_data, format = 'turtle' )

report = validate( data, shacl_graph=shape, abort_on_error = False, meta_shacl = False, debug = False, advanced = True )

使用基于 SPARQL 的约束的替代方案如下所示:

graph_data = """
@prefix hr: <http://learningsparql.com/ns/humanResources#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix schema: <http://schema.org/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

hr:Employee a rdfs:Class .
hr:BadThree rdfs:comment "some comment about missing" .
hr:BadTwo a hr:BadOne .
hr:YetAnother a hr:Another .
hr:YetAnotherName a hr:AnotherName .
hr:Another a hr:Employee .
hr:AnotherName a hr:name .
hr:BadOne a hr:Dangling .
hr:name a rdf:Property .
"""

shape_data = '''
@prefix hr: <http://learningsparql.com/ns/humanResources#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix schema: <http://schema.org/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

schema:SchemaShape
    a sh:NodeShape ;
    sh:target [
        a sh:SPARQLTarget ;
        sh:select """
            SELECT ?this
            WHERE {
                ?this ?p ?o .
            }
            """ ;
    ] ; 

    sh:sparql [ 
        a sh:SPARQLConstraint ; 
        sh:message "Node does not have type rdfs:Class." ; 
        sh:prefixes hr: ; 
        sh:select """ 
            SELECT $this 
            WHERE { 
                $this rdf:type ?o . 

                FILTER NOT EXISTS {
                    ?o rdf:type* rdfs:Class
                }
                FILTER ( strstarts( str( $this ), str( hr: ) ) ) 
            }
            """ ;
    ]
.
'''


data  = rdflib.Graph().parse( data = graph_data, format = 'turtle' )
shape = rdflib.Graph().parse( data = shape_data, format = 'turtle' )

report = validate( data, shacl_graph=shape, abort_on_error = False, meta_shacl = False, debug = False, advanced = True )

【讨论】:

  • 关于 1) 老实说,据我了解,这只是定义一些查询本地前缀,然后您可以在 SPARQL 查询本身中使用这些前缀。但这没有提到是$this 变量绑定的过滤器。关于 2) 推理,在您的情况下,RDFS 推理规则将在数据图验证之前应用,即根据 RDFS 规则,将生成新的三元组并将其添加到数据图中。
  • 如果您对此不满意,为什么不同时使用基于 SPARQL 的约束?而不是sh:property 部分,试试sh:sparql [ sh:message "Node does not have type rdfs:Class." ; sh:prefixes hr: ; sh:select """ SELECT $this WHERE { $this rdf:type ?o . FILTER NOT EXISTS {?o rdf:type* rdfs:Class} FILTER (strstarts(str($this), str(hr:)))} """ ; - 这不是你想要的吗?
  • 我不确定基于 SPARQL 的约束比答案中使用的约束有什么优势。他们似乎都有相同的结果。
  • 确实如此,我从来没有说过不同的话。我的意思是,您在“正常”的 SHACL 约束中苦苦挣扎,但最初说您已经能够通过 SPARQL 实现您所需要的。所以我的提示只是为了向您展示除了选择目标节点之外还可以使用 SPARQL 作为约束的机会 - 如果您已经有查询,则下次使用。
猜你喜欢
  • 2018-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多