You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用pyshacl验证数据图时出现BadSyntax错误排查

排查PySHACL验证Linked Building Data时的BadSyntax错误

我尝试用PySHACL将数据图和SHACL形状图做验证,目标是检查小型关联建筑数据里两堵墙的间距。数据图是现有转换器生成的Turtle格式文件,我认为它没问题,但运行代码时抛出了BadSyntax错误,无法定位形状图的语法问题。

原代码

# 从本地文件加载数据图
from pyshacl import validate
from rdflib import Graph

g = Graph()
Datagraph = g.parse("C:/Users/aagr657/OneDrive - The University of Auckland/UoA/Outcomes/RQ2/Models/Walls_with_Crane_LBD.ttl", format="ttl")

# 编写形状图
Shapegraph = ''' 
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix bot: <https://w3id.org/bot#> .
@prefix ifc: <https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix lbd: <https://linkebuildingdata.org/LBD#> .
@prefix props: <http://lbd.arch.rwth-aachen.de/props#> .
@prefix geo: <http://www.opengis.net/ont/geosparql#> .
@prefix unit: <http://qudt.org/vocab/unit/> .
@prefix IFC4-PSD: <https://www.linkedbuildingdata.net/IFC4-PSD#> .
@prefix smls: <https://w3id.org/def/smls-owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix inst: <https://www.ugent.be/myAwesomeFirstBIMProject#> .
@prefix fog: <https://w3id.org/fog#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

ifc:geometricconstraintshape a sh:NodeShape ;
        sh:targetClass bot:Element;
        sh:sparql[
            sh:message "The geometric constraint is violated" ;
            sh:select " " "
            SELECT $this
            WHERE{
                inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353 a bot:element .
                inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd a bot:element .
                inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353_geometry_bb lbd:x-min ?x_min .
                inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd_geometry_bb lbd:x-max ?x_max .
                FILTER (ifc:computedistance(?x_min,?x_max)<=12.0) .
                } """ ;
            ] .
        
ifc:computedistance a sh:SPARQLFunction;
    rdfs:comment "Finds the distance between the two elements";
    sh:parameter[
        sh:path lbd:x_min ;
        sh:datatype xsd:double;
        sh:description "The inner x coordinate of the wall on the right side";
        ];
    
    sh:parameter[
        sh:path lbd:x_max ;
        sh:datatype xsd:double;
        sh:description "The outer x coordinate of the wall on the left side";
        ];
    
    sh:returnType xsd:double;
    sh:select"""
    SELECT (($x_min - $x_max) AS ?result)
    WHERE {
        }
    """.
'''

# 执行验证
r = validate(data_graph=Datagraph, shacl_graph=Shapegraph, data_graph_format="ttl", shacl_graph_format="ttl", inference="rdfs", debug=True, abort_on_error=False, meta_shacl=False, serialize_report_graph="ttl")
conforms, results_graph, results_text = r

错误信息

File ~\AppData\Roaming\Python\Python311\site-packages\IPython\core\interactiveshell.py:3505 in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)

  Cell In[15], line 61
    r = validate(data_graph = Datagraph, shacl_graph = Shapegraph, data_graph_format="ttl", shacl_graph_format="ttl", inference = "rdfs", debug = True, abort_on_error = False, meta_shacl = False, serialize_report_graph = "ttl")

  File ~\AppData\Local\anaconda3\Lib\site-packages\pyshacl\validate.py:439 in validate
    loaded_sg = load_from_source(

  File ~\AppData\Local\anaconda3\Lib\site-packages\pyshacl\rdfutil\load.py:406 in load_from_source
    target_g.parse(source=cast(IO[bytes], _source), format=rdf_format, publicID=public_id)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\graph.py:2473 in parse
    c = ConjunctiveGraph.parse(

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\graph.py:2251 in parse
    context.parse(source, publicID=publicID, format=format, **args)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\graph.py:1503 in parse
    raise se

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\graph.py:1494 in parse
    parser.parse(source, self, **args)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:2021 in parse
    p.loadStream(stream)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:479 in loadStream
    return self.loadBuf(stream.read())  # Not ideal

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:485 in loadBuf
    self.feed(buf)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:511 in feed
    i = self.directiveOrStatement(s, j)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:530 in directiveOrStatement
    j = self.statement(argstr, i)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:778 in statement
    j = self.property_list(argstr, i, r[0])

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:1140 in property_list
    i = self.objectList(argstr, j, objs)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:1190 in objectList
    i = self.object(argstr, i, res)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:1487 in object
    j = self.subject(argstr, i, res)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:785 in subject
    return self.item(argstr, i, res)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:877 in item
    return self.path(argstr, i, res)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:884 in path
    j = self.nodeOrLiteral(argstr, i, res)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:1515 in nodeOrLiteral
    j = self.node(argstr, i, res)

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:973 in node
    self.BadSyntax(argstr, j, "']' expected")

  File ~\AppData\Local\anaconda3\Lib\site-packages\rdflib\plugins\parsers\notation3.py:1730 in BadSyntax
    raise BadSyntax(self._thisDoc, self.lines, argstr, i, msg)

BadSyntax

问题定位与修复

错误根源是形状图的Turtle语法问题,和数据图无关——错误栈显示rdflib在解析形状图时触发了语法错误,而数据图加载步骤没有报错,说明数据图是正常的。

具体问题和修复点:

  1. SPARQL字符串的引号嵌套错误:在Python三重单引号包裹的Turtle字符串中,不能直接用三重双引号包裹SPARQL内容,会导致解析器混淆,需调整引号层级。
  2. SPARQL函数参数路径错误:sh:parameter的sh:path应该定义参数变量名(比如$x_min),而不是数据图中的属性lbd:x_min。
  3. 类名大小写不一致:bot:element要改成bot:Element,和sh:targetClass指定的类名匹配。
  4. 末尾标点错误:形状图最后一行的.应该放在三重引号外面,否则会被当成SPARQL的一部分。

修正后的形状图代码

@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix bot: <https://w3id.org/bot#> .
@prefix ifc: <https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix lbd: <https://linkebuildingdata.org/LBD#> .
@prefix props: <http://lbd.arch.rwth-aachen.de/props#> .
@prefix geo: <http://www.opengis.net/ont/geosparql#> .
@prefix unit: <http://qudt.org/vocab/unit/> .
@prefix IFC4-PSD: <https://www.linkedbuildingdata.net/IFC4-PSD#> .
@prefix smls: <https://w3id.org/def/smls-owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix inst: <https://www.ugent.be/myAwesomeFirstBIMProject#> .
@prefix fog: <https://w3id.org/fog#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

ifc:geometricconstraintshape a sh:NodeShape ;
        sh:targetClass bot:Element;
        sh:sparql [
            sh:message "The geometric constraint is violated" ;
            sh:select """
            SELECT $this
            WHERE{
                inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353 a bot:Element .
                inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd a bot:Element .
                inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353_geometry_bb lbd:x-min ?x_min .
                inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd_geometry_bb lbd:x-max ?x_max .
                FILTER (ifc:computedistance(?x_min, ?x_max) <= 12.0) .
            }
            """ ;
        ] .
        
ifc:computedistance a sh:SPARQLFunction;
    rdfs:comment "Finds the distance between the two elements";
    sh:parameter [
        sh:path $x_min ;
        sh:datatype xsd:double;
        sh:description "The inner x coordinate of the wall on the right side";
    ] ;
    sh:parameter [
        sh:path $x_max ;
        sh:datatype xsd:double;
        sh:description "The outer x coordinate of the wall on the left side";
    ] ;
    sh:returnType xsd:double;
    sh:select """
        SELECT (($x_min - $x_max) AS ?result)
        WHERE { }
    """ .

把Shapegraph变量替换成上面的内容后,即可正常加载形状图并执行验证。

内容的提问来源于stack exchange,提问作者AJAY AGRAWAL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 01:32:02