Power Automate DesktopでJSONをCSVにする

# はじめに
ノーコードでWeb APIを利用してみようと思い、Power Automate Desktop（以下PAD）を使ってみています。PADにはWeb APIの返すJSONを[カスタムオブジェクト](https://learn.microsoft.com/ja-jp/power-automate/desktop-flows/variable-data-types#custom-object)に変換する「JSON をカスタム オブジェクトに変換」アクションがあり、PAD内で利用するには十分です。しかしJSONの中のリストをCSVとして保存しようとしたところ苦労しましたのでその内容を記事にしました。

# 環境
OS: Windows 11 Home
PADバージョン: 2.39.00239.23332

# 本文
## 概略
以下の手順でJSONをCSVとして保存します。
1\. リストを含むJSONを用意します。
2\. JSONをカスタムオブジェクトに変換します。
3\. リストカスタムオブジェクトの１番目の要素をJSONテキストに変換します。
4\. キーのリストを正規表現で要素のJSONテキストから取得します。
5\. キーのリストから空の[データテーブル](https://learn.microsoft.com/ja-jp/power-automate/desktop-flows/variable-data-types#datatable)を作成します。
6\. リストカスタムオブジェクトをFor eachでループし、データテーブルに行を追加します。
7\. データテーブルをCSVファイルに書き込みます。

## 手順
### JSONテキストを変数に設定する
ダミーのJSON文字列です。ここではこれを使用します。
「変数設定」アクションの値に貼り付けます。
```json:変数の設定
{
  "users": [
    {
      "_id": 1,
      "name": "Alice",
      "gender": "female",
      "age": 25
    },
    {
      "_id": 2,
      "name": "Bob",
      "gender": "male",
      "age": 32
    },
    {
      "_id": 3,
      "name": "Charlie",
      "gender": "male",
      "age": 28
    }
  ]
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/c5986a26-b8a6-5b60-3d8e-2cfc93989c82.png)


### JSONをカスタムオブジェクトに変換する
「JSON をカスタム オブジェクトに変換」アクションに先ほどのJSONテキストを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/e7c951a6-16fa-4ca9-5285-131383572268.png)


### リストの要素１つをJSONテキストに変換する
カスタムオブジェクトからキーのリストを取り出す方法としてJSONテキストを解析する方法を選択しました。そのためJSONオブジェクトから要素を取り出してJSONテキストに変換しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/d9475a8c-69e1-0f96-c2fb-2f118a4a106b.png)


### キーのリストを取得する
ここが今回の肝です。
JSONテキストからキーを取り出すために「テキストの解析」アクションを利用します。
正規表現は以下の通り、`{"`または`,"`と、`":`の間の最短文字列を取得するようにしています。
```:テキストの解析 - 検索するテキスト
(?<=[{,]").+?(?=":)
```
`正規表現である`をONにし、`最初の出現箇所のみ`はOFFにします。また、一致する結果を変数`ColumnNames`としています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/7c24a6fe-5908-f5dc-d689-b30d18aee932.png)


### データテーブルを作成します
下記のようにリストの頭に`^`を付けると列名として指定することができます。
```:変数の設定
%{ ^ColumnNames }%
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/4921a938-c7ef-87d2-e381-35944f8bd1ce.png)

リストの中の文字列を列名とした空のデータテーブルが作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/626beb34-b48e-3a2c-a013-13579683bcdb.png)


### データテーブルに要素を追加します
For eachを入れ子にしてそれぞれ行と列をデータテーブルとリストに追加しています。様々な列数に対応するためこのようにしています。
カスタムオブジェクトから値を取り出すのに`CurrentItem`にブラケットで`ColumnName`を指定して値を取り出します。

```:項目をリストに追加
%CurrentItem[ColumnName]%
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/7ee2471c-3e89-c927-5869-2802e950fd13.png)


### CSVファイルとして保存します
最後にデータテーブルをCSVファイルに書き込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/69887832-1036-3a7b-e86e-f2a6203b54b9.png)

### 作成したCSV
うまいこと保存されました。今回のサンプルではわかりませんが、ちゃんとエスケープも処理されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/bd6dcf2b-1565-e146-a1cf-c9ec35e0d2f3.png)


## 全体フロー
```:Main
SET Json TO $'''{
  \"users\": [
    {
      \"_id\": 1,
      \"name\": \"Alice\",
      \"gender\": \"female\",
      \"age\": 25
    },
    {
      \"_id\": 2,
      \"name\": \"Bob\",
      \"gender\": \"male\",
      \"age\": 32
    },
    {
      \"_id\": 3,
      \"name\": \"Charlie\",
      \"gender\": \"male\",
      \"age\": 28
    }
  ]
}'''
Variables.ConvertJsonToCustomObject Json: Json CustomObject=> JsonAsCustomObject
Variables.ConvertCustomObjectToJson CustomObject: JsonAsCustomObject.users[0] Json=> CustomObjectAsJson
Text.ParseText.RegexParse Text: CustomObjectAsJson TextToFind: $'''(?<=[{,]\").+?(?=\":)''' StartingPosition: 0 IgnoreCase: False Matches=> ColumnNames
SET DataTable TO { ^ColumnNames }
LOOP FOREACH CurrentItem IN JsonAsCustomObject.users
    Variables.CreateNewList List=> Row
    LOOP FOREACH ColumnName IN ColumnNames
        Variables.AddItemToList Item: CurrentItem[ColumnName] List: Row
    END
    Variables.AddRowToDataTable.AppendRowToDataTable DataTable: DataTable RowToAdd: Row
END
Folder.GetSpecialFolder SpecialFolder: Folder.SpecialFolder.Personal SpecialFolderPath=> MyDocuments
File.WriteToCSVFile.WriteCSV VariableToWrite: DataTable CSVFile: $'''%MyDocuments%\\sample.csv''' CsvFileEncoding: File.CSVEncoding.UTF8 IncludeColumnNames: True IfFileExists: File.IfFileExists.Overwrite ColumnsSeparator: File.CSVColumnsSeparator.SystemDefault

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578163/b793eb0f-a736-7bd0-9371-d150abf4d45c.png)

# おわりに
今回は結構強引に処理しましたがいずれリストカスタムオブジェクトをデータテーブルに変換するアクションが作られるものと思います。（だったらいいな）
いまのところ、たかだかJSONからCSVに変換するだけで10行以上も使います。もっとノーコードが便利になるといいですね。