如何高效为嵌套JsonObject动态新增以自身stat值为名、data值为值的字段
修正后的Gson实现(无额外依赖,适配现有代码)
该方案直接在原JSON对象上修改,不新建冗余结构,完全保留原有字段和数据类型,无重复解析操作。
import com.google.gson.{JsonArray, JsonObject, JsonParser, JsonPrimitive} // 替换为你的实际输入JSON字符串 val inputJsonStr = """{"values":[{"id":"1","properties":[{"stat":"memory","data":8},{"stat":"cpu","data":4}]},{"id":"2","properties":[{"stat":"status","data":"OK"},{"stat":"cpu","data":4}]}]}""" val rootObject = JsonParser.parseString(inputJsonStr).getAsJsonObject // 遍历values数组 val valuesArray = rootObject.getAsJsonArray("values") valuesArray.forEach { valueElem => val valueObj = valueElem.getAsJsonObject // 仅处理存在properties字段的对象 if (valueObj.has("properties")) { val propsArray = valueObj.getAsJsonArray("properties") // 逐个处理properties内的对象 propsArray.forEach { propElem => val propObj = propElem.getAsJsonObject // 仅同时存在stat、data字段时执行新增 if (propObj.has("stat") && propObj.has("data")) { val newFieldKey = propObj.get("stat").getAsString /* 若需要实现你期望输出中非数字类型data设为0的逻辑,使用下面的newFieldValue定义 val newFieldValue = propObj.get("data") match { case num if num.isJsonNumber => num case _ => JsonPrimitive(0) } */ // 保留原始data类型的写法 val newFieldValue = propObj.get("data") propObj.add(newFieldKey, newFieldValue) } } } } // 输出处理后的JSON val outputJsonStr = rootObject.toString
函数式实现(circe库,类型安全)
如果使用Scala生态常用的circe库,代码更简洁,错误处理更完善:
import io.circe.{Json, JsonObject} import io.circe.parser._ import io.circe.syntax._ val inputJsonStr = """{"values":[{"id":"1","properties":[{"stat":"memory","data":8},{"stat":"cpu","data":4}]},{"id":"2","properties":[{"stat":"status","data":"OK"},{"stat":"cpu","data":4}]}]}""" val processResult = for { rootJson <- parse(inputJsonStr) rootObj <- rootJson.asObject.toRight("根节点不是JSON对象") valuesArray <- rootObj("values").flatMap(_.asArray).toRight("values字段不是数组") // 处理每个value元素 updatedValues = valuesArray.map { valueJson => val valueObj = valueJson.asObject.getOrElse(JsonObject.empty) val propsArray = valueObj("properties").flatMap(_.asArray).getOrElse(Seq.empty) // 处理每个properties元素 val updatedProps = propsArray.map { propJson => val propObj = propJson.asObject.getOrElse(JsonObject.empty) val statKey = propObj("stat").flatMap(_.asString).getOrElse("") // 非数字类型默认设为0,需要保留原类型可替换为val dataVal = propObj("data").getOrElse(Json.Null) val dataVal = propObj("data").filter(_.isNumber).getOrElse(Json.fromInt(0)) propObj.add(statKey, dataVal).asJson } valueObj.add("properties", updatedProps.asJson).asJson } // 替换根节点的values字段 updatedRoot = rootObj.add("values", updatedValues.asJson) } yield updatedRoot.asJson.noSpaces // 输出结果,处理失败时返回错误信息 val output = processResult.fold( error => s"JSON处理失败: $error", success => success )
方案优势
- 仅单次解析JSON,无重复读取、手动字符串拼接操作
- 按层级遍历结构,避免原有JsonPath实现的通配符匹配导致的跨元素错配问题
- 直接在原对象上新增字段,完全保留原有
stat、data等字段,不修改原有内容 - 对缺失字段的场景有容错,不会抛出空指针异常
内容的提问来源于stack exchange,提问作者user13755105
相关产品推荐
相关产品推荐

