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



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

APL for Audioは、データバインディングを使ってユーザーから提供されたデータを組み込み、オーディオリソースを取り込んで、データに基づいて条件付きでコンポーネントをインフレートします。ドキュメントでデータバインディングを使用するには、データバインディング式を記述します。これは、埋め込まれた${..}サブストリングを持つJSON文字列です。このドキュメントでは、Alexaがこれらの式を評価する方法について説明します。

データバインディング式の構文の詳細については、データバインディングの構文を参照してください。

データソースを定義する方法については、データソースを参照してください。

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

次のAPLドキュメントについて考えてみましょう。

クリップボードにコピーされました。

{
  "type": "APLA",
  "version": "0.9",
  "mainTemplate": {
    "parameters": [
      "data"
    ],
    "item": {
      "type": "Speech",
      "content": "さやには${payload.data.value}粒の豆があります"
    }
  }
}

この例では、Speechコンポーネントがデータソースのdata.valueプロパティの値を使用しています。この値は、より長い式に挿入されます。

以降のセクションでは、${payload.data.value}式の結果を使ってこの文字列を作成する際に使用するアルゴリズムについて説明します。

ステップ1: 式の評価

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

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

ASTは、現在のデータバインディングコンテキストを使用して評価されます。データバインディングコンテキストは、キーと値のペアからなるJSONディクショナリーで、各値は数値、ブール値、オブジェクト、配列、文字列のいずれかです。「+」などの演算子が必要に応じて暗黙的な型変換をします。たとえば、データバインディングコンテキストに以下が含まれているとします。

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

dataシンボルは、オブジェクト{value: 5}を返し、valueのアトリビュートアクセサーが数値の5を返します。この3つの値からなる連結演算子には2つの文字列と1つの数値があるため、数値を文字列としてキャストして「さやには5粒の豆があります」を文字列値として返します。

ステップ3: 型の強制

最終ステップでは、設定値が正しい型になるようにします。型変換の例は、Truthyと強制の表を参照してください。

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

AlexaがAPLドキュメントをインフレートすると、Alexaはドキュメントを、定義済みのオブジェクトを含む新しいデータバインディングコンテキストに割り当てます。

名前 説明
environment 現在のランタイム環境に関する情報です。
Math ビルトインの数学関数です(データバインディングの構文を参照)。
文字列 ビルトインの文字列関数です(データバインディングの構文を参照)。

environment

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

名前 説明
alexaLocale 文字列 リクエストの現在のロケールです。
agentName 文字列 ランタイム環境の名前です。
agentVersion 文字列 ランタイム環境のバージョンです。
aplaVersion 文字列 サポートされているAPL for Audioのバージョンです(現在は0.9)。
aplVersion 文字列 サポートされているAPLのバージョンです(ない場合はnull)。
apltVersion 文字列 文字表示でサポートされるAPLのバージョンです(ない場合はnull)。

たとえば、environment.aplaVersion0.9aplVersionapltVersionの両方がnullの場合、デバイスはAPL for Audioをサポートしますが、画面はありません。

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

合成の展開

APL for audioの合成にはパラメーターがあります。合成をインフレートすると、名前付きのパラメーターがデータバインディングコンテキストに追加されます。

以下は、SSMLを使って「Joey」の音声を適用する単純な合成の例です。

クリップボードにコピーされました。

{
  "compositions": {
    "JoeyVoice": {
      "description": "常にJoeyの音声を適用するspeechコンポーネントの基本的なラッパーです",
      "parameters": [
        {
          "name": "speechContent",
          "type": "string"
        }
      ],
      "item": {
        "type": "Speech",
        "contentType": "SSML",
        "content": "<speak><voice name='Joey'><lang xml:lang='en-US'>${speechContent}</lang></voice></speak>"
      }
    }
  }
}

ドキュメントのmainTemplateを使ってカスタム合成を参照します。

クリップボードにコピーされました。

{
  "type": "JoeyVoice",
  "when": "${environment.alexaLocale == 'en-US'}",
  "speechContent": "Hello!"
}

この例では、speechContentは、カスタム合成JoeyVoiceのパラメーターです。ドキュメントでJoeyVoiceを使うと、Alexaは、speechContentパラメーターとその値をデータバインディングコンテキストに追加します。これにより、合成は${speechContent}のような式を使ってパラメーターの値を参照します。

speechContentに値を指定しない場合、Alexaは、パラメーターにデフォルト値を設定してデータバインディングコンテキストに追加します。合成を定義する際、パラメーターのデフォルト値を指定できます。上の例では、speechContentのデフォルト値を定義していないため、この例のデフォルト値はnullとなります。

この追加されたデータバインディングコンテキストは、カスタム合成とその子コンポーネントをインフレートする際に有効です。

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

Sequencerなど、一部のコンポーネントは複数の子を持ちます。複数の子を持つコンポーネントは、次のようなグローバル名をデータバインディングコンテキストに追加します。

名前 説明
data コンポーネントのインフレート中にdataプロパティから割り当てられるデータです。dataの詳細については、データ配列のインフレートを参照してください。
index 現在の子コンポーネントのゼロから始まるインデックスです。
length 現在のコンポーネントの子コンポーネントの合計数です。

dataは、複数子コンポーネントのdataプロパティを設定した場合に設定されます。

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

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

配列型の強制

プロパティ定義が既知の型の配列を指定する場合、配列の各要素はプロパティの割り当て中にその型に強制変換されます。たとえば、数値の配列が想定された合成であれば、割り当て時にその配列の各要素に数値が強制されます。

暗黙的な配列化

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

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

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

配列を想定するプロパティには複数のエイリアスがあります。したがって、itemとitemsは同じプロパティを表します。これにより、コードが読みやすくなります。

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

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

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

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

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

  • 値が文字列の場合、データバインディングを使用して評価し、正しい型を強制します(その上で配列化を適用します)。
  • 値が配列の場合は次のようになります。
    • 文字列である配列の各要素について、データバインディングを使用して評価します。結果が1つの項目になる場合、それを配列に挿入します。
    • 項目の配列となる配列の各要素について、すべての項目を配列に挿入します。