1. ホーム
  2. json

[解決済み] Scalaの標準クラスを使ってScalaでJSONをパースするには?

2022-05-14 22:58:05

質問

JSONコードをパースするためにScala 2.8のビルドインJSONクラスを使っています。私は、依存関係を最小限にするために、Liftwebのものまたは他のものを使用したくありません。

私がやっている方法は、あまりにも命令的なように思えますが、それを行うためのより良い方法はありますか?

import scala.util.parsing.json._
...
val json:Option[Any] = JSON.parseFull(jsonString)
val map:Map[String,Any] = json.get.asInstanceOf[Map[String, Any]]
val languages:List[Any] = map.get("languages").get.asInstanceOf[List[Any]]
languages.foreach( langMap => {
val language:Map[String,Any] = langMap.asInstanceOf[Map[String,Any]]
val name:String = language.get("name").get.asInstanceOf[String]
val isActive:Boolean = language.get("is_active").get.asInstanceOf[Boolean]
val completeness:Double = language.get("completeness").get.asInstanceOf[Double]
}

どのように解決するのですか?

クラスキャストを行うエクストラクタを利用した解決方法です。

class CC[T] { def unapply(a:Any):Option[T] = Some(a.asInstanceOf[T]) }

object M extends CC[Map[String, Any]]
object L extends CC[List[Any]]
object S extends CC[String]
object D extends CC[Double]
object B extends CC[Boolean]

val jsonString =
    """
      {
        "languages": [{
            "name": "English",
            "is_active": true,
            "completeness": 2.5
        }, {
            "name": "Latin",
            "is_active": false,
            "completeness": 0.9
        }]
      }
    """.stripMargin

val result = for {
    Some(M(map)) <- List(JSON.parseFull(jsonString))
    L(languages) = map("languages")
    M(language) <- languages
    S(name) = language("name")
    B(active) = language("is_active")
    D(completeness) = language("completeness")
} yield {
    (name, active, completeness)
}

assert( result == List(("English",true,2.5), ("Latin",false,0.9)))

forループの最初で、結果を人為的にリストで囲み、最後にリストを生成しています。そして、forループの残りの部分では、ジェネレータが( <- を使用)と値定義( = を使用) は、unapply メソッドを使用します。

(古い回答は編集で削除されています。気になる方は編集履歴を確認してください)