1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaScriptの多次元ハッシュ(連想配列)を一括でURIエンコードする

Last updated at Posted at 2020-01-23

一括処理したいこと

HTTP通信において、次のような多次元のハッシュ(連想配列)を送信する場合、

sampleHash.js
let hash = { 
  text: "こんにちは",
  user: {
    name: "山田太郎",
    email: "taro@yamada.com"
  }
};

サーバへのリクエストは、次のようにURIエンコードして送信することになります。

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

この処理を、関数を使って一括で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

一括変換する関数

一括変換する関数は、次のとおりです。

sample.js
// テスト用のハッシュ(連想配列)
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エンコードされたデータが返されます。
ネストが続いている場合には、関数を再帰的に呼び出して、ネストが終わるまで処理を続けるようにしています。

再帰呼出しの例(階層が深い場合)

関数の再帰呼出しを使用しているので、次のような入り組んだハッシュ(連想配列)でも変換できます。

sampleHash2.js
let hash = { 
  post: {
    text: "こんにちは",
    id: 348,
    other: {
      url: "https://www.yahoo.co.jp/",
      style: {
        layer1: "階層1",
        layer2: "階層2"
      }
    }
  },
  user: {
    name: "山田太郎",
    email: "taro@yamada.com",
  }
};

出力結果は、次のようになります。

sample.js
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型までです。
何らかの参考となれば幸いです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?