JSONをHTMLに変換するPythonプログラム

## 内容
JSONデータをHTML形式に変換するPythonプログラムを作成してみました。

例えば、以下のjsonファイルを入力とした場合、
``` json:input.json
{
    "person": {
        "name": "John Doe",
        "age": 30,
        "isStudent": false,
        "favoriteColors": ["Blue", "Green", "Red"],
        "address": {
            "street": "123 Main Street",
            "city": "Anytown",
            "country": "United States"
        }
    }
}
```

以下のHTMLを生成します。
<img width="400" alt="378e6597-b6b4-c86f-2fa3-f9569fe05af7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63331/378e6597-b6b4-c86f-2fa3-f9569fe05af7.png">


## プログラムの概要
このプログラムは、JSONデータを整形されたHTMLに変換し、カスタムスタイルを適用できるツールです。Python 3で書かれており、以下のライブラリを使用します。

- json：JSONデータの読み込みと処理
- argparse：コマンドライン引数の処理

プログラムの主な機能は以下の通りです。
- JSONデータをHTMLに変換する。
- ブール値、文字列、数値、配列、オブジェクト、関数など、データ型に対応してHTMLを生成する。
- カスタムのCSSスタイルを適用できる。


## プログラムの使用方法
まず、プログラムの本体（`json_to_html.py`）を作成します。ページ下方の「プログラムコード」項目にコードが記載されているので、コピーして保存します。

次にコマンドラインで実行します。以下は基本的な使用方法です。
``` shell
# パターン１
python3 json_to_html.py -t "My JSON Page" < input.json > output.html

# パターン2
cat input.json | python3 json_to_html.py -t "My JSON Page" > output.html
```
- input.json：変換元のJSONファイル名。
- `-t "My JSON Page"`：オプションで指定できるHTMLページのタイトル。※省略可能
- output.html：HTML出力先のファイル名。

## カスタムスタイルの適用
生成されたHTMLにカスタムスタイルを適用できるよう、以下のリンクが埋め込まれています。`style.css` を用意することで、スタイルのカスタマイズが可能です。
``` html
<link rel="stylesheet" type="text/css" href="style.css"/>
```
ページ下方の「CSSスタイルシート サンプル」項目にサンプルコードを記載しているので参考にしてください。

## プログラムコード
本体のコードはこちらになります。
``` python:json_to_html.py
#!/usr/bin/env python3

import json
import argparse
import sys

def make_html(data):
    if isinstance(data, bool):
        # BOOL
        if data:
            return '<div class="bool-true">True</div>'
        else:
            return '<div class="bool-false">False</div>'
    elif isinstance(data, str):
        # STRING
        if data == "":
            return '<span class="string empty">(Empty Text)</span>'
        else:
            return f'<span class="string">{data}</span>'
    elif isinstance(data, (int, float)):
        # INT or FLOAT
        if isinstance(data, int):
            class_name = "int number"
        else:
            class_name = "float number"
        return f'<span class="{class_name}">{data}</span>'
    elif isinstance(data, list):
        # ARRAY
        if len(data) > 0:
            html = '<table class="array">'
            for i, item in enumerate(data):
                html += '<tr>'
                html += '<td class="value array-value">'
                html += make_html(item)
                html += '</td></tr>'
            html += '</table>'
            return html
        else:
            return '<span class="array empty">(Empty List)</span>'
    elif isinstance(data, dict):
        # OBJECT
        html = '<table class="object">'
        for key, value in data.items():
            html += '<tr>'
            html += f'<th class="key object-key">{key}</th>'
            html += '<td class="value object-value">'
            html += make_html(value)
            html += '</td></tr>'
        html += '</table>'
        return html
    elif callable(data):
        # FUNCTION
        return f'<span class="function">{data}</span>'
    else:
        # UNKNOWN
        return f'<span class="unknown">{data}</span>'

def json_to_html(title):
    input_json = sys.stdin.read()
    data = json.loads(input_json)

    # HTMLを標準出力に出力
    sys.stdout.write('<html><head>')

    # タイトルを追加
    if title:
        sys.stdout.write(f'<title>{title}</title>')

    # スタイルシートをリンク
    sys.stdout.write('<link rel="stylesheet" type="text/css" href="style.css"/>')

    sys.stdout.write('</head><body>')

    if title:
        sys.stdout.write(f'<h1>{title}</h1>')

    # JSONデータをHTMLに変換
    html = make_html(data)
    sys.stdout.write(html)

    sys.stdout.write('</body></html>')

def main():
    parser = argparse.ArgumentParser(description='Convert JSON to HTML with an optional title')
    parser.add_argument('-t', '--title', nargs='?', const='', help='Title for the HTML page')
    args = parser.parse_args()

    json_to_html(args.title)

if __name__ == "__main__":
    main()

```

## CSSスタイルシート サンプル
スタイルシートのサンプルになります。
``` css:style.css
/* 基本のページスタイル */
body {
    font-family: Arial, sans-serif;
    margin: 20px;
}

h1 {
    color: #333;
    text-align: center;
}

/* ブール値のスタイル */
.bool-true, .bool-false {
    font-weight: bold;
}

.bool-true {
    color: green;
}

.bool-false {
    color: red;
}

/* 文字列のスタイル */
.string.empty {
    font-style: italic;
    color: #999;
}

/* 数値のスタイル */
.int, .float {
    font-weight: bold;
}

.number {
    color: blue;
}

/* 配列のスタイル */
.table.array {
    border-collapse: collapse;
    width: 100%;
}

.array-value {
    border: 1px solid #ddd;
    padding: 5px;
    text-align: center;
}

/* オブジェクトのスタイル */
.table.object {
    border-collapse: collapse;
    width: 100%;
}

.object-key {
    border: 1px solid #ddd;
    padding: 5px;
    font-weight: bold;
    text-align: right;
    background-color: #f0f0f0;
}

.object-value {
    border: 1px solid #ddd;
    padding: 5px;
    text-align: center;
}

/* 関数のスタイル */
.function {
    font-style: italic;
    color: #9900cc;
}

/* 未知のデータ型のスタイル */
.unknown {
    color: #ff0000;
}
```

以上