9

私はjson4sライブラリ(lift-jsonに基づく)を試しています。私がやりたいことの 1 つは、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)toの結果を明示的にキャストする必要があるJObject
  2. upsertField関数の結果はJValueです。オブジェクトをさらに操作したい場合は、これを再キャストする必要があります
  3. 機能はupsertField非常にエレガントではありません
  4. 階層の最上位にないフィールドでは機能しません

AST を変換するより良い方法はありますか?

EDIT:問題の回避策として、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 に答える