首页 > 解决方案 > 如何访问 JsValue 中的嵌套值?

问题描述

我有以下 Json 字符串

{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "1600",
               "short_name" : "1600",
               "types" : [ "street_number" ]
            },
            {
               "long_name" : "Amphitheatre Parkway",
               "short_name" : "Amphitheatre Pkwy",
               "types" : [ "route" ]
            },
            {
               "long_name" : "Mountain View",
               "short_name" : "Mountain View",
               "types" : [ "locality", "political" ]
            }
]}]}

我使用以下语句解析它

val payload = Json.parse(results)

然后我得到以下结果

payload: play.api.libs.json.JsValue = {"results":[{"address_components":[{"long_name":"1600","short_name":"1600","types":["street_number"]},{"long_name":"Amphitheatre Parkway","short_name":"Amphitheatre Pkwy","types":["route"]},{"long_name":"Mountain View","short_name":"Mountain View","types":["locality","political"]}]}

当我尝试运行此命令时

val extract = (payload \ "results.address_components") 

我得到以下输出

 play.api.libs.json.JsLookupResult = JsUndefined('results.address_components' is undefined on object

如何访问元素“address_components”?

标签: scalascala.jsplay-json

解决方案


我建议使用类似于GamingFelix 建议的案例类(替代方案在我的回答中的行下方),但如果您想知道为什么您的示例在这里不起作用,原因如下:

您没有正确遍历数组。给定以下 JSON:

{
  "foo": [
    {
      "bar": 123,
      "baz": "abc"
    },
    {
      "bar": 456,
      "baz": "def"
    }
  ]
}

你会得到这样的所有bar值:Json.parse(result) \ "foo" \\ "bar"- 即,使用双反斜杠。您也可以将其链接在一起,例如(Json.parse(result) \\ "field1").map(_ \\ "field2")等。

所以在你的例子中,如果你想要所有的long_name字段,你会这样做:

import play.api.libs.json.Json

val json = Json.parse(
  """{"results" : [{"address_components" : [{"long_name" : "1600","short_name" : "1600","types" : [ "street_number" ]},{"long_name" : "Amphitheatre Parkway","short_name" : "Amphitheatre Pkwy","types" : [ "route" ]},{"long_name" : "Mountain View","short_name" : "Mountain View","types" : [ "locality", "political" ]}]},{"address_components" : [{"long_name" : "16400","short_name" : "1600","types" : [ "street_number" ]},{"long_name" : "Amphitheatre 5Parkway","short_name" : "Amphitheatre Pkwy","types" : [ "route" ]},{"long_name" : "Mounta6in View","short_name" : "Mountain View","types" : [ "locality", "political" ]}]}]}"""
)

(json \ "results" \\ "address_components").map(_ \\ "long_name")

这将返回一个数组数组,因为您要通过多个数组来获取您的值。如果你把 a.foreach(_.foreach(println))放在最后,你会得到这个:

"1600"
"Amphitheatre Parkway"
"Mountain View"
"16400"
"Amphitheatre 5Parkway"
"Mounta6in View"

看到它在 Scastie 上工作。


如果您很好奇,GamingFelix 几乎将这两种方法结合起来的建议并不是最好的——如果您只是将整个事情转换为案例类,则更容易理解正在发生的事情。此外,如果您为每个案例类创建一个伴随对象以放入格式化程序,而不是将所有内容保存在同一个格式化程序对象中,您将不需要在每次需要它们时显式导入格式化程序(Scala 会自动找到它们)。

这就是我的做法:

import play.api.libs.json.{Json, OFormat}

val json = Json.parse(
  """{"results" : [{"address_components" : [{"long_name" : "1600","short_name" : "1600","types" : [ "street_number" ]},{"long_name" : "Amphitheatre Parkway","short_name" : "Amphitheatre Pkwy","types" : [ "route" ]},{"long_name" : "Mountain View","short_name" : "Mountain View","types" : [ "locality", "political" ]}]},{"address_components" : [{"long_name" : "16400","short_name" : "1600","types" : [ "street_number" ]},{"long_name" : "Amphitheatre 5Parkway","short_name" : "Amphitheatre Pkwy","types" : [ "route" ]},{"long_name" : "Mounta6in View","short_name" : "Mountain View","types" : [ "locality", "political" ]}]}]}"""
)

case class MyClass(results: Seq[Result])
object MyClass {
  implicit val format: OFormat[MyClass] = Json.format[MyClass]
}

case class Result(address_components: Seq[AddressComponent])
object Result {
  implicit val format: OFormat[Result] = Json.format[Result]
}

case class AddressComponent(long_name: String, short_name: String, types: Seq[String])
object AddressComponent {
  implicit val format: OFormat[AddressComponent] = Json.format[AddressComponent]
}

val model = json.as[MyClass] // `.as` is unsafe, use `.asOpt` or `.validate` or something like that in a real scenario

model.results.flatMap(_.address_components.map(_.long_name)) // get values out like you normally would in a class

这是对 Scastie 的工作。


推荐阅读