与 Scala 中的大多数库一样,json4s 具有不变性。无法更改 JValue 中的值,但您可以创建一个带有更改的新值(如案例类副本)。
如果您想更改每个“参考”字段,您可以使用带有模式匹配的 mapField。
import org.json4s._
import org.json4s.native.JsonMethods._
val str = """{ "foo": [
{
"bar": {
"baz": {
"ref": "my_old_value"
}}}]}"""
val json = parse(str)
val updated = json.mapField {
case ("foo", JArray(head :: tail)) => ("foo", JArray(head.mapField {
case ("ref", JString("my_old_value")) => ("ref", JString("new value"))
case otherwise => otherwise
} :: tail))
case otherwise => otherwise
}
println(updated)
// JObject(List((foo,JArray(List(JObject(List((bar,JObject(List((baz,JObject(List((ref,JString(new value)))))))))))))))
编辑
我修改了替换方法以增加对数组的支持,现在您可以通过“foo[]”或特定元素“foo[index]”修改数组中的所有元素。在你的作用域中添加这个隐式类。
implicit class JValueOps(underlying:JValue) {
object ArrayIndex {
val R = """^([^\[]+)\[(\d+)\]""".r
def unapply(str: String): Option[(String, Int)] = str match {
case R(name, index) => Option(name, index.toInt)
case _ => None
}
}
object ArrayAll {
val R = """^([^\[]+)\[\]""".r
def unapply(str: String): Option[String] = str match {
case R(name) => Option(name)
case _ => None
}
}
def replace2(l: List[String], replacement: JValue): JValue = {
def rep(l: List[String], in: JValue): JValue = {
(l, in) match {
// eg "foo[0]"
case (ArrayIndex(name, index) :: Nil, JObject(fields)) => JObject(
fields.map {
case JField(`name`, JArray(array)) if array.length > index => JField(name, JArray(array.updated(index, replacement)))
case field => field
}
)
// eg "foo[0]" "bar"
case (ArrayIndex(name, index) :: xs, JObject(fields)) => JObject(
fields.map {
case JField(`name`, JArray(array)) if array.length > index => JField(name, JArray(array.updated(index, rep(xs, array(index)))))
case field => field
}
)
// eg "foo[]"
case (ArrayAll(name) :: Nil, JObject(fields)) => JObject(
fields.map {
case JField(`name`, JArray(array)) => JField(name, JArray(array.map(_ => replacement)))
case field => field
}
)
// eg "foo[]" "bar"
case (ArrayAll(name) :: xs, JObject(fields)) => JObject(
fields.map {
case JField(`name`, JArray(array)) => JField(name, JArray(array.map( elem => rep(xs, elem))))
case field => field
}
)
// eg "foo"
case (x :: Nil, JObject(fields)) => JObject(
fields.map {
case JField(`x`, value) ⇒ JField(x, replacement)
case field ⇒ field
}
)
// eg "foo" "bar"
case (x :: xs, JObject(fields)) => JObject(
fields.map {
case JField(`x`, value) ⇒ JField(x, rep(xs, value))
case field ⇒ field
}
)
case _ => in
}
}
rep(l, underlying)
}
}
那你就可以了
json.replace2("foo[0]" :: "bar" :: "baz" :: "ref" :: Nil, JString("new value"))