使用lift-json修改JSON对象

时间:2013-07-18 07:37:38

标签: scala lift-json

我正在选择一个好的Scala JSON库,而且似乎共识lift-json是目前最好的选择。

使用它(版本2.5.1)后,我已经能够相当容易地完成我需要的大部分事情,除了一个:修改现有的JValue

假设我有JValue的以下实例:

val john = ("id"   -> 1) ~
           ("name" -> "Foo") ~
           ("nested" ->
             ("id" -> 2) ~
             ("name" -> "Bar"))

我想将父元素的名称从Foo更改为foo。我认为transform方法是可行的方法:

john transform {
    case JField("name", _) => JField("name", "foo")
})

但是这会将父元素和嵌套元素的name字段都更改为foo - 回想起来,这真的不应该是一个惊喜。

我查看了文档和代码,但无法找到使用name键选择特定字段的方法。我错过了什么吗?

另一个解决方案(这个工作)似乎正在合并两个JValue对象,但它似乎有点冗长:

john merge JObject(JField("name", "foo") :: Nil)

是否有内置的,更易读的方法来实现相同的结果?我可能会写一个从JFieldJObject的隐式转换,但似乎很奇怪lift-json还没有这样的机制。如果我不得不下注,那就是我没有找到它而不是它不存在。

编辑:我觉得现在有点傻了

john transform {
    case JField("name", "Foo") => JField("name", "foo")
})

不是世界上最优的解决方案,但完全可读且简洁。

2 个答案:

答案 0 :(得分:0)

这很丑,因为它使用了一个可变变量,它也使用了json4s(它使用了引擎盖下的lift-json),但是它可以工作:

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

object JsonTesting {
  def main(args: Array[String]) {
    val john = ("id"   -> 1) ~
           ("name" -> "Foo") ~
           ("nested" ->
             ("id" -> 2) ~
             ("name" -> "Bar"))

    var changed = false
    val john2 = john transformField {
      case JField("name", _) if !changed => 
        changed = true
        JField("name", "foo")
    }
  }
}

我找不到一种更干净的方式告诉它要么只遍历一个深度,要么知道每个节点检查的深度,所以我只能在第一级深度上进行切换。

答案 1 :(得分:0)

使用JValue的replace方法,如下所示:

john.replace(List("name"), "foo")

实施此'替换'方法是一个灾难,名称替换建议(对我来说)一个状态修改,它不是真的,但它做的事情

JObject(List((id,JInt(1)), (name,JString(foo)), (nested,JObject(List((id,JInt(2)), (name,JString(Bar)))))))