1.初めに
この記事ではMacOS/LinuxでPythonでJsonSchemaを用いたcsvバリデーションを行う方法を解説します。
2.前提
動作環境
・python: 3.11.0
・ライブラリ:jsonschema: 4.17.3
・実行環境: mac OS 13.5
3.環境のセットアップ
下記の環境のセットアップにおいて、
venvを利用して、仮想環境のセットアップ行い、
jsonschemaのインストールを行なっています。
venvはPython 3.3から標準ライブラリとして取り込まれた仮想環境管理ツールであるため、追加のインストールは不要になります。
mkdir csv_validation_project cd csv_validation_project python -m venv venv source venv/bin/activate pip install jsonschema
4. Json Schemaについて
Json Schemaの基本構造
例えば、以下のようなJSON Schemaがあった場合、
{ "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer", "minimum": 0}, "email": {"type": "string", "format": "email"} }, "required": ["name", "age"] }
このSchemaは、
を要求しています。
requiredは、必須のプロパティを指定するリストです。nameとageが必須であることを示しています。
5. CSVデータの準備
バリデーションを行う対象となる以下のようなcsvファイルを用意します。
name,age,email John Doe,25,john.doe@example.com Jane Smith,30,jane.smith@example.com
6. CSVバリデーション用のJson Schemaを作成
csvカラムとJSON Schemaの対応付け
csvの各列と対応するJSONSchemaを作成します。
この時、csvの項目名と一致しているかどうかに気をつけてください。
{ "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer", "minimum": 0}, "email": {"type": "string", "format": "email"} }, "required": ["name", "age", "email"] }
データ型と制約の定義
上記の例では、年齢が負の値にならないようにするため、minimum属性を使っています。
また、メールアドレスが正しい形式であることを保証するためにformat属性を使用しています。
7. Json Schemaを用いたcsvファイルのバリデーション
下記に今回csvバリデーションを行うための全体のコードを記載します。main.py
import csv from jsonschema import ValidationError, Draft7Validator, FormatChecker # データを適切な方に変換する関数 def convert_type(value): try: # 整数に変換できるか試す return int(value) except ValueError: try: # 浮動小数点数に変換できるか試す return float(value) except ValueError: # どちらでも変換できない場合はそのまま返す return value # CSVを読み込む関数 def read_csv(file_path): with open(file_path, 'r', encoding='utf-8') as f: reader = csv.DictReader(f) data = [] for row in reader: # 各列のデータ型を変換 converted_row = {key: convert_type(value) for key, value in row.items()} data.append(converted_row) return data # JSON Schemaの定義 schema = { "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer", "minimum": 0}, "email": {"type": "string", "format": "email"} }, "required": ["name", "age", "email"] } # バリデーション関数 def validate_csv_data(data, schema): for i, row in enumerate(data): try: validator = Draft7Validator(schema, format_checker=FormatChecker()) validator.validate(row) print(f"Row {i}: OK") except ValidationError as e: print(f"Error at row {i}: {e.message}") # 実行部分 if __name__ == '__main__': data = read_csv('sample.csv') validate_csv_data(data, schema)
実行方法
main.pyとsample.csvを同じ階層に設置し、下記のコマンドを実行することでバリデーション結果を確認することができます。
$ python main.py Row 0: OK Row 1: OK (.venv)
バリデーション成功時の動作を確認できたため、次に失敗時の動作について確認します。
csvのデータにバリデーションエラーが発生するデータを挿入して実行してみます。
以下のようにcsvに追記します。
name,age,email John Doe,25,john.doe@example.com Jane Smith,30,jane.smith@example.com 12345,40,invalid@example.com Alex Johnson,-5,alex.johnson@example.com Emily Davis,28,a
そして、再度実行します。
すると、下記のようにエラーになったデータについて、
何がエラーかについて表示されます。
$ python main.py Row 0: OK Row 1: OK Error at row 2: 12345 is not of type 'string' Error at row 3: -5 is less than the minimum of 0 Error at row 4: 'a' is not a 'email' (venv)
これで基本的なバリデーションの実装は完了になります。
8. 応用
より複雑な制約を持ったスキーマを導入することもできます。
# JSON Schemaの定義 schema = { "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer", "minimum": 0}, "email": {"type": "string", "format": "email"}, "phone": {"type": "string", "pattern": "^[0-9]{2,4}-[0-9]{2,4}-[0-9]{3,4}$"}, }, "required": ["name", "age", "email"], "if": { "properties": { "age": {"minimum": 15}, }, }, "then": { "required": ["email", "phone"] }, }
このスキーマでは、18歳以上の場合に、emailとphoneが必須になる条件が追加されています。
また、電話番号が次の形式に従う必要があります
9.まとめ
JsonSchemaを使用することで、データが予想通りの形式と内容を持つことを保証し、不正なデータの入力や保存を防ぐことが可能になります。
また、JsonSchemaの制約には様々な種類があるので、今回の紹介で興味を持っていただいた方は、機会があればぜひ使ってみてください。