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の制約には様々な種類があるので、今回の紹介で興味を持っていただいた方は、機会があればぜひ使ってみてください。