You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Groovy解析嵌套JSON遍历后仅返回最后一个对象问题排查

问题描述
  • 场景:使用Groovy脚本解析嵌套JSON数据,源JSON顶层包含merchant_id字段,以及两个同名update_product_request数组节点:第一个节点store_id值为Store_ID1,第二个节点store_id值为Store_ID2;每个update_product_request节点下嵌套update_product_request_list商品数组,数组元素包含quantity、bar_code、product_identifier、original_price、sale_price、uom、currency、size、weight_type等商品属性字段。
  • 原实现逻辑:遵循SAP CPI自定义脚本规范编写处理代码,引入JsonSlurper解析JSON文本、JsonOutput序列化输出处理结果;原计划通过两层each嵌套循环遍历所有update_product_request下的商品条目,对quantity、original_price、sale_price三个字段做空值判断、格式清洗与数值类型转换。
  • 异常现象:脚本执行后输出结果仅保留store_id为Store_ID2的update_product_request节点,Store_ID1对应节点完全丢失,不符合保留两个update_product_request节点的预期;多次调整循环写法均未解决问题,初步判断遍历逻辑存在错误,未正确覆盖所有集合元素。
故障根因

该问题90%以上的诱因是遍历过程中错误覆盖了顶层update_product_request的数组引用:

  • 编写循环时如果在each遍历块内直接执行jsonMap.update_product_request = 当前遍历到的单个requestNode这类赋值操作,会把原本是数组类型的顶层字段直接覆盖为单个节点对象,循环执行完后字段值就只剩最后一次遍历到的Store_ID2节点。
  • 另一类常见错误是新建临时存储集合时作用域错误,把集合初始化写在了循环内部,导致每次遍历都会重置集合,最终也只会存入最后一次遍历的节点数据。
修复代码(适配SAP CPI自定义脚本规范)
import com.sap.gateway.ip.core.customdev.util.Message
import groovy.json.JsonSlurper
import groovy.json.JsonOutput

def Message processData(Message message) {
    // 读取报文体并解析为Map结构
    String rawBody = message.getBody(String)
    def rootJson = new JsonSlurper().parseText(rawBody)

    // 关键:先获取完整的update_product_request数组,不要在遍历中覆盖该引用
    List updateRequestNodes = rootJson.update_product_request as List
    // 遍历所有门店请求节点
    updateRequestNodes.each { currentRequest ->
        // 获取当前节点下的商品列表
        List productList = currentRequest.update_product_request_list as List
        productList.each { currentProduct ->
            // 数值字段空值兜底+格式清洗+类型转换
            currentProduct.quantity = currentProduct.quantity?.toString()?.isBigDecimal() ? currentProduct.quantity.toString().toBigDecimal() : BigDecimal.ZERO
            currentProduct.original_price = currentProduct.original_price?.toString()?.isBigDecimal() ? currentProduct.original_price.toString().toBigDecimal() : BigDecimal.ZERO
            currentProduct.sale_price = currentProduct.sale_price?.toString()?.isBigDecimal() ? currentProduct.sale_price.toString().toBigDecimal() : BigDecimal.ZERO
        }
    }

    // 序列化处理后的结构写回报文
    message.setBody(JsonOutput.toJson(rootJson))
    return message
}
编写注意事项
  • 遍历数组节点前统一强转为List类型,避免JsonSlurper在数组只有单个元素时自动解析为Object类型,导致后续遍历逻辑失效
  • 所有字段修改直接在解析得到的原Map结构对应节点上操作,不要在循环过程中反复给顶层数组字段赋值单个节点对象
  • 如果需要做节点过滤,必须在循环外部初始化结果List,遍历过程中将处理完成的节点逐个add进结果集,循环结束后再一次性赋值给顶层字段
  • 涉及数值转换优先使用BigDecimal类型,避免SAP CPI后续处理金额、库存字段时出现浮点数精度问题

内容的提问来源于stack exchange,提问作者AKASH SHRIVASTAVA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 20:15:44