RFC 9535 JSONPath 2024年2月
Gössner ほか 標準化過程 [ページ]
ストリーム:
Internet Engineering Task Force (IETF)
RFC:
9535
カテゴリ:
標準化過程
公開:
ISSN:
2070-1721
著者:
S. Gössner,
Fachhochschule Dortmund
G. Normington,
C. Bormann,
Universität Bremen TZI

RFC 9535

JSONPath: JSON用クエリ式

概要

JSONPath は、与えられた JSON 値の内部から JSON (RFC 8259) 値を選択し抽出するための文字列構文を定義します。

このメモの位置づけ

これはインターネット標準化過程の文書です。

この文書は Internet Engineering Task Force (IETF) の成果物です。これは IETF コミュニティの合意を表しています。公開レビューを受け、 Internet Engineering Steering Group (IESG) によって公開が承認されています。 インターネット標準に関する詳細情報は RFC 7841 の セクション 2 で入手できます。

この文書の現在の状態、正誤表、およびフィードバックの提供方法に関する情報は、 https://www.rfc-editor.org/info/rfc9535 で入手できます。

目次

1. 序論

JSON [RFC8259] は、構造化データ値の一般的な 表現 形式です。 JSONPath は、与えられた JSON 値の内部から JSON 値を選択し抽出するための文字列構文を定義します。

JSON Pointer [RFC6901] との関係では、JSONPath はその置き換えを意図したものではなく、より強力な 補完手段です。付録 Cを参照してください。

1.1. 用語

この文書におけるキーワード「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、「NOT RECOMMENDED」、 「MAY」、および「OPTIONAL」は、 ここに示すようにすべて大文字で現れる場合に限り、 BCP 14 [RFC2119] [RFC8174] に記述されているように解釈されます。

この文書の文法規則は、[RFC5234] に 記述されているように ABNF として解釈されます。 この文書の ABNF 終端値は、その UTF-8 エンコーディングではなく Unicode スカラー値を定義します。 たとえば、Unicode PLACE OF INTEREST SIGN (U+2318) は ABNF では %x2318 と定義されます。

関数は、fname() のように、関数名の後に一対の 括弧を付けて参照されます。

[RFC8259] の用語は、以下で明確化される場合を除き適用されます。 「primitive」と「structured」という用語は、[RFC8259]セクション 1と同様に、 値の種類を分類するために使用されます。JSON オブジェクトと配列は structured です。その他すべての値は primitive です。 「object」、「array」、「number」、および「string」の定義は 変更されません。 重要なこととして、とくに「object」と「array」は、 一般的なプログラミング文脈でそうであるような汎用的な意味を帯びません。

[RFC9485] の用語が適用されます。

この文書で使用される追加の用語を以下に定義します。

値:

[RFC8259] に従い、JSON の汎用データモデルに適合するデータ項目です。すなわち、 primitive データ(数値、テキスト文字列、および特別な 値 null、true、false)、または structured データ(JSON オブジェクトと配列)です。 [RFC8259] は JSON 値のテキスト表現に焦点を当てており、 ここで想定されている値の抽象化を完全には定義していません。

メンバー:

オブジェクト内の名前/値のペアです。(メンバー自体は 値ではありません。)

名前:

メンバーを構成する名前/値ペア内の名前(文字列)です。 これは [RFC8259] でも使用されていますが、 その仕様では 形式的には定義されていません。 完全性のためにここに含めています。

要素:

JSON 配列内の値です。

インデックス:

配列内の特定の要素を識別する整数です。

クエリ:

JSONPath 式の短い名称です。

クエリ引数:

JSONPath 式が適用される値の短い名称です。

位置:

クエリ引数内における値の位置です。これは、クエリ引数内の オブジェクトと配列を通ってその値まで移動する名前とインデックスの シーケンスと考えることができ、空のシーケンスは クエリ引数そのものを示します。 位置は正規化パス(以下で定義)として表現できます。

ノード:

値と、そのクエリ引数内での位置とのペアです。

ルートノード:

その値がクエリ引数全体である一意のノードです。

ルートノード識別子:

$ であり、クエリ引数のルートノードを参照します。

現在ノード識別子:

@ であり、フィルター式(後述)の評価の文脈における 現在ノードを参照します。

子(ノードの):

ノードが配列である場合は、その要素のノードです。ノードがオブジェクトである場合は、そのメンバー値のノードです。 ノードが配列でもオブジェクトでもない場合、子はありません。

子孫(ノードの):

そのノードの子、およびその子の子、というように 再帰的に含めたものです。より形式的には、ノード間の「子孫」関係は「子」関係の推移 閉包です。

深さ(値内の子孫ノードの):

値内におけるそのノードの祖先の数です。値のルート ノードの深さは 0、 ルートノードの子の深さは 1、その子の深さは 2、というように続きます。

ノードリスト:

ノードのリストです。 ノードリストは JSON で、たとえば配列として表現できますが、この文書は 特定の表現を要求または想定しません。

パラメーター:

関数式内で関数引数 (実引数)を受け取ることができる(関数の)仮パラメーターです。

正規化パス:

値内のノードを識別する JSONPath 式の形式であり、 ちょうどそのノードを結果とするクエリを提供します。 クエリ引数内の各ノードは、ちょうど 1 つの正規化パスによって識別されます(そのノードに対して 正規化パスが「一意」であると言います)。また、特定のクエリ引数に対する 正規化パスであるためには、正規化パスは ちょうど 1 つのノードを識別する必要があります。これは JSON Pointer [RFC6901] に似ていますが、構文的には異なります。 注: この定義は セクション 2.7 の構文上の定義に基づいています。 値内のノードを識別するものの、その 構文に適合しない JSONPath 式は正規化パスではありません。

Unicode スカラー値:

上位サロゲートおよび 下位サロゲートのコードポイントを除く、任意の Unicode [UNICODE] コードポイントです(言い換えると、16 進の包括範囲で 0 から D7FF、または E000 から 10FFFF の整数です)。JSONPath クエリは Unicode スカラー値のシーケンスです。

セグメント:

入力値の子 ([<selectors>]) または子孫 (..⁠[<selectors>]) を選択する構成要素の 1 つです。

セレクター:

セグメント内の単一項目であり、入力値を受け取って 入力値の子ノードからなるノードリストを生成します。

単一クエリ:

特定の方法で構文上制限された セグメントから構成される JSONPath 式であり(セクション 2.3.5.1)、入力 値にかかわらず、その式が最大 1 つのノードを含むノードリストを生成するものです。 注: 常に単一ノードリストを生成するが、セクション 2.3.5.1 の構文に 適合しない JSONPath 式は単一クエリではありません。

1.1.1. ノードのツリーとしての JSON 値

この文書は、クエリ引数を JSON 値のツリーとしてモデル化し、 それぞれが 独自のノードを持つものとします。 ノードは、ルートノードまたはその子孫のいずれかです。

この文書は、クエリを クエリ引数に適用した結果をノードリスト(ノードのリスト)としてモデル化します。

ノードは、クエリ引数のうち選択可能な部分です。 クエリによって選択できるオブジェクトの部分は メンバー値だけです。メンバー名およびメンバー(名前/値ペア)は 選択できません。 したがって、メンバー値にはノードがありますが、メンバーおよびメンバー名にはありません。 同様に、メンバー値はオブジェクトの子ですが、メンバーおよび メンバー名はそうではありません。

1.2. 沿革

この文書は、Stefan Gössner による 広く知られた JSONPath 提案(2007-02-21 付け)[JSONPath-orig] に基づき、その実装の広範な 展開から得られた経験を踏まえ、それに対する規範的な仕様を提供します。

付録 B は、 JSONPath が XML の XPath [XPath] からどのように着想を得たかを説明します。

JSONPath は、PHP や JavaScript などのプログラミング言語における JSON 実装の軽量な補完手段として意図されていました。 そのため、XPath が行ったように独自の式言語を定義する代わりに、 JSONPath はクエリの一部を基盤となる 実行時、たとえば JavaScript の eval() 関数に委譲しました。 より多くの環境で JSONPath が実装されるにつれ、JSONPath 式の移植性は低下していきました。 たとえば、正規表現処理はしばしば 便利な正規表現エンジンに委譲されました。

この文書は、そのような実装固有の依存関係を取り除き、 プログラミング言語や環境をまたいで使用できる共通の JSONPath 仕様として機能することを目的としています。 これは、後方互換性が 常に達成されるわけではないことを意味します。この文書の設計原則は、 使いやすく安定した JSON クエリ言語を得るという目的を損なわない限り、 たとえ粗いものであっても実装間の「合意」に従うことです。

JSONPath という用語は、XPath からの着想に加え、 クエリの結果が JSON クエリ引数内のノードを識別する パスで構成されることから選ばれました。

1.3. JSON 値

JSONPath クエリが適用される JSON 値は、定義上、 有効な JSON 値です。JSON 値は、多くの場合 JSON テキストを解析することで構築されます。

JSON テキストを JSON 値へ解析すること、および JSON テキストが有効な JSON を表さない場合に何が起こるかは、この文書では定義しません。 [RFC8259] のセクション 4 および 8 は、JSON テキストの文法に適合し得るものの、 相互運用可能な JSON の使用ではない特定の状況を 識別しています。これらは予測不能な動作を引き起こす可能性があります。 この文書は、そのような状況における JSONPath クエリの 予測可能な動作を定義しようとはしません。

具体的には、セクション 2.3.12.3.22.3.5、および 2.5.2 の「意味論」サブセクションでは、 検討対象のオブジェクトのいずれかに対する JSON 値が、 単一オブジェクトに対して同じメンバー名を共有する 複数のメンバーを示す JSON テキスト (「重複名」、[RFC8259]セクション 4を参照) から構築された場合に、予測不能になる動作を説明しています。 また、名前によって子を選択する場合(セクション 2.3.1)および文字列を比較する場合 (セクション 2.3.5.2.2)、 これらの文字列は Unicode スカラー値のシーケンスであると想定されます。そうでない場合、その動作は予測不能になります ([RFC8259]セクション 8.2)。

1.4. JSONPath 式の 概要

JSONPath 式は、クエリ引数として知られる JSON 値に適用されます。 出力はノードリストです。

JSONPath 式は、識別子の後に 0 個以上のセグメントが続くもので構成され、各セグメントには 1 つ以上のセレクターが含まれます。

1.4.1. 識別子

ルートノード識別子 $ は、 クエリ引数のルートノード、 すなわち引数全体を参照します。

現在ノード識別子 @ は、 フィルター式(セクション 2.3.5)の評価の文脈における 現在ノードを参照します。

1.4.2. セグメント

セグメントは、入力値の子 ([<selectors>]) または 子孫 (..⁠[<selectors>]) を選択します。

セグメントは、たとえば次のようにブラケット記法を使用できます。

$['store']['book'][0]['title']

または、たとえば次のように、より簡潔なドット記法を使用できます。

$.store.book[0].title

ブラケット記法には、任意の種類の 1 つ以上の (カンマ区切りの)セレクターが含まれます。 セレクターの詳細は次のセクションで説明します。

JSONPath 式は、ブラケット記法とドット 記法を組み合わせて使用できます。

この文書ではブラケット記法を正規のものとして扱い、 省略形のドット記法を ブラケット記法に基づいて定義します。例および説明では、都合に応じて省略形を使用します。

1.4.3. セレクター

名前セレクター、たとえば 'name' は、オブジェクトの名前付きの子を選択します。

インデックスセレクター、たとえば 3 は、 配列のインデックス付きの子を選択します。

[*] では、ワイルドカード *セクション 2.3.2)が ノードのすべての子を選択し、式 ..[*] では、 ノードのすべての子孫を選択します。

配列スライス start:end:stepセクション 2.3.4)は、配列から一連の 要素を選択し、開始位置、終了位置、および 開始から終了まで位置を移動する任意の step 値を与えます。

フィルター式 ?<logical-expr> は、次のように オブジェクトまたは配列の特定の子を選択します。

$.store.book[?@.price < 10].title

1.4.4. 要約

表 1 は、 JSONPath 構文の簡潔な概要を示します。

表 1: JSONPath 構文の概要
構文要素 説明
$ ルートノード 識別子セクション 2.2
@ 現在ノード 識別子セクション 2.3.5(フィルターセレクター内でのみ 有効)
[<selectors>] 子セグメントセクション 2.5.1: ノードの 0 個以上の子を選択する
.name ['name'] の省略形
.* [*] の省略形
..⁠[<selectors>] 子孫 セグメントセクション 2.5.2: ノードの 0 個以上の子孫を選択する
..name ..['name'] の省略形
..* ..[*] の省略形
'name' 名前セレクターセクション 2.3.1: オブジェクトの名前付きの子を選択する
* ワイルドカード セレクターセクション 2.3.2: ノードの すべての子を選択する
3 インデックスセレクターセクション 2.3.3: 配列のインデックス付きの子を選択する(0 から)
0:100:5 配列スライスセレクターセクション 2.3.4: 配列に対する start:end:step
?<logical-expr> フィルター セレクターセクション 2.3.5: 論理式を用いて 特定の子を選択する
length(@.foo) 関数拡張セクション 2.4: フィルター式内で関数を呼び出す

1.5. JSONPath の例

このセクションは参考情報です。JSONPath 式の例を提供します。

これらの例は、図 1 に示す単純な JSON 値に基づいています。 これは書店(自転車もあります)を表しています。

{ "store": {
    "book": [
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 399
    }
  }
}
図 1: JSON 値の例

表 2 は、 この例に適用できるいくつかの JSONPath クエリと、それらの意図される結果を示します。

表 2: JSONPath 式の例 およびそれらを例の JSON 値に適用した場合の意図される結果
JSONPath 意図される結果
$.store.book[*].author 書店内のすべての本の著者
$..author すべての著者
$.store.* 書店内のすべてのもの。いくつかの本と赤い自転車である
$.store..price 書店内のすべてのものの価格
$..book[2] 3 冊目の本
$..book[2].author 3 冊目の本の著者
$..book[2].publisher 空の結果: 3 冊目の本には "publisher" メンバーがない
$..book[-1] 順序上の最後の本
$..book[0,1]
$..book[:2]
最初の 2 冊の本
$..book[?@.isbn] ISBN 番号を持つすべての本
$..book[?@.price<10] 10 より安いすべての本
$..* 入力値に含まれるすべてのメンバー値および配列要素

2. JSONPath の構文と意味論

2.1. 概要

JSONPath は、JSON 値 (クエリ引数)に適用されたときに、その引数の 0 個以上のノードを選択し、 これらのノードをノードリストとして出力する文字列です。

クエリは UTF-8 を用いて符号化されなければなりません(MUST)。 この文書で与えられるクエリの文法は、その UTF-8 形式がまず [RFC3629] に記述されるように Unicode スカラー値へ復号されることを前提としています。同等の 結果をもたらす実装方法も可能です。

JSONPath クエリとして使用される文字列は、整形式かつ 妥当である必要があります。 文字列は、この文書の ABNF 構文に適合する場合、整形式の JSONPath クエリです。 整形式の JSONPath クエリは、この文書が課す両方の意味論的 要件も満たす場合に妥当です。その要件は次のとおりです。

  1. JSONPath 処理に関係する JSONPath クエリ内の整数 (たとえばインデックス値やステップ)は、Internet JSON (I-JSON) で定義される 正確な整数値の範囲内でなければなりません(MUST)(セクション 2.2 of [RFC7493] を参照)。すなわち、 区間 [-(253)+1, (253)-1] の範囲内です。
  2. 関数拡張の使用は、セクション 2.4.3 に記述されるように、 型整合していなければなりません(MUST)。

JSONPath 実装は、整形式かつ妥当でない任意のクエリに対して エラーを発生させなければなりません(MUST)。 JSONPath クエリの整形式性および妥当性は、 そのクエリが適用される JSON 値とは独立しています。 JSONPath クエリの整形式性および妥当性に関するさらなるエラーは、 値へクエリを適用している間に発生し得ません。 これにより、クエリ内の整形式性/妥当性エラーと、 実際にはデータの欠陥に由来し得る不一致とが明確に分離されます。

妥当なクエリが期待する構造と、 データ内で見つかった構造との不一致は、空のクエリ結果につながることがあり、 これは予期しないものであり、いずれかにバグがあることを示す可能性があります。 そのため JSONPath 実装は、空の 結果の原因を見つける助けとなる診断情報を、 アプリケーション開発者に提供したい場合があります。

明らかに、実装は JSONPath クエリの実行時に、たとえばリソース枯渇によって失敗することがあり得ますが、 この文書ではこれはモデル化されません。しかし、実装は 無言で誤動作してはなりません(MUST NOT)。 具体的には、妥当な JSONPath クエリが、 クエリを正しく処理するには大きすぎる構造化値に対して評価される場合 (たとえば、正確な値の範囲外にある数値の処理を必要とする場合)、 実装はオーバーフローの表示を提供しなければなりません(MUST)。

(HTTP エラーモデルに詳しい読者は、整形式性および妥当性について考えるときに 400 系のエラーを思い起こすかもしれません。また、 リソース枯渇および関連するエラーを 500 系のエラーに相当するものとして 認識するかもしれません。)

2.1.1. 構文

構文上、JSONPath クエリはルート識別子 ($)で構成されます。これは クエリ引数のルートノードを含むノードリストを表し、 その後に、空である可能性のあるセグメントのシーケンスが続きます。

jsonpath-query      = root-identifier segments
segments            = *(S segment)

B                   = %x20 /    ; Space
                      %x09 /    ; Horizontal tab
                      %x0A /    ; Line feed or New line
                      %x0D      ; Carriage return
S                   = *B        ; optional blank space

セグメントの構文と意味論は セクション 2.5 で定義されます。

2.1.2. 意味論

この文書では、JSONPath クエリの意味論は 必要な結果を定義し、実装の内部動作を規定しません。 この文書は意味論を手続き的な 段階的形式で記述することがあります。しかし、そのような記述が規範的であるのは、 任意の実装が同一の結果を生成しなければならない(MUST)という意味に限られ、 実装者が同じアルゴリズムを使用することを要求されるという意味ではありません。

意味論は、妥当なクエリが値 (クエリ引数)に対して実行され、ノードリスト (すなわち、その値の 0 個以上のノードのリスト)を生成する、というものです。

クエリは、ルート識別子の後に 0 個以上のセグメントのシーケンスが続くものです。 各セグメントは、直前のルート識別子またはセグメントの結果に適用され、 次のセグメントへの入力を提供します。 これらの結果および入力はノードリストの形式をとります。

ルート識別子から得られるノードリストは、 単一のノード (クエリ引数)を含みます。 最後のセグメントから得られるノードリストが クエリの結果として提示されます。特定の API に応じて、 それはノードにある JSON 値の配列として、 ノードを参照する正規化パスの配列として、またはその両方として、 あるいは実装が望むその他の表現として提示される場合があります。 注: 空のノードリストは妥当なクエリ結果です。

セグメントは、入力ノードリスト内の各ノードに順に作用し、 結果として得られるノードリストは、それらが由来する入力 ノードリストの順序で連結されて、 セグメントの結果を生成します。ノードは複数回選択される場合があり、 その回数だけノードリスト内に現れます。重複ノードは削除されません。

構文的に妥当なセグメントは、クエリ実行時に エラーを生成してはなりません(MUST NOT)。 これは、配列の範囲外にあるインデックスを使用するなど、 誤りと見なされ得る一部の操作が、 単に選択されるノードが少なくなる結果になることを意味します。 (この性質に関する追加の議論は、セクション 2.1 の導入部にあります。)

このアプローチの帰結として、いずれかのセグメントが 空のノードリストを生成する場合、クエリ全体が空の ノードリストを生成します。

クエリの意味論が、複数の可能な順序付けを生成する選択肢を 実装に与える場合、特定の実装は クエリの連続した実行で異なる順序付けを生成することがあります。

2.1.3.

この例を考えます。クエリ引数 {"a":[{"b":0},{"b":1},{"c":2}]} に対して、 クエリ $.a[*].b は、次のノードのリストを選択します (ここではそれらの値で示します): 0, 1

このクエリは、$ の後に 3 つのセグメント: .a, [*], および .b が続くものです。

まず、$ は クエリ引数だけからなるノードリストを生成します。

次に、.a は任意のオブジェクト入力ノードから選択し、 入力ノードのうちメンバー名 "a" に対応する 任意のメンバー値の ノードを選択します。 結果は再び、単一のノードを含むリストです: [{"b":0},{"b":1},{"c":2}]

次に、[*] は入力配列ノードから すべての要素を選択します。 結果は 3 つのノードのリストです: {"b":0}, {"b":1}, および {"c":2}

最後に、.b はメンバー名 b を持つ任意のオブジェクト入力ノードから選択し、 その名前に対応する入力ノードのメンバー値のノードを選択します。 結果は 0, 1 を含むリストです。 これは 3 つのリストの連結です。すなわち、それぞれ 0, 1 を含む長さ 1 の 2 つのリストと、長さ 0 の 1 つのリストです。

2.2. ルート識別子

2.2.1. 構文

すべての JSONPath クエリ(フィルター式内のものを除く。セクション 2.3.5 を参照)は、 ルート識別子 $ で始まらなければなりません(MUST)。

root-identifier     = "$"

2.2.2. 意味論

ルート識別子 $ は、 クエリ引数のルートノードを表し、 そのルートノードからなるノードリストを生成します。

2.2.3.

JSON:

{"k": "v"}

クエリ:

表 3: ルート識別子の 例
クエリ 結果 結果パス コメント
$ {"k": "v"} $ ルートノード

2.3. セレクター

セレクターは、子セグメントセクション 2.5.1および 子孫セグメントセクション 2.5.2の内部にのみ現れます。

セレクターは、入力値の 0 個以上の子からなるノードリストを生成します。

オブジェクトの子、配列の子、 またはオブジェクトか配列のどちらかの子を生成する、さまざまな種類のセレクターがあります。

selector            = name-selector /
                      wildcard-selector /
                      slice-selector /
                      index-selector /
                      filter-selector

各種セレクターの構文と意味論を以下に定義します。

2.3.1. 名前セレクター

2.3.1.1. 構文

名前セレクター '<name>' は、 最大 1 つのオブジェクトメンバー値を選択します。

JSON とは対照的に、 JSONPath 構文では文字列を単一引用符または 二重引用符で囲むことができます。

name-selector       = string-literal

string-literal      = %x22 *double-quoted %x22 /     ; "string"
                      %x27 *single-quoted %x27       ; 'string'

double-quoted       = unescaped /
                      %x27      /                    ; '
                      ESC %x22  /                    ; \"
                      ESC escapable

single-quoted       = unescaped /
                      %x22      /                    ; "
                      ESC %x27  /                    ; \'
                      ESC escapable

ESC                 = %x5C                           ; \ backslash

unescaped           = %x20-21 /                      ; see RFC 8259
                         ; omit 0x22 "
                      %x23-26 /
                         ; omit 0x27 '
                      %x28-5B /
                         ; omit 0x5C \
                      %x5D-D7FF /
                         ; skip surrogate code points
                      %xE000-10FFFF

escapable           = %x62 / ; b BS backspace U+0008
                      %x66 / ; f FF form feed U+000C
                      %x6E / ; n LF line feed U+000A
                      %x72 / ; r CR carriage return U+000D
                      %x74 / ; t HT horizontal tab U+0009
                      "/"  / ; / slash (solidus) U+002F
                      "\"  / ; \ backslash (reverse solidus) U+005C
                      (%x75 hexchar) ;  uXXXX U+XXXX

hexchar             = non-surrogate /
                      (high-surrogate "\" %x75 low-surrogate)
non-surrogate       = ((DIGIT / "A"/"B"/"C" / "E"/"F") 3HEXDIG) /
                      ("D" %x30-37 2HEXDIG )
high-surrogate      = "D" ("8"/"9"/"A"/"B") 2HEXDIG
low-surrogate       = "D" ("C"/"D"/"E"/"F") 2HEXDIG

HEXDIG              = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"

注:

  • Double-quoted 文字列は JSON 文字列構文([RFC8259]セクション 7)に従います。 single-quoted 文字列は類似したパターンに従います。 この構文を改良しようとはしていないため、 U+1F041 ("🁁", DOMINO TILE HORIZONTAL-02-02) のような 0xFFFF を超える スカラー値を持つ文字をエスケープしたい場合、 それらは一対のサロゲートエスケープ (この場合は "\uD83C\uDC41")で表す必要があります。
  • 引用符で囲まれた文字列内の英字は ABNF では大文字小文字を区別しないため、 \u エスケープ内の各 16 進数字 (hexchar が参照する規則で指定されるもの)は小文字でも大文字でもかまいません。 一方、\u 内の u は小文字である必要があります (%x75 として示されます)。
2.3.1.2. 意味論

name-selector 文字列は、周囲の引用符を取り除き、 各エスケープシーケンスを同等の Unicode 文字に置き換えることによって、 メンバー名 M に変換されなければなりません(MUST)。 これは 表 4 に示すとおりです。

表 4: エスケープ シーケンスの置換
エスケープシーケンス Unicode 文字 説明
\b U+0008 BS バックスペース
\t U+0009 HT 水平タブ
\n U+000A LF 行送り
\f U+000C FF フォームフィード
\r U+000D CR 復帰
\" U+0022 引用符
\' U+0027 アポストロフィ
\/ U+002F スラッシュ(ソリダス)
\\ U+005C バックスラッシュ(逆 ソリダス)
\uXXXX セクション 2.3.1.1 を参照 16 進エスケープ

name-selector をオブジェクトノードに適用すると、 名前がメンバー名 M と等しいメンバー値を選択します。 そのようなメンバー値がない場合は何も選択しません。 オブジェクトでない値からは何も選択されません。

注: 名前セレクターの処理では、メンバー名文字列 M と、 そのセレクターが適用される JSON 内のメンバー名文字列を比較する必要があります。 2 つの文字列は、それらが Unicode スカラー値の同一のシーケンスである場合に限り、 等しいと見なされなければなりません(MUST)。 言い換えると、比較の前に、JSONPath 由来のメンバー名文字列 M または JSON 内のメンバー名文字列のいずれに対しても、 正規化操作を適用してはなりません(MUST NOT)。

2.3.1.3.

JSON:

{
  "o": {"j j": {"k.k": 3}},
  "'": {"@": 2}
}

クエリ:

表 5 の例は、子セグメントによる名前セレクターの使用を示します。

表 5: 名前セレクターの 例
クエリ 結果 結果パス コメント
$.o['j j'] {"k.k": 3} $['o']['j j'] ネストされた
オブジェクト内の
名前付き
$.o['j j']⁠['k.k'] 3 $['o']['j j']⁠['k.k'] さらに下へ
ネスト
$.o["j j"]⁠["k.k"] 3 $['o']['j j']⁠['k.k'] クエリ内の
異なる
区切り文字、
変更されない
正規化
パス
$["'"]["@"] 2 $['\'']['@'] 通常でない
メンバー

2.3.2. ワイルドカードセレクター

2.3.2.1. 構文

ワイルドカードセレクターはアスタリスクで構成されます。

wildcard-selector   = "*"
2.3.2.2. 意味論

ワイルドカードセレクターは、オブジェクトまたは配列のすべての子のノードを選択します。 結果のノードリストにおいてオブジェクトの子が現れる順序は規定されません。 JSON オブジェクトは順序を持たないためです。 配列の子は、結果のノードリスト内で配列順に現れます。

オブジェクトの子はそのメンバー値であり、 メンバー名ではないことに注意してください。

ワイルドカードセレクターは、primitive な JSON 値 (すなわち、数値、文字列、truefalse、または null)からは何も選択しません。

2.3.2.3.

JSON:

{
  "o": {"j": 1, "k": 2},
  "a": [5, 3]
}

クエリ:

表 6 の例は、子セグメントによるワイルドカードセレクターの使用を示します。

表 6: ワイルドカード セレクターの例
クエリ 結果 結果パス コメント
$[*] {"j": 1, "k": 2}
[5, 3]
$['o']
$['a']
オブジェクト値
$.o[*] 1
2
$['o']['j']
$['o']['k']
オブジェクト値
$.o[*] 2
1
$['o']['k']
$['o']['j']
代替結果
$.o[*, *] 1
2
2
1
$['o']['j']
$['o']['k']
$['o']['k']
$['o']['j']
非決定的な 順序付け
$.a[*] 5
3
$['a'][0]
$['a'][1]
配列メンバー

上のクエリ $.o[*, *] の例は、 ワイルドカードセレクターが、2 つ以上のメンバーを持つオブジェクトノードに適用される場合、 子セグメント内に現れるたびに異なる順序のノードリストを生成し得ることを示しています (ただし、メンバーが 2 つ未満のオブジェクトノードまたは配列ノードに適用される場合はそうではありません)。

2.3.3. インデックスセレクター

2.3.3.1. 構文

インデックスセレクター <index> は、 最大 1 つの配列要素値に一致します。

index-selector      = int                        ; decimal integer

int                 = "0" /
                      (["-"] DIGIT1 *DIGIT)      ; - optional
DIGIT1              = %x31-39                    ; 1-9 non-zero digit

数値の index-selector を適用すると、 対応する要素が選択されます。 JSONPath ではこれを負にすることができます(セクション 2.3.3.2 を参照)。

妥当であるためには、インデックスセレクター値は I-JSON の正確な値の範囲内でなければなりません(MUST) (セクション 2.1 を参照)。

注:

  • index-selector は 整数(JSON 数値と同様、10 進)です。
  • JSON 数値と同様に、この構文では 01-01 のような先頭に 0 を持つ 8 進数風の整数は許されません。
2.3.3.2. 意味論

非負の index-selector を配列に適用すると、 0 ベースのインデックスを使用して配列要素を選択します。 たとえば、セレクター 0 は最初の要素を選択し、 セレクター 4 は十分な長さの配列の 5 番目の要素を選択します。 インデックスが配列の範囲外にある場合、何も選択されず、それはエラーではありません。 配列でない値からは何も選択されません。

負の index-selector は、 配列の末尾から逆向きに数えます。 負のインデックスに配列の長さを加えることで、同等の非負の index-selector が得られます。 たとえば、セレクター -1 は最後の要素を選択し、 セレクター -2 は少なくとも 2 つの要素を持つ配列の 最後から 2 番目の要素を選択します。 非負のインデックスの場合と同様に、そのような要素が存在しない場合でもエラーではありません。 これは単に、要素が選択されないことを意味します。

2.3.3.3.

JSON:

["a","b"]

クエリ:

表 7 の例は、子セグメントによるインデックスセレクターの使用を示します。

表 7: インデックスセレクターの 例
クエリ 結果 結果パス コメント
$[1] "b" $[1] 配列の要素
$[-2] "a" $[0] 配列の要素、 末尾から

2.3.4. 配列スライス セレクター

2.3.4.1. 構文

配列スライスセレクターは <start>:<end>:<step> の形式を持ちます。 これは、インデックス <start> から開始し、 <end> で終了する(ただし <end> は含まない)配列の要素に一致し、 既定値 1step だけ増分します。

slice-selector      = [start S] ":" S [end S] [":" [S step ]]

start               = int       ; included in selection
end                 = int       ; not included in selection
step                = int       ; default: 1

スライスセレクターは、コロンで区切られた 3 つの任意の 10 進整数で構成されます。 3 番目の整数が省略される場合、2 番目のコロンを省略できます。

妥当であるためには、与えられた整数は I-JSON の 正確な値の範囲内でなければなりません(MUST) (セクション 2.1 を参照)。

2.3.4.2. 意味論

スライスセレクターは、 リリースされなかった ECMAScript 4 (ES4) のために提案されたスライス演算子と、 Python のスライス演算子に着想を得ています。

2.3.4.2.1. 非形式的な導入

このセクションは参考情報です。

配列スライスは、ECMA-262 標準 [ECMA-262] によって定義される JavaScript 言語の Array.prototype.slice メソッドの動作に着想を得ています。 さらに、Python のスライス式に着想を得た step パラメーターが追加されています。

配列スライス式 start:end:step は、 start から始まるインデックスの要素を選択し、 step だけ増分しながら、 end で終了します (end 自体は除外されます)。 したがって、たとえば式 1:3(ここで step は既定で 1)は、 インデックス 12 の要素を(その順序で)選択します。 一方、 1:5:2 はインデックス 13 の要素を選択します。

step が負の場合、要素は 逆順に選択されます。したがって、 たとえば 5:1:-2 はインデックス 53 の要素を (その順序で)選択し、::-1 は配列のすべての要素を 逆順に選択します。

step0 の場合、 要素は選択されません。 (これは Python の動作と異なる唯一の場合であり、Python はこの場合にエラーを発生させます。)

次のセクションでは、JavaScript または Python の動作に依存せずに、 その動作を完全に規定します。

2.3.4.2.2. 規範的意味論

スライス式は、 step パラメーターの符号に応じて、 入力配列の要素の部分集合を、配列と同じ順序または逆順で選択します。 配列でないノードからはノードを選択しません。

スライスは、2 つのスライスパラメーター start および end と、 反復デルタ step によって定義されます。 これらの各パラメーターは 任意です。このセクションの残りでは、len は 入力配列の長さを表します。

step の既定値は 1 です。 start および end の既定値は、 step の符号に依存します。 これは 表 8 に示すとおりです。

表 8: 配列スライスの既定の start および end 値
条件 start end
step >= 0 0 len
step < 0 len - 1 -len - 1

スライス式のパラメーター start および end は、スライス境界として直接使用できず、 まず正規化する必要があります。 この目的での正規化は次のように定義されます。

FUNCTION Normalize(i, len):
  IF i >= 0 THEN
    RETURN i
  ELSE
    RETURN len + i
  END IF

長さ len の配列に適用される 配列インデックス式 i の結果は、 配列スライス式 Normalize(i, len):Normalize(i, len)+1:1 の結果です。

スライス式のパラメーター start および end は、スライス境界 lower および upper を導出するために使用されます。 step の符号によって定義される反復の方向が、 どちらのパラメーターが下限で、どちらが上限であるかを決定します。

FUNCTION Bounds(start, end, step, len):
  n_start = Normalize(start, len)
  n_end = Normalize(end, len)

  IF step >= 0 THEN
    lower = MIN(MAX(n_start, 0), len)
    upper = MIN(MAX(n_end, 0), len)
  ELSE
    upper = MIN(MAX(n_start, -1), len-1)
    lower = MIN(MAX(n_end, -1), len-1)
  END IF

  RETURN (lower, upper)

スライス式は、下限と 上限の間のインデックスを持つ要素を選択します。 次の擬似コードでは、a(i) は配列 ai+1 番目の要素です (すなわち、a(0) が最初の要素、a(1) が 2 番目、以下同様です)。

IF step > 0 THEN

  i = lower
  WHILE i < upper:
    SELECT a(i)
    i = i + step
  END WHILE

ELSE if step < 0 THEN

  i = upper
  WHILE lower < i:
    SELECT a(i)
    i = i + step
  END WHILE

END IF

step = 0 の場合、 要素は選択されず、結果配列は空です。

2.3.4.3.

JSON:

["a", "b", "c", "d", "e", "f", "g"]

クエリ:

表 9 の例は、子セグメントによる配列スライスセレクターの使用を示します。

表 9: 配列スライス セレクターの例
クエリ 結果 結果パス コメント
$[1:3] "b"
"c"
$[1]
$[2]
既定の step による スライス
$[5:] "f"
"g"
$[5]
$[6]
終了インデックスなしの スライス
$[1:5:2] "b"
"d"
$[1]
$[3]
step 2 によるスライス
$[5:1:-2] "f"
"d"
$[5]
$[3]
負の step によるスライス
$[::-1] "g"
"f"
"e"
"d"
"c"
"b"
"a"
$[6]
$[5]
$[4]
$[3]
$[2]
$[1]
$[0]
逆順のスライス

2.3.5. フィルターセレクター

フィルターセレクターは、構造化値、すなわち JSON 配列およびオブジェクトの 要素またはメンバーを反復処理するために使用されます。 構造化値は、フィルターセレクターを用いる 子セグメントまたは子孫セグメントによって提供されるノードリスト内で識別されます。

各反復(要素/メンバー)について、論理式 (フィルター式)が評価され、 要素/メンバーのノードが選択されるかどうかを決定します。 (論理式は数学的には Boolean 値に評価されますが、 この仕様では、JSON が表現できる Boolean 値との区別を保つために logical という用語を使用します。)

反復処理中、フィルター式は、 フィルター対象の構造化値に含まれる各配列要素またはオブジェクトメンバー値の ノードを受け取ります。この要素またはメンバー値は、その後 現在ノードとして知られます。

現在ノードは、フィルター式の部分式における 1 つ以上の JSONPath クエリの開始点として使用でき、 現在ノード識別子 @ によって表記されます。 各 JSONPath クエリは、クエリ結果の存在をテストするため、 比較で使用できるそのクエリ由来の特定の JSON 値を取得するため、 または関数引数として使用できます。

フィルターセレクターは関数拡張を使用できます。これについては セクション 2.4 で扱います。 フィルターセレクターの論理式内では、関数式を使用して ノードリストおよび値に作用できます。 利用可能な関数の集合は拡張可能であり、いくつかの 関数が事前定義されており(セクション 2.4 を参照)、 さらに関数を登録する機能は「Function Extensions」サブレジストリ (セクション 3.2)によって提供されます。 関数が定義されると、一意の名前が与えられ、その返り値および各パラメーターには 宣言型が与えられます。 型システムの範囲は限定されています。その目的は、 関数がなければフィルター式の文法に暗黙に含まれる制約を 表現することです。 型システムはまた、関数式が使用されない場合に文法内で さまざまな種類の式が扱われる方法を模倣する変換 (セクション 2.4.2)を導きます。

2.3.5.1. 構文

フィルターセレクターは ?<logical-expr> の形式を持ちます。

filter-selector     = "?" S logical-expr

フィルター式は副作用のない構成要素からなるため、 評価順序を定義する必要はなく、また定義されません。 同様に、連言(&&)および選言 (||)(後で定義)については、 短絡評価を行う実装と完全評価を行う実装のどちらも 同じ結果に至ります。そのため、どちらの実装戦略も妥当です。

現在ノードは、現在ノード識別子 @ によってアクセス可能です。 この識別子は、その識別子を直接囲んでいる filter-selector の 現在ノードを指します。注: ネストした filter-selector 内では、 直接囲んでいる filter-selector 以外の現在ノード (すなわち、その識別子を直接囲んでいる filter-selector を囲む filter-selector の現在ノード)を指す構文はありません。

論理式は通常の Boolean 演算子 (OR の ||、 AND の &&、NOT の !)を提供します。 それらは Boolean 代数の通常の意味論を持ち、その法則に従います (たとえば [BOOLEAN-LAWS] を参照)。 括弧は logical-expr 内でグループ化のために使用してもかまいません(MAY)。

logical-expr が 括弧で囲まれた式で構成されることは要求されません (これは [JSONPath-orig] では要求されていました)。 ただし、そうすることは可能であり、意味論は 括弧なしの場合と同じです。

logical-expr        = logical-or-expr
logical-or-expr     = logical-and-expr *(S "||" S logical-and-expr)
                        ; disjunction
                        ; binds less tightly than conjunction
logical-and-expr    = basic-expr *(S "&&" S basic-expr)
                        ; conjunction
                        ; binds more tightly than disjunction

basic-expr          = paren-expr /
                      comparison-expr /
                      test-expr

paren-expr          = [logical-not-op S] "(" S logical-expr S ")"
                                        ; parenthesized expression
logical-not-op      = "!"               ; logical NOT operator

テスト式は、 埋め込みクエリによって指定されるノードの存在をテストする (セクション 2.3.5.2.1 を参照)か、関数式の結果をテストします (セクション 2.4 を参照)。 後者の場合、関数の宣言結果型が LogicalTypeセクション 2.4.1 を参照)であれば、 結果が LogicalTrue であるかをテストします。 関数の宣言結果型が NodesType であれば、 結果が空でないかをテストします。 関数の宣言結果型が ValueType である場合、 テスト式でのその使用は型整合しません (セクション 2.4.3 を参照)。

test-expr           = [logical-not-op S]
                      (filter-query / ; existence/non-existence
                       function-expr) ; LogicalType or NodesType
filter-query        = rel-query / jsonpath-query
rel-query           = current-node-identifier segments
current-node-identifier = "@"

比較式は、primitive な値 (すなわち、数値、文字列、truefalse、および null)の間の比較に使用できます。 これらはリテラル値を介して取得できます。また、最大 1 つのノードを選択し、 その値が使用される単一クエリ、または ValueType 型の関数式 (セクション 2.4 を参照)によって取得できます。

comparison-expr     = comparable S comparison-op S comparable
literal             = number / string-literal /
                      true / false / null
comparable          = literal /
                      singular-query / ; singular query value
                      function-expr    ; ValueType
comparison-op       = "==" / "!=" /
                      "<=" / ">=" /
                      "<"  / ">"

singular-query      = rel-singular-query / abs-singular-query
rel-singular-query  = current-node-identifier singular-query-segments
abs-singular-query  = root-identifier singular-query-segments
singular-query-segments = *(S (name-segment / index-segment))
name-segment        = ("[" name-selector "]") /
                      ("." member-name-shorthand)
index-segment       = "[" index-selector "]"

リテラルは、JSON で通常の方法 (文字列が単一引用符区切りを使用できるという拡張を伴う)で表記できます。

注: 引用符で囲まれた文字列内の英字は ABNF では大文字小文字を区別しないため、浮動小数点数内では、 ABNF 式 "e" は文字 'e' または 'E' のどちらでもかまいません。

truefalse、および null は小文字のみです(大文字小文字を区別します)。

number              = (int / "-0") [ frac ] [ exp ] ; decimal number
frac                = "." 1*DIGIT                  ; decimal fraction
exp                 = "e" [ "-" / "+" ] 1*DIGIT    ; decimal exponent
true                = %x74.72.75.65                ; true
false               = %x66.61.6c.73.65             ; false
null                = %x6e.75.6c.6c                ; null

表 10 は、フィルター式演算子を、優先順位が高いもの (最も強く結合する)から低いもの(最も弱く結合する)までの順に列挙します。

表 10: フィルター 式演算子の優先順位
優先順位 演算子の種類 構文
5 グループ化
関数式
(...)
name(...)
4 論理 NOT !
3 関係 == !=
< <= > >=
2 論理 AND &&
1 論理 OR ||
2.3.5.2. 意味論

フィルターセレクターは配列とオブジェクトに対してのみ機能します。 その結果は、それぞれの配列要素またはメンバー値の (0 個1 個複数、またはすべての)リストです。 primitive 値に適用された場合、何も選択しません (したがって、フィルターセレクターの結果には寄与しません)。

結果のノードリストでは、配列の子は 配列内の位置によって順序付けられます。 オブジェクト(配列とは対照的)の子が結果のノードリスト内に現れる順序は規定されません。 JSON オブジェクトは順序を持たないためです。

2.3.5.2.1. 存在テスト

論理コンテキスト内のクエリそのものは、 クエリが少なくとも 1 つのノードを選択する場合に true を返し、 クエリがノードをまったく選択しない場合に false を返す存在テストです。

存在テストは比較と次の点で異なります。

  • 任意の相対クエリまたは絶対クエリ (単一クエリだけでなく)で機能します。
  • 構造化値を選択するクエリでも機能します。

クエリによって選択されたノードの値を調べるには、 明示的な比較が必要です。 たとえば、クエリ @.foo によって選択されたノードが null という値を持つかどうかをテストするには、 否定された存在テスト !@.foo ではなく @.foo == nullセクション 2.6 を参照)を使用します。 後者の存在テストは、@.foo がノードを選択する場合、そのノードの値に関係なく false を返します。 同様に、@.foo == false は、 @.foo がノードを選択し、 そのノードの値が false である場合にのみ true を返します。

2.3.5.2.2. 比較

比較演算子 == および < がまず定義され、次にこれらを用いて !=<=>、および >= が定義されます。

比較のいずれかの側が空のノードリストまたは 特別な結果 Nothingセクション 2.4.1 を参照)になる場合:

  • 演算子 == を使用する比較は、反対側も空のノードリストまたは 特別な結果 Nothing になる場合に限り true を返します。
  • 演算子 < を使用する比較は false を返します。

比較のいずれかの側にあるクエリまたは関数式が、 単一のノードからなるノードリストを結果とする場合、その側は そのノードの値に置き換えられ、その後:

  • 演算子 == を使用する比較は、比較対象が次の場合に限り true を返します。

    • [RFC7493] I-JSON のセクション 2.2に従って相互運用が期待される数値であり、 通常の数学的等価性を用いて等しいと比較されるもの。
    • 数値であり、 少なくとも一方が I-JSON に従って相互運用が期待されないもので、 実装固有の等価性を用いて等しいと比較されるもの。
    • 数値ではない、 等しい primitive 値。
    • 等しい配列。 すなわち、同じ長さの配列であり、最初の配列の各要素が 2 番目の配列の対応する要素と等しいもの、または
    • 重複名を持たない等しいオブジェクト。 すなわち、次の条件を満たすもの:

      • 両方のオブジェクトが同じ名前の集合(重複なし)を持ち、かつ
      • それらの各名前について、オブジェクトによってその名前に関連付けられた値が等しいこと。
  • 演算子 < を使用する比較は、比較対象が両方とも数値または両方とも 文字列であり、その比較を満たす場合に限り true を返します。

    • [RFC7493] I-JSON のセクション 2.2に従って相互運用が期待される数値は、 通常の数学的順序付けを用いて比較しなければなりません(MUST)。 I-JSON に従って相互運用が期待されない数値は、 実装固有の順序付けを用いて比較してもかまいません(MAY)。
    • 空文字列は、 任意の非空文字列より小さいと比較され、かつ
    • 非空文字列は、 最初の文字列が 2 番目の文字列より低い Unicode スカラー値で始まる場合、 または両方の文字列が同じ Unicode スカラー値で始まり、 最初の文字列の残りが 2 番目の文字列の残りより小さいと比較される場合に限り、 別の非空文字列より小さいと比較されます。

!=<=>、および >= は、 他の比較演算子に基づいて定義されます。任意の a および b について:

  • 比較 a != b は、a == b が false を返す場合に限り true を返します。
  • 比較 a <= b は、 a < b が true を返すか、a == b が true を返す場合に限り true を返します。
  • 比較 a > b は、 b < a が true を返す場合に限り true を返します。
  • 比較 a >= b は、 b < a が true を返すか、a == b が true を返す場合に限り true を返します。
2.3.5.3.

最初の例の集合は、いくつかの比較式と、 与えられた JSON 値を入力とした場合のそれらの結果を示します。

JSON:

{
  "obj": {"x": "y"},
  "arr": [2, 3]
}

比較:

表 11: 比較の 例
比較 結果 コメント
$.absent1 == $.absent2 true 空のノードリスト
$.absent1 <= $.absent2 true ==<= を含意する
$.absent == 'g' false 空のノードリスト
$.absent1 != $.absent2 false 空のノードリスト
$.absent != 'g' true 空のノードリスト
1 <= 2 true 数値比較
1 > 2 false 数値比較
13 == '13' false 型の不一致
'a' <= 'b' true 文字列比較
'a' > 'b' false 文字列比較
$.obj == $.arr false 型の不一致
$.obj != $.arr true 型の不一致
$.obj == $.obj true オブジェクト比較
$.obj != $.obj false オブジェクト比較
$.arr == $.arr true 配列比較
$.arr != $.arr false 配列比較
$.obj == 17 false 型の不一致
$.obj != 17 true 型の不一致
$.obj <= $.arr false オブジェクトと配列は < 比較を提供しない
$.obj < $.arr false オブジェクトと配列は < 比較を提供しない
$.obj <= $.obj true ==<= を含意する
$.arr <= $.arr true ==<= を含意する
1 <= $.arr false 配列は < 比較を提供しない
1 >= $.arr false 配列は < 比較を提供しない
1 > $.arr false 配列は < 比較を提供しない
1 < $.arr false 配列は < 比較を提供しない
true <= true true ==<= を含意する
true > true false Boolean は < 比較を提供しない

2 番目の例の集合は、フィルターセレクターを使用する いくつかの完全な JSONPath クエリと、 与えられた JSON 値を入力としてこれらのクエリを評価した結果を示します。 (注: クエリのうち 2 つは関数拡張を使用しています。これらの詳細については セクション 2.4.6 および 2.4.7 を参照してください。)

JSON:

{
  "a": [3, 5, 1, 2, 4, 6,
        {"b": "j"},
        {"b": "k"},
        {"b": {}},
        {"b": "kilo"}
       ],
  "o": {"p": 1, "q": 2, "r": 3, "s": 5, "t": {"u": 6}},
  "e": "f"
}

クエリ:

表 12 の例は、子セグメントによるフィルターセレクターの使用を示します。

表 12: フィルターセレクターの 例
クエリ 結果 結果パス コメント
$.a[?@.b == 'kilo'] {"b": "kilo"} $['a'][9] メンバー値 比較
$.a[?(@.b == 'kilo')] {"b": "kilo"} $['a'][9] 囲み括弧を持つ 同等のクエリ
$.a[?@>3.5] 5
4
6
$['a'][1]
$['a'][4]
$['a'][5]
配列値の比較
$.a[?@.b] {"b": "j"}
{"b": "k"}
{"b": {}}
{"b": "kilo"}
$['a'][6]
$['a'][7]
$['a'][8]
$['a'][9]
配列値の存在
$[?@.*] [3, 5, 1, 2, 4, 6, {"b": "j"}, {"b": "k"}, {"b": {}}, {"b": "kilo"}]
{"p": 1, "q": 2, "r": 3, "s": 5, "t": {"u": 6}}
$['a']
$['o']
非単一クエリの 存在
$[?@[?@.b]] [3, 5, 1, 2, 4, 6, {"b": "j"}, {"b": "k"}, {"b": {}}, {"b": "kilo"}] $['a'] ネストしたフィルター
$.o[?@<3, ?@<3] 1
2
2
1
$['o']['p']
$['o']['q']
$['o']['q']
$['o']['p']
非決定的な 順序付け
$.a[?@<2 || @.b == "k"] 1
{"b": "k"}
$['a'][2]
$['a'][7]
配列値の論理 OR
$.a[?match(@.b, "[jk]")] {"b": "j"}
{"b": "k"}
$['a'][6]
$['a'][7]
配列値の正規 表現一致
$.a[?search(@.b, "[jk]")] {"b": "j"}
{"b": "k"}
{"b": "kilo"}
$['a'][6]
$['a'][7]
$['a'][9]
配列値の正規 表現検索
$.o[?@>1 && @<4] 2
3
$['o']['q']
$['o']['r']
オブジェクト値の論理 AND
$.o[?@>1 && @<4] 3
2
$['o']['r']
$['o']['q']
代替結果
$.o[?@.u || @.x] {"u": 6} $['o']['t'] オブジェクト値の論理 OR
$.a[?@.b == $.x] 3
5
1
2
4
6
$['a'][0]
$['a'][1]
$['a'][2]
$['a'][3]
$['a'][4]
$['a'][5]
値を持たないクエリの 比較
$.a[?@ == @] 3
5
1
2
4
6
{"b": "j"}
{"b": "k"}
{"b": {}}
{"b": "kilo"}
$['a'][0]
$['a'][1]
$['a'][2]
$['a'][3]
$['a'][4]
$['a'][5]
$['a'][6]
$['a'][7]
$['a'][8]
$['a'][9]
primitive 値および 構造化値の比較

上のクエリ $.o[?@<3, ?@<3] の例は、フィルターセレクターが 子セグメント内に現れるたびに、異なる順序のノードリストを生成し得ることを示しています。

2.4. 関数拡張

前のサブセクションで定義されたフィルター式の機能を超えて、 JSONPath はフィルター式の機能を追加するために使用できる拡張点、 「関数拡張」を定義します。

このセクションでは、この拡張点と、この拡張点を使用するいくつかの 関数拡張を定義します。 これらの仕組みは拡張点を使用するように設計されていますが、 JSONPath 仕様の不可欠な一部であり、この仕様の他の不可欠な部分と同様に 実装されることが期待されます。

関数拡張は、登録名(セクション 3.2 を参照)を定義します。 これは 0 個以上の引数のシーケンスに適用でき、 結果を生成します。登録された各関数名は一意です。

関数拡張は、その評価に副作用がないように定義されなければなりません(MUST)。 すなわち、それを含む式に対して可能なすべての評価順序と、 短絡評価または完全評価の選択が、同じ結果に至らなければなりません(MUST)。 (注: メモ化またはロギングは、この意味での副作用ではありません。 それらは実装レベルでのみ可視であり、評価結果に影響しないためです。)

function-name       = function-name-first *function-name-char
function-name-first = LCALPHA
function-name-char  = function-name-first / "_" / DIGIT
LCALPHA             = %x61-7A  ; "a".."z"

function-expr       = function-name "(" S [function-argument
                         *(S "," S function-argument)] S ")"
function-argument   = literal /
                      filter-query / ; (includes singular-query)
                      logical-expr /
                      function-expr

クエリ内の任意の関数式は、 (上記の ABNF に適合することで)整形式であり、 かつ型整合していなければなりません。 そうでない場合、JSONPath 実装はエラーを発生させなければなりません(MUST) (セクション 2.1 を参照)。 どの関数式が型整合しているかを定義するために、 まず型システムを導入します。

2.4.1. 関数式のための 型システム

関数拡張の各パラメーターおよび結果は、 宣言型を持たなければなりません。

宣言型により、JSONPath クエリが適用される任意のクエリ引数とは独立して、 JSONPath クエリの型整合性を検査できます。

表 13 は、 利用可能な型を、それらが含むインスタンスの観点から定義します。

表 13: 関数拡張 型システム
インスタンス
ValueType JSON 値または Nothing
LogicalType LogicalTrue または LogicalFalse
NodesType ノードリスト

注:

  • JSONPath 構文で直接表現できる唯一のインスタンスは、 リテラルとして表現される ValueType 内の特定の JSON 値 (JSONPath では primitive 値に限定されます)です。
  • 特別な結果 Nothing は JSON 値の不在を表し、null を含む任意の JSON 値とは区別されます。
  • LogicalTrue および LogicalFalse は、 リテラル true および false によって表現される JSON 値とは無関係です。

2.4.2. 型変換

少なくとも 1 つのノードの存在をテストすることで、 クエリを論理式で使用できるのと同様に (セクション 2.3.5.2.1)、 宣言型 NodesType の関数式は、 宣言型 LogicalType のパラメーターに対する関数引数として使用できます。 このとき、同等の変換規則は次のとおりです。

  • ノードリストが 1 つ以上のノードを含む場合、 変換結果は LogicalTrue です。
  • ノードリストが空の場合、 変換結果は LogicalFalse です。

注:

  • ノードリストから値を抽出する方法はいくつかあるため、 NodesType から ValueType への暗黙の変換は 意外なものになり得ます。そのため、これは定義されていません。
  • 宣言型が NodesType の関数式は、 value()セクション 2.4.8 を参照)のような関数拡張の呼び出しで その式を包むことによって、宣言型 ValueType のパラメーターに対する 引数として間接的に使用できます。 この関数拡張は NodesType 型のパラメーターを受け取り、 ValueType 型の結果を返します。

関数式の型整合性は、これでこの型システムに基づいて定義できます。

2.4.3. 関数式の 型整合性

関数式が型整合しているためには、次の条件を満たします。

  1. その宣言型は、その式が現れる文脈において 型整合していなければなりません。

    文法に従うと、関数式は 3 つの異なる 直接の文脈に現れることができ、それぞれ次の型整合性条件につながります。

    論理式内の test-expr として:

    関数の宣言結果型は LogicalType、または (セクション 2.4.2 に従う変換を生じさせる) NodesType です。

    比較内の comparable として:

    関数の宣言結果型は ValueType です。

    別の関数式内の function-argument として:

    関数の宣言結果型は、 囲んでいる関数の対応するパラメーターについての次の規則を満たします。

  2. その引数は、対応するパラメーターの宣言型に対して 型整合していなければなりません。

    関数式の引数は、 関数の各引数が対応するパラメーターの宣言型に対して、 次の条件のいずれかに従って使用できる場合に型整合しています。

    • 引数が、パラメーターの宣言型と同じ宣言結果型を持つ 関数式である場合。
    • パラメーターの宣言型が LogicalType であり、引数が次のいずれかである場合。

      • 宣言結果型 NodesType を持つ関数式。 この場合、引数は セクション 2.4.2 に従って LogicalType に変換されます。
      • 関数式ではない logical-expr
    • パラメーターの宣言型が NodesType であり、引数がクエリ (単一クエリを含む)である場合。
    • パラメーターの宣言型が ValueType であり、引数が次のいずれかである場合。

      • リテラルとして表現された値。
      • 単一クエリ。この場合:

        • クエリが単一のノードからなるノードリストを結果とする場合、 引数はそのノードの値です。
        • クエリが空のノードリストを結果とする場合、 引数は特別な結果 Nothing です。

2.4.4. length() 関数拡張

パラメーター:
  1. ValueType
結果:

ValueType(符号なし整数または Nothing

length() 関数拡張は、 値の長さを計算し、それをフィルター式内でのさらなる処理に利用できるようにする方法を提供します。

$[?length(@.authors) >= 5]

その唯一の引数は ValueType のインスタンスです (上の例のように単一クエリから取得される可能性があります)。 結果も ValueType のインスタンスです。 すなわち、符号なし整数または特別な結果 Nothing です。

  • 引数値が文字列の場合、結果は その文字列内の Unicode スカラー値の数です。
  • 引数値が配列の場合、結果は 配列内の要素数です。
  • 引数値がオブジェクトの場合、結果は オブジェクト内のメンバー数です。
  • その他の任意の引数値については、結果は 特別な結果 Nothing です。

2.4.5. count() 関数拡張

パラメーター:
  1. NodesType
結果:

ValueType(符号なし整数)

count() 関数拡張は、 ノードリスト内のノード数を取得し、それをフィルター式内でのさらなる処理に 利用できるようにする方法を提供します。

$[?count(@.*.author) >= 5]

その唯一の引数はノードリストです。 結果は、ノードリスト内のノード数を示す値(符号なし整数)です。

注:

  • ノードリストの重複排除はありません。
  • ノードリスト内のノード数は、それらの値や それらが持ち得る子とは独立して数えられます。 たとえば、count(@) のような空でない単一ノードリストの count は常に 1 です。

2.4.6. match() 関数拡張

パラメーター:
  1. ValueType(文字列)
  2. ValueType[RFC9485] に適合する文字列)
結果:

LogicalType

match() 関数拡張は、 与えられた文字列が、[RFC9485] に記述された形式の 与えられた正規表現に(全体として。セクション 2.4.7 を参照) 一致するかどうかを確認する方法を提供します。

$[?match(@.date, "1974-05-..")]

その引数は ValueType のインスタンスです (上の例の最初の引数のように、単一クエリから取得される可能性があります)。 最初の引数が文字列でない場合、または 2 番目の引数が [RFC9485] に適合する文字列でない場合、 結果は LogicalFalse です。 それ以外の場合、最初の引数である文字列は、 2 番目の引数である文字列に含まれる I-Regexp と照合されます。 文字列が I-Regexp に一致する場合、結果は LogicalTrue であり、 そうでない場合は LogicalFalse です。

2.4.8. value() 関数拡張

パラメーター:
  1. NodesType
結果:

ValueType

value() 関数拡張は、 NodesType のインスタンスを値に変換し、 それをフィルター式内でのさらなる処理に利用できるようにする方法を提供します。

$[?value(@..color) == "red"]

その唯一の引数は NodesType のインスタンスです (上の例のように filter-query から取得される可能性があります)。 結果は ValueType のインスタンスです。

  • 引数が単一のノードを含む場合、 結果はそのノードの値です。
  • 引数が空のノードリストである場合、または 複数のノードを含む場合、結果は Nothing です。

注: 単一クエリは ValueType が期待される任意の場所で使用できるため、 単一クエリとともに value() 関数拡張を使用する必要はありません。

2.4.9.

表 14: 関数式の 例
クエリ コメント
$[?length(@) < 3] 型整合している
$[?length(@.*) < 3] @.* が非単一クエリであるため、 型整合していない
$[?count(@.*) == 1] 型整合している
$[?count(1) == 1] 1 はクエリでも関数式でもないため、 型整合していない
$[?count(foo(@.*)) == 1] 型整合している。 ここで foo() は、型 NodesType のパラメーターと結果型 NodesType を持つ関数拡張である
$[?match(@.timezone, 'Europe/.*')] 型整合している
$[?match(@.timezone, 'Europe/.*') == true] LogicalType は比較で使用できないため、 型整合していない
$[?value(@..color) == "red"] 型整合している
$[?value(@..color)] ValueType はテスト式で使用できないため、 型整合していない
$[?bar(@.a)] 任意の宣言型のパラメーターと 結果型 LogicalType を持つ任意の関数 bar() について型整合している
$[?bnl(@.*)] 宣言型 NodesType または LogicalType のパラメーターと 結果型 LogicalType を持つ任意の関数 bnl() について型整合している
$[?blt(1==1)] 型整合している。 ここで blt() は、宣言型 LogicalType のパラメーターと結果型 LogicalType を持つ関数である
$[?blt(1)] 同じ関数 blt() について型整合していない。 1 はクエリ、 logical-expr、または関数式ではないためである
$[?bal(1)] 型整合している。 ここで bal() は、宣言型 ValueType のパラメーターと結果型 LogicalType を持つ関数である

2.5. セグメント

入力ノードリスト内の各ノードについて、 セグメントは 1 つ以上のセレクターをそのノードに適用し、 各セレクターの結果を入力ノードごとのノードリストへ連結します。 それらはさらに入力ノードリストの順序で連結され、 単一のセグメント結果ノードリストを形成します。

クエリ内のセグメントが多いほど、結果ノードリストのノードは、 入力値内でより深い位置にあることになります。

  • N 個のセグメントを持つクエリ(N >= 0)は、 入力値内で深さ N 以上にあるノードからなるノードリストを生成します。
  • N 個のセグメントを持つクエリ(N >= 0)で、 それらすべてが子セグメントセクション 2.5.1である場合、 入力値内で正確に深さ N にあるノードからなるノードリストを生成します。

セグメントには、子セグメントと子孫セグメントの 2 種類があります。

segment             = child-segment / descendant-segment

各種類のセグメントの構文と意味論を以下に定義します。

2.5.1. 子セグメント

2.5.1.1. 構文

子セグメントは、角括弧で囲まれた、 空でないカンマ区切りのセレクター列で構成されます。

単一のワイルドカードセレクターまたは名前セレクターがある場合のために、 省略記法も提供されています。

child-segment       = bracketed-selection /
                      ("."
                       (wildcard-selector /
                        member-name-shorthand))

bracketed-selection = "[" S selector *(S "," S selector) S "]"

member-name-shorthand = name-first *name-char
name-first          = ALPHA /
                      "_"   /
                      %x80-D7FF /
                         ; skip surrogate code points
                      %xE000-10FFFF
name-char           = name-first / DIGIT

DIGIT               = %x30-39              ; 0-9
ALPHA               = %x41-5A / %x61-7A    ; A-Z / a-z

.* は、wildcard-selector から直接 構築された child-segment であり、 [*] の省略形です。

.<member-name> は、 member-name-shorthand から構築された child-segment であり、 ['<member-name>'] の省略形です。 注: これは、ABNF 規則 member-name-shorthand で指定される特定の 文字から構成されるメンバー名に対してのみ使用できます。 したがって、たとえば $.foo.bar$['foo']['bar'] の省略形です (ただし $['foo.bar'] の省略形ではありません)。

2.5.1.2. 意味論

子セグメントはセレクター列を含み、 それぞれが入力値の 0 個以上の子を選択します。

異なる種類のセレクターを、単一の子セグメント内で組み合わせることができます。

入力ノードリスト内の各ノードについて、 子セグメントの結果ノードリストは、その各セレクターからの ノードリストを、セレクターがリスト内に現れる順序で連結したものです。 注: 複数のセレクターによって一致した任意のノードは、 その回数だけノードリスト内に保持されます。

セレクターが複数の可能な順序でノードリストを生成できる場合、 子セグメント内のそのセレクターの各出現は、 異なる順序のノードリストを生成することがあります。

要約すると、子セグメントは入力値の構造を さらに 1 レベル掘り下げます。

2.5.1.3.

JSON:

["a", "b", "c", "d", "e", "f", "g"]

クエリ:

表 15: 子セグメントの 例
クエリ 結果 結果パス コメント
$[0, 3] "a"
"d"
$[0]
$[3]
インデックス
$[0:2, 5] "a"
"b"
"f"
$[0]
$[1]
$[5]
スライスとインデックス
$[0, 0] "a"
"a"
$[0]
$[0]
重複した項目

2.5.2. 子孫セグメント

2.5.2.1. 構文

子孫セグメントは、二重ドット .. の後に、(ブラケット記法を用いる)子セグメントが続くもので構成されます。

子セグメントの省略形に対応する省略記法も提供されています。

descendant-segment  = ".." (bracketed-selection /
                            wildcard-selector /
                            member-name-shorthand)

..* は、 wildcard-selector から直接構築された descendant-segment であり、..[*] の省略形です。

..<member-name> は、 member-name-shorthand から構築された descendant-segment であり、 ..⁠['<member-name>'] の省略形です。 注: child-segment の類似した省略形と同様に、これは ABNF 規則 member-name-shorthand で指定される特定の 文字から構成されるメンバー名に対してのみ使用できます。

注: .. 単独では妥当な セグメントではありません。

2.5.2.2. 意味論

子孫セグメントは、入力値の 0 個以上の子孫を生成します。

入力ノードリスト内の各ノードについて、 子孫セレクターは、入力ノードおよびその各子孫を次のように訪問します。

  • 任意の配列のノードは 配列順に訪問され、かつ
  • ノードはその子孫より前に 訪問されます。

オブジェクトの子が訪問される順序は規定されません。 JSON オブジェクトは順序を持たないためです。

子孫セグメントが ..⁠[<selectors>] の形式であるとします (任意の省略形をブラケット記法へ変換した後)。 また、訪問順のノードを D1, ..., Dn (ここで n >= 1)とします。 注: D1 は入力値です。

1 <= i <= n を満たす各 i について、 ノードリスト Ri は、 子セグメント [<selectors>] をノード Di に適用した結果として定義されます。

入力ノードリスト内の各ノードについて、 子孫セグメントの結果は R1, ..., Rn の (その順序での)連結です。 これらの結果はさらに入力ノードリストの順序で連結され、 セグメントの結果を形成します。

要約すると、子孫セグメントは各入力値の構造を 1 レベル以上掘り下げます。

2.5.2.3.

JSON:

{
  "o": {"j": 1, "k": 2},
  "a": [5, 3, [{"j": 4}, {"k": 6}]]
}

クエリ:

(4 番目の例は 2 つの同等のクエリで表現できることに注意してください。 それらは、表 16 でほぼ同一の 2 行ではなく、 1 つの表行に示されています。)

表 16: 子孫 セグメントの例
クエリ 結果 結果パス コメント
$..j 1
4
$['o']['j']
$['a'][2][0]['j']
オブジェクト値
$..j 4
1
$['a'][2][0]['j']
$['o']['j']
代替結果
$..[0] 5
{"j": 4}
$['a'][0]
$['a'][2][0]
配列値
$..[*]
または
$..*
{"j": 1, "k": 2}
[5, 3, [{"j": 4}, {"k": 6}]]
1
2
5
3
[{"j": 4}, {"k": 6}]
{"j": 4}
{"k": 6}
4
6
$['o']
$['a']
$['o']['j']
$['o']['k']
$['a'][0]
$['a'][1]
$['a'][2]
$['a'][2][0]
$['a'][2][1]
$['a'][2][0]['j']
$['a'][2][1]['k']
すべての値
$..o {"j": 1, "k": 2} $['o'] 入力値が訪問される
$.o..[*, *] 1
2
2
1
$['o']['j']
$['o']['k']
$['o']['k']
$['o']['j']
非決定的な 順序付け
$.a..[0, 1] 5
3
{"j": 4}
{"k": 6}
$['a'][0]
$['a'][1]
$['a'][2][0]
$['a'][2][1]
複数のセグメント

注: 上の $..[*] および $..* の例における結果の順序は、 次の場合を除いて保証されません。

  • {"j": 1, "k": 2}1 および 2 より前に現れなければなりません。
  • [5, 3, [{"j": 4}, {"k": 6}]]53、および [{"j": 4}, {"k": 6}] より前に現れなければなりません。
  • 53 より前に現れなければならず、 3[{"j": 4}, {"k": 6}] より前に現れなければなりません。
  • 5 および 3{"j": 4}4{"k": 6}、および 6 より前に現れなければなりません。
  • [{"j": 4}, {"k": 6}]{"j": 4} および {"k": 6} より前に現れなければなりません。
  • {"j": 4}{"k": 6} より前に現れなければなりません。
  • {"k": 6}4 より前に現れなければならず、かつ
  • 46 より前に現れなければなりません。

上のクエリ $.o..[*, *] の例は、 セレクターが子孫セグメント内に現れるたびに、 異なる順序のノードリストを生成し得ることを示しています。

上のクエリ $.a..[0, 1] の例は、 子セグメント [0, 1] が各ノードに順に適用されることを示しています。 (これは、この仕様に適合しない一部の JSONPath 実装で見られるように、 セレクターごとにノードが 1 回ずつ訪問されるのではありません。)

2.6. null の意味論

注: JSON の null は、他の任意の JSON 値と同じように扱われます。 すなわち、「undefined」または「missing」を意味するものとは見なされません。

2.6.1.

JSON:

{"a": null, "b": [null], "c": [{}], "null": 1}

クエリ:

表 17: null を含む (または含まない)例
クエリ 結果 結果パス コメント
$.a null $['a'] オブジェクト値
$.a[0] 配列として使用された null
$.a.d オブジェクトとして使用された null
$.b[0] null $['b'][0] 配列値
$.b[*] null $['b'][0] 配列値
$.b[?@] null $['b'][0] 存在
$.b[?@==null] null $['b'][0] 比較
$.c[?@.d==null] 「missing」 値との比較
$.null 1 $['null'] JSON の null では まったくなく、単なるメンバー名文字列

2.7. 正規化パス

正規化パスは、値内のノードの位置を一意に表す表現であり、 その値内のノードを一意に識別します。 具体的には、正規化パスは制限された構文(以下で定義)を持つ JSONPath クエリであり、 たとえば $['book'][3] のようなものです。これを値に適用すると、 正規化パスによって識別されるノードだけからなるノードリストが結果となります。 注: 正規化パスは、特定の値内におけるノードの同一性を表します。 値内の任意の特定のノードを識別する正規化パスは、ちょうど 1 つだけ存在します。

ノードリストは、文字列の配列として JSON でコンパクトに表現できます。 ここで各文字列は正規化パスです。

正規化パスは、ノードリストのテストおよび後処理 (たとえば重複ノードの削除)を簡単にする予測可能な形式を提供します。 正規化パスは、この文書の例では結果パスとして使用されます。

正規化パスは、ドット記法ではなく、正準的なブラケット記法を使用します。

正規化パスでは、文字列のメンバー名を区切るために単一引用符が使用されます。 これにより、正規化パスが二重引用符で区切られた文字列 (たとえば JSON テキスト)内に現れるときに、エスケープが必要な文字数が減ります。

正規化パスでは、特定の文字はただ 1 つの方法でのみエスケープされます。 その他すべての文字はエスケープされません。

normalized-path      = root-identifier *(normal-index-segment)
normal-index-segment = "[" normal-selector "]"
normal-selector      = normal-name-selector / normal-index-selector
normal-name-selector = %x27 *normal-single-quoted %x27 ; 'string'
normal-single-quoted = normal-unescaped /
                       ESC normal-escapable
normal-unescaped     =    ; omit %x0-1F control codes
                       %x20-26 /
                          ; omit 0x27 '
                       %x28-5B /
                          ; omit 0x5C \
                       %x5D-D7FF /
                          ; skip surrogate code points
                       %xE000-10FFFF

normal-escapable     = %x62 / ; b BS backspace U+0008
                       %x66 / ; f FF form feed U+000C
                       %x6E / ; n LF line feed U+000A
                       %x72 / ; r CR carriage return U+000D
                       %x74 / ; t HT horizontal tab U+0009
                       "'" /  ; ' apostrophe U+0027
                       "\" /  ; \ backslash (reverse solidus) U+005C
                       (%x75 normal-hexchar)
                                       ; certain values u00xx U+00XX
normal-hexchar       = "0" "0"
                       (
                          ("0" %x30-37) / ; "00"-"07"
                             ; omit U+0008-U+000A BS HT LF
                          ("0" %x62) /    ; "0b"
                             ; omit U+000C-U+000D FF CR
                          ("0" %x65-66) / ; "0e"-"0f"
                          ("1" normal-HEXDIG)
                       )
normal-HEXDIG        = DIGIT / %x61-66    ; "0"-"9", "a"-"f"
normal-index-selector = "0" / (DIGIT1 *DIGIT)
                        ; non-negative decimal integer

与えられたノードを識別する正規化パスは 1 つしか存在できないため、 構文はどの文字をエスケープし、どの文字をエスケープしないかを規定します。 そのため、normal-hexchar の定義は、 直接印字可能ではない文字、たとえば U+000B LINE TABULATION のように、 \n などの標準 JSON エスケープが利用できない文字を 16 進エスケープするために設計されています。

2.7.1.

表 18: 正規化パスの 例
パス 正規化パス コメント
$.a $['a'] オブジェクト値
$[1] $[1] 配列インデックス
$[-3] $[2] 長さ 5 の配列に対する 負の配列インデックス
$.a.b[1:2] $['a']['b'][1] ネストした構造
$["\u000B"] $['\u000b'] Unicode エスケープ
$["\u0061"] $['a'] Unicode 文字

3. IANA に関する考慮事項

3.1. メディア型 application/jsonpath の登録

IANA は次のメディア型 [RFC6838] を登録しました。

型名:

application

サブタイプ名:

jsonpath

必須パラメーター:

N/A

任意パラメーター:

N/A

符号化に関する考慮事項:

binary (UTF-8)

セキュリティに関する考慮事項:

RFC 9535 の「セキュリティに関する考慮事項」セクションを参照してください。

相互運用性に関する考慮事項:

N/A

公開仕様:

RFC 9535

このメディア型を使用するアプリケーション:

JSON データ内でクエリを伝達する必要があるアプリケーション

フラグメント識別子に関する考慮事項:

N/A

追加情報:


この型の非推奨エイリアス名:

N/A

マジックナンバー:

N/A

ファイル拡張子:

N/A

Macintosh ファイル型コード:

N/A

詳細情報の問い合わせ先となる人物およびメールアドレス:
iesg@ietf.org
意図される用途:

COMMON

使用上の制限:

N/A

著者:

JSONPath WG

変更管理者:

IETF

3.2. 関数拡張 サブレジストリ

この仕様に従い、IANA は新しい「JSONPath」レジストリ内に 新しい「Function Extensions」サブレジストリを作成しました。 「Function Extensions」サブレジストリのポリシーは「Expert Review」 ([RFC8126] のセクション 4.5 )です。

専門家には、一般に適用可能な意味論を示唆する関数拡張名の割り当てを 控えめに行い、広く使用される可能性が高く、 その簡潔さを十分に活用できる関数のためにそれらを温存するよう指示されています。 専門家にはまた、登録者に仕様 ([RFC8126] のセクション 4.6)を提供するよう促すことも指示されていますが、 例外を設けることもできます。たとえば、登録時点では仕様が利用できないものの、 近く提供される可能性が高い場合です。 専門家が、展開され使用されている関数拡張を認識した場合、 そのような登録が将来起こり得る衝突を回避できると判断するなら、 自ら登録を開始してもかまいません。

サブレジストリ内の各エントリーは、次を含まなければなりません。

関数名:

文字で始まり、その後に文字、数字、およびアンダースコア文字を含むことができる 小文字 ASCII [RFC0020] 文字列 ([a-z][_a-z0-9]*)。サブレジストリ内の他のエントリーは、 同じ関数名を持つことはできません。

簡潔な説明:

簡潔な説明

パラメーター:

この関数拡張で期待される各引数について 1 つずつ、 0 個以上の宣言型をカンマ区切りで並べたリスト

結果:

この関数拡張の結果の宣言型

変更管理者:

[RFC8126] のセクション 2.3を参照してください。

参照:

関数拡張の説明を提供する参照文書

このサブレジストリの初期エントリーは 表 19 に列挙されています。 「Change Controller」列のエントリーはすべて値「IETF」を持ち、 「Reference」列のエントリーはすべて値「RFC 9535 のセクション 2.4」を持ちます。

表 19: 関数拡張サブレジストリの 初期エントリー
関数名 簡潔な説明 パラメーター 結果
length 文字列、配列、またはオブジェクトの長さ ValueType ValueType
count ノードリストのサイズ NodesType ValueType
match 正規表現による完全一致 ValueType, ValueType LogicalType
search 正規表現による部分文字列一致 ValueType, ValueType LogicalType
value ノードリスト内の単一ノードの値 NodesType ValueType

4. セキュリティに関する考慮事項

JSONPath のセキュリティに関する考慮事項は、次に由来し得ます。

4.1. JSONPath 実装に対する 攻撃ベクトル

歴史的に、JSONPath はしばしば、クエリの一部を 基盤となるプログラミング言語エンジン、たとえば JavaScript の eval() 関数に渡すことで実装されてきました。 このアプローチはインジェクション攻撃につながることがよく知られており、 これらの攻撃を防ぐには完全な入力検証が必要になります (JSON 自体に関する同様の考慮事項については [RFC8259] のセクション 12を参照)。 その代わりに、JSONPath 実装は、プログラミング言語エンジンのパーサーに頼らず、 クエリの構文全体を実装する必要があります。

可用性に対する攻撃では、特定の実装が特定の場合に示す、 異常に高コストな実行時性能を引き起こそうとする可能性があります。 (ハッシュテーブル実装における問題については [RFC8949] のセクション 10を、 正規表現実装における性能問題については [RFC9485] のセクション 8を参照。) 実装者は、攻撃者が特別に細工した JSONPath クエリまたはクエリ引数を送信して、 驚くほど高い、場合によっては指数関数的な CPU 使用量や、たとえば子孫セグメントの ナイーブな再帰実装を通じたスタックオーバーフローを引き起こせる限り、 良好な平均性能だけでは不十分であることを認識する必要があります。 実装は、これらの攻撃を軽減するための適切なリソース管理を備える必要があります。

4.2. JSONPath クエリの形成方法に対する 攻撃ベクトル

JSONPath クエリは静的でないことが多く、 インデックス値、メンバー名、またはフィルター式で比較する値を提供する変数から形成されます。 これらの変数は検証される必要があり (たとえば、与えられた値が許す場合に限り .name のような特定の構成を形成できるようにする)、 かつ変換される必要があります(たとえば、文字列区切り文字をエスケープする)。 これらの検証および変換を正しく行わないと、予期しない失敗につながる可能性があり、 とりわけ攻撃者が値を制御している場合(たとえば Web フォームに入力することによって)、 可用性、機密性、および完全性の侵害につながり得ます。 結果として生じる攻撃の種類であるインジェクション(たとえば SQL インジェクション)は、 アプリケーションセキュリティ脆弱性の主要原因の上位に一貫して見られ、 特別な注意を必要とします。

4.3. JSONPath を用いるセキュリティ 仕組みに対する攻撃

JSONPath がセキュリティ仕組みの一部として使用される場合、 攻撃者は予期しない、または予測不能な挙動を引き起こそうとしたり、 JSONPath 実装間の挙動の違いを利用しようとしたりできます。

予期しない、または予測不能な挙動は、 [RFC8259] によって予測不能と記述される特定の構成を持つ クエリ引数から生じる可能性があります。 [RFC7493] に適合する任意のクエリ引数については、 オブジェクトの順序付けに関する場合を除き、予測可能な挙動を期待できます。

その他の攻撃は、UTF-8([RFC3629] のセクション 10を参照)や Unicode 文字集合など、基盤技術の挙動を標的にする可能性があります。

5. 参考文献

5.1. 規範的参考文献

[RFC0020]
Cerf, V., 「ネットワーク交換用 ASCII 形式」, STD 80, RFC 20, DOI 10.17487/RFC0020, , <https://www.rfc-editor.org/info/rfc20>.
[RFC2119]
Bradner, S., 「要求レベルを示すために RFC で 使用するキーワード」, BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC3629]
Yergeau, F., 「UTF-8、ISO 10646 の変換 形式」, STD 63, RFC 3629, DOI 10.17487/RFC3629, , <https://www.rfc-editor.org/info/rfc3629>.
[RFC5234]
Crocker, D., Ed. and P. Overell, 「構文仕様のための拡張 BNF: ABNF」, STD 68, RFC 5234, DOI 10.17487/RFC5234, , <https://www.rfc-editor.org/info/rfc5234>.
[RFC6838]
Freed, N., Klensin, J., and T. Hansen, 「メディア型仕様および 登録手続き」, BCP 13, RFC 6838, DOI 10.17487/RFC6838, , <https://www.rfc-editor.org/info/rfc6838>.
[RFC7493]
Bray, T., Ed., 「I-JSON メッセージ 形式」, RFC 7493, DOI 10.17487/RFC7493, , <https://www.rfc-editor.org/info/rfc7493>.
[RFC8126]
Cotton, M., Leiba, B., and T. Narten, 「RFC における IANA Considerations セクションの書き方に関するガイドライン」, BCP 26, RFC 8126, DOI 10.17487/RFC8126, , <https://www.rfc-editor.org/info/rfc8126>.
[RFC8174]
Leiba, B., 「RFC 2119 キーワードにおける 大文字と小文字の曖昧性」, BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC8259]
Bray, T., Ed., 「JavaScript Object Notation (JSON) データ交換形式」, STD 90, RFC 8259, DOI 10.17487/RFC8259, , <https://www.rfc-editor.org/info/rfc8259>.
[RFC9485]
Bormann, C. and T. Bray, 「I-Regexp: 相互運用可能な正規表現形式」, RFC 9485, DOI 10.17487/RFC9485, , <https://www.rfc-editor.org/info/rfc9485>.
[UNICODE]
The Unicode Consortium, 「Unicode® Standard」, <https://www.unicode.org/versions/latest/>. 執筆時点では、<https://www.unicode.org/versions/Unicode15.0.0/UnicodeStandard-15.0.pdf>

5.2. 参考情報の参考文献

[BOOLEAN-LAWS]
「Boolean 代数: 法則」, , <https://en.wikipedia.org/w/index.php?title=Boolean_algebra&oldid=1191386550#Laws>.
[COMPARISON]
Burgmer, C., 「JSONPath Comparison」, <https://cburgmer.github.io/json-path-comparison/>.
[E4X]
ISO, 「情報技術 - XML 用 ECMAScript (E4X) 仕様」, 廃止, ISO/IEC 22537:2006, , <https://www.iso.org/standard/41002.html>. 同等の仕様も廃止されていますが、次から利用可能です。 <https://ecma-international.org/publications-and-standards/standards/ecma-357>
[ECMA-262]
ECMA International, 「ECMAScript 言語 仕様」, Standard ECMA-262, Third Edition, , <https://www.ecma-international.org/wp-content/uploads/ECMA-262_3rd_edition_december_1999.pdf>.
[JSONPath-orig]
Gössner, S., 「JSONPath - JSON のための XPath」, , <https://goessner.net/articles/JsonPath/>.
[RFC6901]
Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed., 「JavaScript Object Notation (JSON) Pointer」, RFC 6901, DOI 10.17487/RFC6901, , <https://www.rfc-editor.org/info/rfc6901>.
[RFC8949]
Bormann, C. and P. Hoffman, 「簡潔なバイナリオブジェクト表現 (CBOR)」, STD 94, RFC 8949, DOI 10.17487/RFC8949, , <https://www.rfc-editor.org/info/rfc8949>.
[SLICE]
「スライス記法」, commit 82f95b4, , <https://github.com/tc39/proposal-slice-notation>.
[XPath]
Berglund, A., Ed., Chamberlin, D., Ed., Simeon, J., Ed., Robie, J., Ed., Fernandez, M., Ed., Kay, M., Ed., and S. Boag, Ed., 「XML Path Language (XPath) 2.0 (Second Edition)」, W3C REC-xpath20-20101214, , <https://www.w3.org/TR/2010/REC-xpath20-20101214/>.

付録 A. 収集された ABNF 文法

この付録は、文書全体で使用されている ABNF の記述から ABNF 文法を収集したものです。

図 2 は、 JSONPath クエリの構文を定義する、収集された ABNF 文法を含みます。

jsonpath-query      = root-identifier segments
segments            = *(S segment)

B                   = %x20 /    ; Space
                      %x09 /    ; Horizontal tab
                      %x0A /    ; Line feed or New line
                      %x0D      ; Carriage return
S                   = *B        ; optional blank space
root-identifier     = "$"
selector            = name-selector /
                      wildcard-selector /
                      slice-selector /
                      index-selector /
                      filter-selector
name-selector       = string-literal

string-literal      = %x22 *double-quoted %x22 /     ; "string"
                      %x27 *single-quoted %x27       ; 'string'

double-quoted       = unescaped /
                      %x27      /                    ; '
                      ESC %x22  /                    ; \"
                      ESC escapable

single-quoted       = unescaped /
                      %x22      /                    ; "
                      ESC %x27  /                    ; \'
                      ESC escapable

ESC                 = %x5C                           ; \ backslash

unescaped           = %x20-21 /                      ; see RFC 8259
                         ; omit 0x22 "
                      %x23-26 /
                         ; omit 0x27 '
                      %x28-5B /
                         ; omit 0x5C \
                      %x5D-D7FF /
                         ; skip surrogate code points
                      %xE000-10FFFF

escapable           = %x62 / ; b BS backspace U+0008
                      %x66 / ; f FF form feed U+000C
                      %x6E / ; n LF line feed U+000A
                      %x72 / ; r CR carriage return U+000D
                      %x74 / ; t HT horizontal tab U+0009
                      "/"  / ; / slash (solidus) U+002F
                      "\"  / ; \ backslash (reverse solidus) U+005C
                      (%x75 hexchar) ;  uXXXX U+XXXX

hexchar             = non-surrogate /
                      (high-surrogate "\" %x75 low-surrogate)
non-surrogate       = ((DIGIT / "A"/"B"/"C" / "E"/"F") 3HEXDIG) /
                      ("D" %x30-37 2HEXDIG )
high-surrogate      = "D" ("8"/"9"/"A"/"B") 2HEXDIG
low-surrogate       = "D" ("C"/"D"/"E"/"F") 2HEXDIG

HEXDIG              = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
wildcard-selector   = "*"
index-selector      = int                        ; decimal integer

int                 = "0" /
                      (["-"] DIGIT1 *DIGIT)      ; - optional
DIGIT1              = %x31-39                    ; 1-9 non-zero digit
slice-selector      = [start S] ":" S [end S] [":" [S step ]]

start               = int       ; included in selection
end                 = int       ; not included in selection
step                = int       ; default: 1
filter-selector     = "?" S logical-expr
logical-expr        = logical-or-expr
logical-or-expr     = logical-and-expr *(S "||" S logical-and-expr)
                        ; disjunction
                        ; binds less tightly than conjunction
logical-and-expr    = basic-expr *(S "&&" S basic-expr)
                        ; conjunction
                        ; binds more tightly than disjunction

basic-expr          = paren-expr /
                      comparison-expr /
                      test-expr

paren-expr          = [logical-not-op S] "(" S logical-expr S ")"
                                        ; parenthesized expression
logical-not-op      = "!"               ; logical NOT operator
test-expr           = [logical-not-op S]
                      (filter-query / ; existence/non-existence
                       function-expr) ; LogicalType or NodesType
filter-query        = rel-query / jsonpath-query
rel-query           = current-node-identifier segments
current-node-identifier = "@"
comparison-expr     = comparable S comparison-op S comparable
literal             = number / string-literal /
                      true / false / null
comparable          = literal /
                      singular-query / ; singular query value
                      function-expr    ; ValueType
comparison-op       = "==" / "!=" /
                      "<=" / ">=" /
                      "<"  / ">"

singular-query      = rel-singular-query / abs-singular-query
rel-singular-query  = current-node-identifier singular-query-segments
abs-singular-query  = root-identifier singular-query-segments
singular-query-segments = *(S (name-segment / index-segment))
name-segment        = ("[" name-selector "]") /
                      ("." member-name-shorthand)
index-segment       = "[" index-selector "]"
number              = (int / "-0") [ frac ] [ exp ] ; decimal number
frac                = "." 1*DIGIT                  ; decimal fraction
exp                 = "e" [ "-" / "+" ] 1*DIGIT    ; decimal exponent
true                = %x74.72.75.65                ; true
false               = %x66.61.6c.73.65             ; false
null                = %x6e.75.6c.6c                ; null
function-name       = function-name-first *function-name-char
function-name-first = LCALPHA
function-name-char  = function-name-first / "_" / DIGIT
LCALPHA             = %x61-7A  ; "a".."z"

function-expr       = function-name "(" S [function-argument
                         *(S "," S function-argument)] S ")"
function-argument   = literal /
                      filter-query / ; (includes singular-query)
                      logical-expr /
                      function-expr
segment             = child-segment / descendant-segment
child-segment       = bracketed-selection /
                      ("."
                       (wildcard-selector /
                        member-name-shorthand))

bracketed-selection = "[" S selector *(S "," S selector) S "]"

member-name-shorthand = name-first *name-char
name-first          = ALPHA /
                      "_"   /
                      %x80-D7FF /
                         ; skip surrogate code points
                      %xE000-10FFFF
name-char           = name-first / DIGIT

DIGIT               = %x30-39              ; 0-9
ALPHA               = %x41-5A / %x61-7A    ; A-Z / a-z
descendant-segment  = ".." (bracketed-selection /
                            wildcard-selector /
                            member-name-shorthand)
図 2: JSONPath クエリの収集された ABNF

図 3 は、 JSONPath 正規化パスの構文を定義する、収集された ABNF 文法を含みます。 また、図 2 の規則 root-identifierESCDIGIT、および DIGIT1 も使用します。

normalized-path      = root-identifier *(normal-index-segment)
normal-index-segment = "[" normal-selector "]"
normal-selector      = normal-name-selector / normal-index-selector
normal-name-selector = %x27 *normal-single-quoted %x27 ; 'string'
normal-single-quoted = normal-unescaped /
                       ESC normal-escapable
normal-unescaped     =    ; omit %x0-1F control codes
                       %x20-26 /
                          ; omit 0x27 '
                       %x28-5B /
                          ; omit 0x5C \
                       %x5D-D7FF /
                          ; skip surrogate code points
                       %xE000-10FFFF

normal-escapable     = %x62 / ; b BS backspace U+0008
                       %x66 / ; f FF form feed U+000C
                       %x6E / ; n LF line feed U+000A
                       %x72 / ; r CR carriage return U+000D
                       %x74 / ; t HT horizontal tab U+0009
                       "'" /  ; ' apostrophe U+0027
                       "\" /  ; \ backslash (reverse solidus) U+005C
                       (%x75 normal-hexchar)
                                       ; certain values u00xx U+00XX
normal-hexchar       = "0" "0"
                       (
                          ("0" %x30-37) / ; "00"-"07"
                             ; omit U+0008-U+000A BS HT LF
                          ("0" %x62) /    ; "0b"
                             ; omit U+000C-U+000D FF CR
                          ("0" %x65-66) / ; "0e"-"0f"
                          ("1" normal-HEXDIG)
                       )
normal-HEXDIG        = DIGIT / %x61-66    ; "0"-"9", "a"-"f"
normal-index-selector = "0" / (DIGIT1 *DIGIT)
                        ; non-negative decimal integer
図 3: JSONPath 正規化パスの収集された ABNF

付録 B. XPath に着想を得たもの

この付録は参考情報です。

JSONPath が考案された当時、XML は、XML 文書からデータを分析、 変換、および選択的に抽出するための強力なツールが利用可能であることで 注目されていました。 [XPath] はそのようなツールの 1 つです。

2007 年には、新興の JSON コミュニティに対して同じ種類の問題を解決するものが必要であることが 明らかになりました。具体的には次のためです。

(注: XPath は 2007 年以降進化しており、近年のバージョンでは名目上、 JSON 値内での操作もサポートしています。 この付録では、2007 年に利用可能だった、より広く使用されていた XPath のバージョンのみを 扱います。)

JSONPath は XPath の全体的な感覚を取り入れていますが、 その概念を、動的言語で JSON を使用する人に馴染みのある 構文(および部分的な意味論)へ対応付けます。

たとえば、JavaScript、Python、PHP などの一般的な動的プログラミング言語では、 XPath 式の意味論は次のようになります。

/store/book[1]/title

これは次の式で実現できます。

x.store.book[0].title

またはブラケット記法では次のようになります。

x['store']['book'][0]['title']

ここで、変数 x はクエリ引数を保持します。

JSONPath 言語は、次のように設計されました。

B.1. JSONPath と XPath

JSONPath 式は、XPath 式が XML 文書と組み合わせて使用されるのと同じように、 JSON 値に適用されます。 JSONPath は、XPath の先頭の / と同様に、 クエリ引数のルートノードを参照するために $ を使用します。

JSONPath 式は、ドット記法$.store.book[0].title) またはブラケット記法$['store']['book'][0]['title'])を使用して階層をさらに下へ移動します。 どちらもクエリ式内の XPath の / を置き換えるものであり、 ドット記法は軽量ですが制限のある構文として機能し、 ブラケット記法は重量級ですが、より一般的な構文です。

JSONPath と XPath はどちらも、ワイルドカードに * を使用します。 JSONPath の子孫セグメント記法は .. で始まり、 [E4X] から借用したもので、 XPath の // に似ています。 配列スライス構文 [start:end:step] は JSONPath 独自のものであり、 ECMASCRIPT 4 の [SLICE] に着想を得ています。

フィルター式は、次のように ?<logical-expr> という構文でサポートされます。

$.store.book[?@.price < 10].title

表 20 は、 類似する XPath の概念との比較を提供することで、 表 1 を拡張します。

表 20: JSONPath と比較した XPath 構文
XPath JSONPath 説明
/ $ ルート XML 要素
. @ 現在の XML 要素
/ . または [] 子演算子
.. n/a 親演算子
// ..name, ..⁠[index], ..*, または ..[*] 子孫(JSONPath はこの構文を E4X から借用している)
* * ワイルドカード: 名前に関係なくすべての XML 要素
@ n/a 属性アクセス: JSON 値には 属性がない
[] [] XML 要素コレクションの反復および 述語に使用される添字演算子
| [,] 和集合演算子(結果はノード集合の組み合わせになる)。 JSONPath ではリスト演算子と呼ばれ、メンバー名、配列インデックス、 およびスライスの組み合わせを許す
n/a [start:end:step] ES4 から借用した配列スライス演算子
[] ? フィルター(スクリプト)式を適用する
シームレス n/a 式エンジン
() n/a グループ化

さらに説明するため、表 21 は、いくつかの XPath 式と それらに対応する JSONPath 式を示します。

表 21: XPath 式の例と それらの JSONPath 対応表現
XPath JSONPath 結果
/store/book/author $.store.book[*].author store 内のすべての本の著者
//author $..author すべての著者
/store/* $.store.* store 内のすべてのもの。 いくつかの本と赤い自転車である
/store//price $.store..price store 内のすべてのものの価格
//book[3] $..book[2] 3 番目の本
//book[last()] $..book[-1] 順序上の最後の本
//⁠book[position()<3] $..book[0,1]
$..book[:2]
最初の 2 冊の本
//book[isbn] $..book[?@.isbn] ISBN 番号を持つすべての本をフィルターする
//book[price<10] $..book[?@.price<10] 10 より安いすべての本をフィルターする
//* $..* XML 文書内のすべての要素。 入力値に含まれるすべてのメンバー値および配列要素

XPath には、この比較に列挙されているものよりもはるかに多くの機能 (省略しない構文によるロケーションパス、演算子、および関数)があります。 さらに、XPath と JSONPath では添字演算子の動作に 重要な違いがあります。

  • XPath 式の角括弧は、常に直前のパス断片から結果として得られる ノード集合に対して作用します。インデックスは常に 1 から始まります。
  • JSONPath では、角括弧は直前のクエリセグメントから結果として得られる ノードリスト内の各ノードに対して作用します。 配列インデックスは常に 0 から始まります。

付録 C. JSON Pointer

この付録は参考情報です。

JSON Pointer [RFC6901] に関して、JSONPath は置き換えを意図したものではなく、 より強力な補完物として意図されています。 2 つの標準の目的は異なります。

JSON Pointer は、構造が既知である JSON 値の中の単一の値を識別するためのものです。

JSONPath は、たとえば正規化パスを使用することで、 JSON 値の中の単一の値を識別できます。 しかし JSONPath は、構造が一般的な意味でしか知られていない JSON 値から 複数の値を検索して抽出するために使用できるクエリ構文でもあります。

正規化 JSONPath は、任意の JSON 値に関する知識なしに、構文を変換することによって JSON Pointer へ変換できます。その逆は一般には成り立ちません。 すなわち、JSON Pointer 内の数値の参照トークン(パス構成要素)は、 オブジェクトのメンバー値または配列の要素を識別する可能性があります。 JSONPath クエリへ変換するには、これらの場合を区別するために JSON 値の構造に関する知識が必要です。

謝辞

この文書は、JSONPath を定義した Stefan Gössner の 元のオンライン記事 [JSONPath-orig] に基づいています。

本の例は、ドイツのビーレフェルト大学が 2002 年に使用していた講義資料から採られました。

本作業は、40 を超える JSONPath 実装に多数のクエリを適用した挙動を詳述する 優れた JSONPath 比較プロジェクト [COMPARISON] について、 Christoph Burgmer に負うところが大きいものです。

貢献者

Marko Mikulicic
InfluxData, Inc.
Pisa
Italy
Edward Surov
TheSoul Publishing Ltd.
Limassol
Cyprus
Greg Dennis
Auckland
New Zealand

著者の連絡先

Stefan Gössner(編集者
Fachhochschule Dortmund
Sonnenstraße 96
D-44139 Dortmund
Germany
Glyn Normington(編集者
Winchester
United Kingdom
Carsten Bormann(編集者
Universität Bremen TZI
Postfach 330440
D-28359 Bremen
Germany