My Photo

« 「ペルソナ4 ザ・ゴールデン」クリア | Main | LaravelでHello World とか諸々 »

May 08, 2015

JSONのオブジェクトは順序性を持たない

jQueryでリクエストを投げてPHPで配列のデータをJSON形式で返すアプリケーションを考える。

サーバ側のプログラムのサンプル。

$data = array('5' => array('areaName' => '大森')
            , '7' => array('areaName' => '蒲田')
            , '3' => array('areaName' => '大井町'));

print json_encode($data);

クライアント側のプログラムのサンプル。data はPOSTパラメータでサーバ側では使っていないが、Ajaxでサーバ側にパラメータを渡す例として書いておいた。

var url = "./ajax.php";
var data = { "mode" : "hoge" };
$.post(url, data,
  function(data) {
    for (var key in data) {
      alert("key=" + key + ",areaName=" + data[key].areaName);
    }
  },
  "json"
);

これを実行するとクライアント側ではサーバ側の元のデータの順序、つまり「大森」、「蒲田」、「大井町」と表示されると期待してしまうが、実際は「大井町」、「大森」、「蒲田」の順で表示される。
#Firefoxの場合。他のブラウザでは試していない。
原因はPHPの json_encode() がPHPの配列をJSONのオブジェクトに変換してしまうためである。実際のレスポンスのボディは以下のようになっている(デコードしてインデントを付けている)。

{
  "5": {
    "areaName": "大森"
  },
  "7": {
    "areaName": "蒲田"
  },
  "3": {
    "areaName": "大井町"
  }
}

これは3つのプロパティを持つJSONオブジェクトであり、配列ではないのでプロパティに順序なんてない。実際の出力の順序を見るとプロパティ名の降順で出力しているように見える。たまたまかもしれないが。

対策としては、サーバ側で json_encode() を使うのをやめて、PHPの配列を受け取ってJSON形式の配列を返す処理を自前で書けばいい。
修正したコードを以下に示す。下記のサーバ側コードで json_encode() の代わりの関数 json_array_encode() は汎用的なものではなく、配列のデータの形式が決まっているものとしてその形式だけにとりあえず対応したものである。json_array_encode() ではareaNameの値をUNICODEコードポイントの文字列に変換するために json_encode() を使っている。

サーバ側

$data = array('5' => array('areaName' => '大森')
            , '7' => array('areaName' => '蒲田')
            , '3' => array('areaName' => '大井町'));

print json_array_encode($data);

exit;

function json_array_encode($data) {
	$buf = array();
	
	foreach ($data as $k => $v) {
		$buf[] = '{"areaId":"' . $k . '","areaName":' . json_encode($v['areaName']) . '}';
	}

	return '[' . implode(',', $buf) . ']';
}

クライアント側

var url = "./ajax.php";
var data = { "mode" : "aaa" };
$.post(url, data,
  function(data) {
    for (var key in data) {
      alert("areaId=" + data[key].areaId + ",areaName=" + data[key].areaName);
    }
  },
  "json"
);

修正後のレスポンスのボディは以下のようにオブジェクトではなく配列となっている。
表示の順序は「大森」、「蒲田」、「大井町」とサーバ側のPHPの配列の順序どおりになる。

[
  {
    "areaId": "5",
    "areaName": "大森"
  },
  {
    "areaId": "7",
    "areaName": "蒲田"
  },
  {
    "areaId": "3",
    "areaName": "大井町"
  }
]

参考ページ: PHPと異なり,JavaScriptの連想配列とfor in構文には順序の概念がないので注意すること - プログラミングとIT技術をコツコツ勉強するブログ

« 「ペルソナ4 ザ・ゴールデン」クリア | Main | LaravelでHello World とか諸々 »

JavaScript」カテゴリの記事

PHP」カテゴリの記事

Comments

Post a comment

(Not displayed with comment.)

TrackBack

TrackBack URL for this entry:
http://app.cocolog-nifty.com/t/trackback/26461/61560368

Listed below are links to weblogs that reference JSONのオブジェクトは順序性を持たない:

« 「ペルソナ4 ザ・ゴールデン」クリア | Main | LaravelでHello World とか諸々 »

April 2017
Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            
無料ブログはココログ

日本blog村

  • にほんブログ村 IT技術ブログへ
  • にほんブログ村 アニメブログへ
  • にほんブログ村 サッカーブログ アルビレックス新潟へ

好きな音楽家

メモ

XI-Prof