如何解析Scala中的JSON数据?

时间:2018-02-13 11:34:04

标签: scala spark-streaming

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

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

提取t

我使用下面的代码将其解析为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值

3 个答案:

答案 0 :(得分:2)

问题是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]]]

现在,值是具有以下值的地图列表,您可以像使用常规列表一样获取内部值

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)

答案 1 :(得分:0)

关于第二个问题

  

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

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

如果要解析较大的整数时间戳,则更有意义,因为您可以轻松地开始降低精度(如果超出2 ^ 51〜= 4,5×10¹⁵,即Double的边界,则时间戳将被舍入。类型小数部分精度)。但是,在您的情况下,例如1518501114949的数字要小100倍,因此仍有一定的安全余量,并且可能使用Double方法将生成的Long转换为.toLong足够了。

答案 2 :(得分:0)

upickle库提供了健壮,优雅的解决方案。

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

请参见here,详细了解为什么upickle / ujson是解析JSON的最佳Scala库。