我正在选择一个好的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)
是否有内置的,更易读的方法来实现相同的结果?我可能会写一个从JField
到JObject
的隐式转换,但似乎很奇怪lift-json
还没有这样的机制。如果我不得不下注,那就是我没有找到它而不是它不存在。
john transform {
case JField("name", "Foo") => JField("name", "foo")
})
不是世界上最优的解决方案,但完全可读且简洁。
答案 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)))))))