值表达式 (Value Expressions)

最后更新:2026年7月20日

Script 中,凡是需要值的位置(URL、请求 body、字段值、条件、筛选值、目标 id 等)都是下面三种形态之一。本文档说明这三种形态、值来自何处(上下文根),以及 WEEGLOO 数据特有的 Locale 映射规则。Statement 目录中的所有字段都遵循此规则。

三种形态

形态规则示例
引用 (reference)在上下文中解析字符串内的 { /json-pointer }"{ /payload/fields/title }"
字面量 (literal)不含 { /ptr } 的值(字符串、数字、布尔值、对象、数组)。原样使用。"draft", 42, true, { "a": 1 }
运算与条件 (JsonLogic)以单个运算符作为键的对象。操作数本身又是值表达式(引用、字面量、嵌套)。{ "+": [ "{ /vars/n }", 1 ] }

这三种形态可以嵌套:在 JsonLogic 操作数中放入引用,把引用的结果再放入运算,即可这样组合。

引用:{ /json-pointer }

在花括号内放入 RFC 6901 JSON Pointer(必须以 / 开头)。花括号周围允许有空格({ /a/b }{/a/b} 相同)。

单一指针与混合模板:类型规则

  • 当整个字符串是单一指针时,会保持该值的原始类型(数字则数字,对象则对象,数组则数组)。
  • 与字面量文本混合时,会拼接(concatenation)为字符串
"{ /payload/fields/count }"                 // 若为数字值则保持数字原样(例如 42)
"{ /payload/fields/tags }"                  // 若为数组则保持数组原样
"page-{ /payload/fields/n }-of-10"          // 字符串拼接 → "page-42-of-10"
"Bearer { /payload/fields/token }"          // 字符串拼接 → "Bearer abc123"

缺失值与转义

  • 当路径不存在或值为空时,单一指针会作为 null 处理混合模板会作为空字符串处理
  • 若要把 { 当作字面量使用,请用 \{ 转义(该位置不会被解释为指针)。

上下文根:值从何而来

{ /pointer } 的顶层段是下面五种之一。

内容
/payload调用时传入的 JSON payload(输入)。例如:{ /payload/fields/email }
/headers调用时传入的请求 HTTP 头。键为小写,每个名称对应单个值。例如:{ /headers/authorization }
/<name>带有 name 的前置 statement 的结果。例如:{ /order/sys/id }
/vars/<name>SetVar 声明的 script-scoped 可变变量。例如:{ /vars/total }
/error仅在 Trycatch 块内使用。即捕获到的错误 { message, statement }。例如:{ /error/message }

statement 结果的形态

带有 name 的 statement,其结果形态因类型而异。

statement结果形态引用示例
Http{ status, body }{ /resp/status }, { /resp/body/choices/0/message/content }
ResourceCreateResourceRead(单条)、ResourceFind(单条)资源本身{ /post/sys/id }, { /post/fields/title/en-US }
ResourcePageRead{ items, next }{ /page/items/0/sys/id }, { /page/next }
  • ResourceFind 在没有匹配时绑定 null。用 { "==": [ "{ /found }", null ] } 来分支判断是否存在。
  • ResourceRead(单条)在目标不存在时会报错(可用 Try 处理)。详情参见 Statement 目录的资源读取

运算与条件:JsonLogic

需要计算或条件时,使用 jsonlogic.com 规范中的运算符对象。

  • 数据访问统一使用 { /ptr } 引用,而非原生的 var(dot-path)写法。引擎先解析操作数中的指针,再应用运算符。
  • 单键对象的键如果是已注册的运算符,就当作运算处理;否则当作普通对象。

运算符表

分类运算符含义与示例
条件if(别名 ?:{ "if": [条件, 真值, 条件2, 真值2, …, 默认值] }。取第一个为真的条件对应的值;若都不满足,则取最后的默认值。
逻辑andor短路求值。and 返回第一个 falsy(或最后一个),or 返回第一个 truthy(或最后一个),并以其值本身返回。
逻辑! (not)、!! (to-bool){ "!": x } 是对 truthy 取反,{ "!!": x } 是判断是否 truthy。存在性检查常用 !!
相等==!=宽松比较(强制转换为数字后比较。"1"==1 为真)。
相等===!==严格比较(连类型也比较)。
比较<<=>>=可链式{ "<": [1,2,3] }1<2 AND 2<3。无法数字化(NaN)时为 false。
算术+所有操作数之和。
算术-一个操作数时取负,两个操作数时做减法。
算术*/%乘、除、取余。
聚合minmax操作数的最小值、最大值。
字符串cat把所有操作数拼接成字符串。
包含in{ "in": [needle, haystack] }。haystack 是字符串时判断子字符串,是集合时判断元素包含。
数组merge把多个数组或值扁平化为一个数组(用于累积收集)。

不支持数组遍历运算符(mapfilterreduceallsomenone)。Script 通过 Loop 遍历数组(参见 Statement 目录的 Loop)。

数字转换与示例

数字转换规则如下。数字保持原样,true 转为 1,false 转为 0,字符串会被解析(无法解析则为计算失败值),null 转为 0。

{ "-":  [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] }   // 余额 - 费用
{ "<":  [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] }   // 余额 < 费用 → boolean
{ "and": [ { "<": [ "{ /a/body/risk }", 0.5 ] }, { ">=": [ "{ /b/body/score }", 700 ] } ] }
{ "cat": [ "id-", "{ /payload/sys/id }" ] }                                    // "id-<uuid>"
{ "!!": "{ /found/sys/id }" }                                                  // 存在则为 true
{ "merge": [ "{ /vars/ids }", [ "{ /row/sys/id }" ] ] }                        // 向数组累积一个元素
{ "if": [ "{ /page/next }", "{ /page/next }", "END" ] }                        // 有 next 则取 next,没有则取 "END"

真假判定 (Truthiness)

ifandor!!! 以及 If.conditionLoop.while 按以下规则判定真假。

  • falsynullfalse、数字 0、空字符串 ""、空集合(空数组)。
  • truthy:其余全部(非 0 的数字、非空的字符串和数组、所有对象)。

键也可以引用

fields 这样的映射,其也支持 { /ptr } 引用。键会在运行时解析。

"fields": { "{ /payload/fields/fieldName }": { "en-US": "{ /payload/fields/fieldValue }" } }

如果两个键解析为相同的值,就会发生冲突并导致引擎报错。

Locale 映射 (LocaleValueMap):ContentMedia 特有的规则

WEEGLOO ContentMedia 的每个字段都不是单一值,而是按 Locale 划分的映射(例如 balance{ "en-US": 1, "ko-KR": 10 })。因此读写时必须连同 Locale 一起处理。Media 同样,其 titledescription(标量)、file(摄取指令)都是 Locale 映射。像 /payload 或 HTTP 响应这类并非 ContentMedia 的 JSON 则与此规则无关(保持 schema 所定义的结构,是标量就是标量)。

读取

  • 要取得标量,需Locale 一起指定:{ /<name>/fields/<field>/<locale> }(例如 { /post/fields/title/en-US })。
  • 不带 Locale 时,{ /<name>/fields/<field> } 会返回 Locale 映射的整个对象
  • localized:false 字段只存在于默认 Locale 存储桶中,因此用该默认 Locale 代码来读取。

写入 (ResourceCreate、ResourceUpdate、ResourcePatch 的 fields)

值是Locale 划分的映射 { "<locale>": <标量值表达式> }。与读取对称。

"fields": {
  "title":  { "en-US": "Hello", "ko-KR": "안녕" },   // 多个 Locale 就并列存储桶
  "status": { "en-US": "paid" }
}
  • ResourceCreate 必须在所有要填充的字段中都包含 Space 默认 Locale 存储桶(default-locale 规则)。
  • ResourceUpdate 是整体替换fields 中不存在的字段和 Locale 会被移除(包括 file)。
  • ResourcePatch 只更新指定的字段和存储桶(其余字段和 Locale 保持不变)。
  • 用字面量 null 删除:当值为字面量 null 时,会删除该 (field, locale) 存储桶(这是在 Patch 中清空特定 Locale 的标准做法)。""(空字符串)不是删除,而是设置为空值。值表达式({ /ptr })在运行时求值为 null 时不是删除,而是报错(不会静默吞掉 payload 的缺失)。删除只适用于字面量 null
  • Mediafile:值不是标量,而是摄取指令 { "source": …, "encoding": "url"|"base64" }。包含文件的写入仅限 Async(参见 Statement 目录的 ResourceCreate)。
  • localized:false 字段只放入默认 Locale 存储桶
  • Locale 代码(映射的键)也可以用 { /ptr } 引用(参见上文 键也可以引用)。用于创建动态 Locale

locale 便利字段

ResourceCreateResourceUpdateResourcePatch 中提供 locale 时,引擎会自动把 fields 的每个值包装成 { <locale>: 值 } 存储桶。 也就是说只需提供标量即可。

// 下面两个是等价的
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
  "locale": "en-US", "fields": { "title": "Hello" } }
 
{ "type": "ResourceCreate", "resource": "Content", "contentType": { "sys": { "id": "ct_post" } },
  "fields": { "title": { "en-US": "Hello" } } }

如果在提供 locale 的同时又在值中嵌套了 Locale 映射({ "en-US": … }),就会变成 { <locale>: { "en-US": … } } 这样的双重嵌套(属于作者失误)。请统一为:用 locale 时只写标量,不用时只写显式的 Locale 映射。

where 与 order 中的 Locale

  • whereorder 中,fields.XSpace 默认 Locale 会被引擎自动应用(与 CMA 查询一致)。
  • 要针对特定 Locale,请用 fields.X.<locale> 明确指定。
"where": { "fields.slug": { "eq": "{ /payload/fields/slug }" } }   // 默认 Locale 的 slug
"where": { "fields.title.ko-KR": { "prefix": "안" } }              // 特定 Locale