Scala Play框架如何按属性值修改Json移除JsArray指定元素
问题描述
现有如下结构的JSON文件:
{ "data": [ { "id": 1001, "processes": [ { "process_id": 301, "status": "accepted" }, { "process_id": 302, "status": "accepted" }, { "process_id": 303, "status": "failed" }, { "process_id": 304, "status": "failed" } ] } ] }
需求为遍历JSON结构,移除所有status属性值为failed的processes子元素,期望输出结构如下:
{ "data": [ { "id": 1001, "processes": [ { "process_id": 301, "status": "accepted" }, { "process_id": 302, "status": "accepted" } ] } ] }
之前尝试使用ScalaJsonTransformers实现时,发现该组件的prune、update方法仅支持操作JsObject,无法直接作用于JsArray,先后尝试两种方案均未生效:
- 方案1:编写过滤逻辑
该代码可以正确过滤出符合条件的元素,但无法回写到原始JSON结构中。val inputJsonObj = Json.parse(inputJsonStr).as[Seq[JsObject]] val modifiedJson = inputJsonObj.map(model => (model \ "processes").as[Seq[JsObject]].filter(info => { val status = (info \ "status").as[String] status match { case "accepted" => true case _ => // 尝试在此处调用prune/update方法,无法生效 false } })) - 方案2:创建可变JsObject覆写
processes字段
该方案同样无法达到预期效果。Json.parse(resp).as[mutable.Seq[JsObject]] ++ Json.obj("processes" -> modifiedJson)
要求:实现过程不使用case class。
实现方案
直接基于Play JSON的原生JsValue结构做层级修改即可,不需要依赖JsonTransformers的数组操作能力,核心逻辑是遍历data数组下的每个对象,取出processes数组做过滤后,重新组装成新的JsObject替换原字段,完整代码如下:
import play.api.libs.json._ // 解析原始JSON val rawJson = Json.parse(inputJsonStr).as[JsObject] // 处理data字段:遍历data数组内的每个元素,过滤processes数组 val updatedData = JsArray( (rawJson \ "data").as[Seq[JsObject]].map { dataItem => // 过滤当前dataItem下的processes数组,只保留status=accepted的项 val validProcesses = (dataItem \ "processes").as[Seq[JsObject]].filter { process => (process \ "status").asOpt[String].contains("accepted") } // 覆写processes字段为过滤后的结果 dataItem ++ Json.obj("processes" -> JsArray(validProcesses)) } ) // 组装最终结果 val resultJson = rawJson ++ Json.obj("data" -> updatedData) // 如需输出为格式化字符串,使用如下代码 // val resultStr = Json.prettyPrint(resultJson)
逻辑说明
- 之前两种方案失效的核心原因:过滤得到符合要求的
processes列表后,没有将过滤结果回写到外层的data对象、根JSON结构中,仅单独拿到了过滤后的子列表,没有替换原结构的对应字段。 - 代码中使用
asOpt替代直接as做类型转换,可避免JSON结构不符合预期时直接抛出类型转换错误,容错性更好。 - 全程直接操作
JsValue/JsObject/JsArray原生JSON类型,无需定义任何case class,满足要求。
内容的提问来源于stack exchange,提问作者Prakhar Bhatt
相关产品推荐
相关产品推荐

