一括処理したいこと
HTTP通信において、次のような多次元のハッシュ(連想配列)を送信する場合、
let hash = {
text: "こんにちは",
user: {
name: "山田太郎",
email: "taro@yamada.com"
}
};
サーバへのリクエストは、次のようにURIエンコードして送信することになります。
text=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF&user[name]=%E5%B1%B1%E7%94%B0%E5%A4%AA%E9%83%8E&user[email]=taro%40yamada.com
この処理を、関数を使って一括でURIエンコードすることがこの記事の目的です。
また、ネストの階層が深くても処理できるような工夫が必要です(これには、関数の再帰呼出しを使用します)。
なお、jQueryを使うと自動でURIエンコードをしてくれますし、JavaScriptでもJSON形式を使えば面倒な処理は不要になります。
そのため、この記事のような処理をすることは、あまり多くないかもしれません。
データ加工のイメージ
多次元ハッシュをURIエンコードで送信する場合のルールは次のような感じです。
- ネストしている要素は1つずつ独立させる
- 下の階層のキーは、
[ ]
で括って、上の階層のキーと繋げて1つのキーとする
text: こんにちは
user[name]: 山田太郎
user[email]: taro@yamada.com
なお、ネストが3階層以上になる場合のキーはuser[name][firstname]
のように角括弧で続けて記述します。
そして、URIの形式なので、次の加工も必要です。
- キーと値は
=
で関連付ける - 要素と要素は
&
で接続する
text=こんにちは&user[name]=山田太郎&user[email]=taro@yamada.com
最後に、URIエンコード(UTF-8)で変換します(再掲)。
text=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF&user[name]=%E5%B1%B1%E7%94%B0%E5%A4%AA%E9%83%8E&user[email]=taro%40yamada.com
一括変換する関数
一括変換する関数は、次のとおりです。
// テスト用のハッシュ(連想配列)
let hash = {
text: "こんにちは",
user: { name: "山田太郎", email: "taro@yamada.com" }
};
// 一括変換する関数
function encodeURIFromHash(data, stockKey="", prefix="&", suffix="") {
let resultStr = "";
if (typeof(data) === "object") { // 対象データがオブジェクトである場合は再帰呼出し
Object.keys(data).forEach(function(key) {
resultStr += encodeURIFromHash(data[key], stockKey + prefix + encodeURIComponent(key) + suffix, "[", "]");
});
} else { // 対象データがオブジェクトでなければ確定
resultStr = stockKey + "=" + encodeURIComponent(data);
}
if (stockKey === "") { resultStr = resultStr.slice(1); } //1文字目の不要な"&"又は"="を削除
return resultStr;
}
// 処理結果の表示
console.log(encodeURIFromHash(hash));
// 出力結果: text=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF&user[name]=%E5%B1%B1%E7%94%B0%E5%A4%AA%E9%83%8E&user[email]=taro%40yamada.com
encodeURIFromHash関数
の第1引数に、変換したいハッシュ形式のデータを指定すれば、戻り値としてURIエンコードされたデータが返されます。
ネストが続いている場合には、関数を再帰的に呼び出して、ネストが終わるまで処理を続けるようにしています。
再帰呼出しの例(階層が深い場合)
関数の再帰呼出しを使用しているので、次のような入り組んだハッシュ(連想配列)でも変換できます。
let hash = {
post: {
text: "こんにちは",
id: 348,
other: {
url: "https://www.yahoo.co.jp/",
style: {
layer1: "階層1",
layer2: "階層2"
}
}
},
user: {
name: "山田太郎",
email: "taro@yamada.com",
}
};
出力結果は、次のようになります。
let ans = encodeURIFromHash(hash);
console.log(ans); // 変換結果を表示
// 出力結果: post[text]=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF&post[id]=348&post[other][url]=https%3A%2F%2Fwww.yahoo.co.jp%2F&post[other][style][layer1]=%E9%9A%8E%E5%B1%A4%EF%BC%91&post[other][style][layer2]=%E9%9A%8E%E5%B1%A4%EF%BC%92&user[name]=%E5%B1%B1%E7%94%B0%E5%A4%AA%E9%83%8E&user[email]=taro%40yamada.com
console.log(decodeURIComponent(ans)); // 変換結果をデコード
// 出力結果: post[text]=こんにちは&post[id]=348&post[other][url]=https://www.yahoo.co.jp/&post[other][style][layer1]=階層1&post[other][style][layer2]=階層2&user[name]=山田太郎&user[email]=taro@yamada.com
最後に
挙動を確認しているのは、文字列型、数値型、Boolean型までです。
何らかの参考となれば幸いです。