「結局 JSON ってなんなん?」という「私」へ捧ぐ

:relaxed:<底辺アマグラマだけどそろそろ JSON について知っておかねば!
:arrow_down:
:thinking:<……?

これだけあちこちで利用されているわりになんだかんだで色々なサイトを回る必要があったり下手したら間違いが書いてあったりしたので自分なりにまとめてみた。

## 概要

JavaScript Object Notation(以下 JSON と略す)とは、JavaScript の記法を基にした軽量データ記述言語である。 何度か改訂を行っており、現時点での最新の仕様は RFC 8259 および IETF STD 90 および ECMA-404 2nd edition である。

JSON で記述されたデータを利用するためのライブラリやツール(パーサ)は様々な言語に存在しており、あなたの素晴らしいシステムにすぐにでも JSON を取り入れることができる。

>:warning:
JSON はデータの記法を定義するが、データの扱いはパーサに依存する。 たとえば、JSON は``0``と``false``、``1``と``1.0``、``null``と``""``を区別するが、パーサはこれらを区別しないかもしれない。

## JSON と値

JSON は値を表記する言語であり JSON の実体とは値である。 JSON で扱う値には大きく分けて 2 種類存在するが、ここではそれらをプリミティブ値、複合値と呼び分けることにする。

>:bulb:
かつての仕様では、ここでいうところの複合値のみが正しい JSON テキストとされていた。 そのため、プリミティブ値をパースしようとすると例外を投げるパーサもあるかもしれない。

### プリミティブ値

プリミティブ値には「数値」「文字列値」「真理値」「空値」が存在する。

#### 数値

数値とは、ひとつの実数を表す値であり、その書式は十進数表記の整数か小数、またそれらの``e``または``E``による指数表記である。

>:warning:
整数部(ないし、指数表記の仮数部)の先頭に、不要な 0 や正号を置くことは禁止されている。 よって、``02``や``+3.5``といった表記は違法である。

>:warning:
IEEE 754 浮動小数点規格で標準化されている無限大と非数は、JavaScript にも実装されているが、JSON の数値としては扱えない:cry:。

#### 文字列値

文字列値とは、文字の並びを表す値であり、その書式はダブルクォーテーションで囲まれた、0 文字以上の任意の Unicode 文字の集まりである。

>:warning:
文字列値として制御文字を置くことは禁止されている。 よって、``"
"``といった表記は違法である。

>:bulb:
制御文字を扱う場合、バックスラッシュのあとに対応するラテン小文字 1 文字を後置することで表現する。 ただし、すべての制御文字を表現することはできない。 その場合は後述する Unicode 文字番号を用いる。

>|文字     |符号位置 |対応するラテン文字
|:-:|:-:|:-:
|後退     |U+0008   |b
|水平タブ |U+0009   |t
|改行     |U+000A   |n
|書式送り |U+000C   |f
|復帰     |U+000D   |r

>:warning:
バックスラッシュ(上述のエスケープに用いる)やダブルクォーテーション(文字列値の範囲を示す)を直接置くことは禁止されている。

>:bulb:
これらの記号を扱う場合、バックスラッシュのあとにその記号を後置することで表現する。 直接置くことを禁止されてはいないが、スラッシュを同様の方法で表現することもできる。

>:bulb:
また、U+0000 から U+FFFF までの任意の文字を``\uXXXX``(XXXX は十六進数 Unicode 文字番号)のように表現することもできる。

#### 真理値

真理値とは、真か偽かを表す値であり、その書式は``true``か``false``である。

>:warning:
真理値の表記はすべて小文字でなければならないとされている。 よって、``TRUE``や``False``といった表記は違法である。

#### 空値

空値とは、無効(不在、不明など)であることを表す値であり、その書式は``null``である。

>:warning:
空値の表記はすべて小文字でなければならないとされている。 よって、``NULL``や``Null``といった表記は違法である。

### 複合値

複合値には「配列」「オブジェクト」が存在する。

#### 配列

配列とは、順序をもった値(要素)の集合であり、その書式は角括弧で囲まれた、順序に従って並べられたカンマ区切りの 0 個以上の値である。

#### オブジェクト

オブジェクトとは、名前をもった値(メンバ)の集合であり、その書式は波括弧で囲まれた、名前となる文字列とコロンを前置されたカンマ区切りの 0 個以上の値である。

>:bulb:
オブジェクトは辞書や連想配列、あるいはハッシュテーブルなどと、名前はキーなどと呼ばれることもある。 これらはパーサがオブジェクトをどのように実装するかに由来すると思われる。

>:warning:
同じオブジェクトの中で同じ名前を使うべきではない(SHOULD NOT)。

### 可読性のための整形

値、メンバの名前、値を区切るカンマ、名前と値を分けるコロン、角括弧、波括弧はトークンと呼ばれ、トークンの前後には任意の数の空白文字類を含むことが許される。 空白文字類とは、スペース、水平タブ、改行、復帰である。これらはデータとしては無視されるが、人間にとっての可読性を向上させる場合がある。

### 正しい JSON の例

ここまでを踏まえて、以下を見てみる。 以下はすべて有効な値である(つまり、すべて正しい JSON である)。

```json
42
```

```json
3.14
```

```json
6.0e+23
```

```json
"Hello, world!"
```

```json
"八王子\n八　王　子\n八　　王　　子\n八　王　子\n八王子"
```

```json
[1,1,2,3,5,8,13,21]
```

```json
[false, true, "Aonyx cinereus"]
```

```json
["😇"]
```

```json
[]
```

```json
{"year":2018,"month":7,"day":13}
```

```json
[
  {
    "name": "Alice",
    "age": 16,
    "sex": "1",
    "partner": null
  },
  {
    "name": "Bob",
    "age": 52,
    "sex": "1",
    "partner": "Eve"
  }
]
```

```json
[{"":[[{"":{"":{"":[]}}}]]}]
```

## JSON のメタ情報

### 文字コード

JSON のエンコード方式は UTF-8 とするよう定められている。 また、インターネットで転送する場合、BOMless とされている。

### 改行コード

JSON は構文上改行コードを必要とせず、また改行と復帰の双方ともに空白文字類に含まれているため、改行コードをどのようにするかは JSON を(目視で)利用する環境に合わせてよい。

### 拡張子

JSON ファイルの規定の拡張子は[.json]である。 聞いたこともない拡張子かもしれないが決して得体のしれない気味の悪いファイルではないので安心してよい。

## JSON に関連する諸技術

### Base64

JSON を要求する API に対して画像などのバイナリデータを渡したいとき、よく利用されるノウハウが Base64 である。

Base64 は、バイナリデータの 6 bits ずつを対応する ASCII 文字に変換し、データ長保証のために 4$n$ 桁になるようパディングを行った形であり、そのため JSON の文字列値として扱うことができる。

>:warning:
Base64 によってエンコードすると、その原理上本来のデータよりデータ量が増大する。 具体的には、元のデータ量の $\frac{4}{3}$ 倍を下回らない最小の 4 の倍数となる。 これを考慮に入れて設計する必要がある。

>:warning:
Base64 の仕様は RFC 4648 にあるが、使用される環境による制約条件からいくつかのバリエーションが使われていることには留意する必要がある。 とくに 63 番目と 64 番目の ASCII 文字、それにパディングの有無ははっきりしない。

## 以上、翻訳調なまとめ終わり

「未完成の記事」というわけではないですが、何度も更新可能という強みを生かして「ここさえ見れば JSON の基礎知識はバッチリ!」という記事にしていきたい。いろんなサイトをハシゴするのは面倒ですしね…

NG ワード: 「公式の規格を読め」