ワークフロー開発中に、必要なロジックを実装するために、ここまで説明してきた ツールだけでは不十分な場合があります。例えば、式で比較する前やコンテキスト変数に保存する前などです。このような場合、ワークフローのマークアップに組み込まれたJavaScript(JS)エンジンを使用するオプションが、実行可能なソリューションを提供するはずです。
ワークフローの中でJavaScriptを使用する場合は、XMLパーサーのエラーを避けるために、常に<![CDATA[ ... ]]>
タグの中に記述する必要があります。JSスコープのオープンとクローズは、?}?.
JSスコープ内からコンテキスト変数にアクセスするには、context.variable_nameを
使います。イベントデータにアクセスするには、同様にevent.field
.Nameを使います:
<setvar id="add_digit_from_speech_command">
<context_of>workflow</context_of>
<context_update>
<param name="number" type="long"><![CDATA[ ?{ context.number + Number(event.command.substr(event.command.length - 1, event.command.length)) }? ]]></param>
</context_update>
</setvar>
上の例でわかるように、任意のネイティブJSを書くことができる。これは複数行にまたがることもできるし、より複雑な処理も可能だ。次の記事で、さらにいくつかの例を紹介する。
組み込み機能
JS コンテキストを開くことなく、ワークフロー XML で直接使用できる埋め込み関数がいくつかあります。これらの例のいくつかは、特定のユースケースで定期的に使用されます:
- exists: exists(#{shelve})
- toUppercase: toUppercase( '#{マテリアル名}' )
- toLowercase: toLowercase( '#{マテリアル名}')
- trim: trim( #{マテリアル名} )
- contains: contains( #{first_code}, #{second_code})
- startsWith: startsWith( #{first_code}, #{second_code})
- endsWith: endsWith( #{first_code}, #{second_code})
- equals: equals( #{first_code}, #{second_code})
- substring: substring( #{材料名}, 0, 3)
以下の例には、toUpperCase
、trim、
substring
関数が含まれています。
<rule id="speak_material">
<expression><![CDATA[ #{event:command} == toUpperCase('#{material_name}') ]]></expression>
<actions>
<setvar id="set_material_type">
<context_update>
<param name="material_type" type="string">trim(substring(#{material_name}, 0, 3))</param>
</context_update>
</setvar>
</actions>
</rule>
音声コマンドは常に大文字で出力されるため、上記は典型的な例です。音声コマンドをワークフロー内のコンテンツと比較したい場合は、常に大文字に変換する必要があります。
ヒントとコツ 文字列
型のparam
タグ内では、コードの可読性を高めるために空白を使用しないでください。例えば、<param name="material_type" type="string">trim(substring(#{material_name}, 0, 3)) </param>と
すると、trimを使ったにもかかわらず、例えばMAT_(_は
空白)となってしまいます。
例
JSエンジンが便利な使用例をもう少し見てみよう:
データへの動的アクセス
別のコンテキスト変数の内容に基づいて)動的にデータにアクセスする必要がある場合もある:
<setvar id="set_step">
<context_update>
<param name="step" type="object"><![CDATA[ ?{context.steps[context.current_step_index]}? ]]></param>
</context_update>
</setvar>
条件付きデータ操作
これを実装するために複数のアクションやルールを作成することもできるが、JSを使えば簡潔にできる:
<setvar id="set_text_color">
<context_update>
<param name="label_text_color" type="string"><![CDATA[ ?{ (context.urgent)? 'red' : 'black' }? ]]></param>
</context_update>
</setvar>
オブジェクトの生成と操作
JavaScriptは、オブジェクトを生成したり操作したりするのにも役立ちます。下の例では、ワーカーが音声コマンドを使って0~99の金額を表現できるようにしたいとします。各発話コマンドは個別に発話文法に追加する必要がありますが、JavaScript を使用すると、これを次のように短縮できます:
<action id="add_amount_speech_commands" type="speech_modify_commands_in_grammar">
<param name="slot">wf_editor_slot</param>
<param name="commands"><![CDATA[ ?{
Array.apply(null, {length: 100})
.map(Number.call, Number)
.map(function(e) {
return { 'name': 'AMOUNT ' + (e), 'description': `AMOUNT [0-99]`}
}
)}? ]]></param>
<param name="modification">add_commands</param>
</action>
表現
JSが表現に役立つユースケースもある。以下の例では、サードパーティ製デバイスが切断されたときに発信されるイベントを処理している。JSを使って、切断されたデバイスのMACアドレスの文字列を検索している。
<rule id="device_vanished">
<expression><![CDATA[ #{event:command}== 'DEVICEVANISHED' && ?{context.mac.search(event.mac)>-1}?]]></expression>
<actions>
<action ref="back_to_start"/>
</actions>
</rule>
注意:JavaScriptの使用は式に対して制限されています。すべての式の内容は、ロジックを壊す可能性のある改行や空白をすべて取り除くためにトリミングされます。そのため、式の中で複数行のJavaScriptを使用することはできません。
ワイルドカード・ウィジェット
JSのもう一つの典型的な使用例はワイルドカード・ウィジェットである。まだレイアウトを導入していないので、ここでは例を見ませんが、ウィジェットのドキュメントには例があります。
📌課題
現在のバージョンのコンポーネントでは、選択した出力はすべて大文字で、次のコンポーネントのUIではそのように表示されます。もう少し見栄えを良くしましょう:
- JavaScriptまたは埋め込み関数を使用して、結果の選択肢をより自然な大文字で保存します。
ダウンロードコンポーネント(事前課題)
ソリューション
以下に模範的な解決策を示す:
<rule id="choice_made">
<expression><![CDATA[ #{event:command} == 'APPLE' || #{event:command} == 'PEAR' ]]></expression>
<actions>
<setvar id="save_choice">
<context_of>workflow</context_of>
<context_update>
<param name="choice" type="string"><![CDATA[ ?{ event.command.slice(0,1) + event.command.slice(1).toLowerCase() }? ]]></param>
</context_update>
</setvar>
<action ref="show_confirmation_dialog"/>
</actions>
</rule>
ダウンロード・コンポーネント(事後課題)
次回のレッスンでは、いよいよコンポーネントのユーザーインターフェースの設計方法について見ていきます。