【问题标题】:How to parse JSON data in Scala?如何在 Scala 中解析 JSON 数据?
【发布时间】:2020-12-18 00:16:15
【问题描述】:

我是 Scala 新手。我想在 scala 中解析 JSON 数据。

我想循环这些数据,并在每次迭代中从值中提取 id,v,qt 的数据

我正在使用下面的代码将其解析为 JSON

import scala.util.parsing.json._

val data =
  """
{
  "timestamp":
  1518501114949
  , "values":
  [
  {
    "id":
    "abc"
    , "v":
    0
    , "q":
    true
    , "t":
    1518501114487
  }
  ,
  {
    "id":
    "xyz"
    , "v":
    15
    , "q":
    true
    , "t":
    1518501114494
  }
  ]
}
"""

val parsed = JSON.parseFull(data)

我得到如下输出

 Some(Map(timestamp -> 1.518501114949E12, values -> List(Map(id -> abc, v -> 0.0, q -> true, t -> 1.518501114487E12), Map(id -> xyz, v -> 15.0, q -> true, t -> 1.518501114494E12), Map(id -> klm, v -> 12.6999998, q -> true, t -> 1.518501114487E12), Map(id -> 901.Hotmelt.PSA.0759_PSAM01_Vac, v -> 1.0, q -> true, t -> 1.518501114494E12))))

但我不知道如何循环并获取之后的所有值

我不明白为什么时间戳被转换为 E12 值

【问题讨论】:

标签: scala spark-streaming


【解决方案1】:

问题是 parseFull 返回一个带有 Any 内部的 Option,所以你首先需要摆脱它:

使用下面的代码,您将保留这些值:

val listAsAny = parsed match {
  case Some(e:Map[Any,Any]) => e("values")
  case None => println("Failed.")
}

但它们仍然是 Any,因此您可以将其转换如下:

val values = listAsAny.asInstanceOf[List[Map[String, Any]]]

现在 values 是具有以下值的映射列表,您可以像使用常规列表一样获取其中的值

List(Map(id -> abc, v -> 0.0, q -> true, t -> 1.518501114487E12), Map(id -> xyz, v -> 15.0, q -> true, t -> 1.518501114494E12))

例如,要检索您可以执行的 id:

values.map(_("id"))

结果将是:

List(abc, xyz)

【讨论】:

  • 除了json.parseFull()还有其他解析数据的方法
  • 以及为什么时间戳被转换为 E12
  • 因为它认为它是一个数字。检查这个答案,它可能会帮助stackoverflow.com/questions/4170949/…
  • 作为临时解决方案,您可以按如下方式检索您的时间戳: values.map(_("t").toString.replaceAll("\\.", "").replaceAll("E12 ", ""))
  • @SCouto 不,看在上帝的份上,不要使用字符串替换来操作数字!只需使用 .toLong 将其转换为 long。无论如何,这个公认的答案并没有解决这个问题,JSON.parseFull 函数出于某种神秘的原因将所有数字都变成了double,这在大整数的情况下很愚蠢,在那里人们很容易失去精度
【解决方案2】:

upickle 库提供强大、优雅的解决方案。

val parsed = ujson.read(data)
parsed("values").arr.map(_("id").str) // ArrayBuffer("abc", "xyz")

有关为什么 upickle / ujson 是解析 JSON 的最佳 Scala 库的更详细讨论,请参阅 here

【讨论】:

  • 有什么方法可以用来检查架构和数据类型?
【解决方案3】:

关于你的第二个问题

我不明白为什么时间戳被转换为 E12 值

这个特殊的 JSON 解析器将所有数字视为 Double 分数,这就是为什么您会得到分数 × 10¹²(E12 后缀)的科学记数法。 here 的答案是关于如何更改此解析器对数字的默认行为,即可以实现自己的解析器,该解析器将返回 Long 而不是默认的 Double

如果你有大整数时间戳来解析更有意义,因为你很容易开始失去精度(如果超过 2^51 ~= 4,5×10¹⁵,时间戳将被四舍五入,这是 Double 类型小数的边界部分精度)。但是,在您的情况下,像 1518501114949 这样的数字要小 100 倍,因此仍有一些安全余量,并且可能使用 .toLong 方法将生成的 Double 转换为 Long 就足够了。

【讨论】:

    猜你喜欢
    • 2018-12-09
    • 1970-01-01
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    • 2019-08-15
    • 2016-04-11
    • 2021-10-28
    • 1970-01-01
    相关资源
    最近更新 更多