【问题标题】:Strange behaviour of Scala in pattern matching in case of JSON fields (json4s framework)在 JSON 字段(json4s 框架)的情况下,Scala 在模式匹配中的奇怪行为
【发布时间】:2015-06-29 17:48:45
【问题描述】:

我正在尝试遍历 JSON 并提取有关字段中对象类型的信息:

import org.json4s._
import org.json4s.JsonAST.{JArray, JString, JObject, JInt, JBool, JDouble}
import org.json4s.JsonDSL._
import org.json4s.native.JsonMethods._

def guessTypes(example: JValue): JObject = example match {
case JObject(lst) => JObject(lst.map {
  case (f, JObject(nested)) => JField(f, ("type" -> "object") ~ ("properties" -> guessTypes(nested)))
  case (f, JString(s)) => JField(f, "type" -> "string")
  case (f, JInt(num)) => JField(f, "type" -> "integer")
  case (f, JDouble(double)) => JField(f, "type" -> "double")
  case (f, JBool(b)) => JField(f, "type" -> "bool")
  case (f, JArray(jarray: List[JInt])) => JField(f, ("type" -> "array") ~ ("items" -> "integer"))
  case (f, JArray(jarray: List[JString])) => JField(f, ("type" -> "array") ~ ("items" -> "string"))
  case (f, JArray(jarray: List[JObject])) => JField(f, ("type" -> "array") ~ ("items" -> "object")) ~ ("properties" -> jarray.map{ x => guessTypes(x)}))
})}

如果发生:

def example = """
    |{
    |  "partners_data": [
    |    {
    |      "info": {
    |        "label": "partner45"
    |      },
    |      "partner_id": "partner45",
    |      "data": {
    |        "field": 24
    |      }
    |    }
    |  ],
    |  "name": "*****(",
    |  "location": [
    |    1,
    |    2
    |  ],
    |  "is_mapped": false
    |}
  """.stripMargin

得到结果:

{"data":{"type":"array","items":"object"},"name":{"type":"string"},"location":{"type":"数组","items":"object"},"is_mapped":{"type":"bool"}}

这不是合适的结果,因为对于“位置”中的关键“项目”,预期值为“整数”。

看起来 Scala 无法区分 JArrays 中除了 JValue 之外的任何其他内容。如果我替换

case (f, JArray(jarray: List[JInt]))

通过最后一个字符串,对于“location”中的key“items”,会得到“object”的值,但是对于其他字段的值会是错误的。

我怎样才能绕过 scala 模式匹配和 json4s 框架的这种特殊性?

【问题讨论】:

  • 你用的是什么版本的Json4s?使用 "org.json4s" %% "json4s-native" % "3.2.2" 时,我得到了正确的类型。
  • 我正在使用"org.json4s" %% "json4s-native" % "3.2.11"。在我们的例子中,没有机会使用早期版本的 json4s。

标签: scala scala-2.10 json4s


【解决方案1】:

由于 JVM 上的 type erasure,最后三个模式基本相同。

由于 JSON 数组可以包含多种(Scala/Java/...)类型,因此很难匹配列表元素的类型。

您只能检查数组的第一项:

case (f, JArray(JString(_) :: tail)) => 
  JField(f, ("type" -> "array") ~ ("items" -> "string"))
case (f, JArray(jarray @ JObject(_) :: tail)) => 
  JField(f, ("type" -> "array") ~ ("items" -> "object") ~ ("properties" -> jarray.map(guessTypes)))

或者检查数组中的每一项:

case (f, JArray(list : List[JValue])) if list forall { case JInt(_) => true; case _ => false } => 
  JField(f, ("type" -> "array") ~ ("items" -> "integer"))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 2019-12-30
    • 2017-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多