任意のJSONをHTMLテーブルに階層展開して表示するビューアをJavaScriptで実装

# 任意のJSONをHTMLテーブルに階層展開して表示する：型・文字数・値を明示しつつ構造もわかるビューアをJavaScriptで実装

## はじめに

フロントエンドの開発やAPIのレスポンス確認などで、「ネストされたJSONを視覚的に見やすく表示したい」と思ったことはありませんか？

本記事では、以下のような要件を満たす **HTML + JavaScript ベースのJSONビューワー** を実装して紹介します。

---

## 実現すること

- 任意のJSONデータを `<table id="respons">` に展開
- 各行にはユニークな `id` を持たせて操作しやすく
- ネストした構造は `-` 区切りで階層がわかるように
- 配列は `[0]`, `[1]` などインデックス付きで表現
- 出力項目は以下の4列：
  - **キーと階層（インデント付き）**
  - **値の型**
  - **文字数（string/numberのみ）**
  - **値（配列・オブジェクトは空欄、空配列は `[]`）**

---

## 完成イメージ

以下のようなJSONが：

```json
{
  "users": [
    { "name": "Alice", "age": 30, "active": true },
    { "name": "Bob", "age": 25, "active": false },
    { "name": "Charlie", "tags": [], "profile": null }
  ]
}
```

このように表示されます：

| キーと階層         | 型       | 文字数 | 値       |
| ------------- | ------- | --- | ------- |
| users         | array   | -   |         |
|   \[0]        | object  | -   |         |
|       name    | string  | 5   | Alice   |
|       age     | number  | 2   | 30      |
|       active  | boolean | -   | true    |
|   \[1]        | object  | -   |         |
|       name    | string  | 3   | Bob     |
|       age     | number  | 2   | 25      |
|       active  | boolean | -   | false   |
|   \[2]        | object  | -   |         |
|       name    | string  | 7   | Charlie |
|       tags    | array   | -   | \[]     |
|       profile | null    | -   |         |

## 実装コード（コピペで動作します）

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>JSON Viewer</title>
</head>
<body>
  <table id="respons" border="1" cellpadding="4" cellspacing="0" style="border-collapse: collapse; font-family: sans-serif;">
    <tr>
      <th style="text-align: left;">キーと階層</th>
      <th style="text-align: left;">型</th>
      <th style="text-align: left;">文字数</th>
      <th style="text-align: left;">値</th>
    </tr>
  </table>

  <script>
    const jsonData = {
      users: [
        { name: "Alice", age: 30, active: true },
        { name: "Bob", age: 25, active: false },
        { name: "Charlie", tags: [], profile: null }
      ]
    };

    const table = document.getElementById('respons');

    function getType(value) {
      if (value === null) return 'null';
      if (Array.isArray(value)) return 'array';
      return typeof value;
    }

    function escapeHTML(str) {
      return String(str)
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;");
    }

    function renderJSON(data, parentKey = 'respons', depth = 0) {
      const indent = '&nbsp;&nbsp;&nbsp;&nbsp;'.repeat(depth);

      if (Array.isArray(data)) {
        data.forEach((item, index) => {
          const rowId = `${parentKey}-${index}`;
          const type = getType(item);
          const charCount = (type === 'string') ? item.length : (['number'].includes(type) ? String(item).length : '-');
          const valueDisplay = (type === 'array' && item.length === 0) ? '[]' :
                               (['object', 'array'].includes(type)) ? '' :
                               escapeHTML(item);
          const label = `[${index}]`;

          const row = document.createElement('tr');
          row.id = rowId;

          row.innerHTML = `
            <td style="white-space: nowrap;">${indent}${label}</td>
            <td>${type}</td>
            <td>${charCount}</td>
            <td>${valueDisplay}</td>
          `;
          table.appendChild(row);

          if (type === 'object' || type === 'array') {
            renderJSON(item, rowId, depth + 1);
          }
        });
      } else if (typeof data === 'object' && data !== null) {
        for (const key in data) {
          const value = data[key];
          const rowId = `${parentKey}-${key}`;
          const type = getType(value);
          const charCount = (type === 'string') ? value.length : (['number'].includes(type) ? String(value).length : '-');
          const valueDisplay = (type === 'array' && value.length === 0) ? '[]' :
                               (['object', 'array'].includes(type)) ? '' :
                               escapeHTML(value);
          const label = key;

          const row = document.createElement('tr');
          row.id = rowId;

          row.innerHTML = `
            <td style="white-space: nowrap;">${indent}${label}</td>
            <td>${type}</td>
            <td>${charCount}</td>
            <td>${valueDisplay}</td>
          `;
          table.appendChild(row);

          if (type === 'object' || type === 'array') {
            renderJSON(value, rowId, depth + 1);
          }
        }
      }
    }

    renderJSON(jsonData);
  </script>
</body>
</html>
```

## 利用シーン・応用アイデア

- API開発中のレスポンス確認用ツールとして
- ログファイルや設定ファイルの可視化
- フロントエンドのデバッグ表示
- フォームの動的出力テンプレートとして活用


## おわりに

今回は、**構造とデータ型を明示的に表示するJSONビューア**をブラウザ上で簡単に実装できる方法を紹介しました。
この記事が、皆さんの開発やデバッグ効率向上に役立てば幸いです！