在播放中递归转换json

时间:2018-08-13 01:51:25

标签: json scala playframework

我需要以下两种方法json进行转换:

  1. val重命名为
  2. 删除id字段。

我的代码

val tmp=new String ("[{"id":3,"date":"1969-07-20","val":4}, {"id":4,"date":"1944-07-20","val":5}]")

我考虑过使用prunecopyValue转换,但是我知道它们不适用于递归JsPath

感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

如果您想将JSON解析为纯字符串,则可以使用replace做一些简单的事情:

val tmp= """[{"id":3,"date":"1969-07-20","val":4}, {"id":4,"date":"1944-07-20","val":5}]"""

tmp.replaceAll("\"val\"", "\"value\"").replaceAll("\"id\"[^,]*,", "")
// [{"date":"1969-07-20","value":4}, {"date":"1944-07-20","value":5}]

这不是理想的方法,按照惯例,只有在id后接逗号的情况下,此方法才有效,但是您可以理解。您可以使用replaceAll进行正则表达式匹配,并将发现的结果替换为预期的结果。


一种更好的首选方式(在我看来)是将JSON作为JsObject进行操作,并使用案例类进行存储。

假设您具有以下JSON:

val jamesAsJson: JsObject = Json.obj("name" -> "james", "age" -> 34)
// jamesAsJson: play.api.libs.json.JsObject = {"name":"james","age":34}

您可以将其映射到case class,其中有一个相应的object,其中包含一些JSON-y魔术,如下所示:

case class Person(name: String, age: Int)

object Person {
  // This is magic. Don't worry about how it works
  implicit val format: OFormat[Person] = Json.format[Person] 
}

// I know this JSON matches my case class but if you're unsure,
// you should use getOrElse otherwise it'll throw an Exception
val jamesAsPerson = jamesAsJson.validate[Person].get
// jamesAsPerson: Person = Person(james,34)

接下来,您可以使用所需的新字段创建另一个案例类,并将旧数据弹出到新的案例类中:

case class AltPerson(fullName: String, age: Int)

object AltPerson {
  implicit val format: OFormat[AltPerson] = Json.format[AltPerson]
}

val jamesAsAltPerson = AltPerson(jamesAsPerson.name, jamesAsPerson.age)

val jamesAsAltJson = Json.toJson(jamesAsAltPerson)
// jamesAsAltJson: play.api.libs.json.JsObject = {"fullName":"james","age":34}

因此,这是更改字段名称的一种方法。在Scala中,有数百种方法可以执行某些操作。这只是一个。另一种方法是将JSON读取为字符串,在要更改的replaceAll上执行key,然后将其解析为JSON对象以进行下一阶段...

一旦对JSON键感到满意,则操作JsObject字段将非常容易。使用之前的示例,就这么简单:

jamesAsAltJson - "age"
// res0: play.api.libs.json.JsObject = {"fullName":"james"}

此操作可以根据需要进行:

jamesAsAltJson - "age" + ("height" -> JsString("234")) + ("eye colour" -> JsString("blue"))
// res1: play.api.libs.json.JsObject = {"fullName":"james","height":"234","eye colour":"blue"}

最后,您的示例包含一个数组,该数组使事情变得有些复杂,但是您可以使用Scala Play的JSON解析器来做到这一点:

import play.api.libs.json._
// import play.api.libs.json._

val tmp = """[{"id":3,"date":"1969-07-20","val":4}, {"id":4,"date":"1944-07-20","val":5}]"""
// tmp: String = [{"id":3,"date":"1969-07-20","val":4}, {"id":4,"date":"1944-07-20","val":5}]

case class Tmp(id: Int, date: String, `val`: Int)
// defined class Tmp

object Tmp {
    implicit val format: OFormat[Tmp] = Json.format[Tmp]
}
// defined module Tmp

val tmpAsClass = Json.parse(tmp).as[Seq[Tmp]]
// tmpAsClass: Seq[Tmp] = List(Tmp(3,1969-07-20,4), Tmp(4,1944-07-20,5))

case class NewTmp(id: Int, date: String, value: Int)
// defined class NewTmp

object NewTmp {
  implicit val format: OFormat[NewTmp] = Json.format[NewTmp]
}
// defined module NewTmp

val newTmp = tmpAsClass.map(x => NewTmp(x.id, x.date, x.`val`))
// newTmp: Seq[NewTmp] = List(NewTmp(3,1969-07-20,4), NewTmp(4,1944-07-20,5))

// JsArray is annoying to work with so I've used List[JsObject] instead
val jsonList: List[JsObject] = Json.toJson(newTmp).as[List[JsObject]].map(_ - "id")
// jsonList: List[play.api.libs.json.JsObject] = List({"date":"1969-07-20","value":4}, {"date":"1944-07-20","value":5})

Json.toJson(jsonList)
// res0: play.api.libs.json.JsValue = [{"date":"1969-07-20","value":4},{"date":"1944-07-20","value":5}]

答案 1 :(得分:0)

必须请记住,您正在使用Json解析器,该解析器生成Json文档的抽象语法树,并将其转换为代表Json文档的JsValue。出于同样的原因,您不能更改类变量的名称(除非您重写了它),也无法将val更改为value。

但是,我看到您试图在此处将代码表示为字符串,而不是这样做:

val json:JsValue = Json.parse("""
  {
    "arrayObjects" : [{"id":3,"date":"1969-07-20","val":4}, {"id":4,"date":"1944-07-20","val":5}]
  } 
""") 

如果这不是您的意图,那么您就不需要play-json。您只需操作字符串即可找到解决问题的简单方法。

答案 2 :(得分:0)

好吧,如果tmp是String类型的(提醒:使用"""是可编译的),则可以在其上使用.replace

scala> val tmp=new String ("""[{"id":3,"date":"1969-07-20","val":4}, {"id":4,"date":"1944-07-20","val":5}]""")
tmp: String = [{"id":3,"date":"1969-07-20","val":4}, {"id":4,"date":"1944-07-20","val":5}]

scala> tmp.replace("val","whatever") 
res0: String = [{"id":3,"date":"1969-07-20","whatever":4}, {"id":4,"date":"1944-07-20","whatever":5}]

使用案例类的另一种方法

我通常希望尽可能避免String操作。那么这种方法呢:

  1. 具有两个不同的案例类。反映您提供的Json的一个。然后,第二个要转换为的案例类。

  2. 您可以使用Json read并将其转换为第一个case类。您最终获得了该课程的列表。

  3. 您可以通过它映射并删除id(因为第二种情况下没有它);并移动val的值;放入第二个案例类中的value的值中。