为什么 SHACL API 的 SHShape.hasTargetNode Returns 对于目标 Class 是错误的?

Why SHACL API's SHShape.hasTargetNode Returns False For Targeted Class?

在断言 classes 时尝试选择性地调用 shapes/rules 的过程中,我正在使用以下示例形状定义(在 TTL 中):

# baseURI: http://example.org/familyShapes
# imports: http://datashapes.org/dash
# prefix: familyShapes

@prefix dash: <http://datashapes.org/dash#> .
@prefix familyShapes: <http://example.org/familyShapes#> .
@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 xsd: <http://www.w3.org/2001/XMLSchema#> .

<http://example.org/familyShapes>
  rdf:type owl:Ontology ;
  owl:imports <http://datashapes.org/dash> ;
.
familyShapes:FemaleShape
  rdf:type sh:NodeShape ;
  rdfs:label "Female shape" ;
  sh:property [
      sh:path familyShapes:gender ;
      sh:hasValue familyShapes:female ;
    ] ;
.
familyShapes:Gender
  rdf:type rdfs:Class ;
  rdfs:label "Gender" ;
  rdfs:subClassOf rdfs:Resource ;
.
familyShapes:GrandpaRuleShape
  rdf:type sh:NodeShape ;
  rdfs:label "Grandpa rule shape" ;
  sh:rule [
      rdf:type sh:SPARQLRule ;
      rdfs:comment "Shape to infer grandpa/grandchild relationship" ;
      rdfs:label "Infer grandpas and grandchildren" ;
      sh:construct """
        PREFIX familyShapes: <http://example.org/familyShapes#>

        CONSTRUCT {
          ?child familyShapes:grandPa $this .
          $this familyShapes:grandChild ?child .
        }
        WHERE {
        {
           ?child familyShapes:mother ?mom .
           ?mom familyShapes:father $this .
        }
        UNION 
        {
           ?child familyShapes:father ?dad .
           ?dad familyShapes:father $this .
        }
      }
   """ ;
      sh:order 10 ;
    ] ;
  sh:targetClass familyShapes:Person ;
.
familyShapes:MaleShape
  rdf:type sh:NodeShape ;
  rdfs:label "Male shape" ;
  sh:property [
      sh:path familyShapes:gender ;
      sh:hasValue familyShapes:male ;
    ] ;
.
familyShapes:Person
  rdf:type rdfs:Class ;
  rdf:type sh:NodeShape ;
  rdfs:label "Person" ;
  rdfs:subClassOf rdfs:Resource ;
  sh:property [
      rdf:type sh:PropertyShape ;
      sh:path familyShapes:father ;
      sh:class familyShapes:Person ;
      sh:description "A Person's father." ;
      sh:maxCount 1 ;
      sh:name "father" ;
      sh:node familyShapes:MaleShape ;
      sh:nodeKind sh:IRI ;
      sh:sparql [
          sh:message "A person cannot be a father to that same person." ;
          sh:select """PREFIX familyShapes: <http://example.org/familyShapes#>

SELECT $this
WHERE {
    $this familyShapes:father $this .
}""" ;
        ] ;
    ] ;
  sh:property [
      rdf:type sh:PropertyShape ;
      sh:path familyShapes:firstName ;
      sh:datatype xsd:string ;
      sh:description "A Person's first name (aka given name)." ;
      sh:minCount 1 ;
      sh:name "first name" ;
    ] ;
  sh:property [
      rdf:type sh:PropertyShape ;
      sh:path familyShapes:gender ;
      sh:class familyShapes:Gender ;
      sh:description "A Person's gender." ;
      sh:maxCount 1 ;
      sh:minCount 1 ;
      sh:name "gender" ;
    ] ;
  sh:property [
      rdf:type sh:PropertyShape ;
      sh:path familyShapes:lastName ;
      sh:datatype xsd:string ;
      sh:description "A Person's last name (aka family name)." ;
      sh:maxCount 1 ;
      sh:minCount 1 ;
      sh:name "last name" ;
    ] ;
  sh:property [
      rdf:type sh:PropertyShape ;
      sh:path familyShapes:mother ;
      sh:class familyShapes:Person ;
      sh:description "A Person's mother." ;
      sh:maxCount 1 ;
      sh:name "mother" ;
      sh:node familyShapes:FemaleShape ;
      sh:nodeKind sh:IRI ;
      sh:sparql [
          rdfs:comment "A person cannot be that same person's mother." ;
          sh:message "A person cannot be that same person's mother." ;
          sh:select """PREFIX familyShapes: <http://example.org/familyShapes#>

SELECT $this 
WHERE {
    $this familyShapes:mother $this .
}""" ;
        ] ;
    ] ;
  sh:rule [
      rdf:type sh:SPARQLRule ;
      rdfs:label "Infer grandmas and grandchildren" ;
      sh:construct """PREFIX familyShapes: <http://example.org/familyShapes#>

CONSTRUCT {
      ?child familyShapes:grandMa $this .
      $this familyShapes:grandChild ?child .
}
WHERE {
      {
        ?child familyShapes:mother ?mom .
        ?mom familyShapes:mother $this .
      }
      UNION 
      {
        ?child familyShapes:father ?dad .
        ?dad familyShapes:mother $this .
      }
}
        """ ;
    ] ;
.
familyShapes:female
  rdf:type familyShapes:Gender ;
  rdfs:label "female" ;
.
familyShapes:firstName
  rdf:type rdf:Property ;
  rdfs:comment "A Person's first name (aka given name)." ;
  rdfs:label "first name" ;
.
familyShapes:grandChild
  rdf:type owl:ObjectProperty ;
  rdfs:domain familyShapes:Person ;
  rdfs:label "grand child" ;
  rdfs:range familyShapes:Person ;
.
familyShapes:grandMa
  rdf:type owl:ObjectProperty ;
  rdfs:domain familyShapes:Person ;
  rdfs:label "grand ma" ;
  rdfs:range familyShapes:Person ;
.
familyShapes:grandPa
  rdf:type owl:ObjectProperty ;
  rdfs:domain familyShapes:Person ;
  rdfs:label "grand pa" ;
  rdfs:range familyShapes:Person ;
.
familyShapes:male
  rdf:type familyShapes:Gender ;
  rdfs:label "male" ;
.
familyShapes:mother
  rdf:type rdf:Property ;
  rdfs:comment "A Person's mother." ;
  rdfs:label "mother" ;
.

我现在专注于 familyShapes:GrandpaRuleShape 形状(从第 30 行开始),我相信第 58 行的目标是 familyShapes:Person class.

SHACL API 的 RuleUtil.getShapesWithTargetNode 方法 return 是一个空列表,这不是我期望的结果,所以我创建了一个临时的本地副本RuleUtil.getShapesWithTargetNode如下所示的方法帮助我调试自己的代码。

private static List<Shape> getShapesWithTargetNode(RDFNode focusNode, ShapesGraph shapesGraph) {
    // TODO: Not a particularly smart algorithm - walks all shapes that have rules
    List<Shape> shapes = new ArrayList<>();
    for(Shape shape : shapesGraph.getRootShapes()) {
        SHShape sr = shape.getShapeResource();
        boolean shapeHasRule = sr.hasProperty(SH.rule);
        boolean shapeFocused = sr.hasTargetNode(focusNode);
        if(shapeHasRule && shapeFocused) {
            shapes.add(shape);
        }
    }
    return shapes;
}

我已经停止在调试器中使用 focusNode=http://example.org/familyShapes#Person 和表示上述形状文件的 shapesGraph 方法在调试器中执行。在分配了两个布尔值之后,断点位于 for 循环中的条件处。 shape 的第一个值是 familyShapes:GrandpaRuleShape。但是,布尔值 shapeFocusedfalse。布尔值 shapeHasRule 是预期的 true

我原以为 shapeFocused 在这个执行点会是 true。在更高的层次上,我期待这个方法 return 一个至少包含爷爷形状的列表,但它 return 是空的。我想我一定是错误地设置了对该方法的调用,但我不确定我做错了什么。有什么建议吗?

我认为它工作正常。人是 class 并且规则形状具有 sh:targetClass 人。这意味着 focus/target 节点是 class 的 实例 。如果您使用特定的 Person 实例调用该函数,那么它应该可以工作。