如何在 scala 中为 play framework 2.2 解析 json 列表或数组
How to parse json list or array in scala for play framework 2.2
我正在编写一些 RESTful API 测试用例,并且对使用 scala playframwork 的经验很少。
这是我的例子JSON。
[ {
"size" : "5082",
"date-created" : "Wed Nov 19 17:10:39 CST 2014",
"id" : "546d236fb84e894eefd8f769",
"content-type" : "image/png",
"filename" : "chrome-on-windows.PNG"
}, {
"size" : "15684",
"date-created" : "Mon Jan 12 17:28:02 CST 2015",
"id" : "54b4588266b3d11b1c1e9db6",
"content-type" : "image/png",
"filename" : "logos_ncsa.png"
}, {
"size" : "1267871",
"date-created" : "Mon Jan 12 17:28:03 CST 2015",
"id" : "54b4588366b3d11b1c1e9dba",
"content-type" : "image/jpg",
"filename" : "morrowplots.jpg"
} ]
如您所见,我有 list/Array 个 JSON 项。我想获取 "morrowplots.jpg" 文件的 ID 并将其存储到一个变量中以用于成功的 API 调用。
所以我将代码设置为如下所示。下面代码中的结果变量是您在上面看到的 JSON 字符串。
case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)
implicit val fileReads: Reads[FileName] = (
(__ \ "size").read[String] and
(__ \ "datecreated").read[String] and
(__ \ "id").read[String] and
(__ \ "content-type").read[String] and
(__ \ "filename").read[String]
)(FileName.apply _)
val json: JsValue = Json.parse(contentAsString(result))
val nameResult: JsResult[FileName] = json.validate[FileName](fileReads)
info("Right after validate")
nameResult match {
case s: JsSuccess[FileName] => {
val testfile: FileName = s.get
// Do something with testfile
info("Success")
}
case e: JsError => {
info("Error")
info("Errors: " + JsError.toFlatJson(e).toString())
}
}
这给了我以下错误。
[info] + Errors:
{"objsize":[{"msg":"error.path.result.multiple","args":[]}],"objfilename":[{"msg":"error.path.resul
t.multiple","args":[]}],"objid":[{"msg":"error.path.result.multiple","args":[]}],"objcontent-type":[{"msg":"error.path
.result.multiple","args":[]}],"obj*datecreated":[{"msg":"error.path.missing","args":[]}]}
那么如何解决这个 List/Array 问题以及如何通过文件名搜索以获取 ID?
提前致谢。
我不是 Play 方面的专家,所以这可能不是惯用的,但它应该可以解决您的问题。首先,你的 json 是 date-created
而你的 scala 期望 datecreated
。其次,您的 Reads
应该只使用一个斜杠。接下来,你需要 运行 validate
对抗 List[FileName]
.
关于文件名搜索,您现在可以从 JsSuccess
和 运行 中提取列表 filter
。
最终代码看起来像这样
case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)
implicit val fileReads: Reads[FileName] = (
(__ \ "size").read[String] and
(__ \ "date-created").read[String] and
(__ \ "id").read[String] and
(__ \ "content-type").read[String] and
(__ \ "filename").read[String]
)(FileName)
val json: JsValue = Json.parse(contentAsString(result))
val nameResult = json.validate[List[FileName]]
val list = nameResult match {
case JsSuccess(list : List[FileName], _) => list
case e: JsError => {
info("Errors: " + JsError.toFlatJson(e).toString())
List()
}
}
list filter(_.filename contains "morrow")
首先,您可能决定使用内置 json 实用程序而不是执行手动解析。
case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)
object FileName {
implicit val formatFileName = Json.format[FileName]
}
至此,您已拥有解析基本 json 对象所需的一切。编译器将使用宏 (IIRC) 生成与您手写的代码等效的代码。由于您的字段没有外来验证,因此不需要手动编写读取和写入 类。
那你可以这样读:
def readString(str: String) = {
val jsr: JsResult[Seq[FileName]] = Json.parse(str).validate[Seq[FileName]]
jsr.fold(
error => {
???
},
success => {
???
}
)
}
jsr在这里是一个JsResult。它可以是 JsSuccess 或 JsError。
也要注意完整的类型。由于您有一个数组作为输入,因此您应该将输出放在一个集合中,例如一个 Seq。
您可以在 JsResult 上弃牌。 fold 需要两个函数。一种是错误情况,它的类型为 Seq[(JsPath, Seq[ValidationError])] => X,其中 X 是函数的 return 类型。它向您展示了所有阻止您的 json 被翻译成 Seq[FileName].
的问题
另一个是成功案例。它的类型为 Seq[FileName] => X,与之前的 X 相同。
您现在可以决定在这两个函数中放入什么。
正如贾斯汀所指出的,你也可以用火柴来写。它可能更容易,即使功能较少:
def readString(str: String) = {
val jsr: JsResult[Seq[FileName]] = Json.parse(str).validate[Seq[FileName]]
jsr match {
case JsResult(seq) => ???
case e: JsError => ???
}
}
我正在编写一些 RESTful API 测试用例,并且对使用 scala playframwork 的经验很少。
这是我的例子JSON。
[ {
"size" : "5082",
"date-created" : "Wed Nov 19 17:10:39 CST 2014",
"id" : "546d236fb84e894eefd8f769",
"content-type" : "image/png",
"filename" : "chrome-on-windows.PNG"
}, {
"size" : "15684",
"date-created" : "Mon Jan 12 17:28:02 CST 2015",
"id" : "54b4588266b3d11b1c1e9db6",
"content-type" : "image/png",
"filename" : "logos_ncsa.png"
}, {
"size" : "1267871",
"date-created" : "Mon Jan 12 17:28:03 CST 2015",
"id" : "54b4588366b3d11b1c1e9dba",
"content-type" : "image/jpg",
"filename" : "morrowplots.jpg"
} ]
如您所见,我有 list/Array 个 JSON 项。我想获取 "morrowplots.jpg" 文件的 ID 并将其存储到一个变量中以用于成功的 API 调用。
所以我将代码设置为如下所示。下面代码中的结果变量是您在上面看到的 JSON 字符串。
case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)
implicit val fileReads: Reads[FileName] = (
(__ \ "size").read[String] and
(__ \ "datecreated").read[String] and
(__ \ "id").read[String] and
(__ \ "content-type").read[String] and
(__ \ "filename").read[String]
)(FileName.apply _)
val json: JsValue = Json.parse(contentAsString(result))
val nameResult: JsResult[FileName] = json.validate[FileName](fileReads)
info("Right after validate")
nameResult match {
case s: JsSuccess[FileName] => {
val testfile: FileName = s.get
// Do something with testfile
info("Success")
}
case e: JsError => {
info("Error")
info("Errors: " + JsError.toFlatJson(e).toString())
}
}
这给了我以下错误。
[info] + Errors: {"objsize":[{"msg":"error.path.result.multiple","args":[]}],"objfilename":[{"msg":"error.path.resul t.multiple","args":[]}],"objid":[{"msg":"error.path.result.multiple","args":[]}],"objcontent-type":[{"msg":"error.path .result.multiple","args":[]}],"obj*datecreated":[{"msg":"error.path.missing","args":[]}]}
那么如何解决这个 List/Array 问题以及如何通过文件名搜索以获取 ID?
提前致谢。
我不是 Play 方面的专家,所以这可能不是惯用的,但它应该可以解决您的问题。首先,你的 json 是 date-created
而你的 scala 期望 datecreated
。其次,您的 Reads
应该只使用一个斜杠。接下来,你需要 运行 validate
对抗 List[FileName]
.
关于文件名搜索,您现在可以从 JsSuccess
和 运行 中提取列表 filter
。
最终代码看起来像这样
case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)
implicit val fileReads: Reads[FileName] = (
(__ \ "size").read[String] and
(__ \ "date-created").read[String] and
(__ \ "id").read[String] and
(__ \ "content-type").read[String] and
(__ \ "filename").read[String]
)(FileName)
val json: JsValue = Json.parse(contentAsString(result))
val nameResult = json.validate[List[FileName]]
val list = nameResult match {
case JsSuccess(list : List[FileName], _) => list
case e: JsError => {
info("Errors: " + JsError.toFlatJson(e).toString())
List()
}
}
list filter(_.filename contains "morrow")
首先,您可能决定使用内置 json 实用程序而不是执行手动解析。
case class FileName(size: String, datecreated: String, id: String, contenttype: String, filename: String)
object FileName {
implicit val formatFileName = Json.format[FileName]
}
至此,您已拥有解析基本 json 对象所需的一切。编译器将使用宏 (IIRC) 生成与您手写的代码等效的代码。由于您的字段没有外来验证,因此不需要手动编写读取和写入 类。
那你可以这样读:
def readString(str: String) = {
val jsr: JsResult[Seq[FileName]] = Json.parse(str).validate[Seq[FileName]]
jsr.fold(
error => {
???
},
success => {
???
}
)
}
jsr在这里是一个JsResult。它可以是 JsSuccess 或 JsError。
也要注意完整的类型。由于您有一个数组作为输入,因此您应该将输出放在一个集合中,例如一个 Seq。
您可以在 JsResult 上弃牌。 fold 需要两个函数。一种是错误情况,它的类型为 Seq[(JsPath, Seq[ValidationError])] => X,其中 X 是函数的 return 类型。它向您展示了所有阻止您的 json 被翻译成 Seq[FileName].
的问题另一个是成功案例。它的类型为 Seq[FileName] => X,与之前的 X 相同。
您现在可以决定在这两个函数中放入什么。
正如贾斯汀所指出的,你也可以用火柴来写。它可能更容易,即使功能较少:
def readString(str: String) = {
val jsr: JsResult[Seq[FileName]] = Json.parse(str).validate[Seq[FileName]]
jsr match {
case JsResult(seq) => ???
case e: JsError => ???
}
}