Как разобрать строку Json, полученную от HTTP, и перебрать значения

Я использую Scala и Swagger, и мне нужна помощь, чтобы понять, как перебирать значения в json и использовать эти значения для проверки и других целей.

Строка json, которая возвращается после HTTP-запроса на получение, выглядит следующим образом:

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

Мой пользовательский интерфейс позволяет пользователю вводить идентификатор. Что мне нужно сделать, так это просмотреть значение Json, возвращенное из API, и найти тот, который соответствует введенному идентификатору. Как только я найду совпадение, я должен проверить, есть ли в базе данных ключевое слово «Test». Если это так, мне нужно будет показать DbName и короткое имя.

Я нашел здесь руководство (например, Foreach с массивами JSON в Play2 и 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 — это переменная, которая содержит введенный пользователем идентификатор. Может ли кто-нибудь сказать мне, почему ошибка и как ее исправить? Спасибо.

примечание: используйте import org.json4s.JsonAST или import play.api.libs.json


person oneDerer    schedule 20.01.2017    source источник


Ответы (2)


уже получил ответ. так вот как я это сделал:

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
  }
}
person oneDerer    schedule 25.01.2017

Вот подход, использующий circe. Вы можете перемещаться по JSON с помощью курсора и декодировать список Environment, используя класс типов Decoder[A]. Обратите внимание, что вы работаете со значениями 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]])

Вы также можете использовать http://http4s.org/ http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22http4s-blaze-client_2.12%22 и http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22http4s-circe_2.12%22 для выполнения 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
person Stefan Ollinger    schedule 20.01.2017
comment
привет, есть ли способ реализовать это с помощью json4s или play? это уже то, как json реализован в текущем проекте, и я бы предпочел использовать эти же библиотеки для согласованности. - person oneDerer; 23.01.2017