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

在Scala中遍历JSON并添加指定新字段的技术问询

使用Circe Optics批量新增JSON字段(含数组场景)

需求说明

给定原始JSON:

{
  "A": {
    "NestedArray": [
      {
        "AlreadyHere2": "x"
      },
      {
        "AlreadyHere2": "x"
      },
      {
        "AlreadyHere2": "x"
      }
    ]
  }
}

需要根据指定的JSON路径列表,为每个路径对应的位置添加值为CONSTANT的字段,最终生成目标JSON:

{
  "A": {
    "A_1": "CONSTANT",
    "A_2": "CONSTANT",
    "NestedArray": [
      {
        "AlreadyHere2": "x",
        "arrayValue": "CONSTANT"
      },
      {
        "AlreadyHere2": "x",
        "arrayValue": "CONSTANT"
      },
      {
        "AlreadyHere2": "x",
        "arrayValue": "CONSTANT"
      }
    ]
  }
}

指定路径示例:

val list = List("A.A_1", "A.A_2", "A.NestedArray.arrayValue")

要求实现需支持后续新增路径,不能局限于当前JSON结构,需同时处理普通字段新增和数组元素批量新增的场景。

实现方案

1. 引入Circe依赖

在Scala项目的build.sbt中添加以下依赖:

libraryDependencies ++= Seq(
  "io.circe" %% "circe-core" % "0.14.6",
  "io.circe" %% "circe-optics" % "0.14.6",
  "io.circe" %% "circe-parser" % "0.14.6"
)

2. 核心代码实现

import io.circe._
import io.circe.parser._
import io.circe.optics.JsonPath._

object JsonFieldAdder {
  private val CONSTANT_VALUE = Json.fromString("CONSTANT")

  def addFieldsToJson(originalJsonStr: String, paths: List[String]): Either[ParsingFailure, Json] = {
    parse(originalJsonStr).map { baseJson =>
      paths.foldLeft(baseJson) { (currentJson, path) =>
        val pathSegments = path.split('.').toList
        pathSegments match {
          // 处理普通对象字段:路径最后一段是要新增的字段名,前面是对象层级
          case parentSegments :+ newField =>
            // 构建父对象的路径定位器
            val parentPath = parentSegments.foldLeft(root) { (path, segment) =>
              path.selectDynamic(segment)
            }
            // 判断父路径是否指向数组
            val isArrayTarget = currentJson.hcursor
              .downField(parentSegments.head)
              .downFields(parentSegments.tail: _*)
              .focus
              .exists(_.isArray)
            
            if (isArrayTarget) {
              // 数组场景:遍历数组每个元素,添加字段
              parentPath.each.json.modify(_.mapObject(_.add(newField, CONSTANT_VALUE)))(currentJson)
            } else {
              // 普通对象场景:给父对象添加新字段
              parentPath.json.modify(_.mapObject(_.add(newField, CONSTANT_VALUE)))(currentJson)
            }
        }
      }
    }
  }

  // 测试用例
  def main(args: Array[String]): Unit = {
    val rawJson = """{
      "A": {
        "NestedArray": [
          {
            "AlreadyHere2": "x"
          },
          {
            "AlreadyHere2": "x"
          },
          {
            "AlreadyHere2": "x"
          }
        ]
      }
    }"""
    val targetPaths = List("A.A_1", "A.A_2", "A.NestedArray.arrayValue")
    addFieldsToJson(rawJson, targetPaths).foreach(println)
  }
}

3. 关键逻辑说明

  • 路径解析:将每个路径按.拆分为层级段,拆分出父对象路径和要新增的字段名
  • 动态类型判断:通过Circe的hcursor判断父路径指向的是数组还是普通对象,适配不同场景
  • 普通字段新增:定位到目标父对象后,调用mapObject直接添加新字段
  • 数组元素批量处理:使用each操作符遍历数组所有元素,为每个元素统一添加指定字段
  • 扩展性:后续新增的路径只要符合父层级.字段名格式,无论父层级是普通对象还是数组,都能自动适配处理

内容的提问来源于stack exchange,提问作者Jackson Li

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 12:44:53