scala Spray-Json:如何解析 Json 数组?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20523462/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:55:55  来源:igfitidea点击:

Spray-Json: How to parse a Json Array?

jsonscalaspray-json

提问by abronan

I'm new to the Spray-Json API and I'm trying to parse a Json response from the Docker REST API.

我是 Spray-Json API 的新手,我正在尝试解析来自 Docker REST API 的 Json 响应。

Thereis a clean example of the usage of Spray-Json to parse this Google Map Json response :

一个使用 Spray-Json 来解析此 Google Map Json 响应的清晰示例:

{
   "results" : [
      {
         "elevation" : 8815.7158203125,
         "location" : {
            "lat" : 27.988056,
            "lng" : 86.92527800000001
         },
         "resolution" : 152.7032318115234
      }
   ],
   "status" : "OK"
}

In the above example the outermost level is an Object. However, I need to directly parse a Json response whose outermost level is an Arraycomposed of containers information as shown below :

在上面的例子中,最外层是一个Object. 但是,我需要直接解析一个 Json 响应,其最外层是Array由容器信息组成的,如下所示:

[
     {
       "Id": "8dfafdbc3a40",
       "Image": "base:latest",
       "Command": "echo 1",
       "Created": 1367854155,
       "Status": "Exit 0",
       "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}],
       "SizeRw":12288,
       "SizeRootFs":0
     },
     { ... },
     { ... }
]

Here is a code that I adapted from the Google map example :

这是我改编自 Google 地图示例的代码:

package main

import ...

case class Container(id: String, image: String, command: String, created: Long, status: String, ports: List[Port], sizeRW: Long, sizeRootFs: Long)
case class Port(privatePort: Long, publicPort: Long, portType: String)
case class DockerApiResult[T](results: List[T])

object ContainerListJsonProtocol extends DefaultJsonProtocol {
  implicit val portFormat = jsonFormat3(Port)
  implicit val containerFormat = jsonFormat8(Container)
  implicit def dockerApiResultFormat[T :JsonFormat] = jsonFormat1(DockerApiResult.apply[T])
}

object Main extends App {

  implicit val system = ActorSystem("simple-spray-client")
  import system.dispatcher // execution context for futures below
  val log = Logging(system, getClass)

  log.info("Requesting containers info...")

  import ContainerListJsonProtocol._
  import SprayJsonSupport._
  val pipeline = sendReceive ~> unmarshal[DockerApiResult[Container]]

  val responseFuture = pipeline {
    Get("http://<ip-address>:4243/containers/json")
  }

  responseFuture onComplete {
    case Success(DockerApiResult(Container(_,_,_,_,_,_,_,_) :: _)) =>
      log.info("Id of the found image: {} ")
      shutdown()

    case Success(somethingUnexpected) =>
      log.warning("The Docker API call was successful but returned something unexpected: '{}'.", somethingUnexpected)
      shutdown()

    case Failure(error) =>
      log.error(error, "Couldn't get containers information")
      shutdown()
  }

  def shutdown(): Unit = {
    IO(Http).ask(Http.CloseAll)(1.second).await
    system.shutdown()
  }
}

And below is the exception I get (Object expected) :

下面是我得到的例外 ( Object expected):

spray.httpx.PipelineException: MalformedContent(Object expected,Some(spray.json.DeserializationException: Object expected))

I certainly miss something obvious but How to parse a Json Array using Spray-Json?

我当然想念一些明显的东西,但是如何使用 Spray-Json 解析 Json 数组?

Also, is there a simple way to do this without having to deal with custom JsonFormat or RootJsonFormat?

另外,是否有一种简单的方法可以做到这一点而不必处理自定义 JsonFormat 或 RootJsonFormat?

回答by kong

By doing unmarshal[DockerApiResult[Container]], you're telling spray-json that you expect the format to be a json object of the form:

通过这样做unmarshal[DockerApiResult[Container]],您告诉 Spray-json 您希望格式是以下形式的 json 对象:

{ results: [...] }

since case class DockerApiResult[T](results: List[T])is defined as an object with a single results field containing a list.

因为case class DockerApiResult[T](results: List[T])被定义为具有包含列表的单个结果字段的对象。

Instead you need to do:

相反,您需要执行以下操作:

unmarshal[List[Container]]

and then operate on the resulting list directly (or wrap it in a DockerApiResult after it has been parsed by spray-json).

然后直接对结果列表进行操作(或者在被spray-json解析后包装在一个DockerApiResult中)。

If you want spray-json to unmarshal directly into a DockerApiResult, you can write a JsonFormat with something like:

如果您希望 Spray-json 直接解组到 DockerApiResult 中,您可以编写一个 JsonFormat ,如下所示:

implicit object DockerApiResultFormat extends RootJsonFormat[DockerApiResult] {
  def read(value: JsValue) = DockerApiResult(value.convertTo[List[Container]])
  def write(obj: DockerApiResult) = obj.results.toJson
}

回答by Marco Aurelio

fought with this a little and found a way to convert to JsArray from a json parsed string using spray:

对此进行了一些斗争,并找到了一种使用喷雾从 json 解析字符串转换为 JsArray 的方法:

import spray.json._   //parseJson
val kkkk =
  """
    |[{"a": "1"}, {"b": "2"}]
  """.stripMargin.parseJson.asInstanceOf[JsArray]