PowerShellで複数行のjsonファイルを読み込んでプロパティ数分ループする方法

クラウド製品を利用しており、そのデータベース機能の定義ファイルをjson形式で生成する必要があり、地域 x テーブル種類数分の数百種類のjsonファイル生成を行ったメモ。

1. 地域とテーブルの一覧をjsonで作成
2. 一覧ファイルをPowerShellで読み込む
3. 最低限必要な整形処理を施し出力

結合が行えない等の制約があるデータベースなため、奇妙なテーブル構成なことはスルー。

### 元となるjsonファイル
```json:data.json
{
    "prefectures": [
        {
            "code": "Tokyo",
            "Name": "東京"
        },
        {
            "code": "Osaka",
            "Name": "大阪"
        },
        {
            "code": "Aichi",
            "Name": "愛知"
        },
        {
            "code": "Fukuoka",
            "Name": "福岡"
        }
    ],
    "tables": [
        {
            "code": "meeting_room",
            "name": "会議室",
            "field1": "id",
            "field2": "floar",
            "field3": "capacities"
        },
        {
            "code": "parking",
            "name": "駐車場",
            "field1": "id",
            "field2": "area",
            "field3": "space_number",
            "field4": "user_name",
            "field5": "car_number",
            "field6": "expire"
        }
    ]
}
```

以上のjsonファイルを元に生成したいjsonファイルは、
- Tokyo_metting_room.json
- Tokyo_parking.json
- Osaka_meeting_room.json
- Osaka_parking.json
- ...

### 複数行のjsonファイルを読み込む
jsonファイルはGet-Content -Path "filename.json"で読み込みが可能ですが、複数行にまたがるjsonファイルを読み込むには、引数に -Raw を追加する。

```PowerShell
Get-Content -Path "filename.json" -Raw | ConvertFrom-Json
```

もし、-Rawをつけずに複数行のjsonファイルを読み込むと、エラーが表示される

```PowerShell
Get-Content -Path "filename.json" | ConvertFrom-Json

ConvertFrom-Json : ':' または '}' ではなく無効なオブジェクトが渡されました。
```

### 読み込んだjsonファイルのカラムを取得
Get-Contentで読み込んだファイルはObject型、それをパイプでつなぎ、ConvertFrom-JsonでjsonファイルをPSCustomObject型に変換しています。

PSObjectのプロパティにアクセスすることで、Name値が取得できます。

```PowerShell
# $objectはPSCustomObjectに変換された、jsonデータ
$object.psobject.Properties | ForEach-Object {
    return $_.Name
}
```

## 完成系
これらを組み合わた、最終的なソースコード

```PowerShell:parse.ps1
<#
    Jsonデータから地域 x テーブル種類分のjsonを出力
#>
$file = "data.json" # 読み込む定義ファイル
$export = ".\results" # 出力ディレクトリ

# ファイルの存在確認
if (!(Test-Path -Path $file)) {
    exit
}

# 出力フォルダがなければ生成しておく
if (!(Test-Path -Path $export)) {
    New-Item -Path $export -ItemType Directory
}

# 定義ファイルを読み込む
# Get-Contentの引数に -Raw を入れることで複数行のjsonファイルを読み込む
Get-Content -Path $file -Encoding UTF8 -Raw | ConvertFrom-Json | ForEach-Object {
    $prefectures = $_.prefectures
    $tables = $_.tables

    # 地域数分ループする
    $prefectures | ForEach-Object {
        $pref_code = $_.code
        $pref_name = $_.name
        
        # $tables数分ループする
        $tables | ForEach-Object {
            $fields = $_
            # カラムの取得
            $columns = $fields.psobject.Properties | ForEach-Object {
                return $_.Name
            }
            $json = New-Object PSObject | Select-Object -Property $columns
            $table_name = $pref_code + "_" + $fields.code

            # カラムの数分ループする
            $columns | ForEach-Object {
                if ($_ -eq "code") {
                    $json.code = $pref_code + "_" + $fields.($_)
                } elseif ($_ -eq "name") {
                    $json.name = $pref_name + "_" + $fields.($_)
                } else {
                    $json.($_) = $fields.($_)
                }
            }

            # ファイル出力
            $export_directory = "${export}\${table_name}.json"
            $json | ConvertTo-Json | Out-File -FilePath $export_directory -Encoding utf8 -Force
        }
    }
}
```

##生成結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591064/93307add-0445-6f9b-5cd1-9be198e6bd91.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591064/72384e99-60ac-6463-b934-5ffea661b7bb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591064/9bf362f5-87ed-d1a6-f867-ac462c6ab282.png)