【问题标题】:How to Parse Json String received from HTTP and loop through the values如何解析从 HTTP 接收的 Json 字符串并遍历值
【发布时间】:2017-01-20 11:49:56
【问题描述】:

我正在使用 Scala 和 Swagger,我需要帮助弄清楚如何遍历 json 中的值并将这些值用于检查和其他操作。

HTTP get 请求后返回的 json 字符串如下所示:

{
"count": 3,
"items": [
  {
    "Id": "fd0a9e5a",
    "DbName": "Xterior Prod",
    "Name": "XP"
  },
  {
   "Id": "4158a1a6",
   "DbName": "Invidibi Pappear",
   "Name": "ISP"
  },
  {
   "Id": "7e0c57046d3f",
   "DbName": "Multi Test",
   "Name": "MMP"
  }]
}

我的 UI 允许用户输入 ID。我要做的是遍历从 API 返回的 Json 值,并找到与输入的 ID 匹配的值。找到匹配项后,我必须检查数据库中是否包含“Test”关键字。如果是这样,我将需要显示 DbName 和短名称。

我在这里找到了一些指南(例如Foreach with JSON Arrays in Play2 and Scala),但它对我不起作用。当我运行我的代码时,我得到了这个错误:

play.api.libs.json.JsResultException: JsResultException(errors:List(((0)/Id,List(ValidationError(List(error.path.missing),WrappedArray()))), ((0)/DbName,List(ValidationError(List(error.path.missing),WrappedArray()))), ((1)/Id,List(ValidationError(List(error.path.missing),WrappedArray()))), ((1)/DbName,List(ValidationError(List(error.path.missing),WrappedArray()))), ((2)/Id,List(ValidationError(List(error.path.missing),WrappedArray()))), ((2)/DbName,List(ValidationError(List(error.path.missing),WrappedArray()))), 

这是我的代码:

case class DBInfo(Id: String, DbName: String, Name: String)
contentType = "application/json"
    //get json from http

    val httpClient = HttpClients.createDefault()
    val httpResponse = httpClient.execute(new HttpGet("http://www.customers.com/dbInfo"))
    val entity = httpResponse.getEntity

    val content = fromInputStream(httpResponse.getEntity.getContent()).getLines().mkString

    implicit val dbReader = Json.reads[DBInfo]
    val dbList = (Json.parse(content) \ "items").as[List[DBInfo]]
    dbList.foreach { dbI =>
      if (dbI.Id == id)
        if (dbI.DbName.contains("Test"))
          println(dbI.DbName + " - " + dbI.Name)
          else BadRequest("Not allowed")
      else
        BadRequest("ID not found")
    }

id 是保存用户输入的 ID 的变量。有人可以告诉我为什么会出现错误以及如何解决吗?谢谢。

注意:请使用 import org.json4s.JsonAST 或 import play.api.libs.json

【问题讨论】:

    标签: json scala httpclient swagger scalatra


    【解决方案1】:

    已经得到了答案。所以我就是这样做的:

    case class databaseInfo(Id: String, DbName: String, Name: String)
    class dbInfo{
    def CheckDb(id: String): Option[String] = {
        val httpClient = HttpClients.createDefault()
        val httpResponse = httpClient.execute(new HttpGet("http://example.com"))
        val content = fromInputStream(httpResponse.getEntity.getContent()).getLines().mkString
    
        val envItems = (parse(content) \\ "items").children
        for (items <- envItems) {
          val dbItems = items.extract[databaseInfo]
          if (dbItems.EnvId == Some(id)) {
            if (equalsIgnoreCase(dbItems.DbName.mkString, "Test")) //do something
            else //do something
          }
        }
        None
      }
    }
    

    【讨论】:

      【解决方案2】:

      这是一种使用circe 的方法。您可以使用光标导航 JSON,并使用 Decoder[A] 类型类解码为 Environment 列表。请注意,您使用的是 Either[Failure, A] 值。

      import io.circe._
      
      case class Environment(id: String, dbName: String, name: String)
      
      implicit val environmentDecoder: Decoder[Environment] = Decoder.instance[Environment] {
        json =>
          for {
            id <- json.downField("Id").as[String]
            dbName <- json.downField("DbName").as[String]
            name <- json.downField("Name").as[String]
          } yield {
            Environment(id, dbName, name)
          }
      }
      
      // alternatively:
      // implicit val environmentDecoder: Decoder[Environment] =
      //   Decoder.forProduct3[String, String, String, Environment]("Id", "DbName", "Name")(Environment.apply)
      
      
      val text =
        """{
          |  "count": 3,
          |  "items": [{
          |    "Id": "fd0a9e5a",
          |    "DbName": "Xterior Prod",
          |    "Name": "XP"
          |  }, {
          |    "Id": "4158a1a6",
          |    "DbName": "Invidibi Pappear",
          |    "Name": "ISP"
          |  }, {
          |    "Id": "7e0c57046d3f",
          |    "DbName": "Multi Match Test",
          |    "Name": "MMP"
          |  }]
          |}
        """.stripMargin
      
      val json = parser.parse(text).fold(_ => ???, json => json)
      
      
      val res: Either[DecodingFailure, List[Environment]] = json.hcursor.downField("items").as[List[Environment]]
      
      
      println(res)
      // Right(List(Environment(fd0a9e5a,Xterior Prod,XP), Environment(4158a1a6,Invidibi Pappear,ISP), Environment(7e0c57046d3f,Multi Match Test,MMP)))
      
      
      // or simply
      // val res2 = parser.parse(text).right
      //   .flatMap(_.hcursor.downField("items").as[List[Environment]])
      

      你也可以使用http4s'http4s-blaze-clienthttp4s-circe来做HTTP请求:

      import org.http4s._
      import org.http4s.circe._
      import scalaz.concurrent._
      
      val client = org.http4s.client.blaze.defaultClient
      
      val fetchEnvironments: Task[List[Environment]] =
        client.fetchAs[Json](Request(Method.GET, Uri.uri("http://example.com")))
          .flatMap { json =>
            json.hcursor.downField("items").as[List[Environment]].fold(
              failure => Task.fail(failure),
              xs => Task.now(xs)
            )
          }
      
      val xs = fetchEnvironments.unsafePerformSync
      

      【讨论】:

      • 嗨,有没有办法使用 json4s 或 play 来实现这个?这些已经是 json 在当前项目中实现的方式,我更喜欢使用这些相同的库来保持一致性。
      猜你喜欢
      • 2017-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-19
      • 1970-01-01
      • 1970-01-01
      • 2020-07-05
      相关资源
      最近更新 更多