j3d*_*j3d 4 json scala playframework
鉴于以下JSON ......
{
"metadata": {
"id": "1234",
"type": "file",
"length": 395
}
}
Run Code Online (Sandbox Code Playgroud)
...我该如何将其转换为
{
"metadata.id": "1234",
"metadata.type": "file",
"metadata.length": 395
}
Run Code Online (Sandbox Code Playgroud)
TX.
你可以用Play的JSON变换器简洁地完成这项工作.以下是我的头脑,我相信它可以大大改善:
import play.api.libs.json._
val flattenMeta = (__ \ 'metadata).read[JsObject].flatMap(
_.fields.foldLeft((__ \ 'metadata).json.prune) {
case (acc, (k, v)) => acc andThen __.json.update(
Reads.of[JsObject].map(_ + (s"metadata.$k" -> v))
)
}
)
Run Code Online (Sandbox Code Playgroud)
然后:
val json = Json.parse("""
{
"metadata": {
"id": "1234",
"type": "file",
"length": 395
}
}
""")
Run Code Online (Sandbox Code Playgroud)
和:
scala> json.transform(flattenMeta).foreach(Json.prettyPrint _ andThen println)
{
"metadata.id" : "1234",
"metadata.type" : "file",
"metadata.length" : 395
}
Run Code Online (Sandbox Code Playgroud)
如果要处理metadata树中其他位置的字段,只需更改路径即可.
请注意,在这里使用变压器可能过度 - 请参阅例如Pascal Voitot在此主题中的输入,他在此提出以下建议:
(json \ "metadata").as[JsObject].fields.foldLeft(Json.obj()) {
case (acc, (k, v)) => acc + (s"metadata.$k" -> v)
}
Run Code Online (Sandbox Code Playgroud)
它不是可组合的,你可能不想as在实际代码中使用,但它可能就是你所需要的.
这绝对不是微不足道的,但可以通过尝试递归地展平它.我没有对此进行彻底的测试,但它适用于您的示例以及我使用数组提出的其他一些基本功能:
object JsFlattener {
def apply(js: JsValue): JsValue = flatten(js).foldLeft(JsObject(Nil))(_++_.as[JsObject])
def flatten(js: JsValue, prefix: String = ""): Seq[JsValue] = {
js.as[JsObject].fieldSet.toSeq.flatMap{ case (key, values) =>
values match {
case JsBoolean(x) => Seq(Json.obj(concat(prefix, key) -> x))
case JsNumber(x) => Seq(Json.obj(concat(prefix, key) -> x))
case JsString(x) => Seq(Json.obj(concat(prefix, key) -> x))
case JsArray(seq) => seq.zipWithIndex.flatMap{ case (x, i) => flatten(x, concat(prefix, key + s"[$i]")) }
case x: JsObject => flatten(x, concat(prefix, key))
case _ => Seq(Json.obj(concat(prefix, key) -> JsNull))
}
}
}
def concat(prefix: String, key: String): String = if(prefix.nonEmpty) s"$prefix.$key" else key
}
Run Code Online (Sandbox Code Playgroud)
JsObject有一个fieldSet方法返回一个Set[(String, JsValue)]我映射的,与JsValue子类匹配的方法,并从那里递归地继续消耗.
您可以通过传递JsValue给apply:
val json = Json.parse("""
{
"metadata": {
"id": "1234",
"type": "file",
"length": 395
}
}
"""
JsFlattener(json)
Run Code Online (Sandbox Code Playgroud)
我们将它作为练习留给读者,使代码看起来更漂亮.