Copyright © 2025-2026 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
この文書は、SPARQL-RL、すなわちRDF用のDatalog形式の規則言語を定義します。
SPARQL-RLは、ルールセットと基礎データとなるRDFグラフの 組み合わせから新しいRDFデータを生成することにより、推論機能を 提供します。また、SPARQLに似たテキスト構文を提供し、ルールセットが RDFグラフに対してどのように評価されるかを定義します。
文脈が明確な場合、SPARQL規則言語を単にSRLと 呼ぶことができます。
この仕様は、 Data Shapesワーキンググループによって公開されています。
この節では、この 文書の公開時点におけるステータスについて説明します。現在のW3C 出版物の一覧およびこの技術報告書の最新版は、 次の W3C標準および草案の 索引で確認できます。
この文書は、Data Shapesワーキング グループによって、 勧告 トラックを使用した作業草案として公開されました。
作業草案として公開されたことは、 次の主体によって承認されたことを意味するものではありません: W3Cおよびそのメンバー。
これは草案文書であり、いつでも他の 文書によって更新、置換、または廃止される可能性があります。この文書を 進行中の作業以外のものとして引用することは不適切です。 策定予定の勧告に対する今後の更新には、 新機能が組み込まれる可能性があります。
この文書は、 次の方針の下で活動するグループによって作成されました: W3C 特許 方針。 W3Cは、 特許 開示の公開リストを維持しています。 このリストには、グループの成果物に関連して行われた開示が掲載され、 そのページには特許を開示するための 手順も含まれています。ある特許について実際の 知識を有し、その特許に 必須クレーム が含まれていると考える個人は、次に従ってその情報を開示しなければなりません: W3C特許方針の第6節。
この文書には、 2025年8月18日付W3Cプロセス文書が適用されます。
この仕様は、SHACL 1.2仕様ファミリーの一部です。これらの詳細な紹介については、SHACL 1.2の概要を 参照してください。
各仕様は次のとおりです:
作業草案:
ワーキンググループノート草案:
実装者は、上記の仕様への適合度を部分的に確認できます。そのためには、 次の SHACL 1.2テストスイートのテストケースに合格する必要があります。 ただし、テストスイートのすべてのテストに合格しても、 仕様への完全な適合を意味するものではないことに注意してください。 これは、実装がテストスイートによってテストされた側面に適合していることのみを意味します。
この文書では、SPARQL-RLを紹介します。これは、宣言的ルールを通じて 既存のRDFデータから新しいRDFトリプルを導出するための仕組みです。 この文書では、ルールベースの推論の構文および意味論を定義します。
SPARQL-RLの実装は、2つの操作を提供します。 infer操作は、指定された ベースグラフにルールを適用し、ルールの実行によって導出された RDFトリプルを含む推論グラフを生成します。 推論グラフとベースグラフの結合は任意であり、 ユーザーに委ねられます。query操作は、指定された 目標パターンをルールを使用してベースグラフから導出できるかどうかを判定します。
SPARQL-RLでは、空白ノードを含む新しいRDF項を ルールのヘッドにあるトリプルテンプレートで使用できます。
SPARQL-RLは失敗による否定もサポートしますが、これはルールが 実行される順序に応じて異なる推論グラフを生成する可能性があります。 これを回避するため、ルールは単一の暗黙的な 順序をルール間に確立する層別化という手法を使用して評価され、 常に同じ推論グラフが 生成されることを保証します。
次の他の仕様では、この文書で使用される 基本的な用語を定めています:
この文書の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/ |
文書全体を通じて、Turtle形式のRDFグラフを含む色分けされた ボックスが表示されます。これらのTurtle文書の断片では、上記の接頭辞 バインディングを使用します。
# このボックスはルールを表します
# このボックスは入力データを表します
# このボックスは推論データを表します
非規範的と明示された節に加え、この仕様に含まれるすべての作成ガイドライン、図、例、および注記は 非規範的です。この仕様のその他のすべての内容は規範的です。
この文書のキーワードMAY、MUST、MUST NOT、およびSHOULDは、 ここに示すように、すべて 大文字で表記される場合に限り、 BCP 14 [RFC2119] [RFC8174] に記載されているとおりに 解釈されるものとします。
この仕様では、次の適合基準を定義します:
適合するSRL文書とは、
RDF
文字列であり、
RuleSet
生成規則から始まる
文法に適合するものとして、
7.
SPARQL-RL文法で定義されています。
この仕様では、SPARQL-RL プロセッサーが、非適合のルールセットをどのように処理するかを定義しない。
この節は非規範的です。
SPARQL-RLは、ベースグラフとルールセットを指定すると、新しいトリプルを推論します。 評価の出力は、ベースグラフには現れない導出された トリプルを含む推論グラフです。
各ルールには、ボディと呼ばれるパターンと、 ヘッドと呼ばれる結果テンプレートがあります。 ルールは、ボディが結合されたベースグラフおよび その時点までの実行による推論済みトリプルと一致するように、 ボディ内の変数の値を見つけることで実行されます。 その後、これらの値を使用してルールヘッド内のトリプルテンプレートを インスタンス化し、新しい推論済みトリプルを生成します。
ルールは、それ以上トリプルが推論されなくなるまで実行され、 新しい推論済みトリプルが利用可能になると、ルールが複数回 実行される場合があります。
SPARQL-RLの実行は、ルールの実行順序が、 新しい空白ノードを含む新しいRDF項の作成時にも、 パターンの不在をテストする場合にも、異なる結果を生じさせないように定義されています。 つまり、ルールの実行順序に 関係なく、同じ推論グラフが生成されます。
SPARQL-RLには、SPARQL 1.2クエリ言語に着想を得た、人間にとって扱いやすい構文があります。 ルールセットの評価にはSPARQLと類似する要素がありますが、 ルールの実行順序に関係なく同じ推論グラフが生成されることを 保証するため、細部が異なります。
この節の例では、ソフトウェアコンポーネントと その依存関係について説明します。フロントエンドがアプリケーションサーバーを呼び出し、 アプリケーションサーバーは既知の脆弱性を持つ データベースに問い合わせます。
この最初の例には、次のデータグラフとルールセットがあります:
上記のルールをデータに適用すると、依存関係の種類にかかわらず、
:frontendが:appに依存し、:appが
:dbに依存すると結論付けられます。
次に、他のルールによって生成された:dependsOnトリプルに依存するルールを
追加することで、:exposedTo関係を導出できます(下記の4.3 ルールの依存関係も参照してください):
前節の:exposedToルールが到達するのは直接的な
依存関係のみです。:frontendは:dbに直接依存していないため、
:frontendについて:exposedToトリプルは推論されません。
任意の長さの依存関係チェーンに沿って危険への露出を伝播させるため、そのルールを
2つのルールに置き換えます。コンポーネントは自身が持つ
脆弱性にさらされ、さらに直接の依存先がさらされている
あらゆる脆弱性にもさらされます:
前の例と比較すると、ここでは
:db :exposedTo :vuln1(データベースは自身の
脆弱性にさらされています)と、:frontend :exposedTo :vuln1が追加されます。
チェーンの長さにかかわらず、依存関係の
チェーンを通じて危険への露出が:frontendまで到達します。
この最後のルールは再帰的ルールです。ルールのボディが そのルールのヘッドに依存しています。
ルールのボディで式を使用して、ボディの照合時に 変数の値を制限できます。 たとえば、各脆弱性の重大度が指定されている場合、 重大な脆弱性にさらされているコンポーネントに ステータスを付与できます:
FILTERは式を評価し、その式がtrueと評価された場合は現在の
変数バインディングの集合を保持し、式がfalseと評価された場合は
現在の変数バインディングの集合を破棄します。
これは、
SPARQLのFILTER演算
と同じであり、SPARQL-RLはSPARQLと同じ関数および演算子の多くを提供します。
否定では、一致してはならないパターンを指定できます。 これは「失敗による否定」と呼ばれます。
否定要素を評価するため、ルール評価アルゴリズムは、 否定要素内のパターンに一致するトリプルを生成できるすべてのルールが 完了していることを保証します。これは 層別化と呼ばれ、否定が データに由来するか、否定要素内で完了したものかを問わず、 関連するすべての可能なトリプルに基づくことを保証します。否定を含むルールは、これらのトリプルを 生成するルールに_依存する_といいます(下記の4.3 ルールの依存関係を参照してください)。
代入を使用すると、ルールのボディ内で式の結果を変数に 代入できます。これを使用して、データに基づく 新しいRDF項を作成できます。
空白ノードはルールヘッドで使用でき、ルール評価によってトリプルが生成される たびに、それぞれ新しい空白ノードが生成されます。
代入を含むルール、および ルールヘッド内に空白ノードを作成するルールは、1回実行ルールです。 このようなルールは、依存するデータを生成できるすべてのルールの後に実行され、 それらが生成するデータに依存するすべてのルールより前に実行されます。 ルールヘッド内に空白ノードを含むルールも、新しい RDF項を作成するため、1回実行ルールです。
この条件により、そのようなルールが自身にループバックして、無制限の数の RDF項を生成することを防ぎます。
SPARQL-QLのルールセットは、他のルールセットのURLを そのルールセットのルールセットインポートに含めることで、他のルールセットを組み込めます。 これにより、ルールセット間で共有されるライブラリとしてルールを構造化できます。
ルールセットのIMPORTS文は、そのルールセット内のルールが
評価される前に処理されます。インポート手順中に、インポートされたルールセットが
独自のインポートを持つ場合、それらも再帰的に処理されます。
ルールセットの処理中にIMPORTS文をたどると、
循環インポートが発生する可能性があります。ルールセットは1回だけインポートされます。
インポート文のグラフ内の循環によって無限ループが生じることはありません。
ルールセットのインポートのサポートは、SRLプロセッサーでは任意です。 詳細については、4.5 インポートの 処理を参照してください。
データブロックを使用すると、RDFトリプルをルールセットの評価に直接簡潔に提供できます。 データブロック内のトリプルは推論グラフに追加され、 ルールのボディ内での照合に利用できます。
たとえば、ルールセットには、データから導出する代わりに、 既知の事実を直接表明して含めることができます:
データブロックは、空のボディを持つルールと同等です。 そのトリプルは、いかなるルールも 評価されることなく推論グラフの一部になります。
ルールはルールセットにまとめられます。 ルールセットとデータグラフ(ベースグラフ)が評価への入力です。 出力は、推論グラフと呼ばれるグラフであり、 データグラフには現れないトリプルの集合です。
評価中、あるルールに基づいて推論されたトリプルは、 他のルールでの照合に利用できます。 ルールセットの評価は、推論グラフに ルールセットおよびデータグラフの入力から得られる すべての可能なトリプルが含まれるまで続行されます。
評価は、ルール自体を評価する前に ルールセットを準備するための 2つの手順から始まります:
ルールセットの準備が完了すると、評価は 層別化の各層を順番に取得し、 その層内のルールを完了するまで評価してから、 次の層に移ることで進行します。
グラウンドデータとは、ベースグラフ内のトリプルです。 ルールセットの評価中には、推論された トリプルではなく、元のトリプルのみに対してパターン照合を行う 必要がある場合があります。
この一例は、デフォルト値の設定です。 ルールは、ベースグラフに値がすでに含まれているかどうかをテストし、含まれていない場合は、 デフォルト値を計算できます。
NOT DATAを使用すると、ルールボディの他の部分が推論済みトリプルと照合できます。
また、すべてのルールボディの照合をベースグラフに対して行うこともできます。そのためには、
WHERE DATAを使用します。
このようなルールは、ベースグラフからの照合のみに依存します。
SPARQL-RL抽象構文は、SPARQL-RLの論理構造です。 これは、SPARQL-RLの実行アルゴリズムを定義するために使用されます。
SPARQL-RLは、inferおよびqueryという2つの操作を提供します。
クエリは、指定されたゴール パターンを、ベースグラフからルールセットを使用して導出できるかどうかを判定する操作である。 すべてのルールを評価するとは限らず、代わりに、クエリのゴールに回答するために 必要なルールのみを評価してもよい。
クエリは、推論操作を実行し、 続いて、ゴールパターンを結合された ベースグラフおよび推論 グラフに照合することと等価である。
トリプルパターンまたはトリプル テンプレートでは、 タプルの位置 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は
ベースグラフに対して照合される。
|
整形式性とは、 ルールセットの抽象構文に対する一連の条件です。これらの条件は総合的に、 ルールのヘッド内の 変数が、そのルールの ボディ内で定義された値を持つこと、 フィルター要素 または代入式内の各変数が、 評価時点で値を持つこと、 およびルール内の各 代入が、ルールボディ内でそれ以前に使用されていない 新しい変数を導入することを保証します。
初期変数集合が指定されたルール要素の シーケンスについて、整形式性を定義します。
eltiを、ルール要素のシーケンスのi番目の要素とします。
varsiを、 eltiによって定義される変数の集合とします。ここで:
V0を、シーケンスの初期変数とします。
Viを、 V0と、i未満のjについての すべてのvarsjとの和集合とします。
VallをVNとします。 ここで、Nはシーケンスの長さです。
整形式 シーケンスとは、変数集合V0が指定された ルール要素のシーケンスであり、 次の条件を 満たすものです:
ルールは、 ルールボディのシーケンスが、空集合である V0を指定された 整形式シーケンスであり、 ルールヘッドの トリプルテンプレート内の各変数が Vallの要素である場合、整形式 ルールです。
第2のルールの出力が第1のルールのボディの評価に影響する場合、
ルールR1はルールR2に依存します。すなわち、R2のヘッドには、
R1のボディ内のトリプルパターンと一致するトリプルを生成する可能性がある
トリプルテンプレートがあります。
これは、トリプルパターン要素として、または
否定要素の内部にあります。
依存関係には2種類あります:
閉鎖依存関係と開放
依存関係です。
閉鎖依存関係は、ルールR1が実行される前に
ルールR2が可能なすべての出力を生成したことを保証します。
ルールの依存関係が閉鎖されていない場合、それは開放依存関係であり、
ルールR2がさらにトリプルを生成するために再実行される可能性がある間に、
第1のルールR1を実行できます。
その後、R2からの新しいトリプルによってR1が再評価される場合があります。
この最初の例では、第1のルールは 第2のルールに対して開放依存関係を持ちます。
この第2の例では、第1のルールは第2のルールに対して閉鎖依存関係を持ちます。
トリプルパターン?x :status :criticallyExposedは、
第1のルールの否定要素内に現れ、
第2のルールのヘッド内のトリプルテンプレートと一致します。
第1のルールは、第2のルールが可能なすべての出力を
生成するまで評価できません。
トリプルパターンは、 トリプルテンプレートが、そのトリプルパターンと 一致するトリプルを 生成できる場合、そのトリプルテンプレートと一致します。
トリプルパターンが トリプルテンプレートに依存する のは、トリプルパターンがトリプルテンプレートと一致する可能性がある場合である。
トリプルパターンが ルールに依存する のは、トリプルパターンが、ルールのトリプルテンプレートのいずれかに依存している 場合であり、それらのトリプルテンプレートはルールのヘッド内にある。
R1のボディ内のいずれかの
トリプルパターンが、
トリプルパターン要素として、または
否定要素の内部にあるかにかかわらず、
R2のヘッド内の
トリプルテンプレートに
依存する場合、
ルールR1はルールR2に
依存します。
ルールR1のルールR2に対する
ルールの依存関係は、その依存関係が
閉鎖依存関係でない場合、
開放依存関係です。
すなわち、R2に依存するR1の
トリプルパターンは、すべて
トリプルパターン要素としてのみ現れます。
トリプルテンプレートは、テンプレート内の変数を値で置き換えることで、
T2 が T1 と等しくなるようなトリプル T2 が得られる、
トリプルテンプレートの変数の値が存在する場合に、
RDFトリプル T1 を生成できる。
同様に、トリプルパターンは、パターン内の変数を値で置き換えることで、
T2 が T1 と等しくなるようなトリプル T2 が得られる、
トリプルパターンの変数の値が存在する場合に、トリプル T1 と
一致する。
トリプルパターンの場合、これには
対称トリプルが含まれる。
変数がトリプル テンプレート またはトリプルパターンで複数回使用されている場合、置換には同じRDF項 が使用される。
変数をRDF項で置き換える際には、 トリプル項内の変数も対象に含まれる。
ルール間の依存関係は、有向グラフとして表され、 依存関係グラフと呼ばれます。 グラフの頂点はルールセットのルールであり、辺には、 依存関係が開放依存関係であるか 閉鎖依存関係であるかに応じて、 openまたはclosedのラベルが付けられます。
R1がR2に依存する場合、ルールR1から
ルールR2への辺が存在します。
その依存関係が開放依存関係であるか
閉鎖依存関係であるかに応じて、
辺にはopenまたはclosedのラベルが付けられます。
R1からR2への経路が存在する場合、
ルールR1はルールR2に対して
推移的依存関係を持ちます。
依存関係グラフは、データグラフの影響を受けません。
次のアルゴリズムは、 ルールセットから 依存関係 グラフを構築するために使用できる 1つの方法を示します。適合性は、依存関係グラフの定義を 満たす依存関係グラフを生成することに依存し、 この手順を使用することには依存しません。
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
層別化は、 ルールセットを、 層別化レイヤー(「strata」、単数形は 「stratum」とも呼ばれます)の順序付きシーケンスに分割する処理です。より低い 層のルールは、 より高い層のルールより前に評価されます。
層別化は、 否定要素、 代入 要素、および ルールヘッド内で作成される空白ノードが、 より前の(低い)層および ベースグラフを使用して計算された結果のみに依存することを保証するため、 ルール間の依存関係に制約を課します。 これにより、指定されたベースグラフに対する ルールセットの評価から、 単一で明確に定義された有限の結果が得られることを保証します。
層別化処理は、他の評価上の判断を行うためにも 使用できます。この文書では、一貫した評価に必要な 条件を説明し、層別化を形成するために使用できる 1つの方法を示します。互換性のある動作を得るため、実装は ここで説明する条件を満たす必要がありますが、提示された アルゴリズムを実装する必要はありません。
層別化レイヤーSLは、
互いに素な2つのルール集合
(SL.once、SL.general)のペアです。
SL.onceには、
1回実行ルールが含まれます。これは、
代入要素を使用するか、
ルールヘッド内に空白ノードを
生成するルールです。これらのルールはそれぞれ、
層別化レイヤーの評価開始時に正確に1回
評価されます。
SL.generalには残りのルールが含まれ、それらは
新しいトリプルが推論されなくなるまで繰り返し評価されます。
層別化は、次の 条件が 満たされる場合にのみ定義されます。ルールセットがこの条件を満たさない場合、この 仕様では、そのようなルールセットの 評価結果を定義しません。
言い換えると、依存関係グラフの推移的依存関係の循環には、
NOTまたは1回実行ルール(代入、あるいは空白ノードを含むルールの
トリプルテンプレート)が
存在しません。
次のアルゴリズムは、ルールセットのみに基づく 層別化の1つの方法を示します。
## 出力 -- マップ:整数 -> ルールの集合。
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 具体 例に示します。
Webから文書を読み取ることには、セキュリティ上の影響があります。 ルールセットのインポートのサポートは、SRLプロセッサーでは任意です。 さらに、実装は、一部のルールセットのインポートのみをサポートし、 その他をサポートしないなど、部分的なサポートを提供してもよく、 検証済みのコピーからインポートする場合もあります。
インポート処理には、次の条件が適用されます:
IMPORTS文を含むルールセットを拒否し、エラーを通知しなければなりません。
IMPORTS文を処理する際の無限ループを回避するため、
必ずルールセットを1回だけインポートしなければなりません。
解決済みルールセットは、別のルールセットの インポートで言及されたすべてのルールセットを 再帰的に読み取ることによって、その別のルールセットから生成されます。
アルゴリズムの例については、A. インポートアルゴリズムの例を参照してください。
この節は非規範的です。
SRLとSPARQLには密接な関係があります。SRLはSPARQLと互換性を持つように設計されており、 SRLの構文要素の多くはSPARQLのパターン照合から取り入れられたか、 それに着想を得ています。ただし、いくつかの相違点があります。
SRLでは、RULE変数は、FILTERおよびSETの
式で使用される場合も、
ルールヘッドの
トリプルテンプレートで使用される場合も、
使用前に常にバインドされます。SPARQLのCONSTRUCTクエリおよび
INSERT更新では、変数がCONSTRUCTまたは
INSERTテンプレート内に現れても、WHERE節で値を与えられていない場合、
部分的な結果が生成されます。
SET形式とSPARQLのBIND形式では、エラーの
処理動作が異なります。SETでエラーが発生すると、
現在の解は除外されます。一方、BINDは
現在の解内の変数を設定せず、その解を後続に渡します。
SET(?var := expr)は、
SPARQLにおいて
BIND(expr AS ?var)の後に
FILTER(BOUND(?var))を続けることと同じです。
WHERE節の構文には、
UNIONまたはOPTIONAL構文は含まれません。
これらのSPARQL要素は、バインドされていない変数を生じさせる可能性があります。
UNIONまたはOPTIONALの効果は、
整形式ルールを使用することで実現でき、それにより
ルールセットを分析できます。
その他の相違点には、次のものがあります:
NOTの構文は、内部ボディをトリプルパターンおよび
フィルターに制限し、SPARQLのFILTER NOT EXISTSとは異なり、
ネストされたパターンを許可しません。
*および+は許可されません。
任意長のパスは、より一般的な手法として
再帰を使用してSRLで表現できます。
COALESCEもBOUNDもありません。ハッシュ関数もありません。
呼び出されるたびに異なる結果を返す
RANDもありません。
NOW()は許可されており、ルールセット評価全体を通じて同じ
時点を返すように定義されています。これは
SPARQLのNOW()と同じです。
この節では、指定されたデータに対してルールセットを評価した結果を定義します。 実装方法としてこのアルゴリズムを規定するものではありません。 実装は、同じ結果を生成する任意のアルゴリズムを使用できます。
Inputs: data graph G, called the base graph, and a rule set RS.
Output: an RDF graph GI of inferred triples
推論済みトリプルには、 ベースグラフのトリプル集合に存在するトリプルは含まれません。
μ : V → Tです。
ここで、Vはすべての変数の集合であり、
TはすべてのRDF
項の集合です。
μの定義域は
dom(μ)で表され、これは
μが定義されているVの部分集合です。
解マッピングを意味することが明らかな場合は、
解という用語を使用します。
dom(μ0)が空集合となる
解マッピングをμ0と表します。
subst(μ, トリプルパターン)
であり、トリプルパターンを返します。
返されるトリプルパターンでは、
dom(μ)内にある変数の
トリプルパターン内の各出現箇所が、
varに対する
解マッピングによって指定された
RDF項に置き換えられます。
結果のトリプルパターンに変数がない場合、それは
RDFトリプルです。
GをRDFグラフ、
TPをトリプルパターンとします。
関数graphMatch(G, TP)は、トリプルパターンに
適用すると、評価グラフ内にあるトリプルを生成する、
可能なすべての解の集合を返します。
S1およびS2を解とします。
compatible(μ1, μ2) = true
if forall v in dom(μ1) intersection dom(μ2)
μ1(v) = μ2(v)
compatible(μ1, μ2) = false otherwise
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)です。
2つの解に共通する変数がない場合、それらには互換性があり、
2つの解のマージはS1と
S2の和集合です。
EBV(x)は、
RDF項の実効ブール値を返します。
ルールセットの評価では、インポートされたすべてのルールセットを収集し、 4.5 インポートの 処理で説明されているように、単一の結合されたルールセットを構築する。
次に、以下の手順によって、結合されたルールセットを 評価用に準備する。
式は、フィルター要素または 代入要素のいずれで使用される場合でも、 式内の各変数に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
ルールは、ルール本体から 解 シーケンスを計算し、その後、解シーケンスの各 解マッピングを使用して、 ルールヘッドを使用してトリプルを生成することによって評価されます。
トリプルパターン内の空白ノードは、変数のように動作します。 これは、 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 には、データグラフにも含まれているトリプルが含まれる場合があります。
ルールセットの評価は、ルールセットの 階層化の各階層を実行することとして定義され、各階層は、 次の階層に進む前に、順番に完全に実行される。 階層は、まずその階層の各単回実行ルールを評価し、次に新しいトリプルが 生成されなくなるまで、その階層の一般ルールを繰り返し評価することによって評価される。
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
このセクションは非規範的です。
このセクションでは、完全な ルールセットの評価を順を追って説明する。すなわち、ルールの依存関係を決定し (4.3 ルールの 依存関係)、 階層化を計算し (4.4 階層化)、 各階層を順番に評価して 推論グラフを生成する (6.5 ルールセットの 評価)。
この例では、ソフトウェアコンポーネントとその依存関係について説明する。
フロントエンドはアプリケーションサーバーに依存し、そのアプリケーションサーバーは
データベースとロギングライブラリに依存する。データベースには既知の
脆弱性がある。ルールは、依存関係の連鎖に沿って脆弱性への
露出を伝播させ、深刻な脆弱性に露出しているコンポーネントに
:criticallyExposedというステータスを付与し、重大ではないコンポーネントに
:safeToDeployというステータスを付与し、重大な脆弱性に露出している
各コンポーネントに対する通知を作成する。
(実際には、脆弱性がコンポーネントに影響するかどうかは
配備されたバージョンに依存するが、この例ではバージョンを省略し、
脆弱性を直接記述している。)
簡潔にするため、基底グラフでは、より具体的な関係から導出するのではなく、
:dependsOnトリプルを直接記述している。これは、
3.1 基本パターンとは異なる。
ルールには、コメント内でR1からR5までのラベルが付けられており、
このセクションの残りの部分では、これらのラベルを使用して参照する。
これらは、
3.2 再帰から
3.5 代入
とRDF用語の作成までで導入されたルールである。
このルールセットにはIMPORTSがないため、インポート処理を行っても
変更されず、DATAブロックもないため、評価は
基底グラフのみから開始される。
各規則本体内の各トリプルパターンを、 すべての規則ヘッド内のトリプルテンプレートと比較して、どの規則が どの規則に依存するかを特定します (4.3 規則の 依存関係)。
R1 の本体は、単一のトリプルパターン
?x :hasVulnerability ?v です。述語 :hasVulnerability を持つ
トリプルを生成できるトリプルテンプレートを持つ規則ヘッドはないため、
このパターンはデータとのみ一致できます。
R1 には依存関係がありません。
R2 の本体には2つのトリプルパターンがあります。
?x :dependsOn ?y はどの規則ヘッドとも一致できないため、
データとのみ一致します。?y :exposedTo ?v は R1 のヘッドテンプレート
?x :exposedTo ?v と一致し、R2 自身のヘッドとも一致します。
どちらの出現箇所もトリプルパターン要素です
(これらは否定要素内には現れず、
R2 の
本体には代入要素がなく、ヘッドにも空白ノードが
ありません)。したがって、
R2 は R1 に対してオープン依存関係を持ち、
自身に対してもオープン依存関係を持ちます。
R2 の自身に対する依存関係により、R2 は再帰的な規則になります。
R3 の本体では、パターン ?x :exposedTo ?v が
R1 と R2 のヘッドに一致するため、R3 はそれぞれに対してオープン
依存関係を持ちます。パターン ?v :severity ?s はどの
規則ヘッドとも一致しません。
R4 の本体では、パターン ?x rdf:type :Component は
どの規則ヘッドとも一致しません。述語
rdf:type を持つ唯一のヘッドテンプレートは R5 にありますが、その目的語 :Notification は
:Component とは異なる RDF 用語であるため、生成された
トリプルが一致することはありません。
パターン ?x :status :criticallyExposed は、
否定要素
NOT { ?x :status :criticallyExposed } 内に現れ、
R3 のヘッドテンプレートと一致します。このパターンは
否定要素内に現れるため、R4 は R3 に対してクローズド
依存関係を持ちます。
R5 の本体では、パターン ?x :status :criticallyExposed が
R3 のヘッドと一致します。R5 のヘッドには
空白ノードが含まれるため、パターンが通常の
トリプルパターン要素であっても、R3
に対する依存関係はクローズド
依存関係になります。
どの規則本体内のパターンも R5 のヘッドテンプレートとは
一致しないため、R5 に依存する規則はありません。
したがって、依存関係グラフには5つの頂点と6つの 辺があります。
R2 → R1(オープン)
R2 → R2(オープン)
R3 → R1(オープン)
R3 → R2(オープン)
R4 → R3(クローズド)
R5 → R3(クローズド)
R4 と R5 は R1 または
R2 に直接依存していませんが、それぞれが R3 を介して、両方に対する推移的依存関係を持ちます。
グラフ内の唯一の循環は自己辺 R2 → R2 であり、
これはオープン依存関係です。クローズド
依存関係を含む循環はないため、階層化条件が
満たされ、
規則セットには明確に定義された結果があります。
階層化アルゴリズムに 従い、 すべての規則は階層 0 から開始します。その後、何も変化しなくなるまで 辺が繰り返し検査されます。
R4 → R3
(クローズド)では、R4 と R3 がどちらも階層 0 にあるため、R4 は
階層 1 に移動されます。同様に、辺 R5 → R3
(クローズド)により、R5 は階層 1 に移動されます。
さらに辺を1回走査しても変更はないため、階層は
確定します。次に、各階層は
一度だけ実行される規則と一般規則に分割されます。
R5 のヘッドには空白
ノードがあるため、これは一度だけ実行される規則です。ほかの規則には、
代入要素も、ヘッド内の空白ノードもありません。
階層化は次のとおりです。
R1、R2、R3。一度だけ実行される規則はなしR5。一般規則 R4
この順序付けは、上位
階層にある規則の意図を反映しています。コンポーネントを安全にデプロイできるかどうか、および
どのコンポーネントに通知が必要かは、
すべての :status :criticallyExposed トリプルが導出された後にのみ判断できます
— また、それらを導出する規則 R3 は、
その入力を生成する規則 R1 および R2 とともに、
下位の階層で完了します。
評価は、
6.5 規則
セットの評価のアルゴリズムに従います。
評価グラフ GE は基本グラフとして開始し、
推論グラフ GI は空の状態で開始します。各階層は順番に
完了まで評価されます。階層内の規則は
パス単位で評価され、パスが新しいトリプルを生成しなくなるまで繰り返されます。
このアルゴリズムは、1つのパス内で階層内の規則を
評価する順序を固定していません。この実行過程では、
R1、R2、R3 の順序を使用します。異なる順序では、同じ
推論が異なる回数のパスに分散される場合がありますが、
階層 0 は完了まで実行されるため、同じ最終グラフが生成されます。
この規則セットには DATA ブロックがないため、評価中のすべての時点で
GE は G0 と GI を合わせたものです。したがって、この実行過程では
GI のみを追跡し、評価の進行に伴う状態を示すとともに、
各新規トリプルに、それを生成した規則を記します。
階層 0、1回目のパス。
R1:本体が
:db :hasVulnerability :vuln1 と一致し、
?x = :db および ?v = :vuln1 が束縛されます。
ヘッドは :db :exposedTo :vuln1 を生成します。
このトリプルは GE にないため、GE と GI に追加されます。
R2:本体は ?x :dependsOn ?y と
?y :exposedTo ?v を結合します。GE には現在
:db :exposedTo :vuln1 が含まれるため、この結合から1つの解が得られます。
?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 の1回目のパス後の GI
:db :exposedTo :vuln1 . # 新規 (R1)
:app :exposedTo :vuln1 . # 新規 (R2)
:db :status :criticallyExposed . # 新規 (R3)
:app :status :criticallyExposed . # 新規 (R3)
新しいトリプルが生成されたため、階層 0 の評価は 次のパスに続きます。
階層 0、2回目のパス。
R1:前と同様に一致します。:db :exposedTo :vuln1 はすでに
GE にあるため、新しいものは生成されません。
R2:結合からさらに
?x = :frontend、?y = :app、および ?v = :vuln1 が得られ、
新しいトリプル :frontend :exposedTo :vuln1 が生成されます。
露出が依存関係チェーンに沿って2段階伝播するには、
2回のパスが必要でした。
R3:新しいトリプル
:frontend :status :criticallyExposed を生成します。
# 階層 0 の2回目のパス後の GI
:db :exposedTo :vuln1 .
:app :exposedTo :vuln1 .
:frontend :exposedTo :vuln1 . # 新規 (R2)
:db :status :criticallyExposed .
:app :status :criticallyExposed .
:frontend :status :criticallyExposed . # 新規 (R3)
階層 0、3回目のパス。
すべての規則のすべての解が、現在ではすでに
GE 内にあるトリプルのみを生成します。GI は変更されません。
新しいトリプルがないため、階層 0 は完了です。今後
導出可能なすべての :exposedTo トリプルおよび
:status :criticallyExposed トリプルが導出されました。
階層 1、一度だけ実行される規則。 階層内の一度だけ実行される規則が先に評価され、 それぞれが厳密に1回だけ実行されます。
R5:本体が3つの :status :criticallyExposed
トリプルと一致し、解 ?x = :db、?x = :app、および
?x = :frontend が得られます。各解についてヘッドをインスタンス化すると、
新しい空白ノードが作成され、解ごとに
2つのトリプル、すなわち各重大コンポーネントに対する
通知が生成されます。その後、階層内の一般規則が
繰り返し評価されますが、R5 が再び評価されることはありません。
階層 1、一般規則の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、一般規則の2回目のパス。
新しいトリプルはありません。評価は完了し、上に示した GI が
結果となる推論グラフです。
階層化によって、この結果の信頼性が確保されます。
階層 0 の1回目のパス中、まだ
:frontend :status :criticallyExposed が導出される前に評価されていた場合、R4 は
:frontend :status :safeToDeploy であると誤って結論付け、
R5 は :db と :app に対する通知を作成しても、
:frontend に対する通知は作成しなかったはずです。
両方を階層 1 まで遅延させることで、完全な
:status :criticallyExposed トリプルの集合を参照できるため、各階層内で
規則が評価される順序は
最終結果に影響しません。
SPARQL-RL文書とは、
UTF-8 [RFC3629]で符号化された
RDF文字列であり、
RuleSet
生成規則で始まり、
7.6 文法で定義される追加の制約に適合するものです。
U+0000からU+D7FFまで、および
U+E000からU+10FFFFまでの範囲にある
Unicodeスカラー値のみが
許可されます。これにより、U+D800から
U+DFFFまでの範囲にある
サロゲートコードポイントは除外されます。
バージョンラベルとは、SPARQL-RLの構文および意味論への 適合性を識別する文字列です。
| バージョンラベル |
|---|
| "1.2" |
バージョン宣言は文書の早い段階で行われるべきです。
1つのSPARQL-RL文書内に、
複数のVERSIONディレクティブが
現れる場合があります。
各ディレクティブは、そのディレクティブより後の文書部分に適用され、
別のディレクティブが現れるか、文書の末尾に達するまで有効です。
バージョンラベルは、
メディアタイプのversion
パラメーターによって指定することもできます。現在有効な
VERSIONディレクティブがない場合は、
メディアタイプの一部として指定されたバージョンが考慮されます。
空白
(生成規則WS)は、
それ以外では1つの終端記号として(誤)認識される2つの終端記号を
分離するために使用されます。以下に大文字で示されるルール名は、
空白が重要となる箇所を示します。これらは、SPARQL-RLパーサーを構築するための
終端記号として使用可能な選択肢を構成します。
生成規則
Stringでは、空白が重要です。
コメントは、
IRIREF、
STRING_LITERAL1、
STRING_LITERAL2、
STRING_LITERAL_LONG1、または
STRING_LITERAL_LONG2の外部にある
#で始まり、
行末(LFまたは
CRによって示されます)まで続きます。
コメントマーカーより後に行末がない場合は、
ファイルの末尾まで続きます。
コメントは空白として扱われます。
相対IRI参照は、 統一資源識別子(URI):汎用 構文 [RFC3986]の 第5.2節にある基本アルゴリズムのみを使用し、ベースIRIによって解決されます。 RFC3986の第6.2.2節および第6.2.3節で説明されている 構文ベースの正規化もスキームベースの正規化も実行されません。 IRI参照で追加的に許可される文字は、国際化資源識別子 (IRI) [RFC3987]の第6.5節に従い、 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を設定します。
SRL文書では、 3つの形式のエスケープを使用します:
数値エスケープシーケンスは、 Unicodeコードポイントの値を表します。
数値エスケープシーケンスは、次の範囲のコードポイント値を生成してはなりません:
U+D800からU+DFFFまで。
これはUnicode
サロゲートの範囲です。
| エスケープシーケンス | Unicodeコードポイント |
|---|---|
\u hex
hex
hex
hex
|
最上位桁から最下位桁の順に解釈される4桁の16進数によって
符号化された値に対応する、
U+0000からU+D7FFまで、および
U+E000からU+FFFFまでの範囲にある
Unicodeコードポイント。
|
\U hex
hex
hex
hex
hex
hex
hex
hex
|
最上位桁から最下位桁の順に解釈される8桁の16進数によって
符号化された値に対応する、
U+0000から
U+D7FFまで、および
U+E000からU+10FFFFまでの範囲にある
Unicodeコードポイント。
|
ここで、hexは16進文字です
HEX ::= [0-9] | [A-F] |
[a-f]
文字列エスケープシーケンスは、 文字列リテラルで従来エスケープされている文字を表します:
| エスケープシーケンス | Unicodeコードポイント |
|---|---|
\t |
U+0009 |
\b |
U+0008 |
\n |
U+000A |
\r |
U+000D |
\f |
U+000C |
\" |
U+0022 |
\' |
U+0027 |
\\ |
U+005C |
予約文字エスケープシーケンスは、
\の後に
文字~.-!$&'()*+,;=/?#@%_のいずれかが続くものであり、
\の
右側にある文字を表します。
| 数値 エスケープ |
文字列 エスケープ |
予約文字 エスケープ |
|
|---|---|---|---|
PREFIXまたは
BASE宣言で、
RDF項として使用される
IRI
|
はい | いいえ | いいえ |
| ローカル名 | いいえ | いいえ | はい |
| 文字列 | はい | はい | いいえ |
%-エンコードされたシーケンスは、
IRIの文字範囲に含まれ、
ローカル名で明示的に許可されています。
これらは、%の後に
2つの16進文字が続く形で現れ、
同じ3文字のシーケンスを表します。これらのシーケンスは処理中に
デコードされることはありません。
<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を指定します。
ここで使用するEBNFは、XML 1.0 [EBNF-NOTATION]で定義されています。
注記:
[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
|
[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 ')'
|
終端記号の生成規則:
[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 |
::= | '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?' | '#' | '@' | '%' )
|
この文法のテキスト版は こちらから入手できます。
この文書では、いくつかの特定の終端リテラル文字列を使用します [EBNF-NOTATION]。これらの 終端リテラル文字列で使用される Unicode コードポイントを明確にするため、 次の表では、このセクションで使用される特定の 文字について説明します。
| コード | グリフ | 説明 |
|---|---|---|
U+000A |
LF |
改行 |
U+000D |
CR |
復帰 |
U+0023 |
# |
番号記号 |
U+0025 |
% |
パーセント記号 |
U+005C |
\ |
バックスラッシュ |
以下のアルゴリズムは、参照されているすべての文書を再帰的に 訪問することによってインポート文を解決する方法の 1 つを示します。
2 つのルールセット RS1 と RS2 の ルールセット
マージとは、
次のように定義されるルールセット 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_merge は
RDF
マージ
操作です。
SPARQL-RLのインターネットメディアタイプ(以前はMIMEタイプと呼ばれていました)は、
「application/sparql-rl」です。
以下の情報は、審査、承認、およびIANAへの登録のため、 Internet Engineering Steering Group(IESG)に提出されています。
versionversionとして使用可能な値は、
バージョンラベルで定義されています。
profileprofileパラメーターの値は、空白で区切られたURIの空でないリストです。
詳細および背景については、[RFC6906]を参照してください。
この節は非規範的です。
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などの 形式に関する考慮事項が含まれます。
この節は非規範的です。
SPARQL-RL文書には、個人を特定できる情報(PII)または 機密性が高いと見なされるその他の情報の表現を含む可能性がある、 追加のアプリケーションデータを含めることができます。 このような情報を含むルールセットを公開する作成者は、 そのような情報を公開する必要性および用途に加え、 データが利用され、場合によっては開示されることが想定される地域に 適用される規制(たとえば、 GDPR、 CCPA、 その他)を慎重に検討し、 特にデータへのアクセスに認可措置が必要かどうかを考慮することが推奨されます。
この節は非規範的です。
次の人々が、Data ShapesワーキンググループのルールタスクフォースにおけるSPARQL-RLの 開発に貢献しました: Robert David、David Habgood、Livio Robaldo、Ognjen Savkovic、Simon Steyskal、Ted Thibodeau Jr、およびAndy Seaborne。
Data Shapesワーキンググループのメンバーには@@が含まれていました。
この仕様には課題が記載されていません。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: