SHACL 比较两个不同节点上的值?

SHACL to compare values on two different nodes?

我正在尝试为开始日期必须小于或等于结束日期的日期比较编写 SHACL 约束。当使用 :beginDate:endDate 谓词将日期附加到同一节点时,约束是直接的:

:StartEndRuleShape a :PropertyShape  ;
  sh:path              :beginDate ;
  sh:lessThanOrEquals  :endDate ;
  sh:message "Begin Date is after End Date." .

现实世界的模型更为复杂。在附图中,请注意 :AnimalSubject hasReferenceInterval 的方式。 ReferenceInterval IRI 有一个 :ReferenceBegin 和一个 :ReferenceEnd,它们依次使用 time:inXSDDate 谓词分配日期值。在这种情况下如何应用约束以确保 ReferenceBegin 值等于或小于 ReferenceEnd 值?这是使用 SHACL-SPARQL 还是 sequencePath 的情况?我一直无法找到任何一个的好例子。 干杯!

我在违反约束的数据上测试了以下 SHACL-SPARQL:ReferenceBegin = "2016-12-07", ReferenceEnd = "2016-12-06",但验证报告未检测到违规。如果我 运行 SPARQL 本身,它确实会挑选出观察结果。关于为什么的任何想法?我正在使用 Stardog/Stardog Studio 并且还在他们的用户支持平台上发帖。

@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix sh:  <http://www.w3.org/ns/shacl#> .
@prefix time: <http://www.w3.org/2006/time#> .
@prefix xsd:  <http://www.w3.org/2001/XMLSchema#> .
@prefix :     <http://foo.bar.org/> .

:IntervalShape a sh:NodeShape ;
 sh:targetClass :ReferenceInterval ;
 sh:sparql [
  a sh:SPARQLConstraint ;
  sh:message "End Date must be greater than or equal to Begin Date";
  sh:prefixes [
    sh:declare [
      sh:prefix "time" ;
      sh:namespace "http://www.w3.org/2006/time#"^^xsd:anyURI ;
    ] 
  ] ;
 sh:select
  """SELECT $this (?beginDate AS ?intervalStart) (?endDate AS ?intervalEnd)
    WHERE {
      $this     :hasReferenceInterval ?interval .
      ?interval :ReferenceBegin       ?beginIRI ;
                :ReferenceEnd         ?endIRI .
      ?beginIRI time:inXSDDate        ?beginDate .
      ?endIRI   time:inXSDDate        ?endDate .
      FILTER  (! (?endDate >= ?beginDate ))
    }""" ;
] .

看来您的约束有两个问题:

  1. 您在 SHACL 中声明了 time 前缀,而不是 base 前缀。你想要:

    sh:prefixes [
        sh:declare [
          sh:prefix "time" ;
          sh:namespace "http://www.w3.org/2006/time#"^^xsd:anyURI ;
        ], [
          sh:prefix "" ;
          sh:namespace "http://foo.bar.org/"^^xsd:anyURI ;
        ]
      ] ;
    
  2. 您的焦点节点是 :ReferenceInterval,但是您的查询的编写方式,$this 只会绑定到 :hasReferenceInterval [a :ReferenceInterval] 的实体。我重写了查询,使 ?interval 现在是 $this,如下所示:

    sh:select
      """SELECT $this (?beginDate AS ?intervalStart) (?endDate AS ?intervalEnd)
        WHERE {
          $this     :ReferenceBegin       ?beginIRI ;
                    :ReferenceEnd         ?endIRI .
          ?beginIRI time:inXSDDate        ?beginDate .
          ?endIRI   time:inXSDDate        ?endDate .
          FILTER  (! (?endDate >= ?beginDate ))
        }""" ;
    

    添加此约束后,我发现了违规行为。