原文: JSON Stringify Example – How to Parse a JSON Object with JS

JSON、または JavaScript Object Notation は、私たちの身の回りにあります。ウェブアプリを使用したことがあれば、そのウェブアプリがデータを構造化したり、保存したり、サーバーとデバイス間で送信したりするために JSON を使用している可能性が非常に高いでしょう。

この記事では、まず JSON と JavaScript の違いについて簡単に説明し、次にブラウザと Node.js プロジェクトで JSON を解析するさまざまな方法について説明します。

JSON と JavaScript の違い

JSON は通常の JavaScript のように見えますが、JSON はテキストファイルと同様のデータ形式と考える方が良いでしょう。JSON は JavaScript の構文を基にしているため、非常に似ています。

JSON オブジェクトと JSON 配列を見て、それらを JavaScript の物と比較してみましょう。

JSON オブジェクトと JavaScript オブジェクトリテラルの違い

まず、こちらが JSON オブジェクトです:

{
  "name": "Jane Doe",
  "favorite-game": "Stardew Valley",
  "subscriber": false
}
jane-profile.json

JSON オブジェクトと通常の JavaScript オブジェクト (オブジェクトリテラルとも呼ばれます) の主な違いは、引用符に関係しています。JSON オブジェクトのすべてのキーと文字列型の値は、ダブルクォーテーション (") で囲まれている必要があります。

JavaScript のオブジェクトリテラルはもう少し柔軟です。オブジェクトリテラルでは、キーや文字列を必ずしもダブルクォーテーションで囲む必要はありません。代わりに、シングルクォーテーション (') を使用するか、キーに関しては引用符を使用しないことも可能です。

上記のコードを JavaScript のオブジェクトリテラルとして表すと、次のように書くことができます:

const profile = {
  name: 'Jane Doe',
  'favorite-game': 'Stardew Valley',
  subscriber: false
}

キー 'favorite-game' がシングルクォーテーションで囲まれていることに注意してください。オブジェクトリテラルでは、単語がダッシュ (-) で区切られているキーは引用符で囲む必要があります。

引用符を避けたい場合は、キーをキャメルケース (favoriteGame) に書き直すか、単語をアンダースコアで区切る (favorite_game) ことができます。

JSON 配列と JavaScript 配列の違い

JSON 配列は、JavaScript の配列とほぼ同じように動作し、文字列、ブール値、数値、および他の JSON オブジェクトを含むことができます。たとえば次のような配列があるとします:

[
  {
    "name": "Jane Doe",
    "favorite-game": "Stardew Valley",
    "subscriber": false
  },
  {
    "name": "John Doe",
    "favorite-game": "Dragon Quest XI",
    "subscriber": true
  }
]
profiles.json

これを素の JavaScript で書き直した例がこちらです:

const profiles = [
  {
    name: 'Jane Doe',
    'favorite-game': 'Stardew Valley',
    subscriber: false
  },
  {
    name: 'John Doe',
    'favorite-game': 'Dragon Quest XI',
    subscriber: true
  }
];

文字列としての JSON

JSON にオブジェクトと配列があるのなら、それらをプログラム内で通常の JavaScript のオブジェクトリテラルや配列のように使用できるのではないかと思っているかもしれません。

それができない理由は、JSON は実際には単なる文字列であるからです。

たとえば、上記の jane-profile.jsonprofiles.json のように、JSON を別のファイルに書き込むと、そのファイルは実際には JSON オブジェクトや配列の形をしたテキストを含んでいます。その形式がたまたま JavaScript のように見えるだけです。

そして、API にリクエストを送信すると、次のようなものが返ってきます:

{"name":"Jane Doe","favorite-game":"Stardew Valley","subscriber":false}

テキストファイルの場合と同様に、プロジェクトで JSON を使用したい場合は、これを解析して、プログラミング言語が理解できる形式に変更する必要があります。たとえば、Python で JSON オブジェクトを解析すると、辞書型のデータが作成されます。

その理解をもとに、JavaScript で JSON を解析するさまざまな方法を見てみましょう。

ブラウザで JSON を解析する方法

ブラウザで JSON を扱う場合、たいていは API を介してデータを受信または送信します。

いくつかの例を見てみましょう。

fetch を使用して JSON を解析する方法

API からデータを取得する最も簡単な方法は、fetch を使用することです。fetch には .json() メソッドが含まれており、JSON レスポンスを使用可能な JavaScript オブジェクトリテラルや配列へと簡単に解析できます。

以下は、Chuck Norris Jokes API から開発者向けのジョークを取得するために、fetch を使用して GET リクエストを行うコードです:

fetch('https://api.chucknorris.io/jokes/random?category=dev')
  .then(res => res.json()) // the .json() method parses the JSON response into a JS object literal
  .then(data => console.log(data));

ブラウザでそのコードを実行すると、コンソールに次のような内容がログされます:

{
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "elgv2wkvt8ioag6xywykbq",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/elgv2wkvt8ioag6xywykbq",
    "value": "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."
}

これは JSON オブジェクトのように見えますが、実際には JavaScript のオブジェクトリテラルであり、プログラム内で自由に使用できます。

JSON.stringify() を使用して JSON を文字列に変換する方法

しかし、API にデータを送信したい場合はどうすれば良いでしょうか?

たとえば、他の人が後で読めるように Chuck Norris のジョークを Chuck Norris Jokes API に送信したいとします。

まず、ジョークを JavaScript のオブジェクトリテラルとして書きます:

const newJoke = {
  categories: ['dev'],
  value: "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."
};

API にデータを送信するので、newJoke オブジェクトリテラルを JSON 文字列に変換する必要があります。

幸いにも、JavaScript にはそのための非常に役立つメソッド、JSON.stringify() が含まれています:

const newJoke = {
  categories: ['dev'],
  value: "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."
};

console.log(JSON.stringify(newJoke)); // {"categories":["dev"],"value":"Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."}

console.log(typeof JSON.stringify(newJoke)); // string

この例では、オブジェクトリテラルを JSON 文字列に変換していますが、JSON.stringify() は配列にも使えます。

あとは、JSON 文字列化されたジョークを POST リクエストで API に送信するだけです。

Chuck Norris Jokes API には実際にはこの機能はありません。しかし、もしこの機能があるとしたら、コードは次のようになるでしょう:

const newJoke = {
  categories: ['dev'],
  value: "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."
};

fetch('https://api.chucknorris.io/jokes/submit', { // fake API endpoint
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(newJoke), // turn the JS object literal into a JSON string
})
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => {
    console.error(err);
  });

これで、fetch を使用して受信した JSON を解析し、JSON.stringify() を使用して JavaScript のオブジェクトリテラルを JSON 文字列に変換できました。

ブラウザでローカル JSON ファイルを操作する方法

残念ながら、ブラウザでローカルの JSON ファイルをロードすることはできません (またはお勧めしません)。

fetch は、ローカルファイルを読み込もうとするとエラーをスローします。たとえば、いくつかのジョークが含まれている JSON ファイルがあるとします:

[
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "elgv2wkvt8ioag6xywykbq",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/elgv2wkvt8ioag6xywykbq",
    "value": "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."
  },
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "ae-78cogr-cb6x9hluwqtw",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/ae-78cogr-cb6x9hluwqtw",
    "value": "There is no Esc key on Chuck Norris' keyboard, because no one escapes Chuck Norris."
  }
]
jokes.json

そして、それを解析して、シンプルな HTML ページ上にジョークのリストを作成したいとします。

以下のようなページを作成して、ブラウザで開くとします:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width" />
    <title>Fetch Local JSON</title>
  </head>
  <script>
    fetch("./jokes.json", { mode: "no-cors" }) // disable CORS because path does not contain http(s)
      .then((res) => res.json())
      .then((data) => console.log(data));
  </script>
</html>
index.html

コンソールには、次のように表示されます:

Fetch API cannot load file://<path>/jokes.json. URL scheme "file" is not supported

デフォルトでは、ブラウザはセキュリティ上の理由からローカルファイルへのアクセスを許可しません。これは良いことであり、この動作を迂回しようとしてはいけません。

代わりに、最善の方法はローカル JSON ファイルを JavaScript に変換することです。幸いなことに、JSON の構文は JavaScript と非常に似ているため、簡単に変換できます。

必要なのは新しいファイルを作成し、JSON を変数として宣言することだけです:

const jokes = [
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "elgv2wkvt8ioag6xywykbq",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/elgv2wkvt8ioag6xywykbq",
    "value": "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."
  },
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "ae-78cogr-cb6x9hluwqtw",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/ae-78cogr-cb6x9hluwqtw",
    "value": "There is no Esc key on Chuck Norris' keyboard, because no one escapes Chuck Norris."
  }
]
jokes.js

そして、それを別個のスクリプトとしてページに追加します:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width" />
    <title>Fetch Local JSON</title>
  </head>
  <script src="jokes.js"></script>
  <script>
    console.log(jokes);
  </script>
</html>

これで、jokes 配列をコードで自由に使用できるようになります。

または JavaScript モジュールを使用することもできますが、これはこの記事の範囲外です。

では、Node.js を使用してローカル JSON ファイルを操作したい場合はどうすれば良いでしょうか?それを見てみましょう。

Node.js で JSON を解析する方法

Node.js は、ブラウザの外で JavaScript を実行することができる JavaScript ランタイムです。Node.js についてはこちらで詳しく説明されています。

Node.js を使用してローカルのコンピューター上でコードを実行するか、サーバー上で完全な Web アプリケーションを実行するかに関わらず、JSON を操作する方法を知っておくと良いでしょう。

以下の例でも、同じ jokes.json ファイルを使用します:

[
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "elgv2wkvt8ioag6xywykbq",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/elgv2wkvt8ioag6xywykbq",
    "value": "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."
  },
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "ae-78cogr-cb6x9hluwqtw",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/ae-78cogr-cb6x9hluwqtw",
    "value": "There is no Esc key on Chuck Norris' keyboard, because no one escapes Chuck Norris."
  }
]
jokes.json

require() を使用して JSON ファイルを解析する方法

最も簡単な方法から始めましょう。

ローカルの JSON ファイルがある場合、require() を使用して、他の Node.js モジュールと同様にロードするだけで使用できます:

const jokes = require('./jokes.json');

JSON ファイルは自動的に解析され、プロジェクトで使用できるようになります:

const jokes = require('./jokes.json');

console.log(jokes[0].value); // "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."

これは同期的な方法であることに注意してください。つまり、プログラムは続行する前にファイル全体を解析し終わるまで停止します。非常に大きな JSON ファイルはプログラムの遅延を引き起こす可能性があるため、注意が必要です。

また、この方法で JSON を解析すると、全体がメモリに読み込まれるため、この方法は静的な JSON ファイルに使用するのが最適です。プログラムが実行中に JSON ファイルが変更されると、プログラムを再起動して更新された JSON ファイルを解析するまで、それらの変更にアクセスできません。

fs.readFileSync()JSON.parse() を使用して JSON ファイルを解析する方法

これは、Node.js プロジェクトで JSON ファイルを解析するどちらかというと古典的な方法 (他に適切な言い方がないので) です。ファイルを fs (ファイルシステム) モジュールで読み取り、次に JSON.parse() で解析します。

fs.readFileSync() メソッドの使い方を見てみましょう。まず、プロジェクトに fs モジュールを追加します:

const fs = require('fs');

次に、jokes.json ファイルの出力を保存する新しい変数を作成し、それに fs.readFileSync() を割り当てます:

const fs = require('fs');
const jokesFile = fs.readFileSync();

fs.readFileSync() にはいくつかの引数があります。最初の引数は読み込みたいファイルへのパスです:

const fs = require('fs');
const jokesFile = fs.readFileSync('./jokes.json');

しかし、この状態で jokesFile をコンソールにログ出力すると、次のようになります:

<Buffer 5b 0a 20 20 7b 0a 20 20 20 20 22 63 61 74 65 67 6f 72 69 65 73 22 3a 20 5b 22 64 65 76 22 5d 2c 0a 20 20 20 20 22 63 72 65 61 74 65 64 5f 61 74 22 3a ... 788 more bytes>

これは、fs モジュールがファイルを読み取っているものの、ファイルのエンコーディングや形式がわかっていないことを意味します。fs は JSON のようなテキストベースのファイルだけでなく、ほとんどのファイルを読み込むために使用できるため、ファイルがどのようにエンコードされているかを指定する必要があります。

テキストベースのファイルの場合、エンコーディングは通常 utf8 です:

const fs = require('fs');
const jokesFile = fs.readFileSync('./jokes.json', 'utf8');

今度は jokesFile をコンソールにログ出力すると、ファイルの内容が表示されます。

しかし、これまでのところ、単にファイルを読み取っているだけで、それはまだ文字列です。jokesFile を使用可能な JavaScript オブジェクトや配列に解析するために、別のメソッドを使用する必要があります。

そのために、JSON.parse() を使用します:

const fs = require('fs');
const jokesFile = fs.readFileSync('./jokes.json', 'utf8');
const jokes = JSON.parse(jokesFile);

console.log(jokes[0].value); // "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."

その名前が示すように、JSON.parse() は JSON 文字列を受け取り、JavaScript のオブジェクトリテラルまたは配列に解析します。

require メソッドと同様に、fs.readFileSync() は同期メソッドであり、JSON でも他の種類のファイルでも、大きなファイルを読み込む場合、プログラムを遅くする可能性があります。

また、それはファイルを 1 回読み取り、メモリに読み込みます。ファイルが変更された場合、いずれかの時点でファイルを再度読み込む必要があります。この処理を簡単にするために、ファイルを読み込むための簡単な関数を作成すると良いでしょう。

次のようになります:

const fs = require('fs');
const readFile = path => fs.readFileSync(path, 'utf8');

const jokesFile1 = readFile('./jokes.json');
const jokes1 = JSON.parse(jokesFile1);

console.log(jokes1[0].value); // "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."

// the jokes.json file changes at some point

const jokesFile2 = readFile('./jokes.json');
const jokes2 = JSON.parse(jokesFile2);

console.log(jokes2[0].value); // "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."

fs.readFile()JSON.parse() を使用して JSON を解析する方法

fs.readFile() メソッドは fs.readFileSync() に非常に似ていますが、非同期で動作します。これは、読み取るべき大きなファイルがあり、その処理が他のコードをブロックするのを避けたい場合に便利です。

基本的な例を以下に示します:

const fs = require('fs');

fs.readFile('./jokes.json', 'utf8');

これまでのところ、fs.readFileSync() と似ていますが、jokesFile のような変数には割り当てていません。非同期なので、fs.readFile() の後のコードはファイルの読み取りが完了する前に実行されます。

代わりに、コールバック関数を使用して、その内部で JSON を解析します:

const fs = require('fs');

fs.readFile('./jokes.json', 'utf8', (err, data) => {
  if (err) console.error(err);
  const jokes = JSON.parse(data);

  console.log(jokes[0].value);
});

console.log("This will run first!");

これにより、次のようにコンソールに出力されます:

This will run first!
Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris.

fs.readFileSync() と同様に、fs.readFile() もファイルをメモリに読み込みます。つまり、ファイルが変更された場合は、ファイルを再度読み込む必要があります。

また、fs.readFile() は非同期ですが、最終的には読み込んでいるファイル全体をメモリに読み込みます。巨大なファイルの場合は、Node.js のストリームを検討する方が良いかもしれません。

Node.js で JSON.stringify() を使用して JSON を文字列に変換する方法

最後に、Node.js で JSON を解析する場合、API の応答として JSON を返す必要があるかもしれません。

幸いなことに、これはブラウザと同じように機能します。JavaScript のオブジェクトリテラルや配列を JSON 文字列に変換するには、単に JSON.stringify() を使用します:

const newJoke = {
  categories: ['dev'],
  value: "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."
};

console.log(JSON.stringify(newJoke)); // {"categories":["dev"],"value":"Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."}

以上です!ブラウザと Node.js プロジェクトで JSON を操作する際に知っておくべきことについて、ほぼすべて説明しました。

さあ、思うままに JSON を解析したり文字列に変換したりしてください。

この記事に不足している点を見つけましたか?あなたのプロジェクトではどのように JSON を解析していますか?Twitter で教えてください。