如何在Scala中解析JSON数据?

6

我是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类解析JSON?的重复问题。 - SCouto
ujson 库是解析 JSON 的现代、最佳解决方案。请查看我的答案以获取更多详细信息。 - Powers
3个回答

5
问题在于parseFull返回一个内部有任意类型的选项,因此您需要首先摆脱它:
使用下面的代码,您将保留值:
val listAsAny = parsed match {
  case Some(e:Map[Any,Any]) => e("values")
  case None => println("Failed.")
}

但它们仍然是任意的,因此您可以按照以下方式进行转换:

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()之外,还有其他解析数据的方法吗? - Tarun Khaneja
为什么时间戳被转换为 E12? - Tarun Khaneja
因为它被视为一个数字。请检查此答案,它可能会有所帮助。https://dev59.com/82855IYBdhLWcg3wvXDd - SCouto
作为一个临时解决方案,你可以按以下方式检索你的时间戳:values.map(_("t").toString.replaceAll("\.", "").replaceAll("E12", "")) - SCouto
@SCouto 不要使用字符串替换来操作数字,直接使用 .toLong 将其转换为 long 类型。另外,这个被接受的答案并没有解决问题。由于某些神秘的原因,JSON.parseFull 函数会将所有数字转换为 double,这在大整数的情况下是愚蠢的,因为会丧失精度。 - Marcin Tarsier

1

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

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

点击这里,了解更详细的讨论,为什么upickle / ujson是解析JSON最好的Scala库。


有没有办法用它来检查模式和数据类型? - whatsinthename

0

关于您的第二个问题

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

这个特定的JSON解析器将所有数字都视为Double小数,因此您会得到带有分数×10¹²(E12后缀)的科学计数法。这里有一个答案,介绍如何更改此解析器对数字的默认行为,即可以实现自己的解析器,该解析器将返回Long而不是默认的Double

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接