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



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

APLドキュメントはデータバインディング式を利用して次のことを行います。

  • ユーザー提供データを取り込む
  • スタイルや他の視覚的リソースを組み込む
  • パラメーターをレイアウトに渡す
  • 画面の特徴に合わせてレイアウトをインフレートする

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

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ドキュメントがインフレートされると、データバインディングコンテキストは削除されます。削除されたデータバインディングコンテキストには現在次の定義済みオブジェクトがあります。

名前 説明
environment 現在のランタイム環境に関する情報です。
viewport 現在のデバイスの設定情報Viewportの特性を参照してください。
Math ビルトインの数学関数です。関数の呼び出しを参照してください。
String ビルトインの文字列関数です。関数の呼び出しを参照してください。

environment

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

名前 説明
agentName ランタイム環境の名前です。
agentVersion ランタイム環境のバージョンです。

agentNameagentVersionで得られる情報は、APLドキュメントをレンダリングするために使用するランタイムエージェントの開発チームのデバッグをサポートするためのものです。可能であれば、APLのバグや問題をレポートするときにこの情報を提供してください。これらのプロパティ値をもとに条件応答を行うことはしないでください。エージェントが更新されると、これらの値も変更される可能性があるためです。

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

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

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

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

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

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

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

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

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

SequenceContainerPagerなどの特定のコンポーネントには複数の子コンポーネントがあります。これらのコンポーネントは次のようなグローバル名をデータバインディングコンテキストに追加します。

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

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

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

子の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つの項目になる場合、それを配列に挿入します。結果が複数の項目になる場合、すべての項目を配列に挿入します。