はじめに
※ 当記事は Hiroさん の 「JSONと仲良くなるために」のPowerApps版としてを記載してみました。
JSONのことやPowerAutomateでの扱い方を詳しく知りたい方は「JSONと仲良くなるために 」をご覧ください。
これを読めばJSONと友達になれます
概要
JSON、好きなデータフォーマットだと思ってました。
だって、自分でKey値を指定して、値を設定できる。しかも、それが横並びで表示されてるからわかりやすい!
…好きだと思ってました、APIのレスポンスで出会うまでは…
Keyと値はそこにある、見えている、でもデータ階層が深すぎて思った通りに値が取得できない!!
例えば、以前に紹介した記事「PowerApps で JANコードリーダー&商品情報取得アプリを作成する」で利用したYahoo商品検索APIのレスポンスはこれ↓
{
"totalResultsAvailable": 52,
"totalResultsReturned": 20,
"firstResultsPosition": 1,
"request": {
"query": ""
},
"hits": [
{
"index": 1,
"name": "バンダイ RG 1/144 MSN−06S シナンジュ",
"description": "バンダイ RG 1/144 MSN−06S シナンジュ 885",
"headLine": "",
"url": "https://store.shopping.yahoo.co.jp/yamada-denki/7863086011.html",
"inStock": true,
"code": "yamada-denki_7863086011",
"condition": "new",
"imageId": "yamada-denki_7863086011",
"image": {
"small": "https://item-shopping.c.yimg.jp/i/c/yamada-denki_7863086011",
"medium": "https://item-shopping.c.yimg.jp/i/g/yamada-denki_7863086011"
},
"exImage": {
"url": "https://item-shopping.c.yimg.jp/i/l/yamada-denki_7863086011",
"width": 600,
"height": 600
},
"review": {
"rate": 5,
"count": 5,
"url": "https://shopping.yahoo.co.jp/review/item/list?store_id=yamada-denki&page_key=7863086011"
},
"affiliateRate": 1,
"price": 3344,
"premiumPrice": 3344,
"premiumPriceStatus": false,
"premiumDiscountType": null,
"premiumDiscountRate": null,
"priceLabel": {
"taxable": true,
"defaultPrice": 3344,
"discountedPrice": null,
"fixedPrice": null,
"premiumPrice": null,
"periodStart": null,
"periodEnd": null
},
"janCode": "4549660075905",
"isbn": "",
"releaseDate": null,
"seller": {
"sellerId": "yamada-denki",
"name": "ヤマダデンキ PayPayモール店",
"url": "https://paypaymall.yahoo.co.jp/store/yamada-denki/top/",
"isBestSeller": true,
"isPMallSeller": true,
"payment": "1 16 4096",
"review": {
"rate": 4.13,
"count": 34251
},
"imageId": "yamada-denki_1"
},
"delivery": {
"area": "",
"deadLine": null,
"day": null
}
},
{
"index": 2,
"name": "バンダイ RG 1/144 MSN−06S シナンジュ",
"description": "バンダイ RG 1/144 MSN−06S シナンジュ 885",
"headLine": "",
"url": "https://store.shopping.yahoo.co.jp/best-tecc/7863086011.html",
"inStock": true,
"code": "best-tecc_7863086011",
"condition": "new",
"imageId": "best-tecc_7863086011",
… 以下略 …
バンダイのプラモデル「RG 1/144 シナンジュ」(かっこいいよね) をJANコードで検索した結果です。
これをPowerAppsで、コレクション"Comodity"にClearCollectします。
どうですか?このコレクション"Comodity"の中にあるレスポンスJSONから、
↑この部分の商品画像のURL
"https://item-shopping.c.yimg.jp/i/l/yamada-denki_7863086011"
をPowerAppsで抜き出せますか?
そんなの簡単だよ!というPowerApps玄人の方々にはこの記事は不要です。
当記事は、
・できそうだけど自信がない
・試行錯誤したらいけると思う
・まったく無理
という方に、「JSONから目的の値を取得する必勝法」をお伝えできたらと思います。
まずは観察
↑上にあるJSONですが見難くありませんか?
これでは**Keyと値の組み合わせ(オブジェクトといいます)**やデータ構造(配列)が判別しにくですよね。
そこで、まずは識別しやすくするために、着色や整形しましょう。
それには、Visual Studio Code(VSCode)がおすすめです。
VSCodeの簡単な使い方はこちら
(日本語化とJSONの表示方法を記載しています)
これで随分と見やすくなりました。
Keyや値、データ構造がすぐにわかりますね。
次に分析と対策
ぱっと見て、JSONのデータ構造はネスト(入れ子)にネストしていく、階層構造を持っていることが分かります。
この階層が曲者で、この階層を崩していかない限り、欲しいデータが取得できません。
でも、3パターンの対応法でこの階層を攻略できます。
パターン①
[ファイル]メニューの[コレクション]で中身をのぞいてみましょう
この通り、"Comodity"テーブル(表)にレコード(行)が1件追加されています。
さらにこの中には
"firstResultsPosition"や"totalResultsAvailable"のようなオブジェクト
"hits"や"request"といったテーブルやレコード
がカラムとして存在しています。
このようなテーブルから最初(1件目)のレコードを抜き出すには「Fast()関数」を使います。
さらに抜き出したレコードのカラムを特定すれば、値が取得できます。
よってこのパターンに対する対策は
対策①:FIRST()関数でコレクションの1件目のレコードを特定しKeyを指定する
です
First([JSONを格納したコレクション]).[取り出したいKey名]
パターン②
Key の後に「 { 」(中カッコ)が現れてネストする
中身を覗くと
一見、上記パターン①と同じように見えるのですが、このパターンは
"exImage"というカラム(列)に、レコード(行)が格納されている
状態です。
このような入れ子になったレコードのカラムを特定し、値を取得するには「 . 」(ピリオド)に続きカラムを指定します。
よってこのパターンに対する対策は
対策②:Keyとkeyを「 . 」(ピリオド)で繋ぐ
です
[上構造のKey名].[下構造のKey名]
パターン③
**Key の後に「 [ 」(大カッコ)と「 { 」(中カッコ)が現れてネストする
中身は
これは、テーブル(表)に、レコード(行)が複数格納されている状態です。
今回のサンプルの商品検索APIは最大20件の検索結果を持ってきてくれます。
"[ ]"で囲まれた配列に20個の検索結果オブジェクトが詰め込まれているということです。
"Hits":[
{検索結果01},
{検索結果02},
{検索結果03},
:
{検索結果20},
]
テーブルから特定のレコードを選び、カラム(列)を指定するときは「Lookup()関数」を使います。
(「Index())」という関数でも対応できます。)
よってこのパターンに対する対策は
対策③:Lookup()関数でテーブルのN件目のレコードを特定しKeyを指定する
です
パターン④ 2021/2/12追記
**データの先頭で「 [ 」(大カッコ)と「 { 」(中カッコ)が現れてネストする
これはデータ先頭で、パターン③ と同じ「テーブル(表)にレコード(行)が複数格納」となっているだけです。
ですから、このパターンに対する対策は対策③と同じ、
対策④:Lookup()関数でコレクションのN件目のレコードを特定しKeyを指定する
です
Lookup([JSONを格納したコレクション],[レコードを特定する条件]).[取り出したいKey名]
ギャラリーコントロールの一覧表示可能なのも同じです。
パターン④
このパターンは、下階層にKeyがないため、keyの指定ができません。
取り出したい値の位置が分かっているなら、下記の関数が有効です。
Index([上構造のKeyまで特定した値],[取り出したい値の位置]).Value
※取り出したい値の位置は上から順に1,2,3…です。
対策④:Index()関数で配列のN件目のレコードを特定しValueの値を取得する
です
最後に実践
3つのパターンの対策方法を組み合わせて、目的の値にアクセスしていきます。
実際に、記事のはじめの方で書きました"url"の値を、コレクション"Comodity"から取得してみます。
"url": "https://item-shopping.c.yimg.jp/i/l/yamada-denki_7863086011",
手順1
パターン①です。カスタムコネクタからのレスポンスが格納されたコレクションのテーブル構造から、1番目のレコードを特定します。
配列から一つ目(=最初)のレコードの"hits"を取得するために、Fast()関数を使いましょう。
First(Comodity).hits
手順2
次はパターン③です。これもテーブルから特定のレコードを取り出す対応になります。
上記の手順1で取得したオブジェクト"hits"に対して、
・検索条件で、レコードの特定を行い"exImage"を取得するならLookup()
LookUp(LookUp(Comodity,true).hits,index=1).exImage
※カラム"index"の値が1のレコードを指定しています
・何番目かのレコードから"exImage"を取得するなら、[Index()]
Index(First(Comodity).hits,3).exImage
※3番目のレコードを指定しています
・対象はテーブルなので、ギャラリーコントロールで一覧表示することも可能です
###手順3
次はパターン②です。入れ子となっているレコードの値を取得します。
上記の手順2で取得したオブジェクト"exImage"に、ピリオドで"url"をつなげます。
LookUp(LookUp(Comodity,true).hits,index=1).exImage.url
まとめ
一見、難解で複雑な構造を持つJSONの深層に隠された値でも、今回の「情報分析⇒4つのパターン対応」でゲットできるはずです。
これでJSONとも少しは仲良くなれたでしょうか?