有时在工作流开发过程中,我们到目前为止讨论过的工具不足以实现所需的逻辑。通常,每当您需要操作原始输入数据时,例如,在表达式中比较原始输入数据之前或将其保存在上下文变量中之前,都会发生这种情况。在这些情况下,在工作流标记中使用我们的嵌入式 JavaScript (JS) 引擎的选项应该会提供一个可行的解决方案。
在工作流中使用 JavaScript 时,应始终在标记中 <![CDATA[ ... ]]> ,以避免 XML 解析器错误。使用 ?{ ... }?打开和关闭 JS 作用域。您可以使用 从 JS 作用域内部访问 context.variable_name上下文变量。要访问事件数据,您可以类似地使用,例如 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 上下文。其中一些示例经常用于特定用例:
下面的示例包含 toUpperCase和 trim, substring函数。
<规则 id=“speak_material”>
<表达式><![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 类型 string标签中使用空格以获得更好的代码可读性,因为它会成为您正在操作的字符串的一部分。例如, <param name="material_type" type="string">trim(substring(#{material_name}, 0, 3)) </param> 即使您使用了 trim,也会导致例如 MAT_ (其中 _ 是空格)。
让我们再看几个 JS 引擎派上用场的用例示例:
有时您需要动态访问数据(基于另一个上下文变量的内容):
<setvar id=“set_step”>
<context_update>
<参数名称=“step” type=“object”><![CDATA[ ?{context.steps[context.current_step_index]}?]]></param>
</context_update>
</setvar>
虽然您也可以创建多个操作和规则来实现这一点,但 JS 允许简洁:
<setvar id=“set_text_color”>
<context_update>
<参数名称=“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”>
<参数名称=“插槽”>wf_editor_slot</参数>
<参数名称=“命令”><![CDATA[ ?{
Array.apply(null, {length: 100})
.map(Number.call, Number)
.map(function(e) {
return { 'name': 'AMOUNT ' + (e), 'description': 'AMOUNT [0-99]'}
}
)}? ]]></param>
<参数名称=“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 的另一个典型用例是 通配符小部件。由于我们还没有介绍布局,我们不会在这里看一个例子,但 小部件文档 有一个。
在组件的当前版本中,我们选择的输出全部为大写,并在下一个组件的 UI 中显示为大写。让我们让它看起来更好一点:
下面是一个示例性解决方案:
<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>
在下一课中,我们将最终研究如何设计组件的用户界面。