Help us understand the problem. What is going on with this article?

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

一括処理したいこと

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした