4

我有一个带有一些字段的 json,我想检查其中一些是否存在。我正在提取值并针对 JNothing 进行测试,但它太冗长了:

val json: JValue = ...

val jsonIsType1 = (json \ "field1") != JNothing && (json \ "field2") != JNothing

是否有更紧凑的方法来使用 json4s/lift-json 检查 json 对象中是否存在字段?理想情况下是这样的:

val jsonIsType1 = json.has("field1") && json.has("field2")
4

2 回答 2

20

JValue 没有“has”运算符,但 Scala 的隐式功能允许您轻松添加该功能。

这是一个例子:

implicit class JValueExtended(value: JValue) {
  def has(childString: String): Boolean = {
    (value \ childString) != JNothing
  }
}

使用示例:

scala> val json = Json.parse("""{"field1": "ok", "field2": "not ok"}""")

scala> json.has("field1")
res10: Boolean = true
于 2014-02-09T23:18:34.697 回答
2

您还可以在 for comprehension 中组合多个读取/验证步骤。以下是两个函数,一个返回 an Option[_],一个返回 a Boolean。第一个允许也处理数据,而后者只进行验证。

import org.json4s.jackson.JsonMethods._

val text =
  """
    |{
    |  "foo": "bar",
    |  "baz": "fnord",
    |  "qux": true
    |}
  """.stripMargin

val json = parse(text)

def readFoo(x: JValue): Option[(String, String, Boolean)] = for {
  JObject(_) <- x.toOption
  JString(foo) <- (x \ "foo").toOption
  JString(baz) <- (x \ "baz").toOption
  JBool(qux) <- (x \ "qux").toOption
  if (qux == true)
} yield (foo, baz, qux)

def validateOnly(x: JValue): Boolean = (for {
  JObject(_) <- x.toOption
  JString(foo) <- (x \ "foo").toOption
  JString(baz) <- (x \ "baz").toOption
  JBool(qux) <- (x \ "qux").toOption
  if (qux == true)
} yield true) getOrElse false

println(readFoo(json))            // Some((bar,fnord,true))
println(readFoo(json).isDefined)  // true
println(validateOnly(json))       // true
于 2014-02-10T14:02:24.573 回答