繁体   English   中英

play-json:如何使用Reads [T]获取“动态”键的值?

[英]play-json: how to get value of “dynamic” key using Reads[T]?

我有一个SeqJsValue元素。 每个元素代表具有两个字段的以下JSON结构:

{
  "name": "xy"
  "key ∈ {A,B,C}": ["// some values in an array"]
}

这意味着我知道第一个字段的键(总是“ name”),但不知道数组的键,因为它是“ dynamic”的。 但是: 可能的键是已知的,可以是“ A”,“ B”或“ C”。

我想做的是将每个这些JsValue对象映射到case类:

case class Element(name: String, values: Seq[String])

如您所见,动态密钥的名称甚至都不重要。 我只想获取与其关联的数组。

但是:如果键不同,如何使用Reads[T]获取数组?

implicit val reads: Reads[Element] = (
  (__ \ "name").read[String] and
  (__ \ "???").read[Seq[String]]
)(Element.apply _)

还是必须“手动”完成,如果是,怎么做?

您可以使用orElse方法

case class Element(name: String, values: Seq[String])
object Element {
  implicit val reads: Reads[Element] = (
  (__ \ "name").read[String] and
  (__ \ "a").read[Seq[String]]
    .orElse((__ \ "b").read[Seq[String]])
    .orElse((__ \ "c").read[Seq[String]])
  )(Element.apply _)
}

如其他答案所述, orElse可以在这里工作,但是如果您希望获得更大的灵活性,则可以始终编写类似返回“ Reads的方法来查找满足某些谓词的键的方法:

import play.api.libs.json._

def findByKey[A: Reads](p: String => Boolean): Reads[A] = Reads[A] {
  case JsObject(fields) => fields.find(kv => p(kv._1)).map(
    _._2.validate[A]
  ).getOrElse(JsError("No valid field key"))
  case _ => JsError("Not an object")
}

接着:

import play.api.libs.functional.syntax._

case class Element(name: String, values: Seq[String])

object Element {
  implicit val reads: Reads[Element] = (
    (__ \ "name").read[String] and findByKey[Seq[String]](Set("A", "B", "C"))
  )(Element.apply _)
}

最后:

scala> Json.parse("""{ "name": "foo", "A": ["bar", "baz"] }""").asOpt[Element]
res0: Option[Element] = Some(Element(foo,List(bar, baz)))

scala> Json.parse("""{ "name": "foo", "A": [1, 2] }""").asOpt[Element]
res1: Option[Element] = None

您选择哪种方法取决于您的口味,并且可能部分取决于更通用的findByKey在其他情况下是否对您有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM