# 機能設計書 27-JsonPath

## 概要

本ドキュメントは、Symfony JsonPathコンポーネントの機能設計を記述する。このコンポーネントはRFC 9535に準拠したJSONPath式を使用してJSONドキュメントをクロールする機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：大規模なJSONドキュメントから特定のデータを効率的に抽出することは、API連携やデータ処理において頻繁に必要となる。JSONPathはXPathに類似したクエリ言語であり、標準化されたRFC 9535により、JSONドキュメント内の要素を宣言的に指定・抽出できる。本コンポーネントはこの規格に準拠した実装を提供する。

**機能の利用シーン**：APIレスポンスからの特定フィールド抽出、大規模JSONの部分的解析、フィルタ条件に基づくデータ抽出、ストリームリソースからの効率的なJSON要素抽出。

**主要な処理内容**：
1. JsonCrawlerによるJSONPathクエリの評価とデータ抽出
2. JsonPathTokenizerによるJSONPath式のトークン化（Name、Bracket、Recursive）
3. フィルタ式（?）による条件付き要素抽出（比較演算子、論理演算子対応）
4. RFC 9535準拠の関数（length, count, match, search, value）のサポート
5. スライス記法（start:end:step）による配列要素の範囲指定
6. 再帰降下（..）による任意の深さの要素検索
7. ストリームリソース対応（JsonStreamerのSplitterとの連携による効率的な部分デシリアライズ）

**関連システム・外部連携**：JsonStreamer（Splitterによるストリーム分割）と連携する。

**権限による制御**：直接的な権限制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （直接的な画面関連なし） | - | バックエンドJSON処理 |

## 機能種別

データ操作 / JSONクエリ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| raw | string/resource | Yes | JSONデータ（文字列またはストリーム） | 有効なJSON |
| query | string/JsonPath | Yes | JSONPath式 | RFC 9535準拠のクエリ文字列 |

### 入力データソース

JSON文字列、ストリームリソース（ファイル、HTTP応答等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| results | array | クエリにマッチした値の配列 |

### 出力先

PHPの配列

## 処理フロー

### 処理シーケンス

```
1. JsonCrawler初期化
   └─ JSON文字列またはストリームリソースを受け取る
2. find()呼び出し
   └─ JsonPath文字列の場合JsonPathオブジェクトに変換
3. evaluate()でクエリ評価
   └─ 複合ブラケット式の特別処理（フィルタ+セレクタ混在）
   └─ JsonPathTokenizerでトークン化
   └─ ストリームリソースの場合はSplitterで最小デシリアライズ
4. evaluateTokensOnDecodedData()でトークン順次評価
   └─ Name: ドット記法のプロパティアクセス
   └─ Bracket: ブラケット式の評価（インデックス、スライス、フィルタ）
   └─ Recursive: 再帰降下による全要素の収集
5. 結果の正規化
   └─ normalizeStorage()でstdClass/array正規化
```

### フローチャート

```mermaid
flowchart TD
    A[JsonCrawler::find] --> B[JsonPath解析]
    B --> C[evaluate]
    C --> D{複合ブラケット式?}
    D -->|Yes| E[直接json_decode+evaluateBracket]
    D -->|No| F[トークン化]
    F --> G{入力はストリーム?}
    G -->|Yes| H[Splitterで最小化]
    G -->|No| I[json_decode]
    H --> J{最小化成功?}
    J -->|Yes| K[部分JSONでトークン評価]
    J -->|No| L[全体読み取り+json_decode]
    I --> M[evaluateTokensOnDecodedData]
    K --> M
    L --> M
    M --> N[normalizeStorage]
    N --> O[結果配列返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-27-01 | RFC 9535準拠 | JSONPath式はRFC 9535の仕様に厳密に準拠する | 全クエリ評価 |
| BR-27-02 | RFC 9535関数 | length, count, match, search, valueの5関数をサポート | フィルタ式内の関数呼び出し |
| BR-27-03 | 非特異クエリ制限 | 比較演算子の引数に非特異（non-singular）クエリは使用不可 | フィルタ式の比較時 |
| BR-27-04 | 特異引数関数制限 | length, match, search関数は特異引数（singular argument）のみ許可 | 関数呼び出し時 |
| BR-27-05 | 先頭/末尾カンマ禁止 | ブラケット式内のカンマリストは先頭・末尾カンマ不可 | ブラケット式解析時 |
| BR-27-06 | 整数オーバーフロー検出 | インデックスやスライスの整数値がオーバーフローした場合エラー | ブラケット式解析時 |
| BR-27-07 | 先頭ゼロ禁止 | インデックスやスライスの数値に先頭ゼロは不可（-0も禁止） | ブラケット式解析時 |

### 計算ロジック

スライス記法: `start:end:step` で start、end が負の場合は配列長からの相対位置。step=0は空結果。stepが正の場合 start から end未満まで、stepが負の場合 start から end超過まで。

## データベース操作仕様

### 操作別データベース影響一覧

直接的なデータベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvalidArgumentException | 入力がstring/resourceでない | 有効な型を指定 |
| - | InvalidJsonPathException | 不正なJSONPath式 | RFC 9535準拠のクエリを使用 |
| - | InvalidJsonStringInputException | 不正なJSON文字列 | 有効なJSONを入力 |
| - | JsonCrawlerException | クエリ評価中のエラー（非特異クエリ比較等） | クエリを修正 |
| - | LogicException | ストリーム入力でJsonStreamerが未インストール | composer require symfony/json-streamer |

### リトライ仕様

リトライは不要。

## トランザクション仕様

直接的なトランザクション管理は行わない。

## パフォーマンス要件

ストリームリソース入力時、JsonPathUtils::findSmallestDeserializableStringAndPathにより最小限のJSON部分のみをデシリアライズすることで、大規模JSONの処理においてメモリ使用量を最小化する。

## セキュリティ考慮事項

- 正規表現パターンのRFC 9485準拠変換により、不正な正規表現による攻撃を防止
- json_decodeの深さ制限（512）によるスタックオーバーフロー防止
- @preg_matchのエラー抑制による不正パターンの安全な処理

## 備考

JsonPathコンポーネントはRFC 9535（JSONPath: Query Expressions for JSON）に準拠しており、標準化されたJSONクエリ言語の実装である。ストリームリソース対応により、JsonStreamerとの連携で大規模JSONの効率的な処理が可能。

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | JsonPath.php | `src/Symfony/Component/JsonPath/JsonPath.php` | JSONPath式を表すデータクラス |
| 1-2 | JsonCrawlerInterface.php | `src/Symfony/Component/JsonPath/JsonCrawlerInterface.php` | クローラーインターフェース（find()メソッド） |
| 1-3 | JsonPathToken.php | `src/Symfony/Component/JsonPath/Tokenizer/JsonPathToken.php` | トークンデータ構造（type + value） |
| 1-4 | TokenType.php | `src/Symfony/Component/JsonPath/Tokenizer/TokenType.php` | トークン型（Name, Bracket, Recursive） |
| 1-5 | Nothing.php | `src/Symfony/Component/JsonPath/Nothing.php` | 欠損値を表す特殊列挙型 |

**読解のコツ**: JSONPathのトークンは3種類のみ（Name=ドット記法、Bracket=ブラケット記法、Recursive=再帰降下）。Nothing列挙型はプロパティの不存在と値null/0を区別するために使われる。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | JsonCrawler.php | `src/Symfony/Component/JsonPath/JsonCrawler.php` | JSON Path評価の中核実装 |

**主要処理フロー**:
1. **58-64行目**: コンストラクタでstring/resource入力の検証
2. **66-69行目**: find()でJsonPath文字列の場合オブジェクト変換後evaluate()呼び出し
3. **71-137行目**: evaluate()でトークン化 -> ストリーム最適化 -> json_decode -> 評価
4. **153-192行目**: evaluateTokensOnDecodedData()でトークン配列を順次評価。再帰+ブラケットの特別処理
5. **194-201行目**: evaluateToken()でTokenTypeに基づく分岐（Name/Bracket/Recursive）
6. **216-524行目**: evaluateBracket()でブラケット式の全バリエーション処理（インデックス、スライス、フィルタ、ワイルドカード等）
7. **542-625行目**: evaluateFilterExpression()でフィルタ式の再帰的評価（論理演算子、比較演算子、関数呼び出し）
8. **743-804行目**: evaluateFunction()でRFC 9535関数（length, count, match, search, value）の実行
9. **826-834行目**: compare()で比較演算子の評価

#### Step 3: トークナイザーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | JsonPathTokenizer.php | `src/Symfony/Component/JsonPath/Tokenizer/JsonPathTokenizer.php` | JSONPath式のトークン化 |

### プログラム呼び出し階層図

```
JsonCrawler::find()
    |
    +-- evaluate()
           |
           +-- isComplexBracketExpression()  [複合ブラケット判定]
           |
           +-- JsonPathTokenizer::tokenize()
           |
           +-- [ストリーム] JsonPathUtils::findSmallestDeserializableStringAndPath()
           |                    +-- Splitter (JsonStreamer)
           |
           +-- json_decode()
           |
           +-- evaluateTokensOnDecodedData()
                  |
                  +-- evaluateToken()
                         |
                         +-- evaluateName()        [ドット記法]
                         +-- evaluateBracket()     [ブラケット式]
                         |       +-- evaluateFilter()
                         |       |       +-- evaluateFilterExpression()
                         |       |              +-- findRightmostLogicalOperator()
                         |       |              +-- evaluateScalar()
                         |       |              +-- compare()
                         |       |              +-- evaluateFunction()
                         |       +-- スライス処理
                         |       +-- インデックス処理
                         |       +-- ワイルドカード処理
                         |
                         +-- evaluateRecursive()   [再帰降下]
```

### データフロー図

```
[入力]                         [処理]                          [出力]

JSON string/resource -------> JsonCrawler::find() -----------> array (マッチ結果)
                                   |
JSONPath query ---------> JsonPathTokenizer::tokenize()
                                   |
                              Token配列
                                   |
                              json_decode() -> decoded data
                                   |
                              evaluateTokensOnDecodedData()
                                   |
                              Token毎に分岐処理
                                   |
                              normalizeStorage()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| JsonCrawler.php | `src/Symfony/Component/JsonPath/JsonCrawler.php` | ソース | JSONPath評価エンジン |
| JsonCrawlerInterface.php | `src/Symfony/Component/JsonPath/JsonCrawlerInterface.php` | ソース | クローラーインターフェース |
| JsonPath.php | `src/Symfony/Component/JsonPath/JsonPath.php` | ソース | JSONPath式データクラス |
| JsonPathUtils.php | `src/Symfony/Component/JsonPath/JsonPathUtils.php` | ソース | ユーティリティ関数 |
| Nothing.php | `src/Symfony/Component/JsonPath/Nothing.php` | ソース | 欠損値列挙型 |
| JsonPathTokenizer.php | `src/Symfony/Component/JsonPath/Tokenizer/JsonPathTokenizer.php` | ソース | トークナイザー |
| JsonPathToken.php | `src/Symfony/Component/JsonPath/Tokenizer/JsonPathToken.php` | ソース | トークンデータ |
| TokenType.php | `src/Symfony/Component/JsonPath/Tokenizer/TokenType.php` | ソース | トークン型列挙 |
| InvalidJsonPathException.php | `src/Symfony/Component/JsonPath/Exception/InvalidJsonPathException.php` | ソース | パスエラー例外 |
| InvalidJsonStringInputException.php | `src/Symfony/Component/JsonPath/Exception/InvalidJsonStringInputException.php` | ソース | JSON入力エラー例外 |
| JsonCrawlerException.php | `src/Symfony/Component/JsonPath/Exception/JsonCrawlerException.php` | ソース | クローラーエラー例外 |
