有时在工作流开发过程中,我们到目前为止讨论过的工具不足以实现所需的逻辑。通常,每当您需要操作原始输入数据时,例如,在表达式中比较原始输入数据之前或将其保存在上下文变量中之前,都会发生这种情况。在这些情况下,在工作流标记中使用我们的嵌入式 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>
在下一课中,我们将最终研究如何设计组件的用户界面。