如何在Scala Play框架中解析JSON数组?

3

我有一个像这样的JSON对象数组

[
  {
    "events": [
      {
        "type": "message",
        "attributes": [
          {
            "key": "action",
            "value": "withdraw_reward"
          },
          {
            "key": "sender",
            "value": "bob"
          },
          {
            "key": "module",
            "value": "distribution"
          },
          {
            "key": "sender",
            "value": "bob"
          }
        ]
      },
      {
        "type": "credit",
        "attributes": [
          {
            "key": "recipient",
            "value": "ross"
          },
          {
            "key": "sender",
            "value": "bob"
          },
          {
            "key": "amount",
            "value": "100"
          }
        ]
      },
      {
        "type": "rewards",
        "attributes": [
          {
            "key": "amount",
            "value": "100"
          },
          {
            "key": "validator",
            "value": "sarah"
          }
        ]
      }
    ]
  },
  {
    "events": [
      {
        "type": "message",
        "attributes": [
          {
            "key": "action",
            "value": "withdraw_reward"
          },
          {
            "key": "sender",
            "value": "bob"
          },
          {
            "key": "module",
            "value": "distribution"
          },
          {
            "key": "sender",
            "value": "bob"
          }
        ]
      },
      {
        "type": "credit",
        "attributes": [
          {
            "key": "recipient",
            "value": "ross"
          },
          {
            "key": "sender",
            "value": "bob"
          },
          {
            "key": "amount",
            "value": "100"
          }
        ]
      },
      {
        "type": "rewards",
        "attributes": [
          {
            "key": "amount",
            "value": "200"
          },
          {
            "key": "validator",
            "value": "Ryan"
          }
        ]
      }
    ]
  }
]

如何遍历类型,检查其type是否等于rewards,然后遍历attributes并验证validator是否等于sarah,并获取键为amountvalue? 对Scala和Play框架还很新。任何帮助都将不胜感激。谢谢

1
你是将JSON读取为case类还是JsArray - Gaël J
尝试使用Json.parse(obj),但由于obj是一个字符串数组,所以没有起作用。 - bahdotsh
2
请阅读文档 - zmerr
1
Json.parse("[]") 是可以工作的。请编辑您的帖子并附上您尝试过的代码,否则我们无法提供帮助。 - Gaël J
可能会有多个,因为您有一个事件数组的数组。因此,它可以是一系列金额值或总和。或者,如果您非常确定只有一个奖励已由Sara验证,那么它将是一个具有一个元素的列表,您可以“直接”检索该元素。所以我假设是后者? - haukeh
显示剩余3条评论
1个回答

4
您可以将JSON解析为一组case类的结构,以便更轻松地处理,然后像这样提取所需字段:
val json = 
"""[
 {"events":[
            {
              "type":"message","attributes":[
                   {"key":"action","value":"withdraw_reward"}, 
                   {"key":"sender","value":"bob"}, 
                   {"key":"module","value":"distribution"}, 
                   {"key":"sender","value":"bob"}
            ]},
           {
             "type":"credit","attributes":[
                  {"key":"recipient","value":"ross"},
                  {"key":"sender","value":"bob"},
                  {"key":"amount","value":"100"}
           ]},
           {
             "type":"rewards","attributes":[
                  {"key":"amount","value":"100"}, 
                  {"key":"validator","value":"sara"}
           ]}
        ]
 },
   {"events":[
            {
              "type":"message","attributes":[
                        {"key":"action","value":"withdraw_reward"}, 
                   {"key":"sender","value":"bob"}, 
                   {"key":"module","value":"distribution"}, 
                   {"key":"sender","value":"bob"}
            ]},
           {
             "type":"credit","attributes":[
                  {"key":"recipient","value":"ross"},
                  {"key":"sender","value":"bob"},
                  {"key":"amount","value":"100"}
           ]},
           {
             "type":"rewards","attributes":[
                  {"key":"amount","value":"200"}, 
                  {"key":"validator","value":"Ryan"}
           ]}
        ]
 }
]
"""

case class EventWrapper(events: Seq[Event])
case class KeyValue(key: String, value: String)
case class Event(`type`: String, attributes: Seq[KeyValue])

 import play.api.libs.json._

    implicit val kvReads: Reads[KeyValue] = Json.reads[KeyValue]
    implicit val eventReads: Reads[Event] = Json.reads[Event]
    implicit val eventWrapperReads: Reads[EventWrapper] = Json.reads[EventWrapper]

    val rewardAmountsValidatedBySara = Json
      .parse(json)
      .as[Seq[EventWrapper]]
      .flatMap {
        _.events.collect {
          case Event(t, attributes) if t == "rewards" && attributes.contains(KeyValue("validator", "sara")) =>
            attributes.collect {
              case KeyValue("amount", value) => value
            }
        }.flatten
      }

    val amount = rewardAmountsValidatedBySara.head

对于你的例子,rewardAmountsValidatedBySara会产生一个字符串列表,其中只包含字符串"100"。你可以像上面展示的那样使用.head来检索(潜在不安全的)字符串。

通常情况下,你不应该这样做,因为它可能会在空列表上抛出异常,所以最好使用.headOption,它返回一个Option,你可以安全地处理它。

请注意,隐式Reads是宏,它们会自动转换成代码,指示Play Json框架如何将JsValue读取到定义的case类中,请参阅文档获取更多信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接