PowerAppsでJSONを解析して編集、格納


:::note alert
こちらの記事は古いです。
PowerFxにParseJSON関数が実装され、Power Appsでも実験的な機能として使えるようになりました！
詳しくは以下です。
https://powerapps.microsoft.com/ja-jp/blog/power-fx-introducing-parsejson/
https://docs.microsoft.com/ja-jp/power-platform/power-fx/reference/function-parsejson

沢山の方がブログやYouTubeで解説されていますので、そちらも参考にしてください。

Completed!!!👏
https://powerusers.microsoft.com/t5/Power-Apps-Ideas/Parse-JSON-in-PowerApps/idi-p/359563

:::

# 概要
- PowerAppsの関数を使ってjsonをコレクションに変換(デシリアライズ)し、ギャラリーコントロールでデータを編集して再びjson文字列に戻す方法です。




![商品スペック編集.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/fc00896f-939d-069f-62e3-253a910fa1e3.gif)
編集後のjsonテキストは見やすいようにインデント付きに変換しています。

# PowerAppsとJSON
- PowerAppsでJSON関数を使用するとコレクション(テーブル)をjsonに変換することができます。
- 反対に、JSONを解析するParseJsonのような関数はありません。 
- せいぜいカスタムコネクタからの応答をレコードやテーブルとして扱えるくらいです。

代替案として、PowerAutomateを経由しテキスト送信→JSONの解析→HTTPコネクタの応答でJSONをコレクションなどに変換する方法があります。
ただし、PowerAutomateを使うことと、プレミアムコネクタが必要になってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/9ebd1a9d-b7da-4854-0bc7-6e31e24b8685.png)

# JSONの解析
- MatchAll関数で、正規表現のサブマッチがコレクションとして返却される動作を利用して、json文字列をコレクションに変換している素晴らしい事例を見かけました。
- フラットなJSONかつスキーマが固定という制約はあります。
- ギャラリーコントロールを組み合わせると、値を編集でき、JSON関数で再びjsonに戻せます。 


※JSONの解析について、ideasではUnderReviewとなっているのですが、中々実装されませんね・・
https://powerusers.microsoft.com/t5/Power-Apps-Ideas/Parse-JSON-in-PowerApps/idi-p/359563


## 解説

### ①上のサンプルの「解析して編集」ボタン
OnSelectには以下のコードを設定します。

```JavaScript:OnSelect
ClearCollect(ItemSpecEntity,{Attribute:"正しいJsonが",Value:"セットされて",Unit:"いません"});
With(
    {TableFromJson:MatchAll(
        TextInput3.Text,
        "\{""Attribute"":""(?<Attribute>[^""]*)"",""Unit"":""(?<Unit>[^""]*)"",""Value"":""(?<Value>[^""]*)""\}"
        )
    },
    If(CountRows(TableFromJson)>1,    
        ClearCollect(
            ItemSpecEntity,
            ShowColumns(
                TableFromJson,
                "Attribute",
                "Value",
                "Unit"
            )
        )
    )
);
```
MatchAll関数によりTextInput3.Textにセットされた文字列に対し、正規表現で評価し、マッチするとサブマッチがコレクションとして格納されます。
名前付きサブマッチを使用すると名前が列名となります。一時変数であるTableFromJsonにテーブルをセットしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/c4fe14fd-041d-9fd2-46f7-f42ebcbeef4c.png)

そしてCountRowsでマッチしたかチェック。コレクションItemSpecEntityに必要な列を絞って(ShowColumns)格納します。
ここで、スキーマが異なる場合はマッチせず場合はTableFromJsonの行数が0になるので、ItemSpecEntityにはデフォルトのAttribute:"正しいJsonが"・・が格納されます。
注意点としては、サブマッチで作成されるコレクションの列がA-Z順で並び替えられてしまいます。
MatchAllでJSONのキーを記述する順番は気をつける必要があります。

### ②サンプル右側のギャラリー
Itemsには先程のItemSpecEntityを設定。
コントロールを配置します。
今回は、値のみユーザー編集させたいのでテキストボックスに設定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/af8d20a1-f43e-357a-e39e-316f8bdc18dd.png)

### ③編集確定ボタン
OnSelectには以下のコードを入力します。

```JavaScript:OnSelect
Clear(ItemSpecEntity);
//ギャラリーを参照してコレクションにセット
ForAll(Gallery_EditJson.AllItems,
    Collect(ItemSpecEntity,{Attribute:Attribute,Value:TextInput_Value.Text,Unit:Unit});
);
UpdateContext({JsonString:JSON(ItemSpecEntity)})
```
ItemSpecEntityを一旦クリアし、ギャラリーのアイテムを参照して新しい値をセット。コレクションを作り直します。
そしてJSON関数でjson文字列に変換します。
サンプル画像ではインデントをつけて見やすくしていますが、上の正規表現に対応するために通常はコンパクトjsonで格納します。
左下の変換後のテキストボックスのDefaultにはJsonStringを設定。


# 誰得？どんなときに使うか
項目によって入力すべきデータの数が不定な場合、又はデータ構造が属性(Attribute)と値(Value)の組み合わせとなる場合です。
RDBでいうEntity-Attribute-Valueパターンで、テーブルを使用するとアプリ側での処理が複雑になりますが、json型を使用すると比較的シンプルに実装することができます。
・[EAV(エンティティ・アトリビュート・バリュー)](https://qiita.com/skyc_lin/items/37365a36416d0dc42431)

具体例としては、洋服の寸法箇所である「ウェスト/丈などを属性」、「寸法値である長さを値」とし、服の分類ごとに必要な属性の種類や数が異なる場合です。
※データ型が固定なら普通に子テーブルで処理した方がいいのですが・・

ローコードなPowerAppsでjson型のフィールドを扱うことができれば、PowerAppsの可能性が広がると思いました。
DataverseやSharePointではまだjson型に対応していないようですので、以下の活用例ではSharePointのテキスト列を使ってjsonを格納しています。

# 活用
以下のようなアプリを作成してみました。
![サンプルアプリ2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/e6e8bc51-f009-d42c-a886-65155e84d616.gif)

- 商品カテゴリはマスターテーブルから選択します。　テーブルには商品カテゴリごとに入力すべきスペック情報をjson(複数行テキスト型)として格納してあります。
- 商品情報編集画面で、商品カテゴリを選択すると、jsonを取得し入力する商品スペックの数が切り替わります。
- そして別画面で商品スペックを入力し、入力後のjsonを文字列として商品情報テーブルに格納します。
- SharePoint側には以下のような感じでアップデートされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293667/4994b96c-5607-b8c0-5fec-176974f5c1e5.png)

検索等には対応しませんが、簡単に記録するだけならシンプルなテーブル構成で実現できました。

他に以下のようなアプリも作成できそうなので、作ったら公開してみたいと思います。

- 設備の点検アプリで、設備ごとに点検項目と記録項目が異なるようなもの。
- 設備ごとの入力項目はjsonでテンプレート化して読み込み、点検項目+点検結果をPatch関数でEntity(親ID)、Attribute(点検項目)、Value(記録値)でテーブルに格納のなど・・