入門 JSON 2

no extension

「入門 JSON」が微妙に評判がいいみたいなので, 今回はもう少し踏み込んだ内容を書いてみたいと思います。 前回では JSON のデータフォーマットについて曖昧な表現や説明のまま流していますが, ここではもう少し厳密に見ていきます。 またもや長文です。 ご注意を。 なお, この記事は「Introducing JSON」日本語訳)と併せてご覧いただくことをお奨めします。

前回は JSON のデータ型について連想配列(members)と配列(array)の2つがあると説明しました。 しかし実際にはもうひとつオブジェクト(object)という型があります。 実は JSON ではこのオブジェクトがデータの基本になっています。 (説明が長くなるので前回はこの部分についてワザと端折りました)

オブジェクトは以下に示すようにブレス記号で囲んだ表現になります。

{ }
{ members }

ここで注意すべきなのはオブジェクトの内容は(空でないなら)必ず連想配列でなければならないことです。 例えば, 以下のようなオブジェクト-配列表現は許容されません。

{
  [ "element1", "element2" ]
}

またこのような表現も(一見正しいように見えますが)間違いです。

{
  { "name1" : "value1" },
  { "name2" : "value2" }
}

オブジェクトを示すブレス記号は単なる区切りではないということです。

次に連想配列ですが, 以下に示すような「名前:値」表現になります。

string : value
members, string : value

名前と値(value)の間はコロン記号で区切ります。 また連想配列を列挙する場合はカンマ記号で区切ります。 名前は必ず文字列(string)でなければなりません(文字列の形式については後述)。 そして配列は以下に示すように配列要素(elements)をブラケット記号で囲んだ表現になります。

[ elements ]

配列要素はひとつ以上の値をカンマ記号を区切り文字として列挙します。

value
elements, value

連想配列にしろ配列にしろ要素を列挙する場合はカンマ記号に注意してください。 例えば以下に示すように最後の要素の後にカンマ記号を入れるのは間違いです。

{ "array" : [
  "element1",
  "element2",
] }

連想配列および配列の値として許容できる形式は以下の通りです。

  • 文字列
  • 数値(number
  • オブジェクト
  • 配列
  • true, false
  • null

例えば配列要素として以下のように連想配列を直接入れることはできません。

{ "array" : [
  "name1" : "value1",
  "name2" : "value2"
] }

連想配列の要素を配列に入れる場合は, いったんオブジェクトにする必要があります。 (以下は連想配列の要素を個別にオブジェクトとする場合)

{ "array" : [
  { "name1" : "value1" },
  { "name2" : "value2" }
] }

文字列は文字(char)の列(chars)をダブルクォーテーション記号で囲んだ形式です。

""
"chars"

文字列として使える文字は通常の UNICODE 文字(ダブルクォーテーション記号およびバックスラッシュ記号(\)を除く)の他, バックスラッシュ記号からはじまるエスケープシーケンスが使えます。 利用可能なエスケープシーケンスを以下に示します。 C 系のプログラミング言語を扱っている方にはなじみのある表現だと思います。

\" quotation mark
\/ solidus
\\ reverse solidus
\b backspce
\f form feed
\n newline
\r carriage return
\t holizontal tab
\ufour-hex-digits charactor code for UNICODE

文字列データにおいて文字コード(厳密には文字エンコーディング)は常に悩みの種ですが, JSON においては UNICODE のみ許容しています。 したがって他の文字コード(Shift-JIS や EUC-JP など)を採用しているツール・サービスでは文字コードの変換処理も必要になります。

数値は10進数のみ(任意のN進数には対応していません)で, マイナス表現や指数表現を許容します。 例えば -1.23e+4 といった感じです。 +1001 といった表現は許容されません(必ずサプレスします)。 また数式表現も許容されません。 (前回紹介した xml2json.cgi は数値の解釈がうまくなく時々変換をしくじります。 私は Perl とか正規表現とかいったものはあまり得意ではないので, どなたかやってくださらないかなぁ...)

JSON は値としてオブジェクトを許容しているため, いくらでもデータを入れ子にすることができます。 この部分がデータフォーマットとしての柔軟性に繋がっていて, XML と同様に従来の RDBMS とはまた違ったデータベース操作を可能にしています。 (いくらでもデータを入れ子にできるというのはリスクでもあります。 データ同士の関連が循環しているような構造のデータベースを JSON に展開するときは注意が必要です)

JSON は Javascript の言語仕様をベースに作られたことは前回説明しましたが, これまで述べたように Javascript に比べると色々と制約が多いと言えます。 しかし実際には JSON は Javascript の eval 関数で簡単にインポートできてしまうため, Javascript で解釈可能な表現ならば何でも受け入れてしまう可能性があります。 特に問題になりそうなのは値(value)として関数(function)が記述されている場合です。

もし JSON データを自前で構文解析して Javascript 表現に変換できるのなら比較的安全に取り扱うことができます。 「JSON in JavaScript」では JSON.parse をパーサとして使うことを推奨しています。 例えば JSON データ json.txt を Javascript 上でインポートするには以下のようなコードにします。

<script type="text/javascript" src="jkl-parsexml.js"></script>
<script type="text/javascript" src="json.js"></script>
<script type="text/javascript">
  var url = "json.txt";
  var json = new JKL.ParseXML.Text(url);
  var text = json.parse();
  var data = JSON.parse(text);
</script>

json.txt の読み込みには前回も紹介した JKL.ParseXML ライブラリを利用しています。 このライブラリではクロスドメインの制約を超えられないのでご注意を。 クロスドメインの制約を超えるためには(前回紹介した) xml2json.cgi などの CGI を使う必要があります。

さて, これで JSON について大体のイメージができたのではないでしょうか。 この記事が少しでもお役に立てれば幸いです。