SHACL 1.2 规则

W3C 工作草案

关于本文档的更多详细信息
此版本:
https://www.w3.org/TR/2026/WD-shacl12-rules-20260819/
最新发布版本:
https://www.w3.org/TR/shacl12-rules/
最新编辑草案:
https://w3c.github.io/data-shapes/shacl12-rules/
历史:
https://www.w3.org/standards/history/shacl12-rules/
提交历史
编辑:
Robert David (Ontotext)
(KurrawongAI)
Andy Seaborne (Apache 软件 基金会)
Simon Steyskal (Siemens AG)
反馈:
GitHub w3c/data-shapes (拉取请求, 新建议题, 开放议题)

摘要

本文档定义了 SHACL 规则

SHACL,即形状约束语言,是一种用于描述 RDF 图结构的语言。 SHACL 可用于多种目的,例如验证、推理、 领域建模、生成本体以告知其他代理、构建用户 界面、生成代码以及集成数据。

SHACL 规则通过根据一组规则与一个基础数据图的组合生成新的 RDF 数据, 来提供推理能力。规则可以表示为 RDF, 或表示为形状规则语言(SRL)。

本规范由 数据形状工作组发布。

本文档状态

本节描述本文档在发布时的状态。 当前 W3C 出版物列表以及本技术报告的最新修订版本可在 W3C 标准与草案 索引中找到。

本文档由 数据形状工作 组作为 工作草案发布,并使用 推荐标准 轨道

作为 工作草案发布并不意味着 W3C 及其成员的认可。

这是一份草案文档,可能会随时被其他文档 更新、取代或废弃。除作为 进行中的工作之外,不宜引用本文档。 对这一即将成为推荐标准的文档的未来更新可能会纳入 新特性

本文档由一个依据 W3C 专利 政策运作的工作组 生成。 W3C 维护一份 与该组交付成果相关的任何专利 披露的公开列表; 该页面还包括 披露专利的说明。实际 知晓某项专利且认为该专利包含 必要权利要求 的个人,必须根据 W3C 专利政策第 6 节披露该信息。

本文档受 2025 年 8 月 18 日 W3C 流程文档管辖。

SHACL 规范

本规范是 SHACL 1.2 规范系列的一部分。有关这些规范的更详细 介绍,请参见 SHACL 1.2 概述

这些规范如下:

工作草案:

SHACL 1.2 核心
定义 SHACL 的核心
SHACL 1.2 SPARQL 扩展
定义 SHACL 与 SPARQL 相关的扩展
SHACL 1.2 节点表达式
定义 SHACL 中用于派生焦点节点和值节点的表达式
SHACL 1.2 规则
定义 SHACL 基于规则的推理方法
SHACL 1.2 用户界面
定义 SHACL 在用户界面生成中的使用方式
SHACL 1.2 剖析
定义使用 SHACL 对数据(包括 SHACL 数据)进行剖析的方法

工作组说明草案:

SHACL 1.2 Overview
概述 SHACL 规范集合
SHACL 1.2 Compact Syntax
定义一种用于表达 SHACL 概念的 RDF 语法

实现者可以通过成功通过 SHACL 1.2 测试套件 的测试用例,部分检查其与上述规范的一致性级别。 但是请注意,通过测试套件中的所有测试并不意味着完全符合这些 规范。 它仅意味着该实现符合测试套件所测试的方面。

1. 引言

本文档介绍 SHACL 1.2 的推理规则,这是一种通过声明式规则 从现有 RDF 数据中派生新的 RDF 三元组的机制。 本文档定义基于规则的推理的语法和语义。

SHACL 规则的实现提供两种操作。 infer 操作将规则应用于给定的 基础图,并生成一个包含通过 执行规则派生出的 RDF 三元组的推理图。 是否将推理图与基础图合并是可选的,并 留给用户决定。query 操作用于确定某个 给定目标模式是否可以使用这些规则从基础图派生出来。

SHACL 规则允许使用新的 RDF 术语,包括空白节点, 这些术语可用于规则头部的三元组模板。

SHACL 规则还支持一些构造,例如失败即否定, 这些构造可能会因规则执行顺序不同而导致不同的推理图。 为避免这种情况,规则使用 分层技术进行求值,该技术在规则之间建立单一的隐式顺序, 确保始终生成相同的推理图。

1.1 术语

以下其他规范提供了本文档中使用的基础术语:

1.2 文档约定

本文档中的一些示例使用 RDF 1.2 Turtle [RDF12-TURTLE]。

在本文档中,使用以下命名空间前缀绑定:

前缀 命名空间
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
rdfs: http://www.w3.org/2000/01/rdf-schema#
srl: http://www.w3.org/ns/shacl-rules#
xsd: http://www.w3.org/2001/XMLSchema#
sparql: http://www.w3.org/ns/sparql#
ex: http://example/

在整个文档中,将出现包含 Turtle 格式 RDF 图的彩色编码框。 这些 Turtle 文档片段使用上面给出的前缀绑定。

# This box represents rules
# This box represents input data
# This box represents inferred data

2. 一致性

除标记为非规范性的章节外,本规范中的所有创作指南、图示、示例和注释也都是非规范性的。本规范中的其他所有内容均为规范性的。

本文档中的关键词 可以必须不得 应该 应按照 BCP 14 [RFC2119] [RFC8174] 中所述的方式解释,并且仅当它们像这里所示以全 大写形式出现时才如此。

本规范为以下内容定义了一致性标准:

一个符合要求的 SRL 文档是一个 RDF 字符串,它 符合从 RuleSet 产生式开始的语法,该产生式定义于 7. 形状规则语言 语法中。

本规范未定义 SPARQL-RL 处理器如何处理不符合要求的规则集

3. SHACL 规则

本节为非规范性内容。

给定一个基础图和一个规则集,SHACL 规则会推断新的三元组。 求值的输出是一个推理图,其中包含派生出的、 不出现在基础图中的三元组。

每个规则都有一个称为主体的模式,以及一个 称为头部的结果模板。 规则通过查找主体中变量的值来执行, 使主体匹配组合后的基础图以及 到目前为止执行过程中产生的任何推理三元组。 然后使用这些值来实例化规则头部中的 三元组模板,以生成新的推理三元组。

规则会一直执行,直到不再推断出更多三元组; 随着新的推理三元组可用,规则可能会被执行多次。

SHACL 规则执行被定义为:在创建新的 RDF 术语时, 包括新的空白节点,以及在测试某个模式是否不存在时, 规则执行顺序不会导致不同结果。换言之,无论规则执行顺序如何, 都会生成相同的推理图。

SPARQL-RL 采用一种受 SPARQL 1.2 查询语言启发的易于人类理解的语法。 规则集求值包含与 SPARQL 类似的元素,但在细节上有所不同, 以确保无论规则执行顺序如何,都生成相同的推理图。

3.1 基本模式

本节中的示例描述了软件组件及其 依赖关系:前端调用应用服务器,而 应用服务器查询一个存在已知 漏洞的数据库。

在第一个示例中,我们有以下数据图和规则集:

将上述规则应用于数据后,可以得出: :frontend 依赖于 :app,而 :app 依赖于 :db,无论依赖关系属于何种类型。

然后,我们可以添加一条依赖于其他规则所生成的 :dependsOn 三元组的规则, 以推导出 :exposedTo 关系(另请参阅下面的 4.3 规则依赖关系):

3.2 递归

上一节中的 :exposedTo 规则只能覆盖直接 依赖关系::frontend 并不直接依赖于 :db,因此 不会为 :frontend 推断出 :exposedTo 三元组。 为了沿任意长度的依赖链传播暴露关系,我们 将该规则替换为两条规则:组件会暴露于其自身具有的 漏洞,并且组件会暴露于其直接依赖项所暴露的任何 漏洞:

与上一个示例相比,这里新增了 :db :exposedTo :vuln1——数据库暴露于其 自身的漏洞——以及 :frontend :exposedTo :vuln1: 暴露关系会沿依赖链传播至 :frontend, 无论该链有多长。

最后一条规则是一条递归规则:规则体 依赖于规则头。

3.3 过滤

我们可以在规则体中使用表达式,以限制规则体匹配过程中 变量的取值。 例如,给定每个漏洞的严重程度, 我们可以为暴露于严重 漏洞的组件赋予状态:

FILTER 对表达式求值,如果表达式求值为 true,则保留当前 变量绑定集;如果表达式求值为 false,则丢弃 当前变量绑定集。 这与 SPARQL 的 FILTER 操作 相同,并且 SHACL Rules 提供了许多与 SPARQL 相同的函数和运算符。

3.4 否定

否定允许你指定一个不得匹配的模式。 这称为“失败即否定”。

为了对否定元素求值,规则求值算法 会确保所有可能生成与否定元素中的模式相匹配的三元组的规则 均已执行完毕。这称为 分层,并确保否定基于 所有相关的可能三元组,无论这些三元组来自数据,还是 否定元素中的三元组均已执行完毕。包含该否定的规则被称为_依赖_于 生成这些三元组的规则(请参阅下面的 4.3 规则依赖关系)。

3.5 赋值和创建 RDF 术语

赋值允许你在规则体中将表达式的结果赋给变量。 这可用于根据数据创建新的 RDF 项。

空白节点可以在规则头中使用,并且每当规则求值生成三元组时, 每个空白节点都会生成一个新的空白节点。

涉及赋值的规则,以及在其 规则头中创建空白节点的规则,都是仅运行一次的规则。 此类规则会在所有可能生成其所依赖数据的规则之后运行, 并在任何依赖其所生成数据的规则之前运行。 在规则头中包含空白节点的规则也会创建新的 RDF 项,因此也是仅运行一次的规则。

此条件可确保此类规则不会循环回自身并导致生成数量不受限制的 RDF 项。

如果对赋值中的表达式求值时发生错误, 则当前解映射会被该赋值拒绝。

3.6 导入规则集

SHACL 规则集可以通过 在该规则集的规则集导入项中包含其他规则集的 URL 来引入它们。 这使得规则可以组织成在规则集之间共享的库。

在对规则集中的任何规则进行求值之前,会先处理该规则集的 IMPORTS 语句。 在导入步骤期间,如果被导入的规则集 有其自己的导入项,则也会递归处理这些导入项。 在处理规则集期间遍历 IMPORTS 语句可能会导致 循环导入。一个规则集只会被导入一次; 导入语句图中的环不会导致无限循环。

SRL 处理器可以选择是否支持导入规则集。 有关更多详细信息,请参阅4.5 处理 导入

3.7 数据块

数据块允许直接向规则集求值简洁地提供 RDF 三元组。 数据块中的三元组会添加到推理图中,并可供 规则体进行匹配。

例如,规则集可以直接附带已断言的已知事实, 而不是从数据中推导这些事实:

数据块等同于一条规则体为空的规则: 无需对任何规则求值,其三元组便会成为推理图的 一部分。

3.8 规则集求值

规则被组织到规则集中。 规则集和数据图(即基础图)是求值的输入。 输出是一个称为推理图的图, 它是未出现在数据图中的三元组集合。

在求值期间,基于一条规则推理出的三元组 可供其他规则进行匹配。 规则集求值会持续进行,直至推理图 包含根据规则集和数据图的输入 可产生的所有三元组。

求值首先通过两个步骤 准备规则集, 然后再对规则本身进行求值:

  1. 在支持的情况下,输入规则集的导入项会被解析,以形成一个 包含所有被导入规则集的所有规则的规则集。 如果任何导入项不被处理器接受,处理器必须发出错误信号 (4.5 处理导入)。
  2. 会计算一个分层4.4.2 分层 算法 以使否定元素赋值元素产生一致且 可预测的结果。分层涉及检查 规则之间的依赖关系 (4.3.1 依赖 图)。

规则集准备完毕后,求值会 按顺序取出分层中的每一层, 对该层中的规则进行求值直至完成, 然后再转到下一层。

3.9 匹配基础数据

基础数据是基础图中的三元组。 在规则集求值期间,可能 有必要仅对原始三元组进行模式匹配,而不对任何推断出的 三元组进行模式匹配。

设置默认值就是一个例子。 规则必须测试基础图是否已经包含一个值,如果不包含, 则规则可以计算一个默认值。

使用 NOT DATA 可允许规则主体的其他部分匹配推断出的三元组。 也可以通过使用 WHERE DATA,针对基础图执行所有规则主体匹配。 此类规则随后仅依赖于 基础图中的匹配。

3.10 SHACL 集成

议题 1074:FOR ?v IN <shape> SRL

FOR ?v IN <shape> 在该模型之上重新引入了目标选择。 它将单条规则与一个 SHACL 形状关联起来,使该规则仅针对形状的目标焦点节点中 符合该形状的节点触发,并将用户命名的“焦点变量”预先绑定到每个 此类节点。

完整提案

4. 形状规则抽象语法

形状规则抽象语法是 SHACL 规则的逻辑结构。 它用于定义 SHACL 规则的执行算法。

4.1 抽象语法的 元素

变量
变量表示三元组模式中一个可能的 RDF 项。 变量也用于表达式中。
表达式
表达式是一个函数或函数形式; 其参数是 RDF 项。 表达式相对于一个解映射进行求值,并给出 一个 RDF 项作为结果。 表达式SHACL 列表参数函数 以及 SPARQL 表达式兼容。
数据块
数据块是一组三元组。 这些三元组作为附加事实添加到推理图中,并 包含在推理过程中。
三元组模板
三元组模板是一个三元组,其中每个元素或者是 一个变量,或者是一个 RDF 项(它可能是一个三元组项)。 该元组的第二个元素必须是一个 IRI 或一个 变量三元组模板出现在规则头中,该规则头属于一个规则
三元组模式
三元组模式是一个三元组,其中每个元素或者是一个 变量,或者是一个 RDF 项(它可能是一个三元组项)。 该元组的第二个元素必须是一个 IRI 或一个 变量
过滤器元素
过滤器元素是一个表达式 ,它作为规则元素出现 它用于限制模式匹配中 变量的值。
三元组模式元素
三元组模式元素是一个三元组模式 ,它作为规则元素出现。
否定元素
否定元素是一个规则元素。 它具有一个否定元素体 ,由一系列三元组模式元素过滤器元素组成。
赋值元素
赋值元素是一个规则元素,它是 一个由以下两项组成的对: 一个变量,称为赋值变量, 以及一个表达式,称为赋值表达式
规则元素
一个规则元素是以下任意一种: 三元组模式元素过滤器元素否定元素,或 赋值元素
规则头
规则头是一系列三元组 模板
规则体
规则体是一系列规则元素; 也就是说,序列中的每个元素都是以下之一: 一个三元组模式元素、 一个过滤器元素、 一个否定元素, 或一个赋值元素
规则集导入
规则集导入(通常简称为“导入”)是一个 URL 集合, 用于指定将在求值期间包含的其他规则集。
规则
规则是一个由规则头(通常简称为 “头”)和 一个规则体(通常简称为“体”)组成的对。 可以为一个规则指定一个 URI,以帮助标识它。
单次运行规则
单次运行规则是在规则集求值过程中的 特定时刻恰好运行一次的规则。
一般规则
一般规则是一个不是单次运行规则的规则。 在规则集求值期间,一般规则可以运行多次。
规则集
规则集是由零个或多个规则组成的集合、 由零个或多个数据块组成的集合, 以及由零个或多个规则集导入组成的集合。 已解析 规则集是一个规则集 ,它不包含任何导入。 已解析规则集通过对另一个规则集 应用导入过程而创建。
基础图
基础图是作为 求值过程输入给出的 RDF 图
推理 图
推理图是由 规则集求值产生的一个 RDF 图。 它包含所有不在基础图中、并通过将规则集应用于 基础图而推导出的三元组。
规则集 求值
规则集求值是将一个规则集 应用于一个基础图以产生一个推理 图的过程。 规则 求值是对一个规则求值一次的过程。 对规则求值会产生由规则头根据 规则体的求值所给出的所有三元组,无论一个 三元组是否位于基础图中、是否已在规则集求值期间被推导出, 或者是否是一个新推导出的三元组。 在规则集求值期间,一个规则可以被求值 多次。

形状规则语言提供两种操作:推断查询

推断
推断是将一个规则集应用于给定的 基础图,并产生一个包含推断 三元组的推断图的操作。它会应用完整的规则集求值
查询

查询是确定给定的目标 模式能否使用规则集从一个基础图推导出的操作。 它可以不对所有规则进行求值;相反,它可以只对 回答查询目标所必需的规则进行求值。

查询等价于执行一次推断操作, 然后将目标模式与组合后的基础图推断图进行匹配。

三元组模式三元组 模板中, 元组的位置 1 非正式地称为主语, 位置 2 非正式地称为谓词,而 位置 3 非正式地称为宾语

一系列规则元素中的元素从 1 开始编号。

以下表示法用于规则集和规则的各种组成部分。

组成部分表示法
组成部分 用法
ruleset.rules 一个规则集的规则。
ruleset.data 由规则集中的数据块并集 形成的 RDF 图
ruleset.imports 一个规则集导入项集合。
rule.head 规则头三元组模板
rule.body 规则规则元素
rule.data 一个布尔标志;如果为 false,则规则主体会 针对基础图进行匹配。
rule.id 规则的标识符,它是一个 空白节点IRI
filter.expr 一个过滤 元素表达式
assign.var [赋值 元素]的赋值变量
assign.expr 赋值表达式
negation.inner 否定元素主体 是一个否定元素
negation.data 一个布尔标志;如果为 false,则 negation.inner 会 针对基础图进行匹配。

4.2 良构性条件

良构性是针对 规则集抽象语法的一组条件。这些条件共同确保 规则变量在 规则的头部中具有在规则主体中定义的值; 过滤器元素赋值表达式中的每个变量 在求值时都具有值; 并且规则中的每个 赋值都会引入一个新变量, 即一个此前未在规则主体中使用过的变量。

给定一个初始变量集合,我们为一系列规则元素 定义良构性

elti 为一系列规则元素中的第 i 个元素。

varsi 为由 elti 定义的变量集合,其中:

V0 为一个序列的初始变量。

ViV0 与所有 varsj 的并集, 其中 j 小于 i

VallVN, 其中 N 是该序列的长度。

给定一个变量集合 V0,如果满足以下条件,则 良构 序列是一系列规则元素

如果在 V0 为空集的情况下,规则规则主体序列是一个良构序列, 并且规则头的每个三元组模板中的每个变量 都是 Vall 的元素, 则该规则是一个良构 规则

当且仅当一个规则集的所有 规则都是良构规则时,该规则集才是一个良构规则集

4.3 规则依赖

如果第二个规则的输出会影响第一个规则主体的求值,则规则 R1 依赖于规则 R2。 也就是说,R2 的头中有一个三元组模板,它可能生成一个与 R1 主体中的三元组模式匹配的三元组, 该三元组模式可以作为三元组模式元素,也可以位于否定元素内部。

有两种依赖关系: 封闭依赖开放 依赖封闭依赖确保规则 R2 在规则 R1 执行之前已经生成其所有可能的输出。 如果规则依赖不是封闭的,则它是开放依赖, 这允许第一个规则 R1 在 规则 R2 可能再次运行以生成更多三元组时执行, 随后这些三元组可使 R1 使用来自 R2 的新三元组重新求值。

在第一个示例中,第一个规则对第二个规则具有开放依赖 关系。

在第二个示例中,第一个规则对第二个规则具有封闭依赖 关系:三元组模式 ?x :status :criticallyExposed 出现在第一个规则的一个否定元素内部,并且 与第二个规则头中的三元组模板匹配。 在第二个规则生成其所有可能的输出之前, 无法对第一个规则进行求值。

三元组 模式匹配

如果一个三元组模板可以生成一个与 一个三元组模式匹配的三元组,则该三元组模式与该三元组模板匹配。

三元组模式依赖

如果一个三元组模式可能与一个三元组模板匹配,则该三元组模式 依赖于一个三元组模板

如果一个三元组模式依赖于规则 中的任一三元组模板,则该三元组模式 依赖于一个规则

规则依赖

如果 R1 主体中的任一 三元组模式,无论是作为三元组模式元素还是 位于否定元素内部, 依赖 于 R2 头中的一个三元组模板,则规则 R1 依赖于 R2

封闭依赖

如果满足以下任一条件,则规则 R1 对规则 R2规则依赖是一个封闭依赖

开放依赖

如果规则 R1 对规则 R2规则依赖不是 封闭依赖,则它是一个开放依赖。 也就是说,R1 中依赖于 R2 的任何三元组模式都仅作为三元组模式元素出现。

如果存在三元组模板中变量的值,使得在模板中用这些值替换变量后 得到一个三元组 T2,并且 T2 等于 T1,则一个三元组模板可以生成一个 RDF 三元组 T1

类似地,如果存在三元组模式中变量的值,使得在模式中用这些值替换变量后 得到一个三元组 T2,并且 T2 等于 T1,则一个三元组模式匹配一个三元组 T1。 对于三元组模式,这包括 对称三元组

如果一个变量在一个三元组 模板三元组模式中使用多次,则使用相同的 RDF 项 作为替换值。

用 RDF 项替换变量时,也包括 三元组项内部的变量。

4.3.1 依赖图

规则之间的依赖关系表示为一个有向图, 称为依赖图。 该图的顶点是规则集中的规则,而边 根据依赖关系是开放依赖还是封闭依赖, 分别标记为开放封闭

依赖图
一个规则集依赖图是一个有向图,其中每个 顶点都是规则集中的一个规则,如果 R1 依赖于 R2,则存在一条从规则 R1 指向规则 R2 的边。 根据该依赖关系 是开放依赖还是封闭依赖,该边被标记为开放封闭
传递规则依赖
如果在依赖图中存在一条从 R1R2 的路径, 则规则 R1 对规则 R2 具有传递依赖
递归规则依赖

如果依赖图中存在一条 涉及 R 的循环路径, 则规则 R 具有递归依赖

依赖图不受数据图影响。

4.3.2 依赖图算法

以下算法给出了一种从 规则集构造依赖 图的 可行方法。一致性取决于生成符合依赖图定义的依赖图, 而不取决于是否使用此过程。

define mergeLabel(oldLabel, newLabel):
    ## 封闭依赖优先于开放依赖。
    if oldLabel == "open" and newLabel == "open":
        return "open"
    else:
        return "closed"
    endif
enddefine

## 输出 -- 具有规则顶点和带标签边的依赖图。
define buildDependencyGraph(ruleSet):
    ## edgeLabelMap 将 (R1, R2) 映射到 "open" 或 "closed"
    let edgeLabelMap be a map from pair (rule, rule) to label

    foreach rule R1 in ruleSet.rules:
        ## 将规则中的每个三元组模式 TP 分类为需要 "open" 或 "closed"
        ## 具体取决于它是否位于否定元素中。
        let bodyDependencies = {}
        foreach rule element RBE in R1.body:
            if RBE is a negation element:
                foreach triple pattern TP in RBE.inner
                    let item be a pair (TP, "closed")
                    add item to bodyDependencies
                endfor
            else if RBE is a triple pattern element of triple pattern TP:
                let item be a pair (TP, "open")
                add item to bodyDependencies
            else if RBE is a condition element:
                ## 不执行任何操作
            else if RBE is an assignment element:
                ## 不执行任何操作
            endif
        endfor

        foreach pair (triple pattern TP, depLabel) in bodyDependencies:
            if R1.body has an assignment element:
              set depLabel to "closed"
            endif
            if R1.head has a triple template with a blank node:
              set depLabel to "closed"
            endif
            ## 查找此三元组模式元素或否定元素的依赖关系。
            foreach rule R2 in ruleSet.rules:
                foreach triple template TT in R2.head:
                    if triple pattern TP matches triple template TT:
                        let key = (R1, R2)
                        if edgeLabelMap contains key:
                            let oldLabel = edgeLabelMap.get(key)
                            let merged = mergeLabel(oldLabel, depLabel)
                            edgeLabelMap.set(key, merged)
                        else:
                            edgeLabelMap.set(key, depLabel)
                        endif
                    endif
                endfor
            endfor
        endfor
    endfor

    let DP = { }
    foreach entry ((R1, R2), label) in edgeLabelMap:
        add an edge (R1 -> R2) labeled with label to DP
    endfor

    the result is DP
    enddefine

4.4 分层

分层是将一个规则集 划分为一系列有序分层层级(也称为 “层”,单数为“层”)的过程。较低中的规则 先于较高中的规则进行求值。

分层规则之间的依赖关系施加约束, 以确保否定元素赋值 元素以及 在规则头中创建的空白节点仅依赖于使用 较早(较低)的基础图计算出的结果。 这保证了在给定基础图上对规则集进行求值时,会得到唯一、明确定义且有限的 结果。

分层过程也可以用于作出其他求值 决策。本文档描述了一致 求值的必要条件,并给出了一种形成 分层的可行方式。实现需要满足 此处所述的条件,以获得兼容的行为,但并不 要求按照所给出的方式实现该算法。

分层层级

一个分层层级 SL 是一对 互不相交的规则集合 (SL.onceSL.general)。 SL.once 包含一次性运行规则,即 使用赋值元素或 在规则头中生成 空白节点的规则;这些规则中的每一个都在分层层级开始求值时恰好求值 一次。 SL.general 包含其余规则,这些规则会被反复求值, 直到不再推断出新的三元组。

分层
一个规则集分层是一系列 分层层级。 一个规则集中的每个规则恰好出现在 其中一个分层层级的一个集合中。

4.4.1 分层条件

仅当满足以下 条件时,才定义分层。如果一个规则集不满足此条件,则本 规范不会为此类规则集的求值定义结果。

分层条件
分层条件要求 一个规则集依赖图中不存在涉及 封闭依赖递归依赖

换句话说,在依赖图的任何传递依赖环中,都不存在 NOT 或一次性运行规则(赋值或规则三元组模板 涉及空白节点)。

4.4.2 分层算法

以下算法给出了一种仅基于 规则集的可行分层方法。

## 输出 -- 映射:整数 -> 规则集合。

define stratification(ruleSet):

    let DP = Dependency graph for the rule set.
    let stratumMap be a map from rule to integer

    ## 依赖图应满足分层条件。
    ## 对无界分层的检查是一项保护措施 
    ## 用于处理违反分层条件的情况。
    let limit = num rules + 1
    let maxStratum = 0

    ## 初始化 stratumMap
    foreach rule in ruleSet.rules:
        stratumMap.set(rule, 0)
        endfor

    boolean changed = true;
    while changed:
        changed = false;
        foreach edge E in DP:
            ## 从 pRule 到 qRule 的带标签边
            let pRule = source of edge
            let qRule = destination of the edge
            let label = edge label

            if label == "open" :
                if stratumMap.get(pRule) < stratumMap.get(qRule) :
                    stratumMap.set(pRule, stratumMap.get(qRule))
                    changed = true;
                endif
            endif
            if label == "closed" :
                if stratumMap.get(pRule) <= stratumMap.get(qRule) :
                    let xStratum = 1 + stratumMap.get(qRule)
                    if ( xStratum > limit )
                        ## 违反分层要求
                        error "Stratification error"
                        endif
                    stratumMap.set(pRule, xStratum)
                    maxStratum = max(maxStratum, xStratum)
                    changed = true;
                endif
            endif
        endfor
    endwhile

    ## 初始化结果映射。
    let stratumRules be a map from integer to rules.
    for i = 0 to maxStratum
        stratumRules.set(i, {})
    endfor

    ## 收集 stratumMap 中具有相同层级编号的规则
    for rule R in map stratumMap:
        let stratumNum = stratumMap.get(R)
        add R to stratumRules.get(stratumNum)
    endfor

    ## 将每个层级划分为 once 和 general
    let stratumLevels be a sequence of pairs of sets of rules.
    for i = 0 to maxStratum:
        let rules = stratumRules.get(i)
        let once = { R in rules | R is a run-once rule }
        let general = rules \ once
        stratumLevels.set(i, pair(once, general))
    endfor

    the result is stratumLevels
enddefine

分层条件的一个结果 是,一旦一个 一次性运行规则求值, 用于确定该规则结果的数据在后续 求值期间将不会发生变化。

对完整规则集逐步应用依赖关系分析和 分层,并继续进行 求值的过程,可参见 6.6 完整 示例

4.5 处理导入

从 Web 读取文档具有安全方面的影响。 SRL 处理器可以选择是否支持导入规则集。 此外,实现可以提供部分支持, 例如支持导入某些规则集而不支持其他规则集, 并且可能从经过验证的副本导入。

以下条件适用于导入处理:

已解析规则集通过递归读取另一个规则集的 导入项中提到的所有规则集, 从该规则集生成。

示例算法见A. 示例导入算法

5. SRL 与 SPARQL 之间的关系

本节为非规范性内容。

SRL 与 SPARQL 关系密切。SRL 旨在与 SPARQL 兼容, 而且 SRL 中的许多构造都取自 SPARQL 或受其启发。 但是,两者之间也存在一些差异。

在 SRL 中,RULE 变量在使用前始终会被绑定,无论是用于 FILTERSET 的表达式,还是用于三元组模板 (位于规则头部中)。 如果变量出现在 CONSTRUCT 模板中,但在 WHERE 子句中未被赋值, SPARQL CONSTRUCT 查询将产生部分结果。

其他差异包括:

6. 规则集求值

本节定义在给定数据上对规则集求值的结果。 它并不规定该算法作为实现方法。 实现可以使用任何能生成相同结果的算法。

输入数据图 G,称为基础图,以及规则集 RS。
输出由推理三元组组成的 RDF 图 GI

推理出的三元组不包括 基础图的三元组集合中已有的三元组。

6.1 求值定义

解映射
一个解映射 μ 是一个偏 函数 μ : VT, 其中 V 是所有变量的集合, 而 T 是所有 RDF 项的集合。 μ 的定义域表示 为 dom(μ),它是 Vμ 有定义的子集。当明确指的是解映射时,我们使用术语 。 用 μ0 表示满足以下条件的解映射: dom(μ0) 是空集。
替换函数
替换函数,或简称为替换, 是一个函数 subst(μ, 三元组模式) ,它返回一个三元组模式 ,其中三元组模式中每次出现的、位于 dom(μ) 中的变量 都会被RDF 项替换,该 RDF 项由 解映射针对 var 给出。 如果得到的三元组模式不包含变量,那么它就是一个 RDF 三元组
求值 图
求值图是一个 RDF 图,它将基础图 与规则集求值期间产生的所有三元组合并在一起。
图匹配
图匹配用于找出将 三元组模式映射到 RDF 图中三元组的各种方式。

G 为一个 RDF 图TP 为一个三元组模式。 函数 graphMatch(G, TP) 返回所有可能的 的集合,这些解 应用于三元组模式时,会产生一个位于 求值图中的三元组

G 为一个 RDF 图TP 为一个三元组模式, 并设 VTP 中出现的变量集合。

graphMatch(G, TP) = { μ | dom(μ) = V and subst(μ, TP) is a triple in G }
解兼容
如果两个解 S1 和 S2 在共有变量上的值一致,则它们是兼容的

设 S1 和 S2 为解。

compatible1, μ2) = true
                      if forall v in dom1) intersection dom2)
                          μ1(v) = μ2(v)
compatible1, μ2) = false otherwise
解 序列
解序列是解的多重集。 该序列没有定义的顺序。 它等价于一个无序列表,并且可以包含重复项。
解合并
如果两个解兼容,则两个解的合并是这样一个解: 它将每个解中的变量映射到来自其中一个解的 RDF 项
μ1μ2 为解映射,并设 S1 和 S2 为解序列。
merge(μ1, μ2) = { μ |
                    μ(v) = μ1(v) if v in dom(μ1)
                    μ(v) = μ2(v) otherwise }
merge(S1, S2) = { μ |
                    μ1 in S1, μ2 in S2
                    and compatible(μ1, μ2)
                    μ(v) = merge(μ1, μ2) }

merge(S1, S2) 的定义域是 domain(S1) ∪︀ domain(S2)

如果两个解没有共同变量,则它们是兼容的, 并且两个解的合并是 S1S2 的并集。

有效布尔值
函数 EBV(x) 返回一个 RDF 项的有效布尔值。

6.2 求值准备

规则集的求值涉及收集所有导入的规则集, 并按照 4.5 处理 导入中的描述构建单个合并规则集。

然后按照以下步骤准备合并后的规则集 以进行求值。

  1. 按照 4.2 良构性 条件中的描述,检查每条规则是否为良构规则
  2. 按照 4.3.2 依赖图算法中的描述,计算依赖图
  3. 按照 4.4.2 分层算法)中的描述,计算合并规则集的分层

6.3 表达式的求值

表达式无论是用于过滤元素还是 赋值元素,都会相对于一个 解映射求值;该解映射为表达式中的每个变量提供一个 RDF 术语值。 4.2 良构性条件 中的良构性要求确保表达式中的所有变量 都出现在解映射中。

define evalFunction(F, μ):
    ## F is an expression: an RDF term, a variable, or op(expr1, ..., exprN)
    ## where op is a function or a functional form.
    if F is an RDF term:
        return F
    if F is a variable:
        ## By well-formedness, F ∈ dom(μ).
        return μ(F)
    ## F is of the form F= op(expr1, ..., exprN)
    if op is a functional form (e.g. IF, logical-or):
        ## Evaluated specifically for op; op may evaluate only some arguments.
        ## For example, IF(c, t, f) evaluates c, then exactly one of t or f.
        return the value defined for op over expr1, ..., exprN under μ
    ## op is an ordinary function: evaluate all arguments first.
    return F(evalFunction(expr1, row), ..., evalFunction(exprN, row))
enddefine

6.4 规则的求值

一个规则通过从规则主体计算一个解 序列来求值, 然后使用该解序列中的每个解映射, 使用规则头生成三元组。

三元组模式中的空白节点表现得像变量。 这与 SPARQL 图模式匹配兼容。

# Evaluate rule body
# This function returns a sequence of solutions

define evalRuleElements(B, SEQ, G, GD):
    where 
        B is a sequence of rule elements
        SEQ is a solution sequence 
        G and GD are RDF graphs

    for each rule element rElt in B:

        if rElt is a triple pattern TP:
            X = graphMatch(G, TP)
            SEQ1 = {}
            for each μ1 in X:
                for each μ2 in SEQ:
                    if compatible(μ1, μ2)
                      μ3 = merge(μ1, μ2)
                      add μ3 to SEQ1
                    endif
                endfor
            endfor
        endif

        if rElt is a condition element F:
            SEQ1 = {}
            for each solution μ in SEQ:
                let x = evalFunction(F.expr, μ)
                if EBV(x) is true:
                    add μ to SEQ1
                endif
            endfor
        endif

        if rElt is a negation expression N:
            SEQ1 = {}
            for each solution μ in SEQ:
                S = sequence{ μ }
                if rElt with DATA:
                    NEG = evalRuleElements(N.inner, S, GD, GD)
                else:
                    NEG = evalRuleElements(N.inner, S, G, GD)
                if NEG is empty
                    add μ to SEQ1
                endif
            endfor
        endif

        if rElt is an assignment A:
            SEQ1 = {}
            for each solution μ in SEQ:
                let x = evalFunction(A.expr, μ)
                if x is not an error:
                    ## Add mapping V -> x to solution μ
                    let μ2 be a solution mapping μ ∪︀ { (A.var, x) }
                    add μ2 to SEQ1
                else
                    # Error: drop solution μ
                endif
            endfor
        endif

        SEQ = SEQ1
    endfor

    return SEQ
enddefine

define evalRule(R, G, GD):
    where 
        R is a well-formed rule
        G and GD are RDF graphs
    let B be R.body 
        where each blank node in a triple pattern in R.body
        is replaced by a variable which is not used in the rule. 
        The same variable is used for each occurrence of the
        same blank node, and a different variable is used for 
       each different blank node.

    # Solution sequence of one solution that does not map any variables.
    let SEQ0: Solution sequence = { μ0 }

    if R.data:
        let SEQ = evalRuleElements(B, SEQ0, GD, GD)
    else
        let SEQ = evalRuleElements(B, SEQ0, G, GD)
    
    # Evaluate rule head
    let OUT = empty set
    for each μ in SEQ:
        let S = {}
        for each triple template TT in R.head:
            let triple = subst(μ, TT)
            Add triple to S
        endfor
        OUT = OUT union S
    endfor
    return OUT
enddefine

OUT 可能包含同样存在于数据图中的三元组。

6.5 规则集的求值

规则集的求值被定义为执行该规则集的 分层中的每个,其中每一层都按顺序 完整执行,然后再转到下一个。 对一个进行求值时,首先对 该层中的每条单次运行规则进行求值,然后重复对 该层中的一般规则进行求值,直至不再产生新的三元组。

let G0 be the input base graph
let RS be the rule set
let D be the graph of all DATA triples in RS

Apply stratification to RS

let LS be the sequence of layers after stratification

# Inference graph
let GI = { t ∈ D | t ∉ G0 }

let GD = G0 ∪︀ D

# Evaluation graph.
let GE = GD

for each stratum ST in LS:
    for each rule R in ST.once:
        let X = evalRule(R, GE, G0)
        let Y = { t ∈ X | t ∉ GE }
        GI = GI ∪︀ Y
        GE = GE ∪︀ Y
    endfor

    let finished = false
    while !finished:
        finished = true
        for each rule R in ST.general:
            let X = evalRule(R, GE, G0)
            let Y = { t ∈ X | t ∉ GE }
            if Y is not empty:
                finished = false
                GI = GI ∪︀ Y
                GE = GE ∪︀ Y
            endif
        endfor
    endwhile
endfor
the result is GI

6.6 完整示例

本节为非规范性内容。

本节逐步说明完整规则集的求值过程:确定规则依赖关系 (4.3 规则 依赖关系)、 计算分层 (4.4 分层), 并依次对每一层进行求值以产生 推理图6.5 规则集 求值)。

该示例描述了软件组件及其依赖关系: 前端依赖应用服务器,而应用服务器依赖 数据库和日志记录库。数据库存在一个已知的 漏洞。规则沿依赖链传播漏洞暴露情况, 为暴露于严重漏洞的组件赋予 :criticallyExposed 状态,为 不严重的组件赋予 :safeToDeploy 状态,并为每个 严重暴露的组件创建一条通知。 (在实践中,漏洞是否影响某个组件 取决于所部署的版本;该示例省略了版本,并 直接声明了漏洞。) 为简洁起见,基础图直接声明 :dependsOn 三元组, 而不是像 3.1 基本模式中那样从更具体的关系推导它们。

这些规则在注释中标记为 R1R5,并在 本节其余部分中通过这些标签引用。 它们是在 3.2 递归3.5 赋值 和创建 RDF 项中引入的规则。 该规则集没有 IMPORTS,因此导入处理 不会改变它;也没有 DATA 块,因此求值仅 从基础图开始。

6.6.1 确定 依赖关系

将每个规则体中的每个三元组模式与 每个规则头中的三元组模板进行比较,以确定哪些规则 依赖于哪些规则 (4.3 规则 依赖关系)。

  • R1 的规则体是单个三元组模式 ?x :hasVulnerability ?v。没有任何规则头包含 能够生成谓词为 :hasVulnerability 的三元组的三元组模板, 因此该模式只能与数据匹配。 R1 没有依赖关系。
  • R2 的规则体包含两个三元组模式。 ?x :dependsOn ?y 无法与任何规则头匹配,因此它只能 与数据匹配。?y :exposedTo ?vR1 的规则头模板 ?x :exposedTo ?v 相匹配,也与 R2 自身的规则头相匹配。两处出现的模式都是三元组模式元素 (它们未出现在否定元素内,并且 R2 没有赋值元素,其 规则头中也没有空白节点),因此 R2R1 具有一个开放依赖关系,并且 对自身也具有一个开放依赖关系。 R2 对自身的依赖关系使 R2 成为一条递归规则。
  • R3 的规则体中,模式 ?x :exposedTo ?vR1R2 的规则头相匹配,使 R3 分别对二者具有一个开放 依赖关系。模式 ?v :severity ?s 不与任何 规则头匹配。
  • R4 的规则体中,模式 ?x rdf:type :Component 不与任何规则头匹配:唯一一个谓词为 rdf:type 的规则头模板位于 R5 中,而其对象 :Notification:Component 是不同的 RDF 项,因此生成的 三元组均无法匹配。 模式 ?x :status :criticallyExposed 出现在 否定元素 NOT { ?x :status :criticallyExposed } 内,并且 与 R3 的规则头模板相匹配。由于该模式 出现在否定元素中,因此 R4R3 具有一个封闭 依赖关系。
  • R5 的规则体中,模式 ?x :status :criticallyExposedR3 的规则头相匹配。R5 的规则头包含一个 空白节点,因此它对 R3 的依赖关系是一个封闭 依赖关系,即使该模式是普通的 三元组模式元素。 所有规则体中的模式均不与 R5 的规则头模板匹配,因此没有规则依赖于 R5

因此,依赖图包含五个顶点和六条 边:

  • R2 → R1(开放)
  • R2 → R2(开放)
  • R3 → R1(开放)
  • R3 → R2(开放)
  • R4 → R3(封闭)
  • R5 → R3(封闭)

尽管 R4R5 均不直接依赖于 R1R2,但二者都通过 R3 对它们具有传递依赖关系

完整示例规则集的依赖图 五个分别标记为 R1、R2、R3、R4 和 R5 的顶点。 虚线箭头表示开放依赖关系:从 R2 指向 R1、 从 R2 指向自身、从 R3 指向 R1,以及从 R3 指向 R2。 实线箭头表示封闭依赖关系:从 R4 指向 R3, 以及从 R5 指向 R3。 R2 R1 R3 R4 R5 开放依赖关系 封闭依赖关系
1 完整示例规则集的依赖图。 开放依赖关系绘制为虚线箭头,封闭 依赖关系绘制为实线箭头。每条边都从 规则体包含匹配三元组模式的规则指向 规则头可能生成匹配三元组的规则。 规则按第 0 层位于顶部、更高 层位于下方的方式排列,与求值顺序一致。

图中唯一的环是自环边 R2 → R2, 它是开放依赖关系。没有任何环涉及封闭 依赖关系,因此满足分层条件, 并且该规则集具有明确定义的结果。

6.6.2 计算 分层

按照 分层算法, 每条规则最初都位于第 0 层。随后反复检查 各条边,直到不再发生变化:

  • 一条开放边要求源规则与其 目标规则位于同一层或更高层。当所有规则均位于第 0 层时, 四条开放边已经满足此条件,因此它们 不会引起任何变化。
  • 一条封闭边要求源规则位于 严格高于目标规则的层,因为目标规则 必须先运行至完成。边 R4 → R3 (封闭)发现 R4R3 均位于第 0 层,因此将 R4 移至第 1 层。同样,边 R5 → R3 (封闭)将 R5 移至第 1 层。

再次遍历各条边不会产生任何变化,因此各层 已最终确定。随后将每一层划分为 仅运行一次的规则一般规则R5 的规则头中有一个空白 节点,因此它是一条仅运行一次的规则;其他规则 均没有赋值元素,其规则头中也没有空白节点。 分层结果为:

  • 第 0 层:一般规则 R1R2R3;没有仅运行一次的规则
  • 第 1 层:仅运行一次的规则 R5;一般规则 R4

此顺序体现了较高 层中规则的意图。只有在 推导出所有 :status :criticallyExposed 三元组之后,才能确定组件是否可以安全部署, 以及哪些组件需要通知——而推导这些三元组的规则 R3 会在下一层完成,同时与向其提供数据的 规则 R1R2 一同完成。

6.6.3 对各层求值

求值遵循 6.5 规则集 求值算法。 求值图 GE 初始为基础图,而 推理图 GI 初始为空。按顺序对每一层求值直至 完成:分轮对该层的规则求值, 并重复各轮,直到某一轮不再生成新的三元组。 该算法未规定一轮中同一层规则的 求值顺序;此处的执行轨迹采用 R1R2R3 的顺序。不同顺序可能会将相同的 推理结果分散到不同数量的轮次中,但由于 第 0 层会运行至完成,因此最终生成的图相同。

由于此规则集没有 DATA 块,因此在求值过程中的每个时刻, GE 都等于 G0 加上 GI。因此,执行轨迹仅跟踪 GI,显示求值进行过程中 它的状态,并用生成每个新三元组的规则进行标记。

第 0 层,第一轮。

  • R1:规则体与 :db :hasVulnerability :vuln1 匹配,将 ?x = :db?v = :vuln1 绑定。 规则头生成 :db :exposedTo :vuln1。 该三元组不在 GE 中,因此将其添加到 GEGI
  • R2:规则体将 ?x :dependsOn ?y?y :exposedTo ?v 连接。此时 GE 包含 :db :exposedTo :vuln1,因此连接产生一个解: ?x = :app?y = :db?v = :vuln1 (来自 :app :dependsOn :db)。 规则头生成 :app :exposedTo :vuln1,这是一个新三元组, 因此将其添加。目前还没有 :frontend 的解,因为 本次开始对 R2 求值时, :app :exposedTo :vuln1 尚不在 GE 中。
  • R3:此时 ?x :exposedTo ?v 可与 :db:app 匹配; 将其与 :vuln1 :severity 9.1 连接并应用 FILTER(?s >= 9.0) 后,两个解均被保留。 规则头生成 :db :status :criticallyExposed:app :status :criticallyExposed,二者均为新三元组。
# 第 0 层第一轮后的 GI
:db  :exposedTo :vuln1 .                    # 新增(R1)
:app :exposedTo :vuln1 .                    # 新增(R2)
:db  :status :criticallyExposed .           # 新增(R3)
:app :status :criticallyExposed .           # 新增(R3)

生成了新的三元组,因此继续对第 0 层 进行下一轮求值。

第 0 层,第二轮。

  • R1:与之前相同地匹配;:db :exposedTo :vuln1 已经 位于 GE 中,因此不会生成新内容。
  • R2:此时连接还会产生 ?x = :frontend?y = :app?v = :vuln1,从而生成 新三元组 :frontend :exposedTo :vuln1。 暴露关系经过两轮才沿 依赖链传播两步。
  • R3:生成新三元组 :frontend :status :criticallyExposed
# 第 0 层第二轮后的 GI
:db       :exposedTo :vuln1 .
:app      :exposedTo :vuln1 .
:frontend :exposedTo :vuln1 .               # 新增(R2)
:db       :status :criticallyExposed .
:app      :status :criticallyExposed .
:frontend :status :criticallyExposed .      # 新增(R3)

第 0 层,第三轮。 此时每条规则的每个解都只会生成 已经位于 GE 中的三元组。GI 保持不变。 没有新的三元组意味着第 0 层已完成:所有 能够推导出的 :exposedTo 三元组和 :status :criticallyExposed 三元组 均已推导出来。

第 1 层,仅运行一次的规则。 首先对该层的仅运行一次的规则求值, 每条规则恰好求值一次。

  • R5:规则体与三个 :status :criticallyExposed 三元组匹配,产生解 ?x = :db?x = :app?x = :frontend。对于每个解,实例化规则头 都会创建一个新的空白节点,每个解生成两个 三元组:为每个严重暴露 的组件生成一条通知。即使该层的一般规则随后会 反复求值,也不会再次对 R5 求值。

第 1 层,一般规则的第一轮。

  • R4:模式 ?x rdf:type :Component:frontend:app:db:logger 匹配。 (它不与 R5 刚刚创建的 rdf:type :Notification 三元组匹配。) 否定元素 NOT { ?x :status :criticallyExposed } 会拒绝 :frontend:app:db 的解,因为 GE 中分别包含它们各自的 :status :criticallyExposed 三元组。 只有解 ?x = :logger 被保留下来,从而生成新的 三元组 :logger :status :safeToDeploy
# 第 1 层后的 GI
:db       :exposedTo :vuln1 .
:app      :exposedTo :vuln1 .
:frontend :exposedTo :vuln1 .
:db       :status :criticallyExposed .
:app      :status :criticallyExposed .
:frontend :status :criticallyExposed .
_:n1      rdf:type :Notification .          # 新增(R5)
_:n1      :concerns :db .                   # 新增(R5)
_:n2      rdf:type :Notification .          # 新增(R5)
_:n2      :concerns :app .                  # 新增(R5)
_:n3      rdf:type :Notification .          # 新增(R5)
_:n3      :concerns :frontend .             # 新增(R5)
:logger   :status :safeToDeploy .           # 新增(R4)

第 1 层,一般规则的第二轮。 没有新的三元组。求值完成,上面所示的 GI 即为所得的推理图

正是分层使该结果可靠。 如果在第 0 层第一轮期间、 尚未推导出 :frontend :status :criticallyExposed 时对 R4 求值, 它就会错误地得出 :frontend :status :safeToDeploy,而 R5 会为 :db:app 创建通知, 却不会为 :frontend 创建通知。 将二者推迟到第 1 层,意味着它们可以看到完整的 :status :criticallyExposed 三元组集合,因此每一层中 规则的求值顺序不会影响 最终结果。

7. 形状规则语言语法

SPARQL-RL 文档 是一个RDF 字符串, 使用 UTF-8 [RFC3629] 编码,并以 RuleSet 产生式开头,并符合 7.6 语法中定义的附加约束。 仅允许使用Unicode 标量值, 范围为 U+0000U+D7FF 以及 U+E000U+10FFFF。 这排除了 代理代码点, 范围为 U+D800U+DFFF

7.1 版本声明

版本标签是一个字符串,用于标识形状规则语言的语法和语义 一致性 版本。

版本标签
版本标签
"1.2"

版本声明应该在文档的较前位置给出。

一个SPARQL-RL 文档中 可以出现多个VERSION指令。 每个指令适用于该指令之后的文档部分, 直到遇到另一个指令或到达文档末尾。

版本标签也可以由 媒体类型version 参数给出。在当前不存在 VERSION 指令的情况下,将考虑 作为媒体类型一部分指定的版本。

7.2 空白

空白 (产生式 WS)用于 分隔两个终结符,否则它们会被(错误地)识别为一个 终结符。下方以大写字母表示的规则名称指示空白 具有重要意义的位置;这些规则构成了用于构建 形状规则语言解析器的一种可能的终结符选择。

空白在产生式 String 中具有重要意义。

7.3 注释

注释以位于 IRIREFSTRING_LITERAL1STRING_LITERAL2STRING_LITERAL_LONG1STRING_LITERAL_LONG2 之外的#开始, 并持续到行尾(由 LFCR 标记), 如果注释标记之后没有行尾,则持续到文件末尾。 注释被视为空白。

7.4 IRI 引用

相对 IRI 引用按照 统一资源标识符(URI):通用 语法 [RFC3986],仅使用 第 5.2 节中的基本算法,基于基础 IRI 进行解析。 不执行基于语法的规范化,也不执行基于方案的规范化 (在 RFC3986 第 6.2.2 和 6.2.3 节中描述)。 根据 国际化资源标识符 (IRI) [RFC3987] 第 6.5 节, IRI 引用中额外允许的字符按照 URI 引用中 非保留字符的相同方式处理。

BASE 指令定义用于按照 [RFC3986] 解析相对 IRI 引用的基础 IRI, 即第 5.1.1 节“嵌入内容中的基础 URI” 第 5.1.2 节“来自 封装实体的基础 URI” 定义了作用域内基础 IRI 如何来自封装文档, 例如具有 xml:base 指令的 SOAP 信封,或具有 Content-Location 标头的 MIME 多部分文档。 第 5.1.3 节“来自检索 URI 的基础 URI”中标识的“检索 URI”, 是特定SPARQL-RL 文档被检索时所使用的 URL。 如果上述内容均未指定基础 URI,则使用默认 基础 URI(第 5.1.4 节“默认基础 URI”)。 每个 BASE 指令都会相对于前一个作用域内基础 URI 设置一个新的作用域内基础 URI。

7.5 转义序列

SRL 文档中使用三种形式的转义:

每种转义序列可使用的上下文
数值
转义
字符串
转义
保留字符
转义
IRI, 用作 RDF 项PREFIXBASE 声明
局部名称
字符串

%-编码序列位于 IRI 的字符范围内, 并且在局部名称中被明确允许。 它们表现为一个% 后跟两个十六进制字符,并表示 相同的三个字符序列。这些序列在处理期间不会 被解码。 写作 <http://a.example/%66oo-bar> 的项 指定 IRI http://a.example/%66oo-bar, 而不是 IRI http://a.example/foo-bar。 在前缀 PREFIX ex: <http://a.example/> 下写作 ex:%66oo-bar 的项 也指定 IRI http://a.example/%66oo-bar

7.6 语法

此处使用的 EBNF 定义于 XML 1.0 [EBNF-NOTATION]。

注:

  1. 语法的入口点是 RuleSet
  2. 关键字不区分大小写,但 'a' 区分大小写。
  3. 转义序列 UCHARECHAR 区分大小写。
  4. DATA 块中不允许使用变量。
  5. 对输入进行词法分析并选择语法规则时,选择最长匹配。
  6. 当使用名称为大写形式的规则作为终结符时, 形状规则语言语法是 LL(1) 和 LALR(1) 的。
[1] RuleSet ::= RuleOrDataBlock
[2] RuleOrDataBlock ::= Prologue ( RuleOrData+ ( Prologue1 RuleOrData? )* )?
[3] RuleOrData ::= Rule | Data
[4] Prologue ::= Prologue1*
[5] Prologue1 ::= BaseDecl | PrefixDecl | VersionDecl | ImportsDecl
[6] BaseDecl ::= 'BASE' IRIREF
[7] PrefixDecl ::= 'PREFIX' PNAME_NS IRIREF
[8] VersionDecl ::= 'VERSION' VersionSpecifier
[9] VersionSpecifier ::= STRING_LITERAL1 | STRING_LITERAL2
[10] ImportsDecl ::= 'IMPORTS' iri
[11] Rule ::= Rule1 | Rule2
[12] Rule1 ::= 'RULE' iri? HeadTemplate ForClause? 'WHERE' 'DATA'? BodyPattern
[13] Rule2 ::= 'IF' iri? ForClause? 'DATA'? BodyPattern 'THEN' HeadTemplate
[14] Data ::= 'DATA' '{' DataTriplesBlock? '}'
[15] HeadTemplate ::= '{' HeadTemplateBlock? '}'
[16] ForClause ::= 'FOR' Var 'IN' iri
[17] BodyPattern ::= '{' BodyTriplesBlock? ( BodyNotTriples '.'? BodyTriplesBlock? )* '}'
[18] BodyNotTriples ::= Filter | Negation | Assignment
[19] Filter ::= 'FILTER' Constraint
[20] Constraint ::= BrackettedExpression | BuiltInCall | FunctionCall
[21] FunctionCall ::= iri ArgList
[22] ArgList ::= NIL | '(' Expression ( ',' Expression )* ')'
[23] ExpressionList ::= NIL | '(' Expression ( ',' Expression )* ')'
[24] Negation ::= 'NOT' 'DATA'? '{' BodyBasic '}'
[25] BodyBasic ::= BodyTriplesBlock? ( BodyBasicNotTriples '.'? BodyTriplesBlock? )*
[26] BodyBasicNotTriples ::= Filter
[27] Assignment ::= 'SET' '(' Var ':=' Expression ')'
[28] DataTriplesBlock ::= TriplesSameSubjectData ( '.' DataTriplesBlock? )?
[29] TriplesSameSubjectData ::= RDFTermData PropertyListNotEmptyData | TriplesNodeData PropertyListData | ReifiedTripleBlockData
[30] PropertyListData ::= PropertyListNotEmptyData?
[31] PropertyListNotEmptyData ::= VerbData ObjectListData ( ';' ( VerbData ObjectListData )? )*
[32] VerbData ::= iri | 'a'
[33] ObjectListData ::= ObjectData ( ',' ObjectData )*
[34] ObjectData ::= GraphNodeData AnnotationData
[35] GraphNodeData ::= RDFTermData | TriplesNodeData | ReifiedTripleData
[36] TriplesNodeData ::= CollectionData | BlankNodePropertyListData
[37] BlankNodePropertyListData ::= '[' PropertyListNotEmptyData ']'
[38] CollectionData ::= '(' GraphNodeData+ ')'
[39] AnnotationData ::= ( ReifierData | AnnotationBlockData )*
[40] AnnotationBlockData ::= '{|' PropertyListNotEmptyData '|}'
[41] ReifierData ::= '~' ReifierIdData?
[42] ReifierIdData ::= iri | BlankNode
[43] ReifiedTripleBlockData ::= ReifiedTripleData PropertyListData
[44] ReifiedTripleData ::= '<<' ReifiedTripleSubjectData VerbData ReifiedTripleObjectData ReifierData? '>>'
[45] ReifiedTripleSubjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTripleData | TripleTermData
[46] ReifiedTripleObjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTripleData | TripleTermData
[47] TripleTermData ::= '<<(' TripleTermSubjectData VerbData TripleTermObjectData ')>>'
[48] TripleTermSubjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTermData
[49] TripleTermObjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTermData
[50] HeadTemplateBlock ::= TriplesBlockTemplate
[51] TriplesBlockTemplate ::= TriplesSameSubjectTemplate ( '.' TriplesBlockTemplate? )?
[52] TriplesSameSubjectTemplate ::= VarOrRDFTerm PropertyListNotEmptyTemplate | TriplesNodeTemplate PropertyListTemplate | ReifiedTripleBlockTemplate
[53] PropertyListTemplate ::= PropertyListNotEmptyTemplate?
[54] PropertyListNotEmptyTemplate ::= Verb ObjectListTemplate ( ';' ( Verb ObjectListTemplate )? )*
[55] ObjectListTemplate ::= ObjectTemplate ( ',' ObjectTemplate )*
[56] ObjectTemplate ::= GraphNodeTemplate AnnotationTemplate
[57] GraphNodeTemplate ::= VarOrRDFTerm | TriplesNodeTemplate | ReifiedTriple
[58] TriplesNodeTemplate ::= CollectionTemplate | BlankNodePropertyListTemplate
[59] BlankNodePropertyListTemplate ::= '[' PropertyListNotEmptyTemplate ']'
[60] CollectionTemplate ::= '(' GraphNodeTemplate+ ')'
[61] AnnotationTemplate ::= ( Reifier | AnnotationBlockTemplate )*
[62] AnnotationBlockTemplate ::= '{|' PropertyListNotEmptyTemplate '|}'
[63] ReifiedTripleBlockTemplate ::= ReifiedTriple PropertyListTemplate
[64] BodyTriplesBlock ::= TriplesBlockPattern
[65] TriplesBlockPattern ::= TriplesSameSubjectPattern ( '.' TriplesBlockPattern? )?
[66] ReifiedTripleBlockPattern ::= ReifiedTriple PropertyListPattern
[67] TriplesSameSubjectPattern ::= VarOrRDFTerm PropertyListNotEmptyPattern | TriplesNodePattern PropertyListPattern | ReifiedTripleBlockPattern
[68] PropertyListPattern ::= PropertyListNotEmptyPattern?
[69] PropertyListNotEmptyPattern ::= ( VerbPath | Var ) ObjectListPattern ( ';' ( ( VerbPath | Var ) ObjectListPattern )? )*
[70] ObjectListPattern ::= ObjectPattern ( ',' ObjectPattern )*
[71] ObjectPattern ::= GraphNodePattern AnnotationPattern
[72] TriplesNodePattern ::= CollectionPattern | BlankNodePropertyListPattern
[73] BlankNodePropertyListPattern ::= '[' PropertyListNotEmptyPattern ']'
[74] CollectionPattern ::= '(' GraphNodePattern+ ')'
[75] AnnotationPattern ::= ( Reifier | AnnotationBlockPattern )*
[76] AnnotationBlockPattern ::= '{|' PropertyListNotEmptyPattern '|}'
[77] GraphNodePattern ::= VarOrRDFTerm | TriplesNodePattern | ReifiedTriple
[78] Reifier ::= '~' ReifierId?
[79] ReifierId ::= Var | iri | BlankNode
[80] ReifiedTriple ::= '<<' ReifiedTripleSubject Verb ReifiedTripleObject Reifier? '>>'
[81] ReifiedTripleSubject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple | TripleTerm
[82] ReifiedTripleObject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple | TripleTerm
[83] TripleTerm ::= '<<(' TripleTermSubject Verb TripleTermObject ')>>'
[84] TripleTermSubject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTerm
[85] TripleTermObject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTerm
[86] Verb ::= VarOrIri | 'a'
[87] VerbPath ::= Path
[88] Path ::= PathSequence
[89] PathSequence ::= PathEltOrInverse ( '/' PathEltOrInverse )*
[90] PathEltOrInverse ::= PathElt | '^' PathElt
[91] PathElt ::= ( iri | 'a' | '(' Path ')' )
[92] RDFTermData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL | TripleTermData
[93] VarOrRDFTerm ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL | TripleTerm
[94] VarOrIri ::= Var | iri
[95] Var ::= VAR1 | VAR2
[96] RDFLiteral ::= String ( LANG_DIR | '^^' iri )?
[97] NumericLiteral ::= NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative
[98] NumericLiteralUnsigned ::= INTEGER | DECIMAL | DOUBLE
[99] NumericLiteralPositive ::= INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE
[100] NumericLiteralNegative ::= INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE
[101] BooleanLiteral ::= 'true' | 'false'
[102] String ::= STRING_LITERAL1 | STRING_LITERAL2 | STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2
[103] iri ::= IRIREF | PrefixedName
[104] PrefixedName ::= PNAME_LN | PNAME_NS
[105] BlankNode ::= BLANK_NODE_LABEL | ANON
[106] Expression ::= ConditionalOrExpression
[107] ConditionalOrExpression ::= ConditionalAndExpression ( '||' ConditionalAndExpression )*
[108] ConditionalAndExpression ::= ValueLogical ( '&&' ValueLogical )*
[109] ValueLogical ::= RelationalExpression
[110] RelationalExpression ::= NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )?
[111] NumericExpression ::= AdditiveExpression
[112] AdditiveExpression ::= MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )*
[113] MultiplicativeExpression ::= UnaryExpression ( '*' UnaryExpression | '/' UnaryExpression )*
[114] UnaryExpression ::= '!' PrimaryExpression
| '+' PrimaryExpression
| '-' PrimaryExpression
| PrimaryExpression
[115] PrimaryExpression ::= BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[116] iriOrFunction ::= iri ArgList?
[117] ExprTripleTerm ::= '<<(' ExprTripleTermSubject Verb ExprTripleTermObject ')>>'
[118] ExprTripleTermSubject ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var
[119] ExprTripleTermObject ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[120] BrackettedExpression ::= '(' Expression ')'
[121] BuiltInCall ::= 'STR' '(' Expression ')'
| 'LANG' '(' Expression ')'
| 'LANGMATCHES' '(' Expression ',' Expression ')'
| 'LANGDIR' '(' Expression ')'
| 'DATATYPE' '(' Expression ')'
| 'IRI' '(' Expression ')'
| 'URI' '(' Expression ')'
| 'BNODE' ( '(' Expression ')' | NIL )
| 'ABS' '(' Expression ')'
| 'CEIL' '(' Expression ')'
| 'FLOOR' '(' Expression ')'
| 'ROUND' '(' Expression ')'
| 'CONCAT' ExpressionList
| 'SUBSTR' '(' Expression ',' Expression ( ',' Expression )? ')'
| 'STRLEN' '(' Expression ')'
| 'REPLACE' '(' Expression ',' Expression ',' Expression ( ',' Expression )? ')'
| 'UCASE' '(' Expression ')'
| 'LCASE' '(' Expression ')'
| 'ENCODE_FOR_URI' '(' Expression ')'
| 'CONTAINS' '(' Expression ',' Expression ')'
| 'STRSTARTS' '(' Expression ',' Expression ')'
| 'STRENDS' '(' Expression ',' Expression ')'
| 'STRBEFORE' '(' Expression ',' Expression ')'
| 'STRAFTER' '(' Expression ',' Expression ')'
| 'YEAR' '(' Expression ')'
| 'MONTH' '(' Expression ')'
| 'DAY' '(' Expression ')'
| 'HOURS' '(' Expression ')'
| 'MINUTES' '(' Expression ')'
| 'SECONDS' '(' Expression ')'
| 'TIMEZONE' '(' Expression ')'
| 'TZ' '(' Expression ')'
| 'NOW' NIL
| 'UUID' NIL
| 'STRUUID' NIL
| 'IF' '(' Expression ',' Expression ',' Expression ')'
| 'STRLANG' '(' Expression ',' Expression ')'
| 'STRLANGDIR' '(' Expression ',' Expression ',' Expression ')'
| 'STRDT' '(' Expression ',' Expression ')'
| 'sameTerm' '(' Expression ',' Expression ')'
| 'isIRI' '(' Expression ')'
| 'isURI' '(' Expression ')'
| 'isBLANK' '(' Expression ')'
| 'isLITERAL' '(' Expression ')'
| 'isNUMERIC' '(' Expression ')'
| 'hasLANG' '(' Expression ')'
| 'hasLANGDIR' '(' Expression ')'
| 'REGEX' '(' Expression ',' Expression ( ',' Expression )? ')'
| 'isTRIPLE' '(' Expression ')'
| 'TRIPLE' '(' Expression ',' Expression ',' Expression ')'
| 'SUBJECT' '(' Expression ')'
| 'PREDICATE' '(' Expression ')'
| 'OBJECT' '(' Expression ')'

终结符的产生式:

[122] IRIREF ::= '<' ([^<>"{}|^`\]-[#x00-#x20] | UCHAR )* '>'
[123] PNAME_NS ::= PN_PREFIX? ':'
[124] PNAME_LN ::= PNAME_NS PN_LOCAL
[125] BLANK_NODE_LABEL ::= '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
[126] VAR1 ::= '?' VARNAME
[127] VAR2 ::= '$' VARNAME
[128] LANG_DIR ::= '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)* ('--' [a-zA-Z]+)?
[129] INTEGER ::= [0-9]+
[130] DECIMAL ::= [0-9]* '.' [0-9]+
[131] DOUBLE ::= ( ([0-9]+ ('.'[0-9]*)? ) | ( '.' ([0-9])+ ) ) [eE][+-]?[0-9]+
[132] INTEGER_POSITIVE ::= '+' INTEGER
[133] DECIMAL_POSITIVE ::= '+' DECIMAL
[134] DOUBLE_POSITIVE ::= '+' DOUBLE
[135] INTEGER_NEGATIVE ::= '-' INTEGER
[136] DECIMAL_NEGATIVE ::= '-' DECIMAL
[137] DOUBLE_NEGATIVE ::= '-' DOUBLE
[138] STRING_LITERAL1 ::= "'" ( ([^#x27#x5C#xA#xD]) | ECHAR | UCHAR )* "'"
[139] STRING_LITERAL2 ::= '"' ( ([^#x22#x5C#xA#xD]) | ECHAR | UCHAR )* '"'
[140] STRING_LITERAL_LONG1 ::= "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR | UCHAR ) )* "'''"
[141] STRING_LITERAL_LONG2 ::= '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR | UCHAR ) )* '"""'
[142] ECHAR ::= '\' [tbnrf\"']
[143] UCHAR ::= ('\u' HEX HEX HEX HEX) | ('\U' HEX HEX HEX HEX HEX HEX HEX HEX)
[144] NIL ::= '(' WS* ')'
[145] WS ::= #x20 | #x9 | #xD | #xA
[146] ANON ::= '[' WS* ']'
[147] PN_CHARS_BASE ::= [A-Z] | [a-z] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | [#x00F8-#x02FF] | [#x0370-#x037D] | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
[148] PN_CHARS_U ::= PN_CHARS_BASE | '_'
[149] VARNAME ::= ( PN_CHARS_U | [0-9] ) ( PN_CHARS_U | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] )*
[150] PN_CHARS ::= PN_CHARS_U | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
[151] PN_PREFIX ::= PN_CHARS_BASE ((PN_CHARS|'.')* PN_CHARS)?
[152] PN_LOCAL ::= (PN_CHARS_U | ':' | [0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )?
[153] PLX ::= PERCENT | PN_LOCAL_ESC
[154] PERCENT ::= '%' HEX HEX
[155] HEX ::= [0-9] | [A-F] | [a-f]
[156] PN_LOCAL_ESC ::= '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?' | '#' | '@' | '%' )

此语法的文本版本可在 此处获取。

7.7 选定的终结符字面量 字符串

本文档使用了一些特定的终结符字面量字符串 [EBNF-NOTATION]。为了明确这些 终结符字面量字符串所使用的 Unicode 码点,下表描述了本节中使用的特定 字符。

代码 字形 描述
U+000A LF 换行符
U+000D CR 回车符
U+0023 # 数字符号
U+0025 % 百分号
U+005C \ 反斜杠

A. 示例导入算法

以下算法展示了一种通过 递归访问所有被引用文档来解析导入语句的方法。

两个规则集 RS1RS2规则集 合并 是一个规则集 MR,其定义如下:

define ruleSetMerge(rule set R1,rule Set RS2):
    MR.rules = RS1.rules ∪︀ RS2.rules
    MR.data = rdf_merge(RS1.data, RS2.data)
    MR.imports = {}
    the result is MR
enddefine

define imports(rule set RS, set of URLs V), returning rule set
    let I = the set of import URLs declared for the rule set RS
    let RS2 be a rule set formed from RS.rules and RS.data
    foreach URL x in I:
        if x ∉ V:
            V = V ∪︀ { x }
            read rule set RS3 from URL x
            RS2 = rulesetMerge(RS2, imports(RS3, V))
        endif
    endfor
    the result is RS2
enddefine

let RS be a rule set
let V = {}
if RS has a location, V = { location of RS }
result is imports(RS, V)

其中 rdf_mergeRDF 合并 操作。

B. 互联网媒体类型和文件 扩展名

形状规则语言的互联网媒体类型(以前称为 MIME 类型) 是 "application/sparql-rl"。

以下信息已提交给互联网工程 指导组(IESG)进行审查、批准并向 IANA 注册。

类型名称:
application
子类型名称:
sparql-rl
必需参数:
可选参数:
version
此参数是可选的。 如果存在,version 的可接受值定义于 版本标签中。
profile
此参数是可选的,用于包含附加信息。 在不了解配置文件的情况下处理时,它不会改变资源表示的语义。 profile 参数的值是一个 以空格分隔的非空 URI 列表。 有关更多信息和背景,请参阅 [RFC6906]。
编码注意事项:
形状规则语言的语法以 Unicode 中的代码点表示 [UNICODE]。编码始终为 UTF-8 [RFC3629]。
Unicode 代码点也可以使用 \uXXXX(U+0 到 U+FFFF)或 \UXXXXXXXX 语法(用于 U+10000 及以上)表示,其中 X 是十六进制数字 [0-9A-F]
安全注意事项:
请参阅C. 安全注意事项以及 UTF-8,ISO 10646 的一种转换格式 [RFC3629] 第 7 节“安全 注意事项”。
互操作性注意事项:
目前没有已知的互操作性问题。
已发布的规范:
本规范。
附加信息:
魔数:
SPARQL-RL 文件可能在文档开头附近包含字符串 'PREFIX' (不区分大小写)。
文件扩展名:
".srl"
基础 URI:
SPARQL-RL 的 'BASE <IRIref>' 项可以更改 查询语言中相对 IRIref 的当前基础 URI,这些 IRIref 会在文档后续部分按顺序使用。
用于获取更多信息的联系人及电子邮件地址:
Data Shapes Working Group <public-shacl@w3.org;
预期用途:
COMMON
使用限制:
作者/变更控制者:
SHACL 1.2 Rules 规范是万维网 联盟 Data Shapes Working Group 的工作成果。W3C 对这些规范拥有变更 控制权。

C. 安全注意事项

本节是非规范性的。

待办

SRL 文档可以包含引用其他SRL 文档IMPORTS 语句。 如果导入的文档本身包含其自己的 IMPORTS 语句, 则也会导入这些文档。

虽然使用 IMPORTS 语句有助于将规则集模块化,但也可能 引入安全风险。 风险包括但不限于:规则集 在求值期间无论是恶意还是意外地导致过量计算; 以及 HTTP 请求被拦截并返回不同的文档, 包括过时的副本。

请参阅4.5 处理导入

编者注

需要有关安全注意事项的意见。

D. 隐私注意事项

本节是非规范性的。

待办

E. 国际化 注意事项

本节是非规范性的。

待办

F. 致谢

本节是非规范性的。

待办

G. 索引

G.1 本 规范定义的术语

G.2 通过引用定义的术语

H. 问题汇总

I. 参考文献

I.1 规范性参考文献

[EBNF-NOTATION]
EBNF 表示法. Tim Bray; Jean Paoli; Michael Sperberg-McQueen; Eve Maler; François Yergeau 等. W3C. W3C 推荐标准. URL: https://www.w3.org/TR/xml/#sec-notation
[I18N-GLOSSARY]
国际化术语表. Richard Ishida; Addison Phillips. W3C. 2024 年 10 月 17 日. W3C 工作组注记. URL: https://www.w3.org/TR/i18n-glossary/
[rdf-concepts]
资源描述框架(RDF):概念 和抽象语法. Graham Klyne; Jeremy Carroll. W3C. 2004 年 2 月 10 日. W3C 推荐标准. URL: https://www.w3.org/TR/rdf-concepts/
[RDF12-CONCEPTS]
RDF 1.2 概念和抽象数据 模型. Andy Seaborne; Gregg Kellogg; Olaf Hartig; Pierre-Antoine Champin. W3C. 2026 年 4 月 7 日. W3C 候选推荐标准. URL: https://www.w3.org/TR/rdf12-concepts/
[RDF12-SEMANTICS]
RDF 1.2 语义. Peter Patel-Schneider; Enrico Franconi; Dörthe Arndt. W3C. 2026 年 4 月 7 日. W3C 候选推荐标准. URL: https://www.w3.org/TR/rdf12-semantics/
[RDF12-TURTLE]
RDF 1.2 Turtle. Gregg Kellogg; Andy Seaborne; Dominik Tomaszuk. W3C. 2026 年 8 月 12 日. W3C 工作草案. URL: https://www.w3.org/TR/rdf12-turtle/
[RFC2119]
用于在 RFC 中指示 要求级别的关键词. S. Bradner. IETF. 1997 年 3 月. 最佳当前实践. URL: https://www.rfc-editor.org/info/rfc2119/
[RFC3629]
UTF-8,ISO 10646 的一种转换格式. F. Yergeau. IETF. 2003 年 11 月. 互联网标准. URL: https://www.rfc-editor.org/info/rfc3629/
[RFC3986]
统一资源标识符(URI):通用 语法. T. Berners-Lee; R. Fielding; L. Masinter. IETF. 2005 年 1 月. 互联网 标准. URL: https://www.rfc-editor.org/info/rfc3986/
[RFC3987]
国际化资源标识符 (IRI). M. Duerst; M. Suignard. IETF. 2005 年 1 月. 提议标准. URL: https://www.rfc-editor.org/info/rfc3987/
[RFC6906]
“profile”链接关系 类型. E. Wilde. IETF. 2013 年 3 月. 信息类. URL: https://www.rfc-editor.org/info/rfc6906/
[RFC8174]
RFC 2119 关键词中大写与小写的歧义. B. Leiba. IETF. 2017 年 5 月. 最佳当前实践. URL: https://www.rfc-editor.org/info/rfc8174/
[shacl12-node-expr]
SHACL 1.2 节点表达式. Robert David; Holger Knublauch; Simon Steyskal. W3C. 2026 年 7 月 21 日. W3C 工作草案. URL: https://www.w3.org/TR/shacl12-node-expr/
[SPARQL12-QUERY]
SPARQL 1.2 查询语言. Olaf Hartig; Andy Seaborne; Ruben Taelman; Gregory Williams; Thomas Pellissier Tanon. W3C. 2026 年 6 月 25 日. W3C 工作草案. URL: https://www.w3.org/TR/sparql12-query/
[UNICODE]
Unicode 标准. Unicode 联盟. URL: https://www.unicode.org/versions/latest/