9

我正在试验 json4s 库(基于lift-json)。我想做的一件事是将 JSON 字符串解析为 AST,然后对其进行操作。

例如,我想更新一个字段(如果该字段不存在,则将该字段插入 AST,如果存在则更新其值)。

我无法在文档中找到如何做到这一点。尝试了可用的方法,我想出了以下方法,虽然可行,但感觉很笨拙。

import org.json4s._
import org.json4s.JsonDSL._
import org.json4s.native.JsonMethods._

object TestJson {
  implicit val formats = DefaultFormats

  def main(args: Array[String]): Unit = {
    val json = """{"foo":1, "bar":{"foo":2}}"""
    val ast = parse(json).asInstanceOf[JObject]

    println( upsertField(ast, ("foo" -> "3")) )
    println( upsertField(ast, ("foobar" -> "3")) )
  }

  def upsertField(src:JObject, fld:JField): JValue = {
    if(src \ fld._1 == JNothing){
      src ~ fld
    }
    else{
      src.replace(List(fld._1), fld._2)
    }
  }
}

我不喜欢它有很多原因:

  1. 必须明确地将结果parse(json)转换为JObject
  2. upsertField函数的结果是 a JValue,如果我想进一步操作该对象,我将不得不重铸它
  3. upsertField只是感觉功能很不雅
  4. 它不适用于不在层次结构顶层的字段

有没有更好的方法来转换 AST?

编辑:作为解决问题的方法,我设法将我的 JSON 转换为 Scala 常规类,并使用镜头操作它们(在 Scala 常规类上使用镜头

4

3 回答 3

12

有创建或覆盖字段的合并功能。您还可以更新不在树根级别的字段。

import org.json4s._
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods._

object mergeJson extends App {

  val json =
    """
      |{
      |  "foo":1,
      |  "bar": {
      |    "foo": 2
      |  }
      |}
      |""".stripMargin

  val ast = parse(json)

  val updated = ast merge (("foo", 3) ~ ("bar", ("fnord", 5)))

  println(pretty(updated))

  //  {
  //    "foo" : 3,
  //    "bar" : {
  //      "foo" : 2,
  //      "fnord" : 5
  //    }
  //  }

}
于 2014-01-30T23:13:42.760 回答
1

让我也给你JSON版本的SON :

import nl.typeset.sonofjson._

val json = parse("""{ "foo" : 1, "bar" : { "foo" : 2 } }""")

// or, perhaps a little easier
val json = obj(foo = 1, bar = obj(foo = 2))

json.foo = "3"
json.foobar = "3"
于 2014-09-21T10:38:37.693 回答
0

当我使用lift json实现一些非常特定的json diff时,我使用了很多递归函数来到达我需要修改值的jpath,并且在递归“折叠”时构造了修改后的json。LiftJson 毕竟是不可变的。您提到镜头是另一种方法,这本身就很有趣。但我目前最喜欢的是 play-json 库,它在您需要进行 json 到 json 转换的情况下就像一个魅力:

来自Mandubian 博客

val gizmo2gremlin = (
  (__ \ 'name).json.put(JsString("gremlin")) and
  (__ \ 'description).json.pickBranch(
      (__ \ 'size).json.update( of[JsNumber].map{ case JsNumber(size) => JsNumber(size * 3) } ) and
      (__ \ 'features).json.put( Json.arr("skinny", "ugly", "evil") ) and
      (__ \ 'danger).json.put(JsString("always"))
      reduce
  ) and
  (__ \ 'hates).json.copyFrom( (__ \ 'loves).json.pick )
) reduce

美味的特点:所有转换器都是可以混合在一起的组合器、验证、无形支持、具有隐式覆盖的案例类的自动编组、独立库。

于 2013-06-23T20:24:24.773 回答