将JSON结构转换为管道格式

时间:2018-07-16 18:07:45

标签: json scala play-json

例如,是否存在一种快速简便的方法来转换JsObject

  Json.obj(
    "title" -> "Working Title",
    "author" -> Json.obj(
      "name" -> "Peter Trunes",
      "location" -> Json.obj(
        "birthplace" -> "Perth",
        "nationality" -> "Australian",
        ..
      ),
      ..
    ),
    ..
  )

转换为所有嵌套的JsPath用管道传输jsObjects的格式?例如

  Json.obj(
    "title" -> "Working Title",
    "author.name" -> "Peter Trunes",
    "author.location.birthplace" -> "Perth",
    "author.location.nationality" -> "Australian",
    ..
  )

我正在使用转换器使用惯性转换技术(如documented here)来操纵Json数据结构,例如,对于author可以做到这一点,例如:

  def authorTrans: Reads[JsObject] =
    (__ \ 'author).read[JsObject].flatMap(
      _.fields.foldLeft((__ \ 'author).json.prune) {
        case (acc, (k, v)) => acc andThen __.json.update(
          Reads.of[JsObject].map(_ + (s"author.$k" -> v))
        )
      }
    )

  def tryTransformAsJsObj(obj: JsValue, transformer: Reads[JsObject]) = {

    obj.transform(transformer) match {
      case JsSuccess(r: JsObject, _) => r
      case e: JsError => JsError.toJson(e)
    }

  }

  tryTransformAsJsObj(jso, authorTrans) // jso is the JsObject structure to be transformed

我在这里使用递归方法来转换每个嵌套的JsObject,但是我一直在努力使它正确,并想知道是否可能缺少一种更简单的技术。欢迎提出想法和建议!

1 个答案:

答案 0 :(得分:0)

这里有一些递归代码,您应该扩展模式匹配以涵盖所有情况,否则您将得到警告:

import play.api.libs.json.{JsObject, JsString, JsValue, Json}

val original = Json.obj(
  "title" -> "Working Title",
  "author" -> Json.obj(
    "name" -> "Peter Trunes",
    "location" -> Json.obj(
      "birthplace" -> "Perth",
      "nationality" -> "Australian"
    )
  )
)

def transform(input: scala.collection.Map[String, JsValue], accum: JsObject, 
  curPath: String): JsObject = {
  val result = input.foldLeft(accum) {
    case (acc, (k, v)) =>
      v match {
        case JsString(str) => acc + (curPath + k -> Json.toJson(str))
        case JsObject(kvs) =>
          val newPath = if (curPath.isEmpty) s"$k." else s"$curPath$k."
          transform(kvs, acc, newPath)
      }
  }

  result
}

transform(original.value, Json.obj(), "")