APLデータバインディングの評価(1.4)



APLデータバインディングの評価

APLドキュメントは、ユーザー提供のデータを取り込み、スタイルやその他の視覚的リソースを組み込み、パラメーターをレイアウトに渡し、データに基づいてレイアウトを条件付きでインフレートさせるためにデータバインディングを使用しています。ドキュメントでデータバインディングを使用するには、データバインディング式を記述します。これは、埋め込まれた${..}サブストリングを持つJSON文字列です。このドキュメントでは、AlexaがAPLの最新バージョンでこれらの式を評価する方法について説明します。

データバインディング構文については個別に取り上げます。

データバインディングアルゴリズム

APLドキュメントのサンプルでTextコンポーネントの定義を考えます。

{
  "type": "Text",
  "text": "さやには豆が${data.value}粒あります",
  "color": "@myBlue",
  "fontSize": "${@textSizePrimary * 1.2}"
}

この定義には評価する3つの式が含まれています。まず、textには長めの式に挿入されるdata.valueという数値が含まれています。次に、colorが「myBlue」に設定されています。この場合、ユーザー定義のリソースを指します。最後に、fontSizeがドキュメントのメインテキストの標準よりも1.2倍大きいサイズに設定されています。

これらのすべての式を、次に示す3段階アルゴリズム (式の評価、リソースの参照、型の強制)を使用して評価します。

ステップ1: 式の評価

右側(RHS)が文字列の場合、アルゴリズムは文字列にデータバインディング式がないかスキャンします('${}'が埋め込まれています)。1つ以上の埋め込み式が見つかると、文字列全体が抽象構文木(AST)に変換されます。たとえば、上記のtextの例では、次のような木構造に変換されます。

Concatenate
  String("さやには豆が")
  AttributeLookup
    Symbol("data")
    String("value")
  String("粒あります")

ASTは次に、現在のデータバインディングコンテキストを使用して評価されます。データバインディングコンテキストは、キーと値のペアからなるJSONディクショナリーで、値は数値、ブール値、オブジェクト、配列、文字列のいずれかです。「+」などの演算子が必要に応じて暗黙的な型変換をします。たとえば、データバインディングコンテキストがここで示すとおりである場合、「data」シンボルはオブジェクト 「{value:5}」を返し、「value」の属性アクセサーが数値の5を返します。この3つの値からなる連結演算子には2つの文字列と1つの数値があるため、数値を文字列としてキャストして「さやには豆が5粒あります」を文字列値として返します。

{
  "data": {
    "value": 5
  }
}

ステップ2: リソースの参照

データバインディングの後、文字列値はシステムで定義されたリソースへの参照である場合があります。リソースの参照は「@」で始まり、ハイフンの付いていない1つの単語で構成されます。リソースは型付けされています。今回の例を見ると、テキストの色は@myBlueに設定されています。エバリュエーターは色のリソースから@myBlueという名前のリソースを探します。ユーザーがこの形式のリソースブロックを指定したとします。

{
  "resources": [
    {
      "colors": {
        "myBlue": "#0033ff"
      }
    }
  ]
}

次にリソース参照ステージでは「@myBlue」が「#0033ff」に置き換えられます。

ステップ3: 型の強制

最終ステップでは、設定値が正しい型になるようにします。colorの例では、「#0033ff」の文字列値が返されています。ターゲット値は色であることがわかっているので、この文字列値を、色を表す正しい内部型に変換する必要があります。

初期状態のデータバインディングコンテキスト

新しいAPLドキュメントがインフレートされると、データバインディングコンテキストは削除されます。削除されたデータバインディングコンテキストには、次の定義済みオブジェクトがあります。

名前 説明 動的
elapsedTime このドキュメントの実行時間(ミリ秒単位)です。
environment 現在のランタイム環境に関する情報です。
localTime ローカル時間(ミリ秒)です。
Math ビルトインの数学関数です。関数の呼び出しを参照してください。
String ビルトインの文字列関数です。関数の呼び出しを参照してください。
Time ビルトインの時間関数(時間関数を参照)です。
utcTime UTC時間(ミリ秒)です。
viewport 現在のデバイスの設定情報です。データバインディングコンテキストのViewportオブジェクトを参照してください。

elapsedTime

elapsedTimeプロパティは、このドキュメントが作成されてからミリ秒単位で単調に増加する時間です。ドキュメントがレンダリングされたときにゼロから始まり、文書が画面上に表示されている間、カウントアップします。elapsedTimeプロパティは、ドキュメントが「フリーズ」しているか、ユーザーから見えないように非表示になっている場合には進みません。

environment

environmentオブジェクトには、動作しているAPL環境についてのランタイム情報が含まれます。次のプロパティが含まれます:

名前 説明
agentName 文字列 ランタイム環境の名前です。
agentVersion 文字列 ランタイム環境のバージョンです。
allowOpenURL ブール値 OpenURLコマンドが有効な場合はtrueです。
animation none | slow | normal ランタイムのアニメーション特性です。
aplVersion 文字列 サポートされているAPLのバージョンです。APLの現在のバージョンは1.4です。
disallowVideo ブール値 Videoコンポーネントが無効な場合はtrueです。

agentName

ランタイム環境の名前です。これはランタイムによって割り当てられる文字列で、デバッグに役立ちます。可能であれば、APLのバグや問題をレポートするときにこの情報を提供してください。必ずしも特定の形式や構造を持つとは限りません。

この値をもとに条件応答を指定しないでください。エージェントが更新されると、これらの値も変更される可能性があるためです。

agentVersion

ランタイム環境のバージョンです。これはランタイムによって割り当てられる文字列で、デバッグに役立ちます。可能であれば、APLのバグや問題をレポートするときにこの情報を提供してください。必ずしも特定の形式や構造を持つとは限りません。

この値をもとに条件応答を指定しないでください。エージェントが更新されると、これらの値も変更される可能性があるためです。

allowOpenURL

ブール値です。OpenURLコマンドが有効な場合はtrue、有効でない場合はfalseです。

animation

デバイスでのアニメーションサポートのレベルを示します。animationの有効な値は次のとおりです。

名前 説明
none このデバイスでは、アニメーションはサポートされていません。すべてのアニメーションコマンドは、高速モードで実行されます。
slow アニメーションはこのデバイスでサポートされていますが、視覚的なパフォーマンスは制限されます。
normal このデバイスでは、標準のアニメーションが許容速度で実行されます。

常にこの値を確認して、slowに設定されている場合は、アニメーションを簡略化するか削除します。

aplVersion

このデバイスでサポートされているAPLのバージョンです。この機能はAPLバージョン1.1で追加されました。APLバージョン1.4の場合、「1.4」を返します。

このプロパティはAPL 1.0には存在しないため、nullを返します。

たとえば、APLの現在のバージョンに基づいて属性文字列を作成するには、次のように記述します。

{
  "resources": [
    {
      "strings": {
        "versionString": "これはAPLバージョン1.0以前です"
      },
      "colors": {
        "versionColor": "red"
      }
    },
    {
      "when": "${environment.aplVersion}",
      "strings": {
        "versionString": "これは想定外のAPLバージョンです:${environment.aplVersion}"
      },
      "colors": {
        "versionColor": "yellow"
      }
    },
    {
      "when": "${environment.aplVersion == '1.4'}",
      "strings": {
        "versionString": "これは想定されるバージョン1.4です"
      },
      "colors": {
        "versionColor": "green"
      }
    }
  ]
}

1.1以降で導入された機能を使用する場合、ドキュメントの該当するセクションを、aplVersionを確認するwhen句でラップする必要があります。

disallowVideo

このランタイムでVideoコンポーネントが無効になっている場合はtrueです。Videoコンポーネントでは、引き続き画面上のスペースを占有しますが、ビデオは再生されず、コンポーネントはコマンドに応答しません。

extension

extensionプロパティは、リクエストとロードされたextensionの状態を報告します。これは、extensionで定義された値への文字列名のマップが含まれています。文字列名は、APLドキュメントによってリクエストされたextensionの名前です(extensionsを参照)。例えば、ドキュメントが「Button」という名前のextension「aplext:remotebutton:v13」をリクエストした場合、データバインディング式を使用して、そのextensionの有無を確認できます。

"when": "${environment.extension.Button}"

マップはtrueと見なされることに注意してください。たとえば、extensionは、「Button」エクステンションの環境内の情報のマップを提供する場合があります。

{
  "author": "Fred Flintstone",
  "version": "1.3"
}

ドキュメントには次のように書くことができます:

{
  "type": "Text",
  "when": "${environment.extension.Button}",
  "text": "extensionのバージョン ${environment.extension.Button.version}をロードしました"
}

このテキストコンポーネントは、「Button」エクステンションが存在する場合にのみ表示され、ロードされたextensionのバージョンが表示されます。

localTime

localTimeプロパティは、Unixエポック(1970年1月1日00:00:00 UTC)以降に経過したミリ秒数で、UTCからのローカルタイムゾーンオフセットとサマータイムによって調整されます。localTimeプロパティは、utcTimeプロパティから派生します。localTimeプロパティは、サマータイムやタイムゾーンの変更などによるシステム時間の変更に伴い、前後に「ジャンプ」する可能性があることに注意してください。localTimeを使用してイベント期間を測定しないでください。

utcTime

utcTimeプロパティは、Unixエポック(1970年1月1日00:00:00 UTC)から経過したミリ秒数です。utcTimeプロパティは通常は単調に増加しますが、NTPを使用するデバイスではタイムサーバーと定期的に同期するためにわずかにシフトすることがあります。utcTimeプロパティは、実際の経過時間を測定するのに適しています。

データバインディングコンテキストを展開する

APLレイアウトにはパラメーターが含まれます。この例でわかるように、レイアウトをインフレートすると、名前付きのパラメーターがデータバインディングコンテキストに追加されます。

  "myQuoteLayout": {
    "parameters": [ "quotes" ],
    "item": {
      "type": "Text",
      "text": "${quotes.shakespeareQuotes[0]}"
    }
  }
// インフレーション
{
  "type": "myQuoteLayout",
  "quotes": {
    "shakespeareQuotes": [
      "まず為すべきことは、法律家を皆殺しにすることだ。",
      "この婦人は大仰なことばかり言うと私は思う。",
      "すべての人を愛し、信頼するのを一握りの人に留めれば、無難に生きれる。"
    ],
  "shakespeareSonnets": [
     "くたびれ果てて私は寝床へと急ぐ。旅に疲れた手足を伸ばせるところへと..." 
	 ]
  }
)

この例では、quotesはカスタムmyQuoteLayoutのパラメーターです。myQuoteLayoutが使用されると、データバインディングコンテキストは、一致する値を持つ新しいquotesプロパティを追加することによって拡張されます。quotesが指定されていない場合は、quotesのデフォルト値(通常はnull)がデータバインディングコンテキストに追加されます。この追加されたデータバインディングコンテキストは、カスタムレイアウトとその子のインフレートに対してのみ有効です。

データバインディングコンテキストの展開

コンポーネントがインフレートされると、データバインディングコンテキストが展開され、追加情報をインフレートされたコンポーネントに渡します。

コンポーネントバインドの展開

各コンポーネントには、現在のデータバインディングコンテキストを展開する任意のバインディングプロパティがあります。バインドプロパティは、(名前、値、型)の組が順序に従って配列されています。各値は現在のデータバインディングコンテキストで評価され、コンテキストに追加されます。

コンポーネントの子要素の展開

複数の子コンポーネントを持つことができるコンポーネントは、次のようなグローバル名をデータバインディングコンテキストに追加します。

名前 説明
data コンポーネントのインフレーション時に、ユーザー指定のデータ配列から割り当てられる新しいデータです。
index 現在の子コンポーネントのゼロから始まるインデックスです。
ordinal 現在の子コンポーネントの1から始まる序数です。順序数の付け方については、SequenceコンポーネントとContainerコンポーネントのnumberingをご覧ください。
length 現在のコンポーネントの子コンポーネントの合計数です。

dataordinalは、適切なプロパティがコンポーネントに設定されているときにのみ設定されます。

多子コンポーネントの一覧については、多子コンポーネントのプロパティを参照してください。

データバインディングコンテキストを明示的に伝える

子のindexordinallengthプロパティを下位方向に伝えなければならない場合があります。たとえば、Sequenceの子がそれ自体Containerであれば、Containerの子のindexプロパティはSequenceではなく、子Containerに基づきます。このような状況では、Containerのindexをその子に伝える目的で、「bind」プロパティを次のように使用できます。

{
  "type": "Sequence",
  "width": "100%",
  "height": "100%",
  "numbered": true,
  "data": "${payload.templateData.properties.rows}",
  "item": {
    "type": "Container",
    "bind": [
      {
        "name": "parentIndex",
        "value": "${index}"
      }
    ],
    "items": [
      {
        "type": "Text",
        "text": "Index ${parentIndex}"
      }
    ]
  }
}

リソースの定義

パッケージで定義された新しいリソースが、現在のデータバインディングコンテキストのパターン@の後に追加されます。たとえば、上記の「myBlue」の色は、「${@myBlue}」として明示的に参照されると共に、「@myBlue」として暗黙的に参照されます。

配列を使ったデータバインディング

多くのAPL式には配列の評価が含まれます。APLは配列型の強制、暗黙的な配列化、データバインディング式の配列への補間をサポートしています。

配列型の強制

プロパティが既知の型の配列を保持するものとして定義される場合、配列の各要素には、プロパティ割り当て時にその型が強制されます。たとえば、数値の配列が想定されたレイアウトであれば、割り当て時にその配列の各要素に数値が強制されます。

暗黙的な配列化

便宜上、値の配列をとるすべてのAPLプロパティには、配列の角かっこを持たない単一のプロパティを使用することもできます。たとえば、Containerのitemsプロパティはコンポーネントの配列として定義されます。渡される項目が1つだけの場合は、次のアプローチは同じ意味を持ちます。

"item": {<<ITEM>>}
"item": [ {<<ITEM>>} ]

APLランタイムはどちらもlength 1の配列に展開します。

配列を想定するプロパティの多くには複数のエイリアスがあります。したがって、itemitemsは同じプロパティを表します。

データバインディング式の配列への補間

配列の展開では、配列から配列への補間をサポートしています。次に例を示します。

// コンテキスト
{
	"a": "value",
	"b": [ "alpha", "bravo" ]
}

"values": "${a}" 		-> values = [ "value" ] // 暗黙的な 配列化
"values": [ "${a}" ] 	-> values = [ "value" ]
"values": "${b}" 		-> values = [ "alpha", "bravo" ]
"values": [ "x", "${b}", "${a}" ] -> values = [ "x", "alpha", "bravo", "value" ]

配列化のルールは次のとおりです。

  • 値が文字列の場合、データバインディングを使用して評価し、正しい型を強制します(その上で配列化を適用します)。

  • 値が配列の場合、文字列である配列の各要素について、データバインディングを使用して評価します。結果が1つの項目になる場合、それを配列に挿入します。結果が複数の項目になる場合、すべての項目を配列に挿入します。