日頃 JSON の値と戯れていると、時々その値をどうこうするときに面倒くさいと思うことが多いかと思います。配列な値が関連すると、面倒くささはさらに増してしまうので、このあたりをなんとかできないかなと考えてみました。
Image may be NSFW.
Clik here to view.
例えば上記の例な場合です。通常であれば SampleArray でループさせて一つずつ値をチェックすることでしか、現状の Logic Apps や Flow では対応ができないので、ここを少しでも楽にしたいというのが目的です。
データベースでは PIVOT などを利用した縦横変換の仕組みがありますので、それを用いることが多いですが、その仕組みをもたない Logic Apps では自前で用意する必要があります。
試しに作成した LogicFlow の全体図は以下になります。
Image may be NSFW.
Clik here to view.
試しで利用していたのは、LUIS の解析結果に含まれる Entity の値、これが配列となっているのでここをターゲットにしました。
Image may be NSFW.
Clik here to view.
まずは下ごしらえです。JSON解析は LUIS からの返却値から、Entity の部分だけを解析させています。こうすることでダイアログから値の指定を行えるようにします。
Image may be NSFW.
Clik here to view.
その際に一点注意があります。サンプルデータを投入してスキーマを作成することが多いかと思いますが、以前のエントリで書いた通り、required 指定が付与された形でスキーマは生成されます。そのため、生成されたスキーマから required 指定の箇所を全て削除し、値が省略されてもよいようにします。もちろん、省略されることがないのであればそのまま利用しても大丈夫です。
次にダミーの JSON を作成しています。これは後々の処理で JSON 値を新規に作成する際の受け皿となるものです。JSON 関数を利用して適当な値を作成しています。
json('{"title":""}')
このような感じで JSON 関数を利用しています。空の JSON 値というのは作成できないので、なんらかの要素は必要です。
そして生成結果を受け取るための変数を用意します。種類はオブジェクトとして、JSON 値を受け取れるようにします。
Image may be NSFW.
Clik here to view.
メインとなるのはこの箇所です。ループで配列の値を回すようにし、それぞれの値をもとに新しい JSON を作成しています。
Image may be NSFW.
Clik here to view.
今回処理するにあたり、ForEach ループの設定で同時実行制御を OFF にし、シーケンシャルに 1 件ずつ処理されるようにしています。これは受け皿となる変数へ結果を設定する際に、結果が正しく設定されるようにするためのものです。同時に処理を行った場合は、片方の値しか入らないなどマルチスレッド実行時の現象に近いことが発生するので、この設定が必要です。
ループの中では、最初にキーとしたい値を取得し、そのキーに対して取得したい値を付与、結果を新しい JSON として生成しています。
キーの取得は、最初に JSON 解析を行ったのでダイアログから指定が可能です。そして一番のポイントとなるのは次の「Typeの値をもとにしたJSON値の作成」な個所です。
ここでは以下のように関数を組み合わせて、新規に JSON 値を生成しています。
addProperty(variables('newValues'),replace(string(outputs('Typeの値を取得')),'.',''),replace(string(items('Entityの値でループ')),'.',''))
addProperty 関数を利用して、新しくキーと値を追加しています。最初の引数 variavles(‘newValues’) が追加対象となる JSON 値です。今回は、キーと値をまとめたいので、受け皿となる変数を指定しています。最終的にこの変数を参照すれば、すべての値が取得できるようにするためです。
二つ目の引数 replace(string(outputs(‘Typeの値を取得’)), ‘.’, ‘’) の箇所は、キーとなるものを指定します。今回のケースでは、キーとなるものに JSON で利用できない値(.)が含まれていたので、それを除去しています。もし利用するケースで、JSON で利用できない文字がない場合は不要ですが、outputs 関数でアクションの結果を参照する場合、string 関数で明示的に文字列にする必要があります。
最後の引数 replace(string(items(‘Enttityの値でループ’)), ‘.’, ‘’) で、新しく作成する JSON に設定する値を指定しています。ここも利用できない文字を除去しています。
このようにすることで、newValues という変数に設定されている JSON 値に対して、キーと値が追加された新しい JSON 値を作成します。もともとの変数 newValues を書き換えはしないのと自己参照ができないのもあり、ここで生成した結果を次のアクションで変数 newValues に再設定します。プログラマであれば、addProperty の結果をそのまま newValues に設定、と 1 つのアクションで済ませたくなりますが、自己参照できないために 2 つのアクションに分ける必要があります。
Image may be NSFW.
Clik here to view.
ループで全ての値を処理すると、このような感じで JSON 値が変数 newValues に設定されているのが確認できます。
こうすることで、変数 newValues に対して以下のような記述にて、値を取得することが可能となります。
variables('newValues')['Hisashi Food::Food']
若干手間があるように見えますが、このように縦横変換することで後続の処理で、毎回ループして値を値を利用しやすくなります。