解析json并根据值返回一个键列表



Scala专家,需要您的帮助。任务是解析这个json并返回"livingstone"商店的ModelId列表,该商店的"organic"=true。

在这种情况下,只有RT001的有机值为true。请帮忙。

注意:正在尝试使用现有的liftweb库。

package Exercises

import net.liftweb.json.{DefaultFormats, _}

object test1 extends App {
val json_response =
"""{
"requestId": "91ee60d5f1b45e#316",
"error": null,
"errorMessages": [
],
"entries": [
{
"modelId":"RT001",
"sku": "SKU-ASC001",
"store": "livingstone",
"ttlInSeconds": 8000,
"metadata": {
"manufactured_date": "2019-01-22T01:25Z",
"organic": "true"
}
},
{
"modelId":"RT002",
"sku": "SKU-ASC002",
"store": "livingstone",
"ttlInSeconds": 8000,
"metadata": {
"manufactured_date": "2019-10-03T01:25Z",
"organic": "false"
}
}
] }"""

val json = parse(json_response)
implicit val formats = DefaultFormats
val elements = (json \ "entries").children

for (subs <- elements) {
val m = subs.extract[Subs]
println(s"Subscriptions: ${m.modelId}, ${m.store}")
println(" k,v: " + m.metadata.exists(_ == ("organic", "true")))
}
case class Subs(modelId: String, store: String, metadata: Map[String, String])

}

正在获取错误。还需要帮助如何根据商店=活石和有机=真进行过滤。

Exception in thread "main" net.liftweb.json.MappingException: No usable value for modelId
Do not know how to convert JArray(List(JString(RT001), JString(RT002))) into class java.lang.String

专家帮助下的最终工作代码:

val json = parse(json_response)
implicit val formats = DefaultFormats

case class Sales(modelId: String, sku: String, store: String, ttlInSeconds: Int, metadata: Map[String, String])
case class Response(entries: List[Sales])
val json1 = parse(json_response)
val response = json.extract[Response]
val subs = response.entries.filter { e =>
e.store == "livingstone" &&
e.metadata.get("organic").contains("true")
}
subs.foreach(x=>println(x.modelId))

在处理JSON时,最好将整个结构转换为Scala,然后处理Scala,而不是直接处理JSON。

因此,创建一个Response类并在单个操作中提取该类,然后根据需要处理entries字段。

以下是一些完全未经测试的代码:

case class Response(entries: List[Subs])
val json = parse(json_response)
val response = json.extract[Response]
val subs = response.entries.filter{e =>
e.store == "livingstone" &&
e.metadata.get("organic").contains("true")
}

请注意,这应该适用于任何允许您从JSON中提取class的JSON库。

因此,正如评论部分已经建议的那样,您可以使用circe库而不是Lift框架,因为它是一个更现代、更广泛使用的解决方案。

您需要做的是声明结构,比如case class的es,它代表您的json。这不是一种推荐的方法,在原始JSON上操作-经验法则-将其解析为一些有意义的结构,然后使用它

除了结构声明之外,还可以为"非标准"情况使用EncoderDecoder,比如Boolean,在organic字段的情况下是String

在您的情况下,代码可能看起来像:

object App {
def main(args: Array[String]): Unit = {
import io.circe._, io.circe.generic.semiauto._, io.circe.generic.auto._, io.circe.parser._
/**
* General purpose response wrapper. Entries type might differ, as I can suppose, that's why it is generic.
* 'errorMessages' - since it is empty array in example, I can only guess about exact type. For sake of example
* let's say it is strings. And same for 'error' field.
*/
case class Response[E](requestId: String, error: Option[String], errorMessages: List[String], entries: List[E])
object Response {
implicit def decoder[E](implicit d: Decoder[E]): Decoder[Response[E]] = deriveDecoder[Response[E]]
implicit def encoder[E](implicit e: Encoder[E]): Encoder[Response[E]] = deriveEncoder[Response[E]]
}
case class Product(modelId: String, sku: String, store: String, ttlInSeconds: Int, metadata: ProductMetadata)
case class ProductMetadata(manufactured_date: ZonedDateTime, organic: Boolean)
object ProductMetadata {
// Boolean codec required - because `organic` is a string in JSON, which has boolean type
implicit val booleanDecoder: Decoder[Boolean] = Decoder[String].emapTry(value => Try(value.toBoolean))
implicit val booleanEncoder: Encoder[Boolean] = Encoder[String].contramap(_.toString)
implicit val decoder: Decoder[ProductMetadata] = deriveDecoder[ProductMetadata]
implicit def encoder: Encoder[ProductMetadata] = deriveEncoder[ProductMetadata]
}
val json =
s"""
|{
|   "requestId":"91ee60d5f1b45e#316",
|   "error":null,
|   "errorMessages":[
|
|   ],
|   "entries":[
|      {
|         "modelId":"RT001",
|         "sku":"SKU-ASC001",
|         "store":"livingstone",
|         "ttlInSeconds":8000,
|         "metadata":{
|            "manufactured_date":"2019-01-22T01:25Z",
|            "organic":"true"
|         }
|      },
|      {
|         "modelId":"RT002",
|         "sku":"SKU-ASC002",
|         "store":"livingstone",
|         "ttlInSeconds":8000,
|         "metadata":{
|            "manufactured_date":"2019-10-03T01:25Z",
|            "organic":"false"
|         }
|      }
|   ]
|}
|""".stripMargin
val parseResult: Either[Error, List[String]] =
for {
parsedJson <- parse(json)
response <- parsedJson.as[Response[Product]]
} yield  {
response.entries.collect {
case Product(modelId, _, "livingstone", _, ProductMetadata(_, true)) => modelId
}
}
println(parseResult)
}

这将产生下一个结果

Right(List(RT001))

希望这能有所帮助!

相关内容

  • 没有找到相关文章

最新更新