2
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.

Python3でJSONのキーだけを再帰的に変換する

Posted at

🥚やりたいこと

JSONファイルのキー(=プロパティ)だけを別の文字表現に変換したい。
具体的に言うと、例えば、以下のようなJSONファイルがあるとする。

{
    "abc": 1,
    "def": {
        "def_abc": 2,
        "def_def": 3
    },
    "ghi": [
        "abc",
        "def",
        [
            {
                "ghi_abc": 4
            }
        ]
    ]
}

上記のJSONファイルを、以下のようにキーのみを大文字にしたり、

{
  "ABC": 1,
  "DEF": {
    "DEF_ABC": 2,
    "DEF_DEF": 3
  },
  "GHI": [
    "abc",
    "def",
    [
      {
        "GHI_ABC": 4
      }
    ]
  ]
}

キャメルケースに変換したりしたい。

{
  "abc": 1,
  "def": {
    "defAbc": 2,
    "defDef": 3
  },
  "ghi": [
    "abc",
    "def",
    [
      {
        "ghiAbc": 4
      }
    ]
  ]
}

この時に、ちゃんとネストの中のオブジェクト(上記で言うと{"ghi_abc": 4}のような)のキーもちゃんと変換できるようにするほか、単なるリテラルやリストには変換の影響がないようにしたい。

🐣やってみたこと

以下のようなPythonスクリプトで変換処理を実装してみた。

import json

def convert(data, func=lambda x: x):
    if isinstance(data, dict):
        obj = {}
        for key, value in data.items():
            obj[func(key)] = convert(value, func)
        return obj
    elif isinstance(data, list):
        obj = []
        for item in data:
            obj.append(convert(item, func))
        return obj
    else:
        return data

def to_uppercase(str):
    return str.upper()

def to_camelcase(str):
    arr = str.split('_')
    return arr[0] + ''.join(x.title() for x in arr[1:])

def main():
    with open('input.json', 'r') as input_file, open('output.json', 'w') as output_file:
        json_obj = json.load(input_file)
        converted = convert(json_obj, to_camelcase)
        json.dump(converted, output_file)

if __name__ == "__main__":
        main()

JSONのキーを再帰的に変換する

def convert(data, func=lambda x: x):
    if isinstance(data, dict):
        obj = {}
        for key, value in data.items():
            obj[func(key)] = convert(value, func)
        return obj
    elif isinstance(data, list):
        obj = []
        for item in data:
            obj.append(convert(item, func))
        return obj
    else:
        return data

この関数でJSONのキーを再帰的に変換している。
最初のif分岐で辞書か配列かそれ以外か判別し、以下のような処理を行う。

  • 辞書の場合 ... 辞書内の項目を順に見ていき、それぞれの項目のキーを変換する。値は再帰的にconvertへ引き渡す。
  • 配列の場合 ... 配列の項目を順に見ていき、その項目を再帰的にconvertへ引き渡す。
  • それ以外  ... そのまま返す。

ちなみに、この実装は以下のように簡潔に書ける。

def convert(data, func=lambda x: x):
    if isinstance(data, dict):
        return {func(key): convert(value, func) for key, value in data.items()}
    elif isinstance(data, list):
        return [convert(item, func) for item in data]
    else:
        return data

実際にキーをどう変換するかの処理は引数のfuncに委譲している。

🐥まとめ

  • json.load()で読み込んだJSONファイルをPythonオブジェクトに読み込んだ際、dict/list/その他で判別するだけで問題ないのだろうか。
  • 公式ドキュメントの変換表を見る限り問題なさそうだが……。
  • パイソニスタのレビュー・マサカリを頂ければ幸いです。
2
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
2
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?