1. Introduction (はじめに)
1.1. Overview (概要)
統一資源識別子 (Uniform Resource Identifier, URI) [RFC3986] は、類似したリソースの共通空間(非公式には「URI空間」)内で特定のリソースを識別するためによく使用されます。例えば、個人のウェブスペースは、次のような共通パターンを使用して委譲されることがよくあります:
http://example.com/~fred/
http://example.com/~mark/
または、辞書エントリのセットは、次のように用語の最初の文字で階層的にグループ化される場合があります:
http://example.com/dictionary/c/cat
http://example.com/dictionary/d/dog
または、サービスインターフェースは、次のような共通パターンでさまざまなユーザー入力によって呼び出される場合があります:
http://example.com/search?q=cat&lang=en
http://example.com/search?q=chien&lang=fr
URIテンプレート (URI Template) は、変数展開 (Variable Expansion) を通じて一連の統一資源識別子を記述するためのコンパクトな文字列です。
URIテンプレートは、可変部分を容易に識別および記述できるように、リソース識別子の空間を抽象化するメカニズムを提供します。URIテンプレートには、利用可能なサービスの発見、リソースマッピングの構成、計算されたリンクの定義、インターフェースの指定、その他の形式のリソースとのプログラマティックな相互作用など、多くの用途があります。例えば、上記のリソースは次のURIテンプレートで記述できます:
http://example.com/~{username}/
http://example.com/dictionary/{term:1}/{term}
http://example.com/search{?q,lang}
以下の用語を定義します:
expression (式): 第2節で定義されている、' と ' の間のテキストで、囲んでいる波括弧を含みます。
expansion (展開): 第3節で定義されているように、式の型、変数名のリスト、および値修飾子に従ってテンプレート式を処理した後に得られる文字列結果。
template processor (テンプレートプロセッサ): URIテンプレートと値を持つ変数のセットが与えられたとき、テンプレート内の式を解析し、各式を対応する展開で置き換えることによって、テンプレート文字列をURI参照 (URI Reference) に変換するプログラムまたはライブラリ。
URIテンプレートは、URI空間の構造的な記述と、変数値が提供されたときにそれらの値に対応するURIを構築する方法についての機械可読な命令の両方を提供します。URIテンプレートは、式の型と式内で指定された変数の値によって定義される値で各区切られた式を置き換えることによって、URI参照に変換されます。式の型は、単純な文字列展開から複数のname=valueリストまでの範囲に及びます。展開はURI一般構文に基づいており、実装は、生成される可能性のあるすべてのURIのスキーム固有の要件を知らなくても、任意のURIテンプレートを処理できます。
例えば、次のURIテンプレートには、変数名の前に表示される "?" 演算子で示されるフォーム形式パラメータ式 (Form-Style Parameter Expression) が含まれています:
http://www.example.com/foo{?query,number}
疑問符 ("?") 演算子で始まる式の展開プロセスは、World Wide Webのフォーム形式インターフェースと同じパターンに従います:
http://www.example.com/foo{?query,number}
\_____________/
|
|
[ 'query', 'number' ] 内の定義された各変数について、
最初の置換の場合は "?" を、その後は "&" を置換し、
続いて変数名、'='、および変数の値を配置します。
変数が次の値を持つ場合:
query := "mycelium"
number := 100
上記のURIテンプレートの展開は次のようになります:
http://www.example.com/foo?query=mycelium&number=100
または、'query' が未定義の場合、展開は次のようになります:
http://www.example.com/foo?number=100
または、両方の変数が未定義の場合、次のようになります:
http://www.example.com/foo
URIテンプレートは、上記の例のように絶対形式で提供することも、相対形式で提供することもできます。テンプレートは、結果の参照が相対形式から絶対形式に解決される前に展開されます。
結果にはURI構文が使用されますが、テンプレート文字列には、国際化資源識別子 (Internationalized Resource Identifier, IRI) 参照 [RFC3987] で見られる、より広範な文字セットを含めることができます。したがって、URIテンプレートはIRIテンプレートでもあり、テンプレート処理の結果は、[RFC3987] の第3.2節で定義されているプロセスに従ってIRIに変換できます。
1.2. Levels and Expression Types (レベルと式の型)
URIテンプレートは、固定されたマクロ定義のセットを持つマクロ言語に似ています:式の型 (Expression Type) が展開プロセスを決定します。デフォルトの式の型は単純文字列展開 (Simple String Expansion) であり、予約されていないURI文字 (Unreserved URI Characters) のセットに含まれない文字をパーセントエンコーディング (Percent-Encoding) した後、単一の名前付き変数がその文字列値で置き換えられます(第1.5節)。
本仕様以前に実装されたほとんどのテンプレートプロセッサは、デフォルトの式の型のみを実装しているため、これらをLevel 1テンプレートと呼びます。
.-----------------------------------------------------------------.
| Level 1 の例、変数値: |
| |
| var := "value" |
| hello := "Hello World!" |
| |
|-----------------------------------------------------------------|
| 演算子 式 展開結果 |
|-----------------------------------------------------------------|
| | 単純文字列展開 (第3.2.2節) |
| | |
| | {var} value |
| | {hello} Hello%20World%21 |
'-----------------------------------------------------------------'
Level 2テンプレートは、予約URI文字 (Reserved URI Characters) を含めることが許可される値の展開のためのプラス記号 ("+") 演算子(第1.5節)と、フラグメント識別子 (Fragment Identifiers) の展開のためのハッシュ記号 ("#") 演算子を追加します。
.-----------------------------------------------------------------.
| Level 2 の例、変数値: |
| |
| var := "value" |
| hello := "Hello World!" |
| path := "/foo/bar" |
| |
|-----------------------------------------------------------------|
| 演算子 式 展開結果 |
|-----------------------------------------------------------------|
| + | 予約文字列展開 (第3.2.3節) |
| | |
| | {+var} value |
| | {+hello} Hello%20World! |
| | {+path}/here /foo/bar/here |
| | here?ref={+path} here?ref=/foo/bar |
|-----+-----------------------------------------------------------|
| # | フラグメント展開、ハッシュプレフィックス (第3.2.4節) |
| | |
| | X{#var} X#value |
| | X{#hello} X#Hello%20World! |
'-----------------------------------------------------------------'
Level 3テンプレートは、1つの式に複数の変数を許可し、各変数はカンマで区切られます。また、ドットプレフィックスラベル (Dot-Prefixed Labels)、スラッシュプレフィックスパスセグメント (Slash-Prefixed Path Segments)、セミコロンプレフィックスパスパラメータ (Semicolon-Prefixed Path Parameters)、およびアンパサンド文字で区切られたname=valueペアで構成されるクエリ構文のフォーム形式構築 (Form-Style Construction) のための、より複雑な演算子を追加します。
.-----------------------------------------------------------------.
| Level 3 の例、変数値: |
| |
| var := "value" |
| hello := "Hello World!" |
| empty := "" |
| path := "/foo/bar" |
| x := "1024" |
| y := "768" |
| |
|-----------------------------------------------------------------|
| 演算子 式 展開結果 |
|-----------------------------------------------------------------|
| | 複数変数を持つ文字列展開 (第3.2.2節) |
| | |
| | map?{x,y} map?1024,768 |
| | {x,hello,y} 1024,Hello%20World%21,768 |
| | |
|-----+-----------------------------------------------------------|
| + | 複数変数を持つ予約文字展開 (第3.2.3節) |
| | |
| | {+x,hello,y} 1024,Hello%20World!,768 |
| | {+path,x}/here /foo/bar,1024/here |
| | |
|-----+-----------------------------------------------------------|
| # | 複数変数を持つフラグメント展開 (第3.2.4節) |
| | |
| | {#x,hello,y} #1024,Hello%20World!,768 |
| | {#path,x}/here #/foo/bar,1024/here |
| | |
|-----+-----------------------------------------------------------|
| . | ラベル展開、ドットプレフィックス (第3.2.5節) |
| | |
| | X{.var} X.value |
| | X{.x,y} X.1024.768 |
| | |
|-----+-----------------------------------------------------------|
| / | パスセグメント、スラッシュプレフィックス (第3.2.6節) |
| | |
| | {/var} /value |
| | {/var,x}/here /value/1024/here |
| | |
|-----+-----------------------------------------------------------|
| ; | パス形式パラメータ、セミコロンプレフィックス (第3.2.7節) |
| | |
| | {;x,y} ;x=1024;y=768 |
| | {;x,y,empty} ;x=1024;y=768;empty |
| | |
|-----+-----------------------------------------------------------|
| ? | フォーム形式クエリ、アンパサンド区切り (第3.2.8節) |
| | |
| | {?x,y} ?x=1024&y=768 |
| | {?x,y,empty} ?x=1024&y=768&empty= |
| | |
|-----+-----------------------------------------------------------|
| & | フォーム形式クエリ継続 (第3.2.9節) |
| | |
| | ?fixed=yes{&x} ?fixed=yes&x=1024 |
| | {&x,y,empty} &x=1024&y=768&empty= |
| | |
'-----------------------------------------------------------------'
最後に、Level 4テンプレートは、各変数名のオプションのサフィックスとして値修飾子 (Value Modifiers) を追加します。プレフィックス修飾子 (Prefix Modifier) (":") は、展開が値の先頭から限られた数の文字のみを使用することを示します(第2.4.1節)。展開修飾子 (Explode Modifier) ("*") は、変数が複合値 (Composite Value) として扱われ、名前のリストまたは (name, value) ペアの連想配列で構成され、各メンバーが個別の変数であるかのように展開されることを示します(第2.4.2節)。
.-----------------------------------------------------------------.
| Level 4 の例、変数値: |
| |
| var := "value" |
| hello := "Hello World!" |
| path := "/foo/bar" |
| list := ("red", "green", "blue") |
| keys := [("semi",";"),("dot","."),("comma",",")] |
| |
| 演算子 式 展開結果 |
|-----------------------------------------------------------------|
| | 値修飾子付き文字列展開 (第3.2.2節) |
| | |
| | {var:3} val |
| | {var:30} value |
| | {list} red,green,blue |
| | {list*} red,green,blue |
| | {keys} semi,%3B,dot,.,comma,%2C |
| | {keys*} semi=%3B,dot=.,comma=%2C |
| | |
|-----+-----------------------------------------------------------|
| + | 値修飾子付き予約文字展開 (第3.2.3節) |
| | |
| | {+path:6}/here /foo/b/here |
| | {+list} red,green,blue |
| | {+list*} red,green,blue |
| | {+keys} semi,;,dot,.,comma,, |
| | {+keys*} semi=;,dot=.,comma=, |
| | |
|-----+-----------------------------------------------------------|
| # | 値修飾子付きフラグメント展開 (第3.2.4節) |
| | |
| | {#path:6}/here #/foo/b/here |
| | {#list} #red,green,blue |
| | {#list*} #red,green,blue |
| | {#keys} #semi,;,dot,.,comma,, |
| | {#keys*} #semi=;,dot=.,comma=, |
| | |
|-----+-----------------------------------------------------------|
| . | ラベル展開、ドットプレフィックス (第3.2.5節) |
| | |
| | X{.var:3} X.val |
| | X{.list} X.red,green,blue |
| | X{.list*} X.red.green.blue |
| | X{.keys} X.semi,%3B,dot,.,comma,%2C |
| | X{.keys*} X.semi=%3B.dot=..comma=%2C |
| | |
|-----+-----------------------------------------------------------|
| / | パスセグメント、スラッシュプレフィックス (第3.2.6節) |
| | |
| | {/var:1,var} /v/value |
| | {/list} /red,green,blue |
| | {/list*} /red/green/blue |
| | {/list*,path:4} /red/green/blue/%2Ffoo |
| | {/keys} /semi,%3B,dot,.,comma,%2C |
| | {/keys*} /semi=%3B/dot=./comma=%2C |
| | |
|-----+-----------------------------------------------------------|
| ; | パス形式パラメータ、セミコロンプレフィックス (第3.2.7節) |
| | |
| | {;hello:5} ;hello=Hello |
| | {;list} ;list=red,green,blue |
| | {;list*} ;list=red;list=green;list=blue |
| | {;keys} ;keys=semi,%3B,dot,.,comma,%2C |
| | {;keys*} ;semi=%3B;dot=.;comma=%2C |
| | |
|-----+-----------------------------------------------------------|
| ? | フォーム形式クエリ、アンパサンド区切り (第3.2.8節) |
| | |
| | {?var:3} ?var=val |
| | {?list} ?list=red,green,blue |
| | {?list*} ?list=red&list=green&list=blue |
| | {?keys} ?keys=semi,%3B,dot,.,comma,%2C |
| | {?keys*} ?semi=%3B&dot=.&comma=%2C |
| | |
|-----+-----------------------------------------------------------|
| & | フォーム形式クエリ継続 (第3.2.9節) |
| | |
| | {&var:3} &var=val |
| | {&list} &list=red,green,blue |
| | {&list*} &list=red&list=green&list=blue |
| | {&keys} &keys=semi,%3B,dot,.,comma,%2C |
| | {&keys*} &semi=%3B&dot=.&comma=%2C |
| | |
'-----------------------------------------------------------------'
1.3. Design Considerations (設計上の考慮事項)
URIテンプレートに類似したメカニズムは、WSDL [WSDL]、WADL [WADL]、OpenSearch [OpenSearch] を含むいくつかの仕様内で定義されています。本仕様は、URIテンプレートを複数のインターネットアプリケーションおよびインターネットメッセージフィールドで一貫して使用できるように構文を拡張し、正式に定義すると同時に、これらの初期の定義との互換性を維持します。
URIテンプレート構文は、強力な展開メカニズムの必要性と実装の容易性の必要性との間で慎重にバランスを取るように設計されています。この構文は、多くの一般的なテンプレートシナリオを表現するのに十分な柔軟性を提供しながら、解析が簡単になるように設計されています。実装は、単一のパスでテンプレートを解析し、展開を実行できます。
一般的な例で使用される場合、テンプレートはシンプルで読みやすくなります。これは、単一文字の演算子がURI一般構文の区切り文字と一致するためです。リストされた変数のいずれも定義されていない場合、演算子に関連付けられた区切り文字("."、";"、"/"、"?"、"&"、"#")は省略されます。同様に、変数値が空の場合、";"(パス形式パラメータ)の展開プロセスは "=" を省略しますが、"?"(フォーム形式パラメータ)のプロセスは値が空の場合でも "=" を省略しません。演算子に事前定義された結合メカニズムがない場合、複数の変数とリスト値は "," でその値を結合します。"+" と "#" 演算子は、変数値内で見つかったエンコードされていない予約文字を置き換えます。他の演算子は、展開前に変数値内で見つかった予約文字をパーセントエンコードします。
URI空間の最も一般的なケースは、Level 1テンプレート式で記述できます。URI生成のみに関心がある場合、テンプレート構文は単純な変数展開のみに制限できます。これは、変数値を変更することでより複雑な形式を生成できるためです。しかし、URIテンプレートには、既存のデータ値の観点から識別子のレイアウトを記述するという追加の目標があります。したがって、テンプレート構文には、リソース識別子が一般的にどのように割り当てられるかを反映する演算子が含まれています。同様に、プレフィックス部分文字列は大規模なリソース空間を分割するためによく使用されるため、変数値の修飾子は、単一の変数名で部分文字列と完全な値文字列の両方を指定する方法を提供します。
1.4. Limitations (制限事項)
URIテンプレートは識別子のスーパーセット (Superset) を記述するため、区切られた各変数式の可能な展開のすべてが既存のリソースのURIに対応するわけではありません。テンプレートに従ってURIを構築するアプリケーションには、置換される変数に対する適切な値のセットが提供されるか、少なくともそれらの値のユーザーデータ入力を検証する手段が提供されることを期待しています。
URIテンプレートはURIではありません:それらは抽象的または物理的なリソースを識別せず、URIとして解析されず、テンプレート式が使用前にテンプレートプロセッサによって展開されない限り、URIが期待される場所で使用すべきではありません。URIテンプレートを持つプロトコル要素とURI参照を期待するプロトコル要素を区別するために、異なるフィールド、要素、または属性名を使用すべきです (should)。
一部のURIテンプレートは、変数マッチング (Variable Matching) の目的で逆向きに使用できます:テンプレートを完全に形成されたURIと比較して、そのURIから変数部分を抽出し、それらを名前付き変数に割り当てます。変数マッチングは、テンプレート式がURIの先頭または末尾、または展開の一部にできない文字(単純な文字列式を囲む予約文字など)で区切られている場合にのみ、うまく機能します。一般的に、正規表現言語は変数マッチングにより適しています。
1.5. Notational Conventions (表記規則)
この文書のキーワード "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"MAY"、および "OPTIONAL" は、[RFC2119] で説明されているように解釈されるものとします。
本仕様は、[RFC5234] の拡張バッカス・ナウア記法 (Augmented Backus-Naur Form, ABNF) 表記を使用します。以下のABNF規則は、規範的参照 [RFC5234]、[RFC3986]、および [RFC3987] からインポートされます。
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
DIGIT = %x30-39 ; 0-9
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
; 大文字小文字を区別しない
pct-encoded = "%" HEXDIG HEXDIG
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
/ %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
/ %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
/ %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
/ %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
/ %xD0000-DFFFD / %xE1000-EFFFD
iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD
1.6. Character Encoding and Unicode Normalization (文字エンコーディングとUnicode正規化)
本仕様は、"character (文字)"、"character encoding scheme (文字エンコーディングスキーム)"、"code point (コードポイント)"、"coded character set (符号化文字集合)"、"glyph (グリフ)"、"non-ASCII (非ASCII)"、"normalization (正規化)"、"protocol element (プロトコル要素)"、および "regular expression (正規表現)" という用語を、[RFC6365] で定義されているように使用します。
ABNF表記は、その終端値をUS-ASCII符号化文字集合 [ASCII] のスーパーセットである非負整数(コードポイント)として定義します。本仕様は、終端値をUnicode符号化文字集合 [UNIV6] 内のコードポイントとして定義します。
構文とテンプレート展開プロセスがUnicodeコードポイントの観点から定義されているにもかかわらず、テンプレートは実際には、それらが出現するコンテキストに適した形式やエンコーディングで、文字のシーケンスとして出現することを理解する必要があります。それがネットワークプロトコル要素に埋め込まれたオクテットであろうと、バスの側面に描かれたグリフであろうと。本仕様は、URIテンプレート文字とそれらの文字を格納または送信するために使用されるオクテットとの間のマッピングのための特定の文字エンコーディングスキームを義務付けません。URIテンプレートがプロトコル要素に出現する場合、文字エンコーディングスキームはそのプロトコルによって定義されます。そのような定義がない場合、URIテンプレートは周囲のテキストと同じ文字エンコーディングスキームであると想定されます。URIテンプレート内の文字列がUnicodeコードポイントのシーケンスとして処理されることが必須 (REQUIRED) となるのは、テンプレート展開プロセス中のみです。
Unicode標準 [UNIV6] は、さまざまな目的のために文字シーケンス間のさまざまな等価性を定義しています。Unicode標準附属書 #15 [UTR15] は、これらの等価性のためのさまざまな正規化形式 (Normalization Forms) を定義しています。正規化形式は、等価な文字列を一貫してエンコードする方法を決定します。理論的には、テンプレートプロセッサを含むすべてのURI処理実装は、URI参照を生成するために同じ正規化形式を使用すべきです (should)。実際には、そうではありません。値がリソースと同じサーバーによって提供されている場合、その文字列はすでにそのサーバーが期待する形式であると想定できます。値がユーザーによって提供される場合、たとえばデータ入力ダイアログを介して提供される場合、テンプレートプロセッサによる展開で使用される前に、その文字列は正規化形式C (NFC: Canonical Decomposition, followed by Canonical Composition、正規分解後に正規合成) として正規化されるべきです (SHOULD)。
同様に、読み取り可能な文字列を表す非ASCIIデータがURI参照で使用するためにパーセントエンコードされる場合、テンプレートプロセッサは最初に文字列をUTF-8 [RFC3629] としてエンコードし、次にURI参照で許可されていないオクテットをパーセントエンコードしなければなりません (MUST)。