Spray-Json:如何解析 Json 数组?
Posted
技术标签:
【中文标题】Spray-Json:如何解析 Json 数组?【英文标题】:Spray-Json: How to parse a Json Array? 【发布时间】:2013-12-29 16:21:04 【问题描述】:我是 Spray-Json API 的新手,我正在尝试解析来自 Docker REST API 的 Json 响应。
There 是使用 Spray-Json 解析此 Google Map Json 响应的一个简洁示例:
"results" : [
"elevation" : 8815.7158203125,
"location" :
"lat" : 27.988056,
"lng" : 86.92527800000001
,
"resolution" : 152.7032318115234
],
"status" : "OK"
在上面的例子中,最外层是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
,
... ,
...
]
这是我改编自 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()
以下是我得到的异常 (Object expected
):
spray.httpx.PipelineException: MalformedContent(Object expected,Some(spray.json.DeserializationException: Object expected))
我当然错过了一些明显的东西,但是 如何使用 Spray-Json 解析 Json 数组?
另外,有没有一种简单的方法可以做到这一点,而不必处理自定义 JsonFormat 或 RootJsonFormat?
【问题讨论】:
就个人而言,我会切换到 Lift-json :) 【参考方案1】:通过unmarshal[DockerApiResult[Container]]
,您是在告诉 spray-json 您希望格式是表单的 json 对象:
results: [...]
因为case class DockerApiResult[T](results: List[T])
被定义为具有包含列表的单个结果字段的对象。
相反,您需要这样做:
unmarshal[List[Container]]
然后直接对生成的列表进行操作(或者通过spray-json解析后包装在DockerApiResult中)。
如果你想将 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
【讨论】:
谢谢!有效。我实际上尝试了unmarshal[List[Container]]
,但我对为空的端口属性感到困惑,我不得不用Option
包装它。无论如何,很好的答案,正是我想要的;)【参考方案2】:
对此进行了一些斗争,并找到了一种使用喷雾从 json 解析字符串转换为 JsArray 的方法:
import spray.json._ //parseJson
val kkkk =
"""
|["a": "1", "b": "2"]
""".stripMargin.parseJson.asInstanceOf[JsArray]
【讨论】:
这是否保持元素的顺序?以上是关于Spray-Json:如何解析 Json 数组?的主要内容,如果未能解决你的问题,请参考以下文章
当 json 元素不存在时,如何设置 spray-json 以设置 null?