本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
在 Step Functi JSONata ons 中使用转换数据
借 JSONata助,您可以获得强大的开源查询和表达式语言,用于在工作流程中选择和转换数据。有关简要介绍和完整 JSONata 参考资料,请参阅 JSONata.org 文档
您必须选择使用现有工作流程的 JSONata 查询和转换语言。在控制台中创建工作流程时,我们建议选择 JSONata 顶级状态机QueryLanguage
。对于使用的现有工作流程或新工作流程 JSONPath,控制台提供了将单个状态转换为的选项 JSONata。
选择后 JSONata,您的工作流程字段将从五个 JSONPath 字段(InputPath
、Parameters
、ResultSelector
ResultPath
、和OutputPath
)减少到只有两个字段:Arguments
和Output
。此外,您不会.$
在 JSON 对象密钥名称上使用。
如果您不熟悉 Step Functions,则只需要知道 JSONata 表达式使用以下语法即可:
JSONata 语法:"{% <JSONata expression> %}"
以下代码示例显示了从 JSONPath 到的转换 JSONata:
# Original sample using JSONPath
{
"QueryLanguage": "JSONPath", // Set explicitly; could be set and inherited from top-level
"Type": "Task",
...
"Parameters": {
"static": "Hello",
"title.$": "$.title",
"name.$": "$customerName", // With $customerName declared as a variable
"not-evaluated": "$customerName"
}
}
# Sample after conversion to JSONata
{
"QueryLanguage": "JSONata", // Set explicitly; could be set and inherited from top-level
"Type": "Task",
...
"Arguments": { // JSONata states do not have Parameters
"static": "Hello",
"title": "{% $states.input.title %}",
"name": "{% $customerName %}", // With $customerName declared as a variable
"not-evaluated": "$customerName"
}
}
给定customerName
分配给的输入{ "title" : "Doctor" }
和变量"María"
,两台状态机都将生成以下 JSON 结果:
{
"static": "Hello",
"title": "Doctor",
"name": "María",
"not-evaluated": "$customerName"
}
在下图中,你可以看到一个图形表示形式,显示了转换 JSONPath (左)到 JSONata (右)将如何降低状态机中步骤的复杂性:

您可以(可选)从状态输入中选择数据并将其转换为参数,然后发送到您的集成操作。然后 JSONata,您可以(可选)选择并转换操作的结果,以分配给变量和状态输出。
注意:赋值和输出步骤并行进行。如果您选择在变量赋值期间转换数据,则转换后的数据将无法在 “输出” 步骤中使用。必须在 “输出” 步骤中重新应用 JSONata 转换。

QueryLanguage 字段
在您的工作流程 ASL 定义中,有一个位于状态机定义的顶层和各个状态的QueryLanguage
字段。通过QueryLanguage
在单个状态内进行设置,可以在现有状态机 JSONata 中逐步采用,而不是一次性升级所有状态机。
该QueryLanguage
字段可以设置为"JSONPath"
或"JSONata"
。如果省略顶级QueryLanguage
字段,则默认为"JSONPath"
。如果某个状态包含州级QueryLanguage
字段,则 Step Functions 将使用该状态的指定查询语言。如果该州不包含QueryLanguage
字段,则它将使用顶级QueryLanguage
字段中指定的查询语言。
用 JSON 字符串编写 JSONata 表达式
当 ASL 字段、JSON 对象字段或 JSON 数组元素的值中的字符串被{% %}
字符包围时,该字符串的计算方式将为 JSONata 。注意,字符串必须以没有前导空格开头,并且必须以%}
没有尾随空格结尾。{%
不当打开或关闭表达式将导致验证错误。
一些示例:
-
"TimeoutSeconds" : "{% $timeout %}"
-
"Arguments" : {"field1" : "{% $name %}"}
处于一种Task
状态 -
"Items": [1, "{% $two %}", 3]
处于一种Map
状态
并非所有 ASL 字段都接受 JSONata。例如,必须将每个州的Type
字段设置为常量字符串。同样,Task
状态的Resource
字段必须是常量字符串。Map
状态Items
字段将接受 JSON 数组或必须计算为数组的 JSONata 表达式。
保留变量:$states
Step Functions 定义了一个名为的保留变量$states
。在 JSONata 状态中,分配了以下结构以$states
供在 JSONata 表达式中使用:
# Reserved $states variable in JSONata states
$states = {
"input": // Original input to the state
"result": // API or sub-workflow's result (if successful)
"errorOutput": // Error Output (only available in a Catch)
"context": // Context object
}
进入状态时,Step Functions 会将状态输入分配给。$states.input
的值$states.input
可用于所有接受 JSONata 表达式的字段。 $states.input
总是指原始状态输入。
对于Task
Parallel
、和Map
状态:
-
$states.result
如果成功,则指 API 或子工作流程的原始结果。 -
$states.errorOutput
指的是 API 或子工作流程失败时的错误输出。$states.errorOutput
可以在Catch
现场的Assign
或中使用Output
。
$states.errorOutput
在创建、更新$states.result
或验证状态机时,如果尝试访问或处于无法访问的字段和状态,则会被捕获。
该$states.context
对象为您的工作流程提供有关其特定执行的信息StartTime
,例如任务令牌和初始工作流程输入。要了解更多信息,请参阅 在 Step Functions 中从 Context 对象访问执行数据 。
处理表达式错误
在运行时, JSONata 表达式求值可能由于多种原因而失败,例如:
-
类型错误-如果
$x
或不是数字{% $x + $y %}
,$y
则表达式(例如)将失败。 -
类型不兼容-表达式的计算结果可能为该字段不接受的类型。例如,该字段
TimeoutSeconds
需要数字输入,因此如果$timeout
返回字符串,则表达式{% $timeout %}
将失败。 -
值超出范围-生成超出字段可接受范围的值的表达式将失败。例如,诸如之类的表达式
{% $evaluatesToNegativeNumber %}
将在TimeoutSeconds
字段中失败。 -
无法返回结果-JSON 不能表示未定义的值表达式,因此该表达式
{% $data.thisFieldDoesNotExist %}
会导致错误。
在每种情况下,解释器都会抛出错误:States.QueryEvaluationError
. 您的任务、地图和并行状态可以提供一个Catch
用于捕捉错误的Retry
字段和一个用于重试错误的字段。
从 JSONPath 转换为 JSONata
以下各节比较并解释了使用 JSONPath 和编写的代码之间的区别 JSONata。
没有更多的路径字段
ASL 要求开发人员在使用时使用 JSONPath字段Path
版本从状态数据中选择值,如中所TimeoutSecondsPath
示。使用时 JSONata,您将不再使用Path
字段,因为 ASL 会自动为您解释非路径字段中{% %}
包含的 JSONata 表达式,例如。TimeoutSeconds
-
JSONPath 旧版示例:
"TimeoutSecondsPath": "$timeout"
-
JSONata :
"TimeoutSeconds": "{% $timeout %}"
同样,Map
状态ItemsPath
已替换为接受 JSON 数组或必须计算为数组的 JSONata 表达式的Items
字段。
JSON 对象
ASL 使用术语有效载荷模板来描述可以包含Parameters
和ResultSelector
字段值 JSONPath 表达式的 JSON 对象。ASL 不会使用术语有效负载模板, JSONata 因为所有字符串都会 JSONata 进行评估,无论它们是单独出现的,还是出现在 JSON 对象或 JSON 数组中。
别再说了。 $
ASL 要求您在要使用的有效载荷模板 JSONPath 和内部函数中的字段名称后附加 .$
“”。当您指定时"QueryLanguage":"JSONata"
,您不再对 JSON 对象字段名称使用 .$
“” 约定。而是用{% %}
字符将 JSONata 表达式括起来。无论对象嵌套在其他数组或对象中的深度如何,您都对所有字符串值字段使用相同的约定。
参数和输出字段
当设置QueryLanguage
为时JSONata
,旧的 I/O 处理字段将被禁用(InputPath
、Parameters
ResultSelector
、ResultPath
和OutputPath
),并且大多数状态将获得两个新字段:Arguments
和Output
。
JSONata 与使用的字段相比,提供了一种更简单的执行 I/O 转换的方法。 JSONPath JSONata的功能比前五个字段Output
更强大 JSONPath。Arguments
这些新的字段名称还有助于简化您的 ASL,并阐明传递和返回值的模型。
Arguments
和Output
字段(以及其他类似的字段,例如Map
状态字段ItemSelector
)将接受 JSON 对象,例如:
"Arguments": {
"field1": 42,
"field2": "{% jsonata expression %}"
}
或者,你可以直接使用 JSONata 表达式,例如:
"Output": "{% jsonata expression %}"
输出也可以接受任何类型的 JSON 值,例如:"Output":true
、"Output":42
。
Arguments
和Output
字段仅支持 JSONata,因此在使用的工作流程中使用它们是无效的 JSONPath。相反,InputPath
、Parameters
、ResultSelector
、ResultPath
OutputPath
、和其他 JSONPath 字段仅在中受支持 JSONPath,因此在 JSONata 用作顶级工作流程或状态查询语言时,使用基于路径的字段是无效的。
通过状态
可选的 “通过” 状态的结果以前被视为虚拟任务的输出。 JSONata 选择为工作流或状态查询语言后,您现在可以使用新的 “输出” 字段。
选择状态
使用时 JSONPath,选择状态具有输入Variable
和许多比较路径,如下所示NumericLessThanEqualsPath
:
# JSONPath choice state sample, with Variable and comparison path
"Check Price": {
"Type": "Choice",
"Default": "Pause",
"Choices": [
{
"Variable": "$.current_price.current_price",
"NumericLessThanEqualsPath": "$.desired_price",
"Next": "Send Notification"
} ],
}
使用 JSONata,选择状态有一个你可以使用 JSONata 表达式Condition
的地方:
# Choice state after JSONata conversion
"Check Price": {
"Type": "Choice",
"Default": "Pause"
"Choices": [
{
"Condition": "{% $current_price <= $states.input.desired_priced %}",
"Next": "Send Notification"
} ]
注意:变量和比较字段仅适用于 JSONPath。状况仅适用于 JSONata。
JSONata 例子
可以在 Workflow Studio 中创建以下示例进行实验 JSONata。您可以创建和执行状态机,也可以使用测试状态来传入数据,甚至修改状态机的定义。
示例:输入和输出
此示例说明在您选择加入时$states.input
如何使用状态输入和Output
字段来指定状态输出 JSONata。
{ "Comment": "Input and Output example using JSONata", "QueryLanguage": "JSONata", "StartAt": "Basic Input and Output", "States": { "Basic Input and Output": { "QueryLanguage": "JSONata", "Type": "Succeed", "Output": { "lastName": "{% 'Last=>' & $states.input.customer.lastName %}", "orderValue": "{% $states.input.order.total %}" } } } }
当以以下内容作为输入执行工作流程时:
{ "customer": { "firstName": "Martha", "lastName": "Rivera" }, "order": { "items": 7, "total": 27.91 } }
测试状态或状态机执行将返回以下 JSON 输出:
{
"lastName": "Last=>Rivera",
"orderValue": 27.91
}

示例:使用筛选 JSONata
您可以使用 JSONata 路径运算符FilterDietProducts
状态。
用于筛选的状态机定义 JSONata
{ "Comment": "Filter products using JSONata", "QueryLanguage": "JSONata", "StartAt": "FilterDietProducts", "States": { "FilterDietProducts": { "Type": "Pass", "Output": { "dietProducts": "{% $states.input.products[calories=0] %}" }, "End": true } } }
测试的样本输入
{ "products": [ { "calories": 140, "flavour": "Cola", "name": "Product-1" }, { "calories": 0, "flavour": "Cola", "name": "Product-2" }, { "calories": 160, "flavour": "Orange", "name": "Product-3" }, { "calories": 100, "flavour": "Orange", "name": "Product-4" }, { "calories": 0, "flavour": "Lime", "name": "Product-5" } ] }
在状态机中测试步骤的输出
{ "dietProducts": [ { "calories": 0, "flavour": "Cola", "name": "Product-2" }, { "calories": 0, "flavour": "Lime", "name": "Product-5" } ] }

JSONata Step Functions 提供的函数
JSONata 包含字符串、数字、聚合、布尔函数、数组、对象、日期/时间和高阶函数的函数库。Step Functions 提供了可以在 JSONata 表达式中使用的其他 JSONata 函数。这些内置函数可用作 Step Functions 内部函数的替代品。内部函数仅在使用 JSONPath 查询语言的状态下可用。
注意:需要整数值作为参数的内置 JSONata 函数会自动向下舍入所提供的任何非整数。
$partiti JSONata on- 等同于对大型数组进行分区的States.ArrayPartition
内在函数。
第一个参数是要分区的数组,第二个参数是代表区块大小的整数。返回值将是一个二维数组。解释器将输入数组分成多个数组,其大小由区块大小指定。如果数组中剩余的项目数小于区块大小,则最后一个数组区块的长度可能小于之前的数组区块的长度。
"Assign": {
"arrayPartition": "{% $partition([1,2,3,4], $states.input.chunkSize) %}"
}
$rang e- JSONata 相当于生成值数组的States.ArrayRange
内在函数。
这个函数需要三个参数。第一个参数是代表新数组第一个元素的整数,第二个参数是代表新数组最后一个元素的整数,第三个参数是新数组中元素的增量值整数。返回值是一个新生成的值数组,其范围从函数的第一个参数到函数的第二个参数,中间的元素由 delta 进行调整。增量值可以是正值或负值,它将从最后一个元素开始递增或递减每个元素,直到达到或超过最终值。
"Assign": {
"arrayRange": "{% $range(0, 10, 2) %}"
}
$hash- JSONata 等效于计算给定States.Hash
输入哈希值的内在函数。
这个函数需要两个参数。第一个参数是要进行哈希处理的源字符串。第二个参数是一个字符串,表示用于哈希计算的哈希算法。哈希算法必须是以下值之一:"MD5"
、、"SHA-1"
、"SHA-256"
"SHA-384"
、"SHA-512"
。返回值是计算出的数据哈希值的字符串。
之所以创建此函数,是因为 JSONata 它本身不支持计算哈希的功能。
"Assign": {
"myHash": "{% $hash($states.input.content, $hashAlgorithmName) %}"
}
$random- JSONata 等同于返回随机数 n 的States.MathRandom
内在函数,其中。0 ≤ n < 1
该函数采用一个可选的整数参数,表示随机函数的种子值。如果您使用具有相同种子值的函数,它将返回相同的数字。
之所以创建这个重载函数,是因为内置 JSONata 函数$random
"Assign": {
"randNoSeed": "{% $random() %}",
"randSeeded": "{% $random($states.input.seed) %}"
}
$uuid-States.UUID
内部函数的 JSONata 版本。
该函数不带任何参数。此函数返回一个 v4 的 UUID。
之所以创建此函数,是因为 JSONata 它本身不支持生成 UUIDs功能。
"Assign": {
"uniqueId": "{% $uuid() %}"
}
$parse-用于反序列化 JSON 字符串的 JSONata 函数。
该函数将字符串化的 JSON 作为其唯一参数。
JSONata 通过支持此功能$eval
;但是,Step Fun $eval
ctions 工作流程不支持此功能。
"Assign": {
"deserializedPayload": "{% $parse($states.input.json_string) %}"
}