使用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在解析形状图时触发了语法错误,而数据图加载步骤没有报错,说明数据图是正常的。
具体问题和修复点:
- SPARQL字符串的引号嵌套错误:在Python三重单引号包裹的Turtle字符串中,不能直接用三重双引号包裹SPARQL内容,会导致解析器混淆,需调整引号层级。
- SPARQL函数参数路径错误:
sh:parameter的sh:path应该定义参数变量名(比如$x_min),而不是数据图中的属性lbd:x_min。 - 类名大小写不一致:
bot:element要改成bot:Element,和sh:targetClass指定的类名匹配。 - 末尾标点错误:形状图最后一行的
.应该放在三重引号外面,否则会被当成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
相关产品推荐
相关产品推荐

