如何在 Scala 中使用 Play json 更新列表中的每个字段

How to update each field in a list using Play json in Scala

我有以下 json 字符串:

{
   "id":123,
   "students":[
      {
         "collected":{
            "field":"field_1"
         },
         "attr":[{
            "name":"test_name",
            "age":"17",
            "color":"blue"
         }]
      }
   ]
}

我想更新我所有 "students" 列表中 "attr" 对象中的所有元素。 通过更新,我的意思是我需要将值更新为键和值

的串联字符串
{
   "id":123,
   "students":[
      {
         "collected":{
            "field":"field_1"
         },
         "attr":[{
            "name":"nametest_name",
            "age":"age17",
            "color":"colorblue"
         }]
      }
   ]
}

我遇到了JsValue的transform方法。这是我的变压器:

val jsonTransformer = (__ \ 'students).json.update(
  of[JsArray].map{
    case JsArray(list) =>
      list.map(o => o)
  }
)

我的转换器没有改变任何东西,因为我似乎找不到遍历 "attr" 字段的方法。

任何人都可以提供见解吗?

将以下内容作为输入(其中 attr 是一个对象数组):

   val input =
      """
        |{
        |   "id":123,
        |   "students":[
        |      {
        |         "collected":{
        |            "field":"field_1"
        |         },
        |         "attr":[{
        |            "name":"test_name",
        |            "age":"17",
        |            "color":"blue"
        |         }]
        |      },
        |      {
        |         "collected":{
        |            "field":"field_2"
        |         },
        |         "attr":[{
        |            "name":"test_name2",
        |            "age":"18",
        |            "color":"red"
        |         }]
        |      }
        |   ]
        |}
        |""".stripMargin

我们可以应用以下转换器来获得所需的结果:

    val attrTransformer = (__ \ "attr").json.update {
      __.read[JsArray].map {
        case JsArray(values) =>

          val updatedValues = values.map { x =>
            JsObject(x.as[JsObject].fields.map { z =>
              val (key, value) = z
              (key, JsString(key + value.as[String]))
            })
          }

          JsArray(updatedValues)
      }
    }

    val transformer = (__ \ "students").json.update(Reads.list(attrTransformer).map(x => JsArray(x)))

    val output = json.transform(transformer).get

转换后的输出为:

{
  "students" : [ {
    "collected" : {
      "field" : "field_1"
    },
    "attr" : [ {
      "name" : "nametest_name",
      "age" : "age17",
      "color" : "colorblue"
    } ]
  }, {
    "collected" : {
      "field" : "field_2"
    },
    "attr" : [ {
      "name" : "nametest_name2",
      "age" : "age18",
      "color" : "colorred"
    } ]
  } ],
  "id" : 123
}

旧答案

考虑以下输入(其中 attr 不是 JsObject 的数组):

    val input =
      """
        |{
        |   "id":123,
        |   "students":[
        |      {
        |         "collected":{
        |            "field":"field_1"
        |         },
        |         "attr":{
        |            "name":"test_name",
        |            "age":"17",
        |            "color":"blue"
        |         }
        |      },
        |      {
        |         "collected":{
        |            "field":"field_2"
        |         },
        |         "attr":{
        |            "name":"test_name2",
        |            "age":"18",
        |            "color":"red"
        |         }
        |      }
        |   ]
        |}
        |""".stripMargin

一个简单的解决方案是创建一个具有更新值的新 JsObject,如下所示。 (没有任何验证)

    val students = (Json.parse(input) \ "students").as[JsArray]
    val requiredStudents = students.value.map { student =>
      val attr = student \ "attr"

      val updatedAttributes = attr.get.as[JsObject].fields.map { x =>
        val (key, value) = x
        (key, JsString(key + value.as[String]))
      }

      val requiredStudent = student.as[JsObject] ++ Json.obj("attr" -> JsObject(updatedAttributes))
      requiredStudent
    }

    requiredStudents.foreach(println)

每个学生的输出如下:

{"collected":{"field":"field_1"},"attr":{"name":"nametest_name","age":"age17","color":"colorblue"}}
{"collected":{"field":"field_2"},"attr":{"name":"nametest_name2","age":"age18","color":"colorred"}}