如何用Groovy在JSON指定位置添加字段及处理批量递增
解决Groovy中JSON指定位置插入键值对及批量递增赋值问题
首先得明确一点:JSON规范里对象的键是无序的,但很多时候我们希望输出的JSON保持特定的可读性顺序,这就需要借助有序的Map实现来处理。
问题1:在指定位置("sell": true之后)插入"total": "1000"
你的代码用json.put()会把键值对加到Map末尾,因为默认JsonSlurper解析出来的是普通HashMap(无序)。要实现有序插入,我们需要用LinkedHashMap来维护键的顺序,步骤如下:
- 先修正原JSON的语法错误(末尾多余的逗号会导致解析失败)
- 解析时指定使用有序的
LinkedHashMap - 遍历目标对象的键值对,在遇到
sell键之后插入total
示例代码:
import groovy.json.JsonSlurper import groovy.json.JsonOutput import java.util.LinkedHashMap // 修正后的JSON(去掉末尾多余的逗号) def desiredJson = '{"count": 4, "max": "12", "min": 0, "details": [{"goBus": {"first": 12800, "second": 11900, "third": 12800},"goAir": {"first": 12800, "second": 11900, "third": 12800}, "gotTrain": {"first": 12800, "second": 11900},"sell": true, "darn": 2,"rate": [{ "busRate": 11900, "flag": false, "percent": 0}]}]}' // 解析为有序的LinkedHashMap def jsonSlurper = new JsonSlurper(type: JsonSlurper.Type.LINKED_HASH_MAP) def json = jsonSlurper.parseText(desiredJson) // 处理details里的每个对象(这里先处理单个的情况) json.details.each { detail -> def newDetail = new LinkedHashMap() detail.each { key, value -> newDetail.put(key, value) // 当遇到sell键时,插入total if (key == 'sell') { newDetail.put('total', '1000') } } // 替换原来的detail对象 json.details.set(json.details.indexOf(detail), newDetail) } // 输出格式化后的JSON log.info JsonOutput.prettyPrint(JsonOutput.toJson(json))
运行后输出的JSON中,total会紧跟在sell之后:
{ "count": 4, "max": "12", "min": 0, "details": [ { "goBus": { "first": 12800, "second": 11900, "third": 12800 }, "goAir": { "first": 12800, "second": 11900, "third": 12800 }, "gotTrain": { "first": 12800, "second": 11900 }, "sell": true, "total": "1000", "darn": 2, "rate": [ { "busRate": 11900, "flag": false, "percent": 0 } ] } ] }
问题2:处理多个重复JSON对象,为每个对象添加递增的total值
如果details数组里有多个对象,我们只需要在遍历的时候维护一个计数器,每次赋值后递增即可:
示例代码:
import groovy.json.JsonSlurper import groovy.json.JsonOutput import java.util.LinkedHashMap // 包含多个detail对象的JSON def desiredJson = '{"count": 4, "max": "12", "min": 0, "details": [{"goBus": {"first": 12800},"sell": true}, {"goBus": {"first": 13800},"sell": true}, {"goBus": {"first": 14800},"sell": true}]}' def jsonSlurper = new JsonSlurper(type: JsonSlurper.Type.LINKED_HASH_MAP) def json = jsonSlurper.parseText(desiredJson) // 初始化计数器 def totalValue = 1000 json.details.each { detail -> def newDetail = new LinkedHashMap() detail.each { key, value -> newDetail.put(key, value) if (key == 'sell') { newDetail.put('total', String.valueOf(totalValue++)) } } json.details.set(json.details.indexOf(detail), newDetail) } log.info JsonOutput.prettyPrint(JsonOutput.toJson(json))
输出结果中,每个detail的total会依次是1000、1001、1002:
{ "count": 4, "max": "12", "min": 0, "details": [ { "goBus": { "first": 12800 }, "sell": true, "total": "1000" }, { "goBus": { "first": 13800 }, "sell": true, "total": "1001" }, { "goBus": { "first": 14800 }, "sell": true, "total": "1002" } ] }
关键说明
- 必须使用
LinkedHashMap来维护键的顺序,因为普通HashMap不保证顺序 - 遍历原对象的键值对,在目标键之后插入新键值对,再替换原对象,才能实现指定位置的效果
- 批量处理时通过计数器实现值的递增,灵活调整初始值和步长即可
内容的提问来源于stack exchange,提问作者avidCoder
相关产品推荐
相关产品推荐

