Как разбирать JSON в Scala с использованием стандартных classов Scala?

Я использую сборку в classе 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:

 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.

(Старый ответ отредактирован - проверьте историю изменений, если вам интересно)

Именно так я выполняю сопоставление шаблонов:

 val result = JSON.parseFull(jsonStr) result match { // Matches if jsonStr is valid JSON and represents a Map of Strings to Any case Some(map: Map[String, Any]) => println(map) case None => println("Parsing failed") case other => println("Unknown data structure: " + other) } 

Мне нравится ответ @ huynhjl, это привело меня к правильному пути. Однако при обработке условий ошибок это не очень удобно. Если нужный узел не существует, вы получаете исключение cast. Я немного адаптировал это, чтобы использовать Option чтобы лучше справиться с этим.

 class CC[T] { def unapply(a:Option[Any]):Option[T] = if (a.isEmpty) { None } else { Some(a.get.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] for { M(map) <- List(JSON.parseFull(jsonString)) L(languages) = map.get("languages") language <- languages M(lang) = Some(language) S(name) = lang.get("name") B(active) = lang.get("is_active") D(completeness) = lang.get("completeness") } yield { (name, active, completeness) } из них class CC[T] { def unapply(a:Option[Any]):Option[T] = if (a.isEmpty) { None } else { Some(a.get.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] for { M(map) <- List(JSON.parseFull(jsonString)) L(languages) = map.get("languages") language <- languages M(lang) = Some(language) S(name) = lang.get("name") B(active) = lang.get("is_active") D(completeness) = lang.get("completeness") } yield { (name, active, completeness) } 

Конечно, это не обрабатывает ошибки настолько, насколько их можно избежать. Это даст пустой список, если отсутствует какой-либо из json-узлов. Вы можете использовать match чтобы проверить наличие узла перед тем, как действовать ...

 for { M(map) <- Some(JSON.parseFull(jsonString)) } yield { map.get("languages") match { case L(languages) => { for { language <- languages M(lang) = Some(language) S(name) = lang.get("name") B(active) = lang.get("is_active") D(completeness) = lang.get("completeness") } yield { (name, active, completeness) } } case None => "bad json" } } 

Я пробовал несколько вещей, предпочитая сопоставление шаблонов как способ избежать кастинга, но столкнулся с проблемами стирания типов в типах коллекций.

Основная проблема заключается в том, что полный тип результата анализа отражает структуру данных JSON и является либо громоздким, либо невозможным для полного состояния. Я думаю, именно поэтому Any используется для усечения определений типов. Использование Any приводит к необходимости литья.

Я взломал что-то ниже, которое является кратким, но чрезвычайно специфично для данных JSON, подразумеваемых кодом в вопросе. Что-то более общее было бы более удовлетворительным, но я не уверен, будет ли это очень элегантно.

 implicit def any2string(a: Any) = a.toString implicit def any2boolean(a: Any) = a.asInstanceOf[Boolean] implicit def any2double(a: Any) = a.asInstanceOf[Double] case class Language(name: String, isActive: Boolean, completeness: Double) val languages = JSON.parseFull(jstr) match { case Some(x) => { val m = x.asInstanceOf[Map[String, List[Map[String, Any]]]] m("languages") map {l => Language(l("name"), l("isActive"), l("completeness"))} } case None => Nil } languages foreach {println} 
 val jsonString = """ |{ | "languages": [{ | "name": "English", | "is_active": true, | "completeness": 2.5 | }, { | "name": "Latin", | "is_active": false, | "completeness": 0.9 | }] |} """.stripMargin val result = JSON.parseFull(jsonString).map { case json: Map[String, List[Map[String, Any]]] => json("languages").map(l => (l("name"), l("is_active"), l("completeness"))) }.get println(result) assert( result == List(("English", true, 2.5), ("Latin", false, 0.9)) ) 
  • Как выйти из цикла в Scala?
  • Запись на несколько выходов с помощью ключа Spark - одно искровое задание
  • Почему «невозможно найти кодировщик для типа, хранящегося в наборе данных» при создании набора данных пользовательского classа case?
  • Как получить идентификатор задачи карты в Spark?
  • Объявление параметра Tuple и странность присваивания
  • Стратифицированная выборка в Spark
  • Запуск пользовательской задачи автоматически до / после стандартной задачи
  • Использование библиотеки Java с зарезервированными словами Scala
  • Как установить размер кучи для sbt?
  • API Карт Google v2 SupportMapFragment внутри ScrollView - пользователи не могут прокручивать карту по вертикали
  • Создание файла jar из файла Scala
  • Interesting Posts

    Установить значок пользовательской папки для сетевой папки в Проводнике Windows

    Mysql выбирает, где не в таблице

    Самый безопасный способ удаления Ubuntu с компьютера с двойной загрузкой

    Динамически добавлять компоненты в JDialog

    ctorParameters.map не является функцией в угловом2-mdl

    Перенаправление на фактическую страницу, что они просматривали до входа в систему

    Выполнение копирования и вставки с помощью Selenium 2

    Преобразование миллисекунд в дату (jQuery / JavaScript)

    Расчет расстояния от моего местоположения до места назначения в андроиде

    Какая встроенная firebase database используется в приложении Delphi?

    Как использовать paginate () с предложением having (), когда столбец не существует в таблице

    Как вы можете передать несколько примитивных параметров AsyncTask?

    Сделать монофонический выход для наушников

    Как отключить автоматический вход последнего активного пользователя в Windows 8.1?

    jQuery: обнаружение нажатой кнопки мыши во время события mousemove

    Давайте будем гением компьютера.