JavaScript Object Notation (JSON) は表現用の標準的なテキストベースの構造データ表現フォーマットで、JavaScript構造データオブジェクトの表記法をベースとしています。一般的にはWebアプリケーションでデータを転送する場合に使われます。(例えば、データをサーバからクライアントへ送信する場合などで、Webページに表示されたりすることもあり、その逆もあります)。頻繁に見かけるデータフォーマットですので、この節ではJavaScriptを使ってJSONをパースする、JSONのデータを参照する、JSONを作るなど、JSONを扱うために必要となる操作を説明します。

前提条件: 基礎的なコンピュータの知識、 HTMLとCSSへの基本的な理解、基礎的なJavaScriptの理解 (JavaScriptの第一歩JavaScriptの構成要素を参照) とオブジェクト指向JavaScriptの基本 (JavaScriptオブジェクトの基本を参照)。
目的: JSON内のデータの扱い方、JSONの作成方法について理解できること。

JSONとは何か

JSON はJavaScriptオブジェクトの構文に従ったテキストベースのフォーマットで、Douglas Crockfordによって普及されました。JSONはJavaScriptオブジェクトの構文に似ていますが、JavaScriptとは独立して扱われることがあり、多くのプログラミング言語環境にはJSONを読み込む(パースする)ことや生成するが機能があります。

JSONは文字列です。ですので、ネットワークを通してデータを転送したい場合に便利です。JSONデータへアクセスしたい場合は、JavaScriptオブジェクトへ変換する必要があります。JavaScriptにはJSONとJavaScriptオブジェクトを相互に変換できるメソッドを持ったJSONというグローバルなオブジェクトがあるので、その変換は大きな問題ではありません。

注記: 文字列をネイティブオブジェクトへ変換することはparsingと呼ばれており、ネイティブオブジェクトをネットワークを通して転送できように文字列へ変換することはstringificationと呼ばれています。

JSONはそれ自身をファイルとして格納することもできます。それはMIME typeapplication/jsonで、 .json という拡張子の付いたただのテキストファイルです。

JSONの構造

上で説明したように、JSONはJavaScriptオブジェクトにとても似ているフォーマットを持った文字列です。JSONでは通常のJavaScriptオブジェクトと同様な基本データ型(文字列、数値、配列、ブーリアンやその他のリテラル型)を使うことができます。これにより、以下のように階層的にデータを構成することができます。

{
  "squadName": "Super hero squad",
  "homeTown": "Metro City",
  "formed": 2016,
  "secretBase": "Super tower",
  "active": true,
  "members": [
    {
      "name": "Molecule Man",
      "age": 29,
      "secretIdentity": "Dan Jukes",
      "powers": [
        "Radiation resistance",
        "Turning tiny",
        "Radiation blast"
      ]
    },
    {
      "name": "Madame Uppercut",
      "age": 39,
      "secretIdentity": "Jane Wilson",
      "powers": [
        "Million tonne punch",
        "Damage resistance",
        "Superhuman reflexes"
      ]
    },
    {
      "name": "Eternal Flame",
      "age": 1000000,
      "secretIdentity": "Unknown",
      "powers": [
        "Immortality",
        "Heat Immunity",
        "Inferno",
        "Teleportation",
        "Interdimensional travel"
      ]
    }
  ]
}

もし、このオブジェクトをJavaScriptプログラムへ読み込んだ場合(例えば、例えば変数superHeroesへ代入する)、JavaScript オブジェクトの基本の節で見たのと同様に ドットや角括弧を使ってデータへアクセスすることができます。例としては以下のようになります。

superHeroes.homeTown
superHeroes['active']

さらに深い階層のデータへアクセスする場合は、単純にプロパティ名や配列のインデックスを連結します。例えば、メンバーリスト中2番目のヒーローの3番目の能力を参照する場合は、以下のようになります。

superHeroes['members'][1]['powers'][2]
  1. まず、変数名superHeroesを指定します。
  2. その中のmembersプロパティへアクセスしたいので、["members"]と指定します。
  3. membersにはオブジェクトの配列が格納されています. ここでは、配列内の2番目のオブジェクトへアクセスするので、[1]を指定します。
  4. そのオブジェクト内で、powers プロパティへアクセスするため, ["powers"]と指定します。
  5. powersプロパティは選択したヒーローの能力を含んだ配列となっており、その中の3番目が欲しいので、[2]と記述します。

注記: 上記のJSONはJSONTest.html で参照することができます。(ページ内のsource codeを参照してください)。ページを読み込んで見て、ブラウザのコンソールで変数内のデータにアクセスしてみてください。

JSON配列

ここまで見てきたように、JSONはJavaScriptオブジェクトとほとんど同じように扱うことができます。配列もJSONで使うことができ、例えば以下のようになります。

[
  {
    "name": "Molecule Man",
    "age": 29,
    "secretIdentity": "Dan Jukes",
    "powers": [
      "Radiation resistance",
      "Turning tiny",
      "Radiation blast"
    ]
  },
  {
    "name": "Madame Uppercut",
    "age": 39,
    "secretIdentity": "Jane Wilson",
    "powers": [
      "Million tonne punch",
      "Damage resistance",
      "Superhuman reflexes"
    ]
  }
]

これも有効なJSONであり、パースしたデータには配列のインデックスを指定するだけです。例えば、[0]["powers"][0]のように表記できます。

その他の注意点

  • JSONはただのデータフォーマットなので、プロパティのみを含むことができ、メソッドを含むことができません。
  • JSONでは文字列とプロパティ名をダブルクォートで括る必要があります。シングルクォートで括ることはできません。
  • 1つだけコンマやコロンが抜けているだけで無効なJSONになりえます。なので、使用しているデータが有効であるかについては注意してみなければなりません(機械的に作ったJSONのほうが、プログラムに問題がなければ、エラーは少なく済みます)。 JSONLint のようなアプリケーションを使ってバリデートすることもできます。
  • JSONは配列やオブジェクトに限らずJSON内に含むことができるデータ型のデータだけでも有効なJSONとなります。 例えば、1つだけの文字列や数値も有効なJSONです。

手を動かして学ぼう: JSONをさわってみる

それでは、Webサイト上でどのようにJSONを使うことができるか例を通して見てみましょう。

はじめに

まず、heroes.html と style.css のコピーをローカルに作成してください。後者は例題ページをスタイリングするためのCSSであり、前者は簡単な形式のHTMLです。

<header>
</header>

<section>
</section>

他には、この演習で書くJavaScriptを含んだ<script>要素があります。この時点では、<header>要素と<section>要素 を取得して、変数へ代入している2行コードのみが書かれています。

var header = document.querySelector('header');
var section = document.querySelector('section');

演習用のJSONデータはhttps://mdn.github.io/learning-area/javascript/oojs/json/superheroes.jsonに用意してあります。

そのデータを演習ページに読み込んで、それを表示するのにいくらかのDOM操作を行います。最終的には、以下の画像のようになります。

JSONの取得

JSONを取得するために、XMLHttpRequest (XHR) と呼ばれるAPIを使います。このAPIはJavaScript経由でサーバーからリソース(画像、テキスト、JSON、HTMLスニペットなど)を取得するのにとても便利なオブジェクトです。つまり、ページ全体を再読み込みせずに、ページの一部のみを更新することができます。このAPIで、より反応性のあるページを作れますし、とてもおもしろそうですが、残念なことに、より詳細なことはこの記事の範疇を超えてしまっています。

  1. まず、取得したいJSONがあるURLを変数へ代入します。次のコードをJavaScriptの最後の行へ追加してください。
  2. var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
  3. HTTPリクエストを作成するのに、new を使ってXMLHttpRequestから新しいリクエストオブジェクトをつくる必要があります。先ほどのコードの下に、次のコードを追加してください。
    var request = new XMLHttpRequest();
  4. 新しいリクエストを開始するのにはopen() メソッドを使います。 次のコードを追加してください。
    request.open('GET', requestURL);

    このメソッドは最低2つのパラメータを引数として取ります(他に任意の引数を与えることもできます)。今回の簡単な例では、次の2つの必須パラメータのみを利用します。

    • リクエストを開始する際にHTTPのメソッドを決める必要があります。今回のケースでは、単純にデータを取得するだけですのでGETが良いでしょう。
    • リクエストを送る先のURL。今回はJSONファイルが置かれているURLです。
  5. 次に、以下の2行のコードを追加してください。XHRオブジェクトがサーバから返されるデータを判断できるようにresponseTypeにJSONを指定します。すると、ブラウザ側でJavaScriptオブジェクトへ変換してくれます。それから、send() メソッドでリクエストを送信します。
    request.responseType = 'json';
    request.send();
  6. 最後に、サーバからのレスポンスを待ち、それを処理するコードを用意するので、以下のコードをこれまでのコードの下に追加してください。
    request.onload = function() {
      var superHeroes = request.response;
      populateHeader(superHeroes);
      showHeroes(superHeroes);
    }

ここでは、先ほどのリクエストに対するレスポンス(response プロパティから取得できます)をsuperHeroesという変数へ代入しています。つまり、この変数にJSONを元にに生成されたJavaScriptオブジェクトが格納されているということです! それから2つの関数をそのオブジェクトを引数として与えて呼び出しています。最初の関数は引数のデータを<header> へ埋め込み、2つ目は各ヒーローごとのインフォメーションカードを作り、<section>へ埋め込みます。

上記の処理は、リクエストオブジェクトでloadイベントが発生した時に呼び出される関数(onloadを参照) に記述しました。このイベントはレスポンスがうまく取得できた場合に呼び出されるので、 request.responseを使って何か処理をしようとしたときに、それが必ず利用できることが保証されています。

ヘッダーへの値のセット

ここまでで、JSONの取得とJavaScriptオブジェクトへの変換ができました、先ほどの2つの関数を実装して使ってみましょう。まずはじめに、以下のコードをこれまでのコードの下に追加してください。

function populateHeader(jsonObj) {
  var myH1 = document.createElement('h1');
  myH1.textContent = jsonObj['squadName'];
  header.appendChild(myH1);

  var myPara = document.createElement('p');
  myPara.textContent = 'Hometown: ' + jsonObj['homeTown'] + ' // Formed: ' + jsonObj['formed'];
  header.appendChild(myPara);
}

JSONから変換したJavaScriptオブジェクトであるjsonObjを使います。まず、createElement()<h1> 要素を生成、そのtextContent プロパティにJSONのsquadNameプロパティをセット、それをヘッダー要素でappendChild()追加します。次には、要素の生成、テキストのセット、ヘッダ要素への追加という同じような操作をパラグラフ要素でも行います。セットするテキストの値がhomeTownformed プロパティの文字列を結合したものであるという点だけが異なります。

ヒーローインフォメーションカードの作成

次に、以下の関数をコードの下へ追記してください。この関数はスーパーヒーローカードの作成と画面表示を行います。

function showHeroes(jsonObj) {
  var heroes = jsonObj['members'];
      
  for (var i = 0; i < heroes.length; i++) {
    var myArticle = document.createElement('article');
    var myH2 = document.createElement('h2');
    var myPara1 = document.createElement('p');
    var myPara2 = document.createElement('p');
    var myPara3 = document.createElement('p');
    var myList = document.createElement('ul');

    myH2.textContent = heroes[i].name;
    myPara1.textContent = 'Secret identity: ' + heroes[i].secretIdentity;
    myPara2.textContent = 'Age: ' + heroes[i].age;
    myPara3.textContent = 'Superpowers:';
        
    var superPowers = heroes[i].powers;
    for (var j = 0; j < superPowers.length; j++) {
      var listItem = document.createElement('li');
      listItem.textContent = superPowers[j];
      myList.appendChild(listItem);
    }

    myArticle.appendChild(myH2);
    myArticle.appendChild(myPara1);
    myArticle.appendChild(myPara2);
    myArticle.appendChild(myPara3);
    myArticle.appendChild(myList);

    section.appendChild(myArticle);
  }
}

始めに、JavaScriptオブジェクトのmembersプロパティを新しい変数に保存します。
この配列は複数のオブジェクトを持ち、オブジェクトはそれぞれのヒーローについての情報を持ちます。

次に、 for loop を使って配列の個々のオブジェクトをなめていきます。それぞれについて:

  1. 新しい要素をいくつか作ります: <article>一つ、<h2>一つ、三つの<p>と一つの<ul>です。
  2. <h2>の中身を今のヒーローの名前(name)にします。
  3. 三つの<p>の中身を、それぞれの secretIdentityage、リストにある情報を紹介していくために「超能力("Superpowers:")」で始まる行とします。
  4. powersプロパティを superPowers という新しい変数に保存します — この変数は今のヒーローの超能力のリストを持つ配列です。
  5. 別の for ループをつかって、今のヒーローの超能力をなめます — それぞれに対する <li> 要素を作成し、超能力をこの要素の中身とし、<ul>要素(myList変数)の listItemappendChild()を使って追加します。
  6. 最後の最後にやるのは、<h2><p><ul><article>(myArticle変数)の中身に追加し、それから<article><section>の中身に追加します。HTMLの中身として表示される順序になりますので、これらの要素を追加していく順序は重要です。

付記: 例を動かしてみるのに問題があったら、heroes-finished.html ソースコードを参照して見て下さい(こちらで ライブ実行 もできます)。

付記: もしJavaScriptオブジェクトにアクセスするのに使っているドット/ブラケット記法をなぞっていくのが難しければ、superheroes.json  のファイルを別のタブやテキストエディタで開いておいて、JavaScriptと並べて読んでいくとわかりやすいかもしれません。JavaScript オブジェクトの基本 記事にも戻って、ドット/ブラケット記法について読み替えしてみて下さい。

オブジェクトとテキスト間の変換

上の例はXHRリクエストでJSONレスポンスを直接JavaScriptオブジェクトに変換していたので、JavaScriptオブジェクトへのアクセスという面では単純でした。次の部分です:

request.responseType = 'json';

時にはこんなにツイていない場合もあります — 時には生のJSON文字列を受けとり、自分でオブジェクトに変換しなければならない場合もあるでしょう。またJavaScriptオブジェクトをネットワーク越しに送信したい場合、送信する前にJSON文字列に変換しなければならないでしょう。ツイている事に、ウェブ開発でこの二つの問題にはしょっちゅうでくわすので、ブラウザには組込みの JSON  オブジェクトが備わっていて、これは以下二つのメソッドを備えています:

  • parse(): JSON文字列を引数に取り、それに対するJavaScriptオブジェクトを返します。
  • stringify(): オブジェクトを引数に取り、等価なJSON文字列形式を返します。

一つめの方の動作例が heroes-finished-json-parse.html にあります (ソース を見て下さい) — ここでは前の方で作成した例と全く同じ事をしていますが、XHRでは生のJSON文字列を返させて、それをparse()でJavaScriptオブジェクトに変換しているところだけが異なります。コードの重要な箇所はこの部分です:

request.open('GET', requestURL);
request.responseType = 'text'; // now we're getting a string!
request.send();

request.onload = function() {
  var superHeroesText = request.response; // get the string from the response
  var superHeroes = JSON.parse(superHeroesText); // convert it to an object
  populateHeader(superHeroes);
  showHeroes(superHeroes);
}

で、ご想像の通り stringify()  は全く反対の向きに動作します。次の行をブラウザーのJavaScriptコンソールに一つずつ打ち込んでいって、実際に動かしてみて下さい:

var myJSON = { "name": "Chris", "age": "38" };
myJSON
var myString = JSON.stringify(myJSON);
myString

JavaScriptオブジェクトを作成してその中身を確認し、次に stringify() を使ってJSON文字列に変換し — 戻り値を新しい変数に保存しています — その値も確認しています。

まとめ

この節では、プログラム内で、JSONを生成する、JSONをパースする、JSONデータを参照するなど、JSONを扱う方法について簡単に説明しました。次の節では、オブジェクト指向JavaScriptについて見ていくことにします。

関連項目

 

このモジュール内の文書

 

ドキュメントのタグと貢献者

このページの貢献者: i12o, r-tamura
最終更新者: i12o,