在工作流程开发过程中,我们讨论过的工具有时不足以实现所需的逻辑。通常情况下,当您需要操作原始输入数据时,例如在表达式中进行比较之前或在上下文变量中保存数据之前,就会出现这种情况。在这种情况下,在工作流标记中使用我们的嵌入式 JavaScript (JS) 引擎应能提供可行的解决方案。
在工作流中使用 JavaScript 时,应始终使用<![CDATA[ ... ]]>
标记,以避免 XML 解析器出错。使用?{
... } 打开和关闭 JS 作用域。}?.
您可以使用 context.variable_name
从 JS 作用域内部访问上下文变量。要访问事件数据,也可以使用类似的方法,如event.field
:
<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。这也可以跨越多行和更复杂的处理方式。你将在下一页看到更多示例。
嵌入式功能
您可以直接在工作流 XML 中使用一些嵌入式函数,而无需打开 JS 上下文。其中一些示例经常在特定用例中使用:
- 存在: exists (#{shelve})
- toUppercase: toUppercase( '#{material_name} ' )
- toLowercase: toLowercase( '#{material_name} ' )
- 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( # {material_name}, 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>
会导致例如MAT_
(其中 _ 是空白),即使您使用了 trim。
示例
让我们再来看几个使用 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 地址中搜索断开连接的设备的 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 的另一个典型用例是通配符部件。由于我们还没有介绍布局,所以这里不举例子,但 widget 文档中有一个例子。
任务
作业 1:
在当前版本的组件中,我们选择的输出都是大写字母,并在下一个组件的用户界面中显示为大写字母。让我们让它看起来更漂亮一些:
- 使用 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>
下载组件(作业后)
在下一课中,我们将最终了解如何设计组件的用户界面。