Следующие данные можно увидеть с различными типами значений. Как я могу получить желаемый результат?
package ceshi
import scala.util.parsing.json.JSON
object ceshi1212 {
def main(args: Array[String]): Unit = {
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]
val jsonString =
"""
{
"languages": [
{
"name": "English",
"is_active": "true",
"completeness": "asdf"
},
{
"name": "Latin",
"is_active": "asdf",
"completeness": "232"
}
,{
"name": "Latin",
"is_active": "0009"
}
,
"error"
]
}
""".stripMargin
// 不规则json error和并列的数组类型不同 怎么解析自动跳过?
val result = for {
Some(M(map)) <- List(JSON.parseFull(jsonString))
L(languages) = map("languages")
M(language) <- languages
S(name) = language("name")
S(active) = language("is_active")
S(completeness) = language.getOrElse("completeness","--")
} yield {
(name, active, completeness)
}
println(result)
//i want result is: List((English,true,asdf), (Latin,asdf,232),(Latain,0009,""))
}
}
я хочу получить результат в виде списка ((английский, true, asdf), (латинский, asdf, 232), (латинский, 0009, "")) примечание: 1 Строка не всегда находится в конце массива, а позиция не определена 2 Три необходимых мне ключа могут быть неполными
Как сказано в комментариях, есть и другие библиотеки, которые можно порекомендовать для работы с json. Взгляните на этот пост, чтобы получить обзор: Какую библиотеку JSON использовать в Scala?
Ответьте на ваш вопрос с конкретным фреймворком (play-json)
Лично я могу порекомендовать использовать фреймворк play json. Чтобы получить описанный вами результат с помощью play json, ваш код может выглядеть так:
import play.api.libs.json._
val json: JsValue = Json.parse(jsonString)
val list = (json \ "languages").as[Seq[JsValue]]
val names = list.map(x => ((x\"name").validate[String] match {
case JsSuccess(v, p ) => v
case _ => ""
}
))
val isActives = list.map(x => ((x\"is_active").validate[String] match {
case JsSuccess(v, p ) => v
case _ => ""
}
))
val completeness = list.map(x => ((x\"completeness").validate[String] match {
case JsSuccess(v, p ) => v
case _ => ""
}
))
// need to know in advance what is your max length of your tuple (tmax)
// since 3rd value "completeness" can be missing, so we just take "" instead
val tmax = 3
val res = for(idx <-0 to tmax-1) yield (names(idx),isActives(idx),completeness(idx))
res.toList
// List[(String, String, String)] = List((English,true,asdf), (Latin,asdf,232), (Latin,0009,""))
Также есть очень хорошая документация по фреймворку play json, просто посмотрите сами: https://www.playframework.com/documentation/2.8.x/ScalaJson
Обратите внимание, что сама спецификация JSON не видит разницы между "" и отсутствием значения. Программное обеспечение, которое ожидает, что значения "" будут представлены как текущее значение "", всегда будет бороться с реализациями в этой и других библиотеках и языках; и, если возможно, следует решить проблему, заставив программное обеспечение правильно обрабатывать отсутствующий элемент. Это неприятный побочный эффект отсутствия явной схемы (как в XML), поэтому ни одна библиотека синтаксического анализа не имеет указаний «заполнить» пустое значение, когда ключ отсутствует.
Если вы можете переключить библиотеку синтаксического анализатора на circe, вы можете справиться с этими типами неверных данных.
Учитывая, что у вас есть модель данных
import io.circe.generic.semiauto._
import io.circe.parser.decode
import io.circe.{Decoder, Json}
case class Languages(languages: Seq[Language])
case class Language(name: String, is_active: String, completeness: Option[String])
Вы можете определить отказоустойчивый декодер последовательностей, который будет пропускать неверные данные, а не завершать синтаксический анализ целиком.
def tolerantSeqDecoder[A: Decoder]: Decoder[Seq[A]] = Decoder.decodeSeq(Decoder[A]
.either(Decoder[Json])).map(_.flatMap(_.left.toOption))
и остальное...
val jsonString = """
{
"languages": [
{
"name": "English",
"is_active": "true",
"completeness": "asdf"
},
{
"name": "Latin",
"is_active": "asdf",
"completeness": "232"
},
{
"name": "Latin",
"is_active": "0009"
},
"error"
]
}
"""
val languageDecoder = deriveDecoder[Language]
implicit val tolerantDecoder = tolerantSeqDecoder[Language](languageDecoder)
implicit val languagesDecoder = deriveDecoder[Languages]
val parsed = decode[Languages](jsonString)
println(parsed)
вне:
Right(Languages(List(Language(English,true,Some(asdf)), Language(Latin,asdf,Some(232)), Language(Latin,0009,None))))
Такой подход предложил один из разработчиков circe: Как игнорировать сбои декодирования в массиве JSON?
scala.until.parsing.json
более чем устарел, лучше взгляните на современную/поддерживаемую библиотеку