SPARQL 1.2 RL

W3C 工作草案

关于本文档的更多详细信息
此版本:
https://www.w3.org/TR/2026/WD-sparql12-rl-20260902/
最新发布版本:
https://www.w3.org/TR/sparql12-rl/
最新编辑者草案:
https://w3c.github.io/data-shapes/sparql12-rl/
历史记录:
https://www.w3.org/standards/history/sparql12-rl/
提交历史记录
测试套件:
https://github.com/w3c/data-shapes/tree/gh-pages/shacl12-test-suite/tests/sparql-rl
编辑者:
Robert David (Ontotext)
(KurrawongAI)
Andy Seaborne (Apache 软件 基金会)
Simon Steyskal (Siemens AG)
反馈:
GitHub w3c/data-shapes (拉取请求, 新建议题, 未解决的议题)

摘要

本文档定义了 SPARQL-RL,一种用于 RDF 的 Datalog 风格规则语言。

SPARQL-RL 通过生成新的 RDF 数据来提供推理,这些数据源自 一组规则与基础数据 RDF 图的组合。它 提供类似 SPARQL 的文本语法,并定义一组 规则如何针对 RDF 图进行求值。

SPARQL 规则语言可简称为 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 推理规则
定义 SHACL 的基于规则的推理框架
SHACL 1.2 节点表达式
定义用于在 SHACL 中派生焦点节点和值节点的表达式
SHACL 1.2 数据剖析
定义使用 SHACL 对数据(包括 SHACL 数据)进行剖析
SHACL 1.2 SPARQL 相关功能
定义 SHACL 的 SPARQL 相关扩展
SHACL 1.2 用户界面
定义 SHACL 用于生成用户界面的方式

工作组说明草案:

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

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

1. 简介

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

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

SPARQL-RL 允许使用新的 RDF 项,包括可在 规则头的三元组模板中使用的空白节点。

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

1.1 术语

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

1.2 文档约定

本文档中的 RDF 数据示例使用 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/sparql-rl#
xsd: http://www.w3.org/2001/XMLSchema#
sparql: http://www.w3.org/ns/sparql#
ex: http://example/

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

# 此框表示规则
# 此框表示输入数据
# 此框表示推断数据

2. 一致性

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

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

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

符合要求的 SRL 文档是 符合语法RDF 字符串,该语法从 RuleSet 产生式开始,如 7. SPARQL-RL 语法中所定义。

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

3. SPARQL-RL

本节是非规范性的。

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

每个规则都有一个称为规则体的模式,以及一个称为 规则头的结果模板。 执行规则时,会查找规则体中各变量的值, 使规则体与合并后的基础图以及 截至此时执行过程中推断出的所有三元组相匹配。 随后使用这些值实例化 规则头中的三元组模板,以生成新的推断三元组。

规则会持续执行,直至不再推断出更多三元组; 随着新的推断三元组变为可用,规则可能会执行多次。

SPARQL-RL 执行的定义方式确保规则执行顺序 在创建新的 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 操作相同, 并且 SPARQL-RL 提供许多与 SPARQL 相同的函数和运算符。

3.4 否定

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

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

3.5 赋值和创建 RDF 项

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

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

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

此条件可确保此类规则不会循环回自身, 从而导致产生无界数量的 RDF 项。

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

3.6 导入规则集

SPARQL-QL 规则集可以通过在该规则集的 规则集导入项中包含其他规则集的 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。 此类规则仅依赖于基础图中的匹配。

4. SPARQL-RL 抽象语法

SPARQL-RL 抽象语法是 SPARQL-RL 的逻辑结构。 它用于定义 SPARQL-RL 的执行算法。

4.1 抽象语法的 元素

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

SPARQL-RL 提供两种操作:inferquery

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

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

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

SPARQL-RL 处理器
SPARQL-RL 处理器是实现 SPARQL-RL 规范、能够对规则集求值,并提供以下一种或两种 操作的系统:推断查询

三元组模式三元组 模板中, 元组的位置 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 个元素。

varsielti 定义的变量集合,其中:

V0 为序列的初始变量。

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

VallV0 与所有 varsj 的并集, 其中 j 为从 1 到 N 的 j,N 为该序列的长度。

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

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

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

4.3 规则依赖关系

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

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

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

在第二个示例中,第一条规则对 第二条规则具有闭合依赖:三元组模式 ?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. SPARQL-RL 与 SPARQL 之间的关系

本节是非规范性的。

SRL 与 SPARQL 关系密切。SRL 旨在与 SPARQL 兼容, SRL 中的许多构造取自或受到 SPARQL 模式匹配的启发。不过,两者之间也存在一些差异。

在 SRL 中,RULE 变量在使用前始终已绑定,无论是用于 FILTERSET 的表达式,还是用于 规则头三元组模板中。SPARQL CONSTRUCT 查询和 INSERT 更新会在变量出现在 CONSTRUCTINSERT 模板中,但未在 WHERE 子句中赋值时 生成部分结果。

其他差异包括:

6. 规则集求值

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

输入: 数据图 G(称为基础图)和规则集 RS。
输出: 由推断三元组组成的 RDF 图 GI

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

6.1 求值定义

解映射
解映射 μ 是一个偏 函数 μ : VT, 其中 V 是所有变量的集合, T 是所有 RDF 项的集合。 μ 的定义域表示 为 dom(μ),它是 μ 在其中有定义的 V 的子集。在明确指 解映射的情况下,我们使用术语 。 使用 μ0 表示满足以下条件的解映射: dom(μ0) 是空集。
替换函数
替换函数,或简称为替换, 是一个函数 subst(μ, triple pattern), 它返回一个三元组模式, 其中,对于三元组模式中 位于 dom(μ) 内的每个变量出现位置,都会将其替换为 解映射var 给出的RDF 项。 如果生成的三元组模式没有变量,则它是一个 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.
    ## μ is a solution sequence
    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, μ), ..., evalFunction(exprN, μ))
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 ∪︀ 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 语法

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

7.1 版本声明

版本标签是用于标识 SPARQL-RL 语法和语义 一致性的字符串。

版本标签
版本标签
"1.2"

版本声明应该在文档前部给出。

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

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

7.2 空白符

空白符 (产生式 WS)用于 分隔两个原本会被(错误地)识别为一个 终结符的终结符。下面以大写形式书写的规则名称指示空白符 具有重要意义的位置;这些名称构成了用于构建 SPARQL-RL 解析器的一种可能的终结符选择。

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

7.3 注释

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

7.4 IRI 引用

根据 统一资源标识符(URI):通用 语法 [RFC3986], 相对 IRI 引用使用基础 IRI 进行解析,并且仅使用第 5.2 节中的 基本算法。 不执行基于语法的规范化或基于方案的规范化 (见 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 相对于前一个基础 URI。

7.5 转义序列

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

可使用各种转义序列的上下文
数字
转义
字符串
转义
保留字符
转义
用作 RDF 项PREFIXBASE 声明的 IRI
本地名称
字符串

%-编码序列位于 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. 当名称为大写形式的规则用作终结符时, SPARQL-RL 语法是 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 ::= 'RULE' iri? HeadTemplate 'WHERE' 'DATA'? BodyPattern
[12] Data ::= 'DATA' '{' DataTriplesBlock? '}'
[13] HeadTemplate ::= '{' HeadTemplateBlock? '}'
[14] BodyPattern ::= '{' BodyTriplesBlock? ( BodyNotTriples '.'? BodyTriplesBlock? )* '}'
[15] BodyNotTriples ::= Filter | Negation | Assignment
[16] Filter ::= 'FILTER' Constraint
[17] Constraint ::= BrackettedExpression | BuiltInCall | FunctionCall
[18] FunctionCall ::= iri ArgList
[19] ArgList ::= NIL | '(' Expression ( ',' Expression )* ')'
[20] ExpressionList ::= NIL | '(' Expression ( ',' Expression )* ')'
[21] Negation ::= 'NOT' 'DATA'? '{' BodyBasic '}'
[22] BodyBasic ::= BodyTriplesBlock? ( BodyBasicNotTriples '.'? BodyTriplesBlock? )*
[23] BodyBasicNotTriples ::= Filter
[24] Assignment ::= 'SET' '(' Var ':=' Expression ')'
[25] DataTriplesBlock ::= TriplesSameSubjectData ( '.' DataTriplesBlock? )?
[26] TriplesSameSubjectData ::= RDFTermData PropertyListNotEmptyData | TriplesNodeData PropertyListData | ReifiedTripleBlockData
[27] PropertyListData ::= PropertyListNotEmptyData?
[28] PropertyListNotEmptyData ::= VerbData ObjectListData ( ';' ( VerbData ObjectListData )? )*
[29] VerbData ::= iri | 'a'
[30] ObjectListData ::= ObjectData ( ',' ObjectData )*
[31] ObjectData ::= GraphNodeData AnnotationData
[32] GraphNodeData ::= RDFTermData | TriplesNodeData | ReifiedTripleData
[33] TriplesNodeData ::= CollectionData | BlankNodePropertyListData
[34] BlankNodePropertyListData ::= '[' PropertyListNotEmptyData ']'
[35] CollectionData ::= '(' GraphNodeData+ ')'
[36] AnnotationData ::= ( ReifierData | AnnotationBlockData )*
[37] AnnotationBlockData ::= '{|' PropertyListNotEmptyData '|}'
[38] ReifierData ::= '~' ReifierIdData?
[39] ReifierIdData ::= iri | BlankNode
[40] ReifiedTripleBlockData ::= ReifiedTripleData PropertyListData
[41] ReifiedTripleData ::= '<<' ReifiedTripleSubjectData VerbData ReifiedTripleObjectData ReifierData? '>>'
[42] ReifiedTripleSubjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTripleData | TripleTermData
[43] ReifiedTripleObjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTripleData | TripleTermData
[44] TripleTermData ::= '<<(' TripleTermSubjectData VerbData TripleTermObjectData ')>>'
[45] TripleTermSubjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTermData
[46] TripleTermObjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTermData
[47] HeadTemplateBlock ::= TriplesBlockTemplate
[48] TriplesBlockTemplate ::= TriplesSameSubjectTemplate ( '.' TriplesBlockTemplate? )?
[49] TriplesSameSubjectTemplate ::= VarOrRDFTerm PropertyListNotEmptyTemplate | TriplesNodeTemplate PropertyListTemplate | ReifiedTripleBlockTemplate
[50] PropertyListTemplate ::= PropertyListNotEmptyTemplate?
[51] PropertyListNotEmptyTemplate ::= Verb ObjectListTemplate ( ';' ( Verb ObjectListTemplate )? )*
[52] ObjectListTemplate ::= ObjectTemplate ( ',' ObjectTemplate )*
[53] ObjectTemplate ::= GraphNodeTemplate AnnotationTemplate
[54] GraphNodeTemplate ::= VarOrRDFTerm | TriplesNodeTemplate | ReifiedTriple
[55] TriplesNodeTemplate ::= CollectionTemplate | BlankNodePropertyListTemplate
[56] BlankNodePropertyListTemplate ::= '[' PropertyListNotEmptyTemplate ']'
[57] CollectionTemplate ::= '(' GraphNodeTemplate+ ')'
[58] AnnotationTemplate ::= ( Reifier | AnnotationBlockTemplate )*
[59] AnnotationBlockTemplate ::= '{|' PropertyListNotEmptyTemplate '|}'
[60] ReifiedTripleBlockTemplate ::= ReifiedTriple PropertyListTemplate
[61] BodyTriplesBlock ::= TriplesBlockPattern
[62] TriplesBlockPattern ::= TriplesSameSubjectPattern ( '.' TriplesBlockPattern? )?
[63] ReifiedTripleBlockPattern ::= ReifiedTriple PropertyListPattern
[64] TriplesSameSubjectPattern ::= VarOrRDFTerm PropertyListNotEmptyPattern | TriplesNodePattern PropertyListPattern | ReifiedTripleBlockPattern
[65] PropertyListPattern ::= PropertyListNotEmptyPattern?
[66] PropertyListNotEmptyPattern ::= ( VerbPath | Var ) ObjectListPattern ( ';' ( ( VerbPath | Var ) ObjectListPattern )? )*
[67] ObjectListPattern ::= ObjectPattern ( ',' ObjectPattern )*
[68] ObjectPattern ::= GraphNodePattern AnnotationPattern
[69] TriplesNodePattern ::= CollectionPattern | BlankNodePropertyListPattern
[70] BlankNodePropertyListPattern ::= '[' PropertyListNotEmptyPattern ']'
[71] CollectionPattern ::= '(' GraphNodePattern+ ')'
[72] AnnotationPattern ::= ( Reifier | AnnotationBlockPattern )*
[73] AnnotationBlockPattern ::= '{|' PropertyListNotEmptyPattern '|}'
[74] GraphNodePattern ::= VarOrRDFTerm | TriplesNodePattern | ReifiedTriple
[75] Reifier ::= '~' ReifierId?
[76] ReifierId ::= Var | iri | BlankNode
[77] ReifiedTriple ::= '<<' ReifiedTripleSubject Verb ReifiedTripleObject Reifier? '>>'
[78] ReifiedTripleSubject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple | TripleTerm
[79] ReifiedTripleObject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple | TripleTerm
[80] TripleTerm ::= '<<(' TripleTermSubject Verb TripleTermObject ')>>'
[81] TripleTermSubject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTerm
[82] TripleTermObject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTerm
[83] Verb ::= VarOrIri | 'a'
[84] VerbPath ::= Path
[85] Path ::= PathSequence
[86] PathSequence ::= PathEltOrInverse ( '/' PathEltOrInverse )*
[87] PathEltOrInverse ::= PathElt | '^' PathElt
[88] PathElt ::= ( iri | 'a' | '(' Path ')' )
[89] RDFTermData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL | TripleTermData
[90] VarOrRDFTerm ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL | TripleTerm
[91] VarOrIri ::= Var | iri
[92] Var ::= VAR1 | VAR2
[93] RDFLiteral ::= String ( LANG_DIR | '^^' iri )?
[94] NumericLiteral ::= NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative
[95] NumericLiteralUnsigned ::= INTEGER | DECIMAL | DOUBLE
[96] NumericLiteralPositive ::= INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE
[97] NumericLiteralNegative ::= INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE
[98] BooleanLiteral ::= 'true' | 'false'
[99] String ::= STRING_LITERAL1 | STRING_LITERAL2 | STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2
[100] iri ::= IRIREF | PrefixedName
[101] PrefixedName ::= PNAME_LN | PNAME_NS
[102] BlankNode ::= BLANK_NODE_LABEL | ANON
[103] Expression ::= ConditionalOrExpression
[104] ConditionalOrExpression ::= ConditionalAndExpression ( '||' ConditionalAndExpression )*
[105] ConditionalAndExpression ::= ValueLogical ( '&&' ValueLogical )*
[106] ValueLogical ::= RelationalExpression
[107] RelationalExpression ::= NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )?
[108] NumericExpression ::= AdditiveExpression
[109] AdditiveExpression ::= MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )*
[110] MultiplicativeExpression ::= UnaryExpression ( '*' UnaryExpression | '/' UnaryExpression )*
[111] UnaryExpression ::= '!' PrimaryExpression
| '+' PrimaryExpression
| '-' PrimaryExpression
| PrimaryExpression
[112] PrimaryExpression ::= BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[113] iriOrFunction ::= iri ArgList?
[114] ExprTripleTerm ::= '<<(' ExprTripleTermSubject Verb ExprTripleTermObject ')>>'
[115] ExprTripleTermSubject ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var
[116] ExprTripleTermObject ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[117] BrackettedExpression ::= '(' Expression ')'
[118] 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 ')'

终结符的产生式:

[119] IRIREF ::= '<' ([^<>"{}|^`\]-[#x00-#x20] | UCHAR )* '>'
[120] PNAME_NS ::= PN_PREFIX? ':'
[121] PNAME_LN ::= PNAME_NS PN_LOCAL
[122] BLANK_NODE_LABEL ::= '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
[123] VAR1 ::= '?' VARNAME
[124] VAR2 ::= '$' VARNAME
[125] LANG_DIR ::= '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)* ('--' [a-zA-Z]+)?
[126] INTEGER ::= [0-9]+
[127] DECIMAL ::= [0-9]* '.' [0-9]+
[128] DOUBLE ::= ( ([0-9]+ ('.'[0-9]*)? ) | ( '.' ([0-9])+ ) ) [eE][+-]?[0-9]+
[129] INTEGER_POSITIVE ::= '+' INTEGER
[130] DECIMAL_POSITIVE ::= '+' DECIMAL
[131] DOUBLE_POSITIVE ::= '+' DOUBLE
[132] INTEGER_NEGATIVE ::= '-' INTEGER
[133] DECIMAL_NEGATIVE ::= '-' DECIMAL
[134] DOUBLE_NEGATIVE ::= '-' DOUBLE
[135] STRING_LITERAL1 ::= "'" ( ([^#x27#x5C#xA#xD]) | ECHAR | UCHAR )* "'"
[136] STRING_LITERAL2 ::= '"' ( ([^#x22#x5C#xA#xD]) | ECHAR | UCHAR )* '"'
[137] STRING_LITERAL_LONG1 ::= "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR | UCHAR ) )* "'''"
[138] STRING_LITERAL_LONG2 ::= '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR | UCHAR ) )* '"""'
[139] ECHAR ::= '\' [tbnrf\"']
[140] UCHAR ::= ('\u' HEX HEX HEX HEX) | ('\U' HEX HEX HEX HEX HEX HEX HEX HEX)
[141] NIL ::= '(' WS* ')'
[142] WS ::= #x20 | #x9 | #xD | #xA
[143] ANON ::= '[' WS* ']'
[144] 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]
[145] PN_CHARS_U ::= PN_CHARS_BASE | '_'
[146] VARNAME ::= ( PN_CHARS_U | [0-9] ) ( PN_CHARS_U | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] )*
[147] PN_CHARS ::= PN_CHARS_U | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
[148] PN_PREFIX ::= PN_CHARS_BASE ((PN_CHARS|'.')* PN_CHARS)?
[149] PN_LOCAL ::= (PN_CHARS_U | ':' | [0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )?
[150] PLX ::= PERCENT | PN_LOCAL_ESC
[151] PERCENT ::= '%' HEX HEX
[152] HEX ::= [0-9] | [A-F] | [a-f]
[153] 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. 互联网媒体类型和文件 扩展名

SPARQL-RL 的互联网媒体类型(以前称为 MIME 类型)是 “application/sparql-rl”。

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

类型名称:
application
子类型名称:
sparql-rl
必需参数:
可选参数:
version
此参数是可选的。 如果存在,version 的可接受值在 版本标签中定义。
profile
此参数是可选的,用于包含附加信息。 在不了解配置文件的情况下处理资源表示时, 它不会改变该资源表示的语义。 profile 参数的值是一个以空格分隔的非空 URI 列表。 有关更多信息和背景,请参阅 [RFC6906]。
编码注意事项:
SPARQL-RL 的语法使用 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 会在文档后续部分依次使用。
用于获取更多信息的联系人及电子邮件地址:
数据形状工作组 <public-shacl@w3.org;
预期用途:
COMMON
使用限制:
作者/变更控制者:
SPARQL-RL 规范是万维网联盟 数据形状工作组的工作成果。W3C 对这些规范拥有变更 控制权。

C. 安全注意事项

本节是非规范性的。

SPARQL-RL 文档可能包含引用其他 SPARQL-RL 文档并将其内容导入当前 文档的 IMPORTS 语句。 如果导入的文档本身包含自己的 IMPORTS 语句, 则也会导入这些文档。

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

将 SPARQL-RL 规则集应用于数据图可能会导致 大量计算和内存使用,这可能被利用 来造成拒绝服务。 应用程序应该谨慎限制应用 SPARQL-RL 规则集可能导致的 计算量和内存使用量。

SPARQL-RL 语法使用 UTF-8 [RFC3629] 编码,并 允许 在字符串数据中使用未转义的控制字符。 尽管本规范不会直接向最终用户公开这些内容, 但这些内容可能会通过用户代理呈现,而呈现此类字符 可能导致所显示的文本被混淆。

SPARQL-RL 可用于处理和创建任意应用程序数据; 安全注意事项会因使用领域而异。 适用于文本的安全工具和协议 (例如 PGP 加密、校验和验证、密码保护的压缩) 也可用于SPARQL-RL 文档。 必须实施能够反映 SPARQL-RL 规则集求值结果中 信息敏感性的安全/隐私协议。

SPARQL-RL 的安全注意事项包括 RDF 数据以及 RDF Turtle等格式的安全注意事项。

D. 隐私注意事项

本节是非规范性的。

SPARQL-RL 文档可以包含附加的应用程序数据, 其中可能包括个人身份信息(PII) 或其他可能被视为敏感的信息。 建议发布包含此类信息的规则集的作者仔细 考虑发布此类信息的必要性和用途, 以及预期使用并可能披露这些数据的地区 所适用的法规(例如 GDPRCCPA其他法规), 尤其应考虑访问这些数据是否需要授权措施。

E. 致谢

本节是非规范性的。

以下人员为数据形状工作组规则任务组中的 SPARQL-RL 开发工作作出了贡献: Robert David、David Habgood、Livio Robaldo、Ognjen Savkovic、Simon Steyskal、Ted Thibodeau Jr 和 Andy Seaborne。

数据形状工作组的成员包括 @@。

F. 索引

F.1 本 规范定义的术语

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

G. 议题摘要

本规范中未列出任何议题。

H. 参考文献

H.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 年 8 月 20 日。W3C 工作草案。URL: https://www.w3.org/TR/sparql12-query/
[UNICODE]
Unicode 标准。Unicode 联盟。URL:https://www.unicode.org/versions/latest/