JSONdata 是一种开源查询和转换语言,专为 JSON 数据设计,我们将使用它来访问和解析 API 返回的 JSON 响应正文中的数据。
您可以使用https://ry.jsondata.org/轻松测试查询,或者如果您喜欢一些更高级的 Javascript 格式,也可以使用https://www.stedi.com/jsondata/Playground测试您的查询。我们还是使用 JSONdata 自己的练习工具来进行介绍。

练习者将启动其发票虚拟对象,我们将其用作参考点。原始输入数据在左侧,JSONdata 表达式查询在右上角,该表达式找到的结果将呈现在右下角。
要重新对齐 JSON 对象,请使用虚拟对象右侧的小缩进工具,并使用右上角的共享功能保存当前的表达式。
关于练习器,这就是您目前需要了解的全部!接下来,在默认发票模板中使用查询。
如果您只是想了解关键知识,或在启用后作为参考,请查看我们的备忘单。
映射数据

根级别字段:帐户
根对象中的嵌套字段:帐户。 “帐户名称”
如果找到另一个 JSON 结构,您可以使用点符号输入以下字段。
根级别数组中的嵌套字段:
此帐户中的首个订单:
Account.Order[0]
提醒:第一项的数组索引从 [0] 开始。数组中最后一项的快捷方式是 [-1]。
同一对象中的第一个产品的颜色:
Account.Order[0].Product[0].Description.Colour
从根级别数组中检索项目数组:
如果有多个值匹配一个查询,JSONeta 会自动将它们聚合。
检查整个对象 Account.Order 并检索其中所有的 OrderID:
Account.Order.OrderID
筛选数据

定义正在访问的目标,例如
Account.Order.OrderID
现在在匹配的位置添加条件 —— 对于数组中的每个循环,添加一对 [] 括号:
例如,仅包含产品价格高于 30 且仅订购了一次的订单,并显示相应产品名称:
Account.Order.Product[Price > 30 and Quantity = 1].'Product Name'
例如:仅包含产品 Description.Weight 大于 1 的订单,并显示相应的 OrderID:
Account.Order[Product[Description.Weight > 1]].OrderID
或者,您也可以检查 true 语句,例如
Account.Order[Product["Purple" in Description.Colour]].OrderID
此外,如果您想检查多个密钥,可以将其与通配符搜索结合使用,例如
Account.Order[Product["Purple" in Description.*]].OrderID
其它路径运算符
( https://docs.jsondata.org/path-operator )
^( ... )(排序依据)
按 OrderID 降序排序:
Account.Order^(>OrderID)
按产品从最便宜到最贵排序:
Account.Order.Product^(Price)
*(通配符)
访问任意SKU,无论直接父级命名如何:
Account.Order.*.SKU
访问任意产品名称,无论父命名如何:
**.'Product Name'
%(母公司)
在当前数据结构中向后搜索:
Account.Order.Product.{
'Account': %.%.`Account Name`,
'Order': %.OrderID,
'Product': `Product Name`
}
#(位置变量绑定)
创建索引,从 0 开始:
Account.Order#$i[Product.[Quantity > 0]].{
'Order ID': OrderID,
'Order Number': $i + 1
}
@(上下文变量绑定)
临时分配新的数据结构,允许跨对象映射:
Account@$A.Account.Order@$O.{
"Account Name": $A.'Account Name',
"OrderID": $O.OrderID
}
条件语句
类似于 JS 中的三元运算符,可以使用 ?用于 if 和 : 用于 else 语句。布尔运算符和/或可用于创建链条件。
IF CONDITION IS TRUTHY ?这样做(否则什么都不做)
IF CONDITION IS TRUTHY ?执行此操作:其它这样做
$count(Account.Order) > 1 ? "REPEAT CUSTOMER"
Account.Order[0].Product[0].Price <= 100 or Account.Order[0].Product[1].Price <= 100 ? "Bargain" : "VIP" = "Bargain"
操作数据
支持的运营商
| 运算符 | 优先级 | 描述 |
| 乘以(*) | 5 | 两个数字相乘 |
| 除号(/) | 5 | 两个数字相除 |
| 模数(%) | 5 | 返回两个数字相除的余数 |
| 串联(&) | 4 | 连接两个字符串 |
| 添加 (+) | 4 | 将两个数字相加 |
| 减 (-) | 4 | 两个数字相减 |
| 等于 (=) | 3 | 测试两个值是否相等 |
| 不等于 (!=) | 3 | 测试两个值是否不相等 |
| 大于(> ) | 3 | 如果左侧的值大于右侧的值,则返回 true |
| 大于或等于 (> =) | 3 | 如果左侧的值大于或等于右侧的值,则返回 true |
| 小于 (< ) | 3 | 如果左侧的值小于右侧的值,则返回 true |
| 小于或等于 (< =) | 3 | 如果左侧的值小于或等于右侧的值,则返回 true |
| 逻辑 AND(和) | 2 | 如果向左和向右的值都为 true,则返回 true |
| 逻辑 OR(或) | 1 | 如果左侧值为 true,或右侧值为 true,则返回 true |
例如连接字符串:
Account.Order[0].Product[0].Description.Colour & " " & Account.Order[0].Product[0].'Product Name'
内置函数
请注意,为便于阅读,这些内容已进行了大量删节。完整的文档参见此处: https://docs.jsondata.org/overview.html
注意:多行表达式需要括在 () 中
强制字符串类型: $string ( Account.Order[0].Product[0].ProductID ):“858383”
强制数字类型: $number ( Account.Order[0].Product[0].SKU ):406654608
大写字符串: $uppercase (客户。订单[ 0 ] .OrderID ):"ORDER103"
小写字符串: $lowercase ( Account . Order [ 0 ]. Product [ 0 ]. Description . color ): "措辞"
输出 0 到 1 之间的随机数: $random ()
计算数组中的对象数量: $count (客户.订单)
计算数组中匹配条件的对象数量: $count (客户.订单.产品[价格>30 ])
字符串的字符数: $length ( Account . 'Account Name' )
替换/移除字符串中的特定字符: $replace ( Account . Order [ 0 ]. Product [ 0 ]. 'Product Name' , "Biller ", "" ):"Hat"
按特定字符数剪切字符串: $substring ( $string ( Account . Order [ 0 ]. Product [ 0 ]. ProductID ), 1 , 2 )
根据特定模式截断字符串: $substringEnd ( Account . Order [ 0 ]. OrderID , "order" )
使用拆分 + 联接的类似结果:
$Join ( $spplit ( Account .Order [ 0 ] .Product [ 0 ]. 'Product Name', " "), '_' )
也可写为 ~>函数:
$spplit ( Account . Order [ 0 ]. Product [ 0 ]. 'Product Name', " ) ~> $加入('_' )
检查字符串是否包含特定模式——模式可以是精确的字符串或正则表达式:
$contains ( Account . Order [ 0 ]. Product [ 0 ]. 'Product Name' , "Hat" )
日期和时间
大多数日期将以 ISO 8601 国际标准传递,如下所示2023-04-20T13:09:39+00:00 (包含时区信息)或2023-04-20T13:09:39Z (键入毫秒UTC 偏移量)。它们易于阅读,但无法由 JSONata 进行原生操作。
因此,通常需要将它们转换为 UNIX 时间,即自 1970 年 1 月 1 日 00:00:00 UTC(Unix 纪元)以来经过的秒数,它不再是人类可读的,而是一个整数与其它 UNIX 日期相比可相加 / 减去 。JSONdata 原生支持毫秒数,即 Unix 纪元(即 UNIX * 1000)以来的毫秒数。
$now ():“2023-04-20T13:39:58.216Z”
$milis ():1681998518175
现在可以通过在字符串中定义图片(您的目标模式),将这些毫秒重新转换为您选择的日期格式: https://www.w3.org/TR/xpath-features-31/#date-图片-string
模式示例: https://www.w3.org/TR/xpath-features-31/#date-time-examples
| 说明符 | 含义 |
| 是 | 年份(绝对值) |
| M | 一年中的月份 |
| D | 一个月中的第几天 |
| F | 一周中的第几天 |
| H | 24 小时制时数 |
| h | 半天中的小时(12 小时) |
| P | 上午/下午标记 |
| m | 一个小时中的第几分钟 |
| s | 一分钟中的第几秒 |
| Z | 时区 |
例如$fromMellis ( $值得一提的是(), '[M]/[D]/[Y01]' ) 将返回"4/20/23" ,
$fromMellis ( $值得一提的是(), '[D01].[M01].[Y0001] [H#1]:[m01]' )将返回"20.04.2023 13:51"
付诸实践——假设您的响应数据中有两个日期,您想知道从今天到现在已经有多少天了。
“2023-04-20T00:00:00.000Z”
“20.04.2023”
将它们都转换为米利斯数 - 第二个日期不符合标准 ISO 8601 模式,因此您需要提供图片,以便 JSONata 知道哪个值是您的日、月、年,以及任何时间信息您可能有 个空闲状态。
$toMellis ( '2023-04-20T00:00:00.000Z' ) :1681948800000
$toMellis ( '20.04.2023' , '[D01].[M01].[Y0001]' ):1681948800000
您也可以通过标准函数 $miles() 获得当前的米利斯时间:1681999968402
现在只需将两者相减,即可得到两个日期之间的差值(以毫秒为单位):1681999968402 - 1681948800000 = 51296367
使用通用时间换算:
1000 毫秒 = 1 秒
60 秒 = 1 分钟
60 分钟 = 1 小时
结果向下舍入,您会收到从现在到您提供的时间戳共计 14 小时的消息:
$ Round (51296367 / 1000 / 60 / 60 ) = 14
将以下各项操作合并为一行:
$round(($millis() - $toMillis('20.04.2023', '[D01].[M01].[Y0001]')) / 1000 / 60 / 60)
特殊输出
工单“OneLines”
由于您可能只有一次回复机会,因此您需要在一个参数中传递尽可能多的信息。JSONana 会为您处理聚合,使您可以自由使用文本副本。
假设您要呈现订单中所有产品的 SKU 和价格:
Account.Order.Product
由于您最终只想使用一大行文本来包含所有已考虑的产品,因此只需创建一个包含所有所需信息的共享数组即可:
Account.Order.Product.(SKU & Price)
现在您只需要将它们组合成一个大字符串,并用换行符作为分隔符:
$join(Account.Order.Product.("SKUs: " & SKU & ", " & "Price: " & Price), "\n")
注意:考虑您的客户关系管理限制 - Zendesk Support提供一些基本的格式设置,因此 \n 在回复电邮中呈现时会正确转换为换行符,但并非所有系统都是如此。
卡片和轮播
卡片和轮播是 JSONdata 的真正优势,因为它可以在本地处理数据查询和聚合,只要您的响应遵循相同的架构。C&C 由一组对象组成,其中每个对象代表您的一张卡片。下图是有两张卡片的简单 C&C 结构示例:
[
{
"imageURL": data.url1,
"title": data.title1,
"description": data.description1
},
{
"imageURL": data.url2,
"title": data.title2,
"description": data.description2
}
]
重要的是,数组中的所有对象都遵循相同的结构,因此可以通过相同的共享密钥访问它们。另请务必注意您的客户关系管理限制。
举一个简单的例子,让我们再次根据发票样本数据构造一个 C&C。让我们从一开始就使用数组开始吧 —— 任何包含多个响应对象的查询结果都将自动转换为数组,但是最好有这个功能,以防您的结果本身仅包含一个对象。
[Account.Order.Product.'Product Name']
[Account.Order.Product.SKU]
[Account.Order.Product.Description.Colour]
这些是我们感兴趣的字段。我们将它们合并为一个对象 —— 请务必为目标对象中的每个键值命名:
[
Account.Order.Product.
{
"name": 'Product Name',
"sku": SKU,
"colour": Description.Colour
}
]
如果您需要更高级别的值,只需在更高级别开始查询即可。如果您还要添加 [帐户,订单。 OrderID ] ,将其替换为数组:
[
Account.Order.
{
"orderId": OrderID,
"name": Product.'Product Name',
"sku": Product.SKU,
"Colour": Product.Description.Colour
}
]
您会注意到,不再有直接的 1:1 匹配,因为每个订单都可以包含多个项目,这就是为什么此响应创建了看似随机的字符串数组。您可以通过以下方法解决此问题:间接访问父对象(请参阅父绑定),在 JSONdata 中暂时分配不同的对象结构(请参阅上下文变量绑定),添加辅助 C&C 以所选顺序循环显示项目,或进一步转换数据,取决于您的理想用户体验。以下是转换后的示例:
[
Account.Order.
{
"orderId": OrderID,
"name": $join(Product.'Product Name', ", "),
"totalPrice": $sum(Product.Price)
}
]
如果您想进一步保护您的查询,让我们添加一些失败保险,以防您没有预期的响应数据(例如 404),并设置截止,以防响应返回的结果比您的客户关系管理可支持的多(例如 10对于 SunCo 小组件):
Account.Order ?
[Account.Order[[0..9]].
{
"orderId": OrderID,
"name": $join(Product.'Product Name', ", "),
"totalPrice": $sum(Product.Price)}]
: [{"orderId": "???", "name": "Cannot find your item?"}]
重要提示:请确保所有 C&C 键都遵循驼峰命名法,不支持_参数名称。
现在所有这些键,例如 orderId、name、totalPrice 都将可用于您的轮播。在用户界面中将轮播类型更改为动态,并添加上面托管查询的参数名称,例如orderList 。

现在您可以通过添加 % 速记来访问数组对象中的任意键 —— 或者直接在卡片的在线交谈中输出:

或者将它们存储到会话中,方法是用一个操作填充您选择的卡片,引用您选择的对象的密钥到您选择的参数名称,例如:


翻译免责声明:本文章使用自动翻译软件翻译,以便您了解基本内容。 我们已采取合理措施提供准确翻译,但不保证翻译准确性
如对翻译准确性有任何疑问,请以文章的英语版本为准。
