# 機能設計書 93-Queryプラグイン

## 概要

本ドキュメントはNushellのQueryプラグイン（nu_plugin_query）について記述する。JSON、XML、Webページに対するクエリ機能を提供するプラグインの設計を定義する。

### 本機能の処理概要

Queryプラグインは、構造化データ（JSON、XML）およびHTMLに対してクエリを実行し、必要なデータを抽出する機能を提供する。各データ形式に応じた専用クエリ言語（gjson、XPath、CSSセレクタ）を使用する。

**業務上の目的・背景**：Web APIからのJSON応答、設定ファイルのXML、Webスクレイピングなど、様々なデータソースから特定の情報を抽出する必要がある。標準のフィルタリング機能だけでは複雑なクエリが困難な場合に、専用のクエリ言語を用いて効率的なデータ抽出を実現する。

**機能の利用シーン**：
- REST APIからのJSONレスポンスから特定のフィールドを抽出する際
- XMLベースの設定ファイルから設定値を取得する際
- Webページからテーブルデータをスクレイピングする際
- HTMLから特定の要素や属性を抽出する際

**主要な処理内容**：
1. JSONクエリ: gjson構文によるJSONデータのパス指定抽出
2. XMLクエリ: XPath 1.0によるXML要素・属性の抽出
3. Webクエリ: CSSセレクタによるHTML要素の選択
4. テーブル抽出: HTMLテーブルの自動パース

**関連システム・外部連携**：gjsonクレート、sxd-xpathクレート、scraperクレート

**権限による制御**：特になし。入力データに対する処理のみ。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はCLIコマンドとして提供され、特定の画面とは関連しない |

## 機能種別

データ抽出 / フィルタリング / パース処理

## 入力仕様

### 入力パラメータ

#### query json

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| query | String | Yes | gjson形式のクエリ文字列 | 有効なgjson構文 |
| input | String (pipeline) | Yes | JSON文字列 | 有効なJSON |

#### query xml

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| query | String | Yes | XPath 1.0形式のクエリ | 有効なXPath |
| --namespaces | Record | No | プレフィックスと名前空間URIのマッピング | - |
| --output-string-value | Switch | No | string_valueを出力に含める | - |
| --output-type | Switch | No | typeを出力に含める | - |
| --output-names | Switch | No | local_name等を出力に含める | - |
| input | String (pipeline) | Yes | XML文字列 | 有効なXML |

#### query web

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --query | String | No | CSSセレクタクエリ | 有効なCSSセレクタ |
| --as-html | Switch | No | 結果をHTMLとして返す | - |
| --attribute | Any | No | 抽出する属性名 | - |
| --as-table | List[String] | No | テーブルのカラムヘッダーリスト | - |
| --inspect | Switch | No | インスペクトモード | - |
| input | String (pipeline) | Yes | HTML文字列 | 有効なHTML |

### 入力データソース

- パイプライン入力: JSON/XML/HTML文字列
- http getなどと組み合わせてWeb APIやWebページから取得

## 出力仕様

### 出力データ

#### query json

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | Any | クエリ結果（型はクエリ内容による） |

- オブジェクト -> Record
- 配列 -> List
- 数値 -> Int/Float
- 文字列 -> String
- Boolean -> Bool
- null -> Nothing

#### query xml

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | Any | スカラー(Number/String/Bool)またはテーブル |

ノードセット結果の場合:
| 項目名 | 型 | 説明 |
|--------|-----|------|
| string_value | String | ノードの文字列値 |
| type | String | ノードタイプ（オプション） |
| local_name | String | ローカル名（オプション） |
| namespace | String | 名前空間URI（オプション） |
| prefixed_name | String | プレフィックス付き名前（オプション） |

#### query web

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | List | マッチした要素のリスト |

### 出力先

- パイプライン出力

## 処理フロー

### 処理シーケンス

```
query json:
1. 入力文字列をJSON文字列として取得
2. gjson::valid()でJSONの妥当性を検証
3. gjson::get()でクエリを実行
4. 結果をNushell値に変換
   └─ @ugly/@prettyモディファイア使用時は文字列で返却

query xml:
1. 入力文字列をXMLとしてパース
2. XPath式を構築
3. 名前空間コンテキストを設定
   └─ xmlプレフィックスは自動登録
4. XPathを評価
5. 結果タイプに応じて変換
   └─ Boolean/Number/String: スカラー値
   └─ Nodeset: テーブル形式

query web:
1. HTML入力をパース
2. 処理モード判定
   └─ --as-table: テーブル抽出モード
   └─ --attribute: 属性抽出モード
   └─ デフォルト: テキスト抽出モード
3. CSSセレクタでマッチング
4. 結果をリストとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[query json] --> B{JSON有効?}
    B -->|No| C[エラー: Invalid JSON]
    B -->|Yes| D[gjson::get実行]
    D --> E{モディファイア使用?}
    E -->|Yes| F[JSON文字列で返却]
    E -->|No| G[Nushell値に変換]

    H[query xml] --> I[XMLパース]
    I --> J{パース成功?}
    J -->|No| K[エラー: Invalid XML]
    J -->|Yes| L[XPath評価]
    L --> M{結果タイプ}
    M -->|Scalar| N[スカラー値返却]
    M -->|Nodeset| O[テーブル返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-93-01 | gjsonモディファイア | @ugly/@pretty使用時は文字列として返却 | query json |
| BR-93-02 | XML名前空間 | xmlプレフィックスは常に利用可能 | query xml |
| BR-93-03 | デフォルト出力 | フラグなしの場合はstring_valueのみ出力 | query xml nodeset |
| BR-93-04 | テーブル抽出 | ヘッダー指定でHTMLテーブルをパース | query web --as-table |

### 計算ロジック

gjson クエリ構文:
- パス指定: `name.first` (ネストしたキー)
- 配列操作: `children.#` (配列長), `children.0` (インデックス)
- ワイルドカード: `friends.#.first` (全要素のfirstを取得)
- モディファイア: `children|@reverse|0` (配列を反転して最初の要素)

XPath構文:
- 要素選択: `/root/child`
- 属性選択: `//@attr`
- 関数: `count()`, `string()`, `local-name()` etc.

CSSセレクタ:
- 要素: `div`, `p`
- クラス: `.class`
- ID: `#id`
- 属性: `[attr="value"]`
- 擬似クラス: `:first-child`

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| Invalid JSON | LabeledError | 入力が有効なJSONでない | 有効なJSON入力を提供 |
| Invalid XML document | LabeledError | 入力が有効なXMLでない | 有効なXML入力を提供 |
| invalid xpath query | LabeledError | XPath構文エラー | XPath構文を修正 |
| CSS query parse error | LabeledError | CSSセレクタ構文エラー | セレクタ構文を修正 |
| query string missing | LabeledError | クエリが指定されていない | クエリを指定 |

### リトライ仕様

特になし。

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

該当なし（読み取り専用処理）。

## パフォーマンス要件

- クエリ処理は即座に実行される
- 大規模ドキュメントの場合はメモリ使用量に注意

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

- 外部からの入力データをパースするため、不正なデータによる影響に注意
- scraperクレートはHTML5パーサーを使用し、不正なHTMLも許容的にパース

## 備考

- gjsonは高速なJSON検索を提供
- sxd-xpathはXPath 1.0をサポート
- scraperはHTML5仕様に準拠したパーサー

---

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

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

### 推奨読解順序

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

プラグインの構造とコマンド登録を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lib.rs | `crates/nu_plugin_query/src/lib.rs` | エクスポートされるコマンド一覧 |
| 1-2 | query.rs | `crates/nu_plugin_query/src/query.rs` | Queryプラグインの定義とコマンド登録 |

**読解のコツ**: SimplePluginCommandトレイトを実装した各コマンドがどのように登録されているかを確認する。

#### Step 2: JSONクエリを理解する

gjsonを使用したJSONクエリ処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | query_json.rs | `crates/nu_plugin_query/src/query_json.rs` | QueryJsonコマンドの実装 |

**主要処理フロー（query_json.rs）**:
1. **88-125行目**: execute_json_query関数 - メイン処理ロジック
2. **109-115行目**: gjson::validでJSON検証
3. **117行目**: gjson::getでクエリ実行
4. **119-124行目**: モディファイアの判定と結果返却
5. **146-178行目**: convert_gjson_value_to_nu_value - 型変換

#### Step 3: XMLクエリを理解する

XPathを使用したXMLクエリ処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | query_xml.rs | `crates/nu_plugin_query/src/query_xml.rs` | QueryXmlコマンドの実装 |

**主要処理フロー（query_xml.rs）**:
1. **112-183行目**: execute_xpath_query関数 - メイン処理ロジック
2. **129行目**: XPathの構築
3. **131行目**: XMLのパース
4. **144-161行目**: 名前空間コンテキストの設定
5. **166行目**: XPath評価
6. **168-182行目**: 結果タイプに応じた返却

#### Step 4: Webクエリを理解する

CSSセレクタを使用したHTMLクエリ処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | query_web.rs | `crates/nu_plugin_query/src/query_web.rs` | QueryWebコマンドの実装 |
| 4-2 | web_tables.rs | `crates/nu_plugin_query/src/web_tables.rs` | HTMLテーブル抽出 |

**主要処理フロー（query_web.rs）**:
1. **109-143行目**: parse_selector_params - パラメータ解析
2. **145-182行目**: begin_selector_query - 処理モード分岐
3. **184-233行目**: retrieve_tables - テーブル抽出
4. **368-397行目**: execute_selector_query - セレクタ実行

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

```
Query (Plugin)
    │
    ├─ QueryCommand         # メインコマンド（ヘルプ表示）
    │
    ├─ QueryJson
    │      └─ execute_json_query()
    │             ├─ gjson::valid()
    │             ├─ gjson::get()
    │             └─ convert_gjson_value_to_nu_value()
    │
    ├─ QueryXml
    │      └─ execute_xpath_query()
    │             ├─ build_xpath()
    │             ├─ parser::parse()
    │             ├─ xpath.evaluate()
    │             └─ node_to_record()
    │
    ├─ QueryWeb
    │      └─ parse_selector_params()
    │             ├─ retrieve_tables()
    │             │      └─ WebTable::find_by_headers()
    │             ├─ execute_selector_query()
    │             ├─ execute_selector_query_with_attribute()
    │             └─ execute_selector_query_with_attributes()
    │
    └─ QueryWebpageInfo     # Webページ情報取得
```

### データフロー図

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

JSON文字列  ─────────▶   gjson::get()         ─────▶   Nushell値
                          └─ クエリ実行                  (Record/List等)

XML文字列   ─────────▶   sxd_xpath            ─────▶   スカラー or
                          ├─ parse()                     テーブル
                          └─ evaluate()

HTML文字列  ─────────▶   scraper              ─────▶   リスト
                          ├─ Html::parse()              (テキスト/HTML/
                          └─ select()                    属性値)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lib.rs | `crates/nu_plugin_query/src/lib.rs` | ソース | モジュールエクスポート |
| query.rs | `crates/nu_plugin_query/src/query.rs` | ソース | プラグイン定義・コマンド登録 |
| query_json.rs | `crates/nu_plugin_query/src/query_json.rs` | ソース | JSONクエリ実装 |
| query_xml.rs | `crates/nu_plugin_query/src/query_xml.rs` | ソース | XMLクエリ実装 |
| query_web.rs | `crates/nu_plugin_query/src/query_web.rs` | ソース | Webクエリ実装 |
| query_webpage_info.rs | `crates/nu_plugin_query/src/query_webpage_info.rs` | ソース | Webページ情報取得 |
| web_tables.rs | `crates/nu_plugin_query/src/web_tables.rs` | ソース | HTMLテーブルパーサー |
| main.rs | `crates/nu_plugin_query/src/main.rs` | ソース | プラグインエントリーポイント |
